Add parsing support for JSON Utility Functions (#9850)

* feat: add parsing support for json utility functions

Signed-off-by: Kushal Kumar <kushalkumargupta4@gmail.com>

* refactor:use backticks in test_cases and remove unused field in JSONUtility struct

Signed-off-by: Kushal Kumar <kushalkumargupta4@gmail.com>

* tests: use backticks for strings

Signed-off-by: Kushal Kumar <kushalkumargupta4@gmail.com>

* refactor: use separate structs for each utility function

Create separate structs and format function for each struct
Update parser to use corresponding structs
Remove previously used JSONUtilityExpr struct

Signed-off-by: Kushal Kumar <kushalkumargupta4@gmail.com>

* ci: fix number of expected conflicts

Signed-off-by: Kushal Kumar <kushalkumargupta4@gmail.com>

* test: add planner tests for the json utility functions

Signed-off-by: Manan Gupta <manan@planetscale.com>

Co-authored-by: Manan Gupta <manan@planetscale.com>
This commit is contained in:
Kushal Kumar 2022-03-24 11:08:37 +05:30 коммит произвёл GitHub
Родитель 31bbb4fa32
Коммит b93679f651
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 6737 добавлений и 6195 удалений

Просмотреть файл

@ -2224,6 +2224,24 @@ type (
alternative Expr // this is what will be used to Format this struct
}
// JSONPrettyExpr represents the function and argument for JSON_PRETTY()
// https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html#function_json-pretty
JSONPrettyExpr struct {
JSONVal Expr
}
// JSONStorageFreeExpr represents the function and argument for JSON_STORAGE_FREE()
// https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html#function_json-storage-free
JSONStorageFreeExpr struct {
JSONVal Expr
}
// JSONStorageSizeExpr represents the function and argument for JSON_STORAGE_SIZE()
// https://dev.mysql.com/doc/refman/8.0/en/json-utility-functions.html#function_json-storage-size
JSONStorageSizeExpr struct {
JSONVal Expr
}
// Offset is another AST type that is used during planning and never produced by the parser
Offset int
)
@ -2264,6 +2282,9 @@ func (*MatchExpr) iExpr() {}
func (*GroupConcatExpr) iExpr() {}
func (*Default) iExpr() {}
func (*ExtractedSubquery) iExpr() {}
func (*JSONPrettyExpr) iExpr() {}
func (*JSONStorageFreeExpr) iExpr() {}
func (*JSONStorageSizeExpr) iExpr() {}
func (*TrimFuncExpr) iExpr() {}
func (Offset) iExpr() {}
@ -2280,6 +2301,9 @@ func (*SubstrExpr) iCallable() {}
func (*ConvertUsingExpr) iCallable() {}
func (*MatchExpr) iCallable() {}
func (*GroupConcatExpr) iCallable() {}
func (*JSONPrettyExpr) iCallable() {}
func (*JSONStorageFreeExpr) iCallable() {}
func (*JSONStorageSizeExpr) iCallable() {}
// Exprs represents a list of value expressions.
// It's not a valid expression because it's not parenthesized.

Просмотреть файл

@ -173,6 +173,12 @@ func CloneSQLNode(in SQLNode) SQLNode {
return CloneRefOfIsExpr(in)
case IsolationLevel:
return in
case *JSONPrettyExpr:
return CloneRefOfJSONPrettyExpr(in)
case *JSONStorageFreeExpr:
return CloneRefOfJSONStorageFreeExpr(in)
case *JSONStorageSizeExpr:
return CloneRefOfJSONStorageSizeExpr(in)
case *JoinCondition:
return CloneRefOfJoinCondition(in)
case *JoinTableExpr:
@ -1129,6 +1135,36 @@ func CloneRefOfIsExpr(n *IsExpr) *IsExpr {
return &out
}
// CloneRefOfJSONPrettyExpr creates a deep clone of the input.
func CloneRefOfJSONPrettyExpr(n *JSONPrettyExpr) *JSONPrettyExpr {
if n == nil {
return nil
}
out := *n
out.JSONVal = CloneExpr(n.JSONVal)
return &out
}
// CloneRefOfJSONStorageFreeExpr creates a deep clone of the input.
func CloneRefOfJSONStorageFreeExpr(n *JSONStorageFreeExpr) *JSONStorageFreeExpr {
if n == nil {
return nil
}
out := *n
out.JSONVal = CloneExpr(n.JSONVal)
return &out
}
// CloneRefOfJSONStorageSizeExpr creates a deep clone of the input.
func CloneRefOfJSONStorageSizeExpr(n *JSONStorageSizeExpr) *JSONStorageSizeExpr {
if n == nil {
return nil
}
out := *n
out.JSONVal = CloneExpr(n.JSONVal)
return &out
}
// CloneRefOfJoinCondition creates a deep clone of the input.
func CloneRefOfJoinCondition(n *JoinCondition) *JoinCondition {
if n == nil {
@ -2106,6 +2142,12 @@ func CloneCallable(in Callable) Callable {
return CloneRefOfFuncExpr(in)
case *GroupConcatExpr:
return CloneRefOfGroupConcatExpr(in)
case *JSONPrettyExpr:
return CloneRefOfJSONPrettyExpr(in)
case *JSONStorageFreeExpr:
return CloneRefOfJSONStorageFreeExpr(in)
case *JSONStorageSizeExpr:
return CloneRefOfJSONStorageSizeExpr(in)
case *MatchExpr:
return CloneRefOfMatchExpr(in)
case *SubstrExpr:
@ -2284,6 +2326,12 @@ func CloneExpr(in Expr) Expr {
return CloneRefOfIntroducerExpr(in)
case *IsExpr:
return CloneRefOfIsExpr(in)
case *JSONPrettyExpr:
return CloneRefOfJSONPrettyExpr(in)
case *JSONStorageFreeExpr:
return CloneRefOfJSONStorageFreeExpr(in)
case *JSONStorageSizeExpr:
return CloneRefOfJSONStorageSizeExpr(in)
case ListArg:
return in
case *Literal:

Просмотреть файл

@ -476,6 +476,24 @@ func EqualsSQLNode(inA, inB SQLNode) bool {
return false
}
return a == b
case *JSONPrettyExpr:
b, ok := inB.(*JSONPrettyExpr)
if !ok {
return false
}
return EqualsRefOfJSONPrettyExpr(a, b)
case *JSONStorageFreeExpr:
b, ok := inB.(*JSONStorageFreeExpr)
if !ok {
return false
}
return EqualsRefOfJSONStorageFreeExpr(a, b)
case *JSONStorageSizeExpr:
b, ok := inB.(*JSONStorageSizeExpr)
if !ok {
return false
}
return EqualsRefOfJSONStorageSizeExpr(a, b)
case *JoinCondition:
b, ok := inB.(*JoinCondition)
if !ok {
@ -1935,6 +1953,39 @@ func EqualsRefOfIsExpr(a, b *IsExpr) bool {
a.Right == b.Right
}
// EqualsRefOfJSONPrettyExpr does deep equals between the two objects.
func EqualsRefOfJSONPrettyExpr(a, b *JSONPrettyExpr) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
return EqualsExpr(a.JSONVal, b.JSONVal)
}
// EqualsRefOfJSONStorageFreeExpr does deep equals between the two objects.
func EqualsRefOfJSONStorageFreeExpr(a, b *JSONStorageFreeExpr) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
return EqualsExpr(a.JSONVal, b.JSONVal)
}
// EqualsRefOfJSONStorageSizeExpr does deep equals between the two objects.
func EqualsRefOfJSONStorageSizeExpr(a, b *JSONStorageSizeExpr) bool {
if a == b {
return true
}
if a == nil || b == nil {
return false
}
return EqualsExpr(a.JSONVal, b.JSONVal)
}
// EqualsRefOfJoinCondition does deep equals between the two objects.
func EqualsRefOfJoinCondition(a, b *JoinCondition) bool {
if a == b {
@ -3165,6 +3216,24 @@ func EqualsCallable(inA, inB Callable) bool {
return false
}
return EqualsRefOfGroupConcatExpr(a, b)
case *JSONPrettyExpr:
b, ok := inB.(*JSONPrettyExpr)
if !ok {
return false
}
return EqualsRefOfJSONPrettyExpr(a, b)
case *JSONStorageFreeExpr:
b, ok := inB.(*JSONStorageFreeExpr)
if !ok {
return false
}
return EqualsRefOfJSONStorageFreeExpr(a, b)
case *JSONStorageSizeExpr:
b, ok := inB.(*JSONStorageSizeExpr)
if !ok {
return false
}
return EqualsRefOfJSONStorageSizeExpr(a, b)
case *MatchExpr:
b, ok := inB.(*MatchExpr)
if !ok {
@ -3552,6 +3621,24 @@ func EqualsExpr(inA, inB Expr) bool {
return false
}
return EqualsRefOfIsExpr(a, b)
case *JSONPrettyExpr:
b, ok := inB.(*JSONPrettyExpr)
if !ok {
return false
}
return EqualsRefOfJSONPrettyExpr(a, b)
case *JSONStorageFreeExpr:
b, ok := inB.(*JSONStorageFreeExpr)
if !ok {
return false
}
return EqualsRefOfJSONStorageFreeExpr(a, b)
case *JSONStorageSizeExpr:
b, ok := inB.(*JSONStorageSizeExpr)
if !ok {
return false
}
return EqualsRefOfJSONStorageSizeExpr(a, b)
case ListArg:
b, ok := inB.(ListArg)
if !ok {

Просмотреть файл

@ -1321,6 +1321,24 @@ func (node *ValuesFuncExpr) Format(buf *TrackedBuffer) {
buf.astPrintf(node, "values(%v)", node.Name)
}
// Format formats the node
func (node *JSONPrettyExpr) Format(buf *TrackedBuffer) {
buf.astPrintf(node, "json_pretty(%v)", node.JSONVal)
}
// Format formats the node
func (node *JSONStorageFreeExpr) Format(buf *TrackedBuffer) {
buf.astPrintf(node, "json_storage_free(%v)", node.JSONVal)
}
// Format formats the node
func (node *JSONStorageSizeExpr) Format(buf *TrackedBuffer) {
buf.astPrintf(node, "json_storage_size(%v)", node.JSONVal)
}
// Format formats the node.
func (node *SubstrExpr) Format(buf *TrackedBuffer) {
if node.To == nil {

Просмотреть файл

@ -1761,6 +1761,30 @@ func (node *ValuesFuncExpr) formatFast(buf *TrackedBuffer) {
buf.WriteByte(')')
}
// formatFast formats the node
func (node *JSONPrettyExpr) formatFast(buf *TrackedBuffer) {
buf.WriteString("json_pretty(")
buf.printExpr(node, node.JSONVal, true)
buf.WriteByte(')')
}
// formatFast formats the node
func (node *JSONStorageFreeExpr) formatFast(buf *TrackedBuffer) {
buf.WriteString("json_storage_free(")
buf.printExpr(node, node.JSONVal, true)
buf.WriteByte(')')
}
// formatFast formats the node
func (node *JSONStorageSizeExpr) formatFast(buf *TrackedBuffer) {
buf.WriteString("json_storage_size(")
buf.printExpr(node, node.JSONVal, true)
buf.WriteByte(')')
}
// formatFast formats the node.
func (node *SubstrExpr) formatFast(buf *TrackedBuffer) {
if node.To == nil {

Просмотреть файл

@ -172,6 +172,12 @@ func (a *application) rewriteSQLNode(parent SQLNode, node SQLNode, replacer repl
return a.rewriteRefOfIsExpr(parent, node, replacer)
case IsolationLevel:
return a.rewriteIsolationLevel(parent, node, replacer)
case *JSONPrettyExpr:
return a.rewriteRefOfJSONPrettyExpr(parent, node, replacer)
case *JSONStorageFreeExpr:
return a.rewriteRefOfJSONStorageFreeExpr(parent, node, replacer)
case *JSONStorageSizeExpr:
return a.rewriteRefOfJSONStorageSizeExpr(parent, node, replacer)
case *JoinCondition:
return a.rewriteRefOfJoinCondition(parent, node, replacer)
case *JoinTableExpr:
@ -2649,6 +2655,87 @@ func (a *application) rewriteRefOfIsExpr(parent SQLNode, node *IsExpr, replacer
}
return true
}
func (a *application) rewriteRefOfJSONPrettyExpr(parent SQLNode, node *JSONPrettyExpr, replacer replacerFunc) bool {
if node == nil {
return true
}
if a.pre != nil {
a.cur.replacer = replacer
a.cur.parent = parent
a.cur.node = node
if !a.pre(&a.cur) {
return true
}
}
if !a.rewriteExpr(node, node.JSONVal, func(newNode, parent SQLNode) {
parent.(*JSONPrettyExpr).JSONVal = newNode.(Expr)
}) {
return false
}
if a.post != nil {
a.cur.replacer = replacer
a.cur.parent = parent
a.cur.node = node
if !a.post(&a.cur) {
return false
}
}
return true
}
func (a *application) rewriteRefOfJSONStorageFreeExpr(parent SQLNode, node *JSONStorageFreeExpr, replacer replacerFunc) bool {
if node == nil {
return true
}
if a.pre != nil {
a.cur.replacer = replacer
a.cur.parent = parent
a.cur.node = node
if !a.pre(&a.cur) {
return true
}
}
if !a.rewriteExpr(node, node.JSONVal, func(newNode, parent SQLNode) {
parent.(*JSONStorageFreeExpr).JSONVal = newNode.(Expr)
}) {
return false
}
if a.post != nil {
a.cur.replacer = replacer
a.cur.parent = parent
a.cur.node = node
if !a.post(&a.cur) {
return false
}
}
return true
}
func (a *application) rewriteRefOfJSONStorageSizeExpr(parent SQLNode, node *JSONStorageSizeExpr, replacer replacerFunc) bool {
if node == nil {
return true
}
if a.pre != nil {
a.cur.replacer = replacer
a.cur.parent = parent
a.cur.node = node
if !a.pre(&a.cur) {
return true
}
}
if !a.rewriteExpr(node, node.JSONVal, func(newNode, parent SQLNode) {
parent.(*JSONStorageSizeExpr).JSONVal = newNode.(Expr)
}) {
return false
}
if a.post != nil {
a.cur.replacer = replacer
a.cur.parent = parent
a.cur.node = node
if !a.post(&a.cur) {
return false
}
}
return true
}
func (a *application) rewriteRefOfJoinCondition(parent SQLNode, node *JoinCondition, replacer replacerFunc) bool {
if node == nil {
return true
@ -5441,6 +5528,12 @@ func (a *application) rewriteCallable(parent SQLNode, node Callable, replacer re
return a.rewriteRefOfFuncExpr(parent, node, replacer)
case *GroupConcatExpr:
return a.rewriteRefOfGroupConcatExpr(parent, node, replacer)
case *JSONPrettyExpr:
return a.rewriteRefOfJSONPrettyExpr(parent, node, replacer)
case *JSONStorageFreeExpr:
return a.rewriteRefOfJSONStorageFreeExpr(parent, node, replacer)
case *JSONStorageSizeExpr:
return a.rewriteRefOfJSONStorageSizeExpr(parent, node, replacer)
case *MatchExpr:
return a.rewriteRefOfMatchExpr(parent, node, replacer)
case *SubstrExpr:
@ -5605,6 +5698,12 @@ func (a *application) rewriteExpr(parent SQLNode, node Expr, replacer replacerFu
return a.rewriteRefOfIntroducerExpr(parent, node, replacer)
case *IsExpr:
return a.rewriteRefOfIsExpr(parent, node, replacer)
case *JSONPrettyExpr:
return a.rewriteRefOfJSONPrettyExpr(parent, node, replacer)
case *JSONStorageFreeExpr:
return a.rewriteRefOfJSONStorageFreeExpr(parent, node, replacer)
case *JSONStorageSizeExpr:
return a.rewriteRefOfJSONStorageSizeExpr(parent, node, replacer)
case ListArg:
return a.rewriteListArg(parent, node, replacer)
case *Literal:

Просмотреть файл

@ -172,6 +172,12 @@ func VisitSQLNode(in SQLNode, f Visit) error {
return VisitRefOfIsExpr(in, f)
case IsolationLevel:
return VisitIsolationLevel(in, f)
case *JSONPrettyExpr:
return VisitRefOfJSONPrettyExpr(in, f)
case *JSONStorageFreeExpr:
return VisitRefOfJSONStorageFreeExpr(in, f)
case *JSONStorageSizeExpr:
return VisitRefOfJSONStorageSizeExpr(in, f)
case *JoinCondition:
return VisitRefOfJoinCondition(in, f)
case *JoinTableExpr:
@ -1398,6 +1404,42 @@ func VisitRefOfIsExpr(in *IsExpr, f Visit) error {
}
return nil
}
func VisitRefOfJSONPrettyExpr(in *JSONPrettyExpr, f Visit) error {
if in == nil {
return nil
}
if cont, err := f(in); err != nil || !cont {
return err
}
if err := VisitExpr(in.JSONVal, f); err != nil {
return err
}
return nil
}
func VisitRefOfJSONStorageFreeExpr(in *JSONStorageFreeExpr, f Visit) error {
if in == nil {
return nil
}
if cont, err := f(in); err != nil || !cont {
return err
}
if err := VisitExpr(in.JSONVal, f); err != nil {
return err
}
return nil
}
func VisitRefOfJSONStorageSizeExpr(in *JSONStorageSizeExpr, f Visit) error {
if in == nil {
return nil
}
if cont, err := f(in); err != nil || !cont {
return err
}
if err := VisitExpr(in.JSONVal, f); err != nil {
return err
}
return nil
}
func VisitRefOfJoinCondition(in *JoinCondition, f Visit) error {
if in == nil {
return nil
@ -2666,6 +2708,12 @@ func VisitCallable(in Callable, f Visit) error {
return VisitRefOfFuncExpr(in, f)
case *GroupConcatExpr:
return VisitRefOfGroupConcatExpr(in, f)
case *JSONPrettyExpr:
return VisitRefOfJSONPrettyExpr(in, f)
case *JSONStorageFreeExpr:
return VisitRefOfJSONStorageFreeExpr(in, f)
case *JSONStorageSizeExpr:
return VisitRefOfJSONStorageSizeExpr(in, f)
case *MatchExpr:
return VisitRefOfMatchExpr(in, f)
case *SubstrExpr:
@ -2830,6 +2878,12 @@ func VisitExpr(in Expr, f Visit) error {
return VisitRefOfIntroducerExpr(in, f)
case *IsExpr:
return VisitRefOfIsExpr(in, f)
case *JSONPrettyExpr:
return VisitRefOfJSONPrettyExpr(in, f)
case *JSONStorageFreeExpr:
return VisitRefOfJSONStorageFreeExpr(in, f)
case *JSONStorageSizeExpr:
return VisitRefOfJSONStorageSizeExpr(in, f)
case ListArg:
return VisitListArg(in, f)
case *Literal:

Просмотреть файл

@ -1377,6 +1377,48 @@ func (cached *IsExpr) CachedSize(alloc bool) int64 {
}
return size
}
func (cached *JSONPrettyExpr) CachedSize(alloc bool) int64 {
if cached == nil {
return int64(0)
}
size := int64(0)
if alloc {
size += int64(16)
}
// field JSONVal vitess.io/vitess/go/vt/sqlparser.Expr
if cc, ok := cached.JSONVal.(cachedObject); ok {
size += cc.CachedSize(true)
}
return size
}
func (cached *JSONStorageFreeExpr) CachedSize(alloc bool) int64 {
if cached == nil {
return int64(0)
}
size := int64(0)
if alloc {
size += int64(16)
}
// field JSONVal vitess.io/vitess/go/vt/sqlparser.Expr
if cc, ok := cached.JSONVal.(cachedObject); ok {
size += cc.CachedSize(true)
}
return size
}
func (cached *JSONStorageSizeExpr) CachedSize(alloc bool) int64 {
if cached == nil {
return int64(0)
}
size := int64(0)
if alloc {
size += int64(16)
}
// field JSONVal vitess.io/vitess/go/vt/sqlparser.Expr
if cc, ok := cached.JSONVal.(cachedObject); ok {
size += cc.CachedSize(true)
}
return size
}
func (cached *JoinCondition) CachedSize(alloc bool) int64 {
if cached == nil {
return int64(0)

Просмотреть файл

@ -317,6 +317,9 @@ var keywords = []keyword{
{"invoker", INVOKER},
{"join", JOIN},
{"json", JSON},
{"json_pretty", JSON_PRETTY},
{"json_storage_size", JSON_STORAGE_SIZE},
{"json_storage_free", JSON_STORAGE_FREE},
{"json_table", UNUSED},
{"key", KEY},
{"keys", KEYS},

Просмотреть файл

@ -2296,6 +2296,42 @@ var (
}, {
input: "create table unused_reserved_keywords (dense_rank bigint, lead VARCHAR(255), percent_rank decimal(3, 0), row TINYINT, rows CHAR(10), constraint PK_project PRIMARY KEY (dense_rank))",
output: "create table unused_reserved_keywords (\n\t`dense_rank` bigint,\n\t`lead` VARCHAR(255),\n\t`percent_rank` decimal(3,0),\n\t`row` TINYINT,\n\t`rows` CHAR(10),\n\tconstraint PK_project PRIMARY KEY (`dense_rank`)\n)",
}, {
input: `SELECT JSON_PRETTY('{"a":"10","b":"15","x":"25"}')`,
output: `select json_pretty('{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') from dual`,
}, {
input: `SELECT JSON_PRETTY(N'{"a":"10","b":"15","x":"25"}')`,
output: `select json_pretty(N'{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') from dual`,
}, {
input: "SELECT jcol, JSON_PRETTY(jcol) from jtable",
output: "select jcol, json_pretty(jcol) from jtable",
}, {
input: "SELECT JSON_PRETTY(@j)",
output: "select json_pretty(@j) from dual",
}, {
input: "SELECT jcol, JSON_STORAGE_SIZE(jcol) AS Size FROM jtable",
output: "select jcol, json_storage_size(jcol) as Size from jtable",
}, {
input: `SELECT jcol, JSON_STORAGE_SIZE(N'{"a":"10","b":"15","x":"25"}') AS Size FROM jtable`,
output: `select jcol, json_storage_size(N'{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') as Size from jtable`,
}, {
input: `SELECT JSON_STORAGE_SIZE('[100, "sakila", [1, 3, 5], 425.05]') AS A, JSON_STORAGE_SIZE('{"a": 1000, "b": "a", "c": "[1, 3, 5, 7]"}') AS B, JSON_STORAGE_SIZE('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}') AS C,JSON_STORAGE_SIZE('[100, "json", [[10, 20, 30], 3, 5], 425.05]') AS D`,
output: `select json_storage_size('[100, \"sakila\", [1, 3, 5], 425.05]') as A, json_storage_size('{\"a\": 1000, \"b\": \"a\", \"c\": \"[1, 3, 5, 7]\"}') as B, json_storage_size('{\"a\": 1000, \"b\": \"wxyz\", \"c\": \"[1, 3, 5, 7]\"}') as C, json_storage_size('[100, \"json\", [[10, 20, 30], 3, 5], 425.05]') as D from dual`,
}, {
input: "SELECT JSON_STORAGE_SIZE(@j)",
output: "select json_storage_size(@j) from dual",
}, {
input: "SELECT JSON_STORAGE_FREE(jcol) FROM jtable",
output: "select json_storage_free(jcol) from jtable",
}, {
input: `SELECT JSON_STORAGE_FREE('{"a":"10","b":"15","x":"25"}')`,
output: `select json_storage_free('{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') from dual`,
}, {
input: `SELECT JSON_STORAGE_FREE(N'{"a":"10","b":"15","x":"25"}')`,
output: `select json_storage_free(N'{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') from dual`,
}, {
input: "SELECT JSON_STORAGE_FREE(@j)",
output: "select json_storage_free(@j) from dual",
}, {
input: "SELECT LTRIM('abc')",
output: "select ltrim('abc') from dual",
@ -2435,6 +2471,9 @@ func TestInvalid(t *testing.T) {
}, {
input: "select 1, next value from seq",
err: "syntax error",
}, {
input: "SELECT jcol, JSON_PRETTY(jcol, jcol) from jtable",
err: "syntax error at position 31",
}, {
input: "select from t1, lateral (with qn as (select t1.a) select (select max(a) from qn)) as dt",
err: "syntax error at position 12 near 'from'",

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -191,6 +191,7 @@ func bindVariable(yylex yyLexer, bvar string) {
%left <str> SUBQUERY_AS_EXPR
%left <str> '(' ',' ')'
%token <str> ID AT_ID AT_AT_ID HEX STRING NCHAR_STRING INTEGRAL FLOAT DECIMAL HEXNUM VALUE_ARG LIST_ARG COMMENT COMMENT_KEYWORD BIT_LITERAL COMPRESSION
%token <str> JSON_PRETTY JSON_STORAGE_SIZE JSON_STORAGE_FREE
%token <str> EXTRACT
%token <str> NULL TRUE FALSE OFF
%token <str> DISCARD IMPORT ENABLE DISABLE TABLESPACE
@ -4744,6 +4745,18 @@ UTC_DATE func_paren_opt
{
$$ = &WeightStringFuncExpr{Expr: $3, As: $4}
}
| JSON_PRETTY openb expression closeb
{
$$ = &JSONPrettyExpr{JSONVal: $3}
}
| JSON_STORAGE_FREE openb expression closeb
{
$$ = &JSONStorageFreeExpr{ JSONVal: $3}
}
| JSON_STORAGE_SIZE openb expression closeb
{
$$ = &JSONStorageSizeExpr{ JSONVal: $3}
}
| LTRIM openb expression closeb
{
$$ = &TrimFuncExpr{TrimFuncType:LTrimType, StringArg: $3}
@ -6019,6 +6032,9 @@ non_reserved_keyword:
| INDEXES
| ISOLATION
| JSON
| JSON_PRETTY
| JSON_STORAGE_FREE
| JSON_STORAGE_SIZE
| KEY_BLOCK_SIZE
| KEYS
| KEYSPACES

Просмотреть файл

@ -2946,3 +2946,22 @@ Gen4 plan same as above
}
}
Gen4 plan same as above
# json utility functions
"select jcol, JSON_STORAGE_SIZE(jcol), JSON_STORAGE_FREE(jcol), JSON_PRETTY(jcol) from user"
{
"QueryType": "SELECT",
"Original": "select jcol, JSON_STORAGE_SIZE(jcol), JSON_STORAGE_FREE(jcol), JSON_PRETTY(jcol) from user",
"Instructions": {
"OperatorType": "Route",
"Variant": "Scatter",
"Keyspace": {
"Name": "user",
"Sharded": true
},
"FieldQuery": "select jcol, json_storage_size(jcol), json_storage_free(jcol), json_pretty(jcol) from `user` where 1 != 1",
"Query": "select jcol, json_storage_size(jcol), json_storage_free(jcol), json_pretty(jcol) from `user`",
"Table": "`user`"
}
}
Gen4 plan same as above

Просмотреть файл

@ -20,7 +20,7 @@ fi
mv $CUR $TMP
output=$(go run ./goyacc -fast-append -o $CUR sql.y)
expectedOutput=$'\nconflicts: 5 shift/reduce'
expectedOutput=$'\nconflicts: 8 shift/reduce'
if [[ "$output" != "$expectedOutput" ]]; then
echo -e "Expected output from goyacc:$expectedOutput\ngot:$output"