Skip to content

Commit

Permalink
Merge pull request #1142 from dolthub/james/json_table
Browse files Browse the repository at this point in the history
adding `json_table` function
  • Loading branch information
jycor authored Aug 16, 2022
2 parents 5570996 + fd72a9e commit ad73827
Show file tree
Hide file tree
Showing 9 changed files with 393 additions and 9 deletions.
7 changes: 7 additions & 0 deletions enginetest/enginetests.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,13 @@ func TestJoinQueries(t *testing.T, harness Harness) {
}
}

func TestJSONTableQueries(t *testing.T, harness Harness) {
harness.Setup(setup.MydbData, setup.Pk_tablesData, setup.Json_table_tablesData)
for _, tt := range queries.JSONTableQueryTests {
TestQuery(t, harness, tt.Query, tt.Expected, tt.ExpectedColumns, nil)
}
}

// TestInfoSchemaPrepared runs tests of the information_schema database
func TestInfoSchemaPrepared(t *testing.T, harness Harness) {
harness.Setup(setup.MydbData, setup.MytableData, setup.Fk_tblData, setup.FooData)
Expand Down
5 changes: 5 additions & 0 deletions enginetest/memory_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ func TestJoinQueries(t *testing.T) {
enginetest.TestJoinQueries(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil))
}

// TestJSONQueries runs the canonical test queries against a single threaded index enabled harness.
func TestJSONTableQueries(t *testing.T) {
enginetest.TestJSONTableQueries(t, enginetest.NewMemoryHarness("simple", 1, testNumPartitions, true, nil))
}

// Convenience test for debugging a single query. Unskip and set to the desired query.
func TestSingleQuery(t *testing.T) {
t.Skip()
Expand Down
120 changes: 120 additions & 0 deletions enginetest/queries/json_table_queries.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright 2022 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package queries

import (
"github.com/dolthub/go-mysql-server/sql"
)

var JSONTableQueryTests = []QueryTest{
{
Query: "SELECT * FROM JSON_TABLE(NULL,'$[*]' COLUMNS(x int path '$.a')) as t;",
Expected: []sql.Row{},
},
{
Query: "SELECT * FROM JSON_TABLE('[{\"a\":1},{\"a\":2}]','$[*]' COLUMNS(x varchar(100) path '$.a')) as tt;",
Expected: []sql.Row{
{"1"},
{"2"},
},
},
{
Query: "SELECT * FROM JSON_TABLE('[{\"a\":1, \"b\":2},{\"a\":3, \"b\":4}]',\"$[*]\" COLUMNS(x int path '$.a', y int path '$.b')) as tt;",
Expected: []sql.Row{
{1, 2},
{3, 4},
},
},
{
Query: "SELECT * FROM JSON_TABLE('[{\"a\":1.5, \"b\":2.25},{\"a\":3.125, \"b\":4.0625}]','$[*]' COLUMNS(x float path '$.a', y float path '$.b')) as tt;",
Expected: []sql.Row{
{1.5, 2.25},
{3.125, 4.0625},
},
},
{
Query: "SELECT * FROM JSON_TABLE(concat('[{},','{}]'),'$[*]' COLUMNS(x varchar(100) path '$.a',y varchar(100) path '$.b')) as t;",
Expected: []sql.Row{
{nil, nil},
{nil, nil},
},
},
{
Query: "select * from JSON_TABLE('[{\"a\":1},{\"a\":2}]', '$[*]' COLUMNS(x int path '$.a')) as t1 join JSON_TABLE('[{\"a\":1},{\"a\":2}]', '$[*]' COLUMNS(x int path '$.a')) as t2;",
Expected: []sql.Row{
{1, 1},
{1, 2},
{2, 1},
{2, 2},
},
},
{
Query: "select * from JSON_TABLE('[{\"a\":1},{\"a\":2}]', '$[*]' COLUMNS(x int path '$.a')) as t1 join one_pk order by x;",
Expected: []sql.Row{
{1, 0, 0, 1, 2, 3, 4},
{1, 1, 10, 11, 12, 13, 14},
{1, 2, 20, 21, 22, 23, 24},
{1, 3, 30, 31, 32, 33, 34},
{2, 0, 0, 1, 2, 3, 4},
{2, 1, 10, 11, 12, 13, 14},
{2, 2, 20, 21, 22, 23, 24},
{2, 3, 30, 31, 32, 33, 34},
},
},
{
Query: "select * from one_pk join JSON_TABLE('[{\"a\":1},{\"a\":2}]', '$[*]' COLUMNS(x int path '$.a')) as t1 order by x;",
Expected: []sql.Row{
{0, 0, 1, 2, 3, 4, 1},
{1, 10, 11, 12, 13, 14, 1},
{2, 20, 21, 22, 23, 24, 1},
{3, 30, 31, 32, 33, 34, 1},
{0, 0, 1, 2, 3, 4, 2},
{1, 10, 11, 12, 13, 14, 2},
{2, 20, 21, 22, 23, 24, 2},
{3, 30, 31, 32, 33, 34, 2},
},
},
{
Query: "select * from JSON_TABLE('[{\"a\":1},{\"a\":2}]', '$[*]' COLUMNS(x int path '$.a')) as t1 union select * from JSON_TABLE('[{\"b\":3},{\"b\":4}]', '$[*]' COLUMNS(y int path '$.b')) as t2",
Expected: []sql.Row{
{1},
{2},
{3},
{4},
},
},
{
Query: "select * from one_pk where pk in (select x from JSON_TABLE('[{\"a\":1},{\"a\":2}]', '$[*]' COLUMNS(x int path '$.a')) as t)",
Expected: []sql.Row{
{1, 10, 11, 12, 13, 14},
{2, 20, 21, 22, 23, 24},
},
},
{
Query: "select * from JSON_TABLE('[{\"a\":1},{\"a\":2}]', '$[*]' COLUMNS(x int path '$.a')) t1 where x in (select y from JSON_TABLE('[{\"b\":1},{\"b\":100}]', '$[*]' COLUMNS(y int path '$.b')) as t2)",
Expected: []sql.Row{
{1},
},
},
{
Query: "SELECT * FROM JSON_TABLE((select t from json_table_tables),'$[*]' COLUMNS(i int path '$.a', j int path '$.b', k int path '$.c', l int path '$.d')) as tt;",
Expected: []sql.Row{
{1, nil, nil, nil},
{nil, 2, nil, nil},
{nil, nil, 3, nil},
{nil, nil, nil, 4},
},
},
}
11 changes: 11 additions & 0 deletions enginetest/scriptgen/setup/scripts/json_table_tables
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

exec
CREATE TABLE `json_table_tables` (
`t` varchar(100)
)
----

exec
insert into json_table_tables values
('[{"a": 1},{"b": 2},{"c": 3},{"d": 4}]');
----
5 changes: 5 additions & 0 deletions enginetest/scriptgen/setup/setup_data.sg.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/dolthub/go-mysql-server
require (
github.com/cespare/xxhash v1.1.0
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81
github.com/dolthub/vitess v0.0.0-20220815191244-a43b8493fb04
github.com/dolthub/vitess v0.0.0-20220815214835-68adfbec4880
github.com/go-kit/kit v0.10.0
github.com/go-sql-driver/mysql v1.6.0
github.com/gocraft/dbr/v2 v2.7.2
Expand Down
10 changes: 2 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,8 @@ github.com/dolthub/jsonpath v0.0.0-20210609232853-d49537a30474 h1:xTrR+l5l+1Lfq0
github.com/dolthub/jsonpath v0.0.0-20210609232853-d49537a30474/go.mod h1:kMz7uXOXq4qRriCEyZ/LUeTqraLJCjf0WVZcUi6TxUY=
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9XGFa6q5Ap4Z/OhNkAMBaK5YeuEzwJt+NZdhiE=
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY=
github.com/dolthub/vitess v0.0.0-20220809164912-4bb30c793f1b h1:KDimfMuvlB0be3XhBBBF5QWIJGzazleccRlHyf/dXX8=
github.com/dolthub/vitess v0.0.0-20220809164912-4bb30c793f1b/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs=
github.com/dolthub/vitess v0.0.0-20220810172629-f4bdb4a721c0 h1:u8yIimnhg5CHQZlBoJxfV+yezvNEmtgXUsmZvvlJ6uo=
github.com/dolthub/vitess v0.0.0-20220810172629-f4bdb4a721c0/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs=
github.com/dolthub/vitess v0.0.0-20220811180048-dec9dd483049 h1:rw68oRFvBt9QdaGrNCEr2TE5NCYax7JfytLQlGsvTg8=
github.com/dolthub/vitess v0.0.0-20220811180048-dec9dd483049/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs=
github.com/dolthub/vitess v0.0.0-20220815191244-a43b8493fb04 h1:apUYKsKc4DgjYkxV+ZfE/B4MdRXbiiwJh7hQ18FeAto=
github.com/dolthub/vitess v0.0.0-20220815191244-a43b8493fb04/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs=
github.com/dolthub/vitess v0.0.0-20220815214835-68adfbec4880 h1:f/t/cgRA43r71qqbQUpcd772hKRuK/m1Nz2fo7f/C7o=
github.com/dolthub/vitess v0.0.0-20220815214835-68adfbec4880/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
Expand Down
22 changes: 22 additions & 0 deletions sql/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2605,6 +2605,9 @@ func tableExprToTable(
case *sqlparser.JoinTableExpr:
return joinTableExpr(ctx, t)

case *sqlparser.JSONTableExpr:
return jsonTableExpr(ctx, t)

case *sqlparser.ParenTableExpr:
if len(t.Exprs) == 1 {
switch j := t.Exprs[0].(type) {
Expand Down Expand Up @@ -2661,6 +2664,25 @@ func joinTableExpr(ctx *sql.Context, t *sqlparser.JoinTableExpr) (sql.Node, erro
}
}

func jsonTableExpr(ctx *sql.Context, t *sqlparser.JSONTableExpr) (sql.Node, error) {
data, err := ExprToExpression(ctx, t.Data)
if err != nil {
return nil, err
}

paths := make([]string, len(t.Spec.Columns))
for i, col := range t.Spec.Columns {
paths[i] = col.Type.Path
}

sch, err := TableSpecToSchema(ctx, t.Spec)
if err != nil {
return nil, err
}

return plan.NewJSONTable(ctx, data, t.Path, paths, t.Alias.String(), sch)
}

func whereToFilter(ctx *sql.Context, w *sqlparser.Where, child sql.Node) (*plan.Filter, error) {
c, err := ExprToExpression(ctx, w.Expr)
if err != nil {
Expand Down
Loading

0 comments on commit ad73827

Please sign in to comment.