Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions pegjs/mariadb.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -2383,6 +2383,13 @@ table_base
type: 'dual'
};
}
/ jt:json_table_expr __ alias:alias_clause? {
return {
expr: jt,
as: alias,
...getLocationObject(),
};
}
/ t:table_name __ alias:alias_clause? {
if (t.type === 'var') {
t.as = alias;
Expand Down Expand Up @@ -2425,6 +2432,89 @@ table_base
return result
}

// JSON_TABLE expression
json_table_expr
= KW_JSON_TABLE __ LPAREN __
expr:expr __ COMMA __
path:literal_string __
KW_COLUMNS __ LPAREN __
columns:json_table_column_list __
RPAREN __ RPAREN {
return {
type: 'json_table',
expr: expr,
path: path,
columns: columns,
...getLocationObject(),
};
}

json_table_column_list
= head:json_table_column tail:(__ COMMA __ json_table_column)* {
return createList(head, tail);
}

json_table_column
= name:ident_name __ KW_FOR __ KW_ORDINALITY {
return {
type: 'ordinality',
name: name,
...getLocationObject(),
};
}
/ name:ident_name __ datatype:data_type __ KW_PATH __ path:literal_string __
on_empty:json_table_on_empty? __ on_error:json_table_on_error? {
return {
type: 'column',
name: name,
datatype: datatype,
path: path,
on_empty: on_empty,
on_error: on_error,
...getLocationObject(),
};
}
/ name:ident_name __ datatype:data_type __ KW_EXISTS __ KW_PATH __ path:literal_string {
return {
type: 'exists',
name: name,
datatype: datatype,
path: path,
...getLocationObject(),
};
}
/ KW_NESTED __ KW_PATH? __ path:literal_string __ KW_COLUMNS __ LPAREN __
columns:json_table_column_list __ RPAREN {
return {
type: 'nested',
path: path,
columns: columns,
...getLocationObject(),
};
}

json_table_on_empty
= KW_NULL __ KW_ON __ KW_EMPTY {
return { type: 'null' };
}
/ KW_DEFAULT __ value:literal_string __ KW_ON __ KW_EMPTY {
return { type: 'default', value: value };
}
/ KW_ERROR __ KW_ON __ KW_EMPTY {
return { type: 'error' };
}

json_table_on_error
= KW_NULL __ KW_ON __ KW_ERROR {
return { type: 'null' };
}
/ KW_DEFAULT __ value:literal_string __ KW_ON __ KW_ERROR {
return { type: 'default', value: value };
}
/ KW_ERROR __ KW_ON __ KW_ERROR {
return { type: 'error' };
}

join_op
= KW_LEFT __ KW_OUTER? __ KW_JOIN { return 'LEFT JOIN'; }
/ KW_RIGHT __ KW_OUTER? __ KW_JOIN { return 'RIGHT JOIN'; }
Expand Down Expand Up @@ -3986,6 +4076,16 @@ KW_CONSTRAINT = "CONSTRAINT"i !ident_start { return 'CONSTRAINT'; }
KW_REFERENCES = "REFERENCES"i !ident_start { return 'REFERENCES'; }


// JSON_TABLE Keywords
KW_JSON_TABLE = "JSON_TABLE"i !ident_start { return 'JSON_TABLE'; }
KW_PATH = "PATH"i !ident_start { return 'PATH'; }
KW_COLUMNS = "COLUMNS"i !ident_start { return 'COLUMNS'; }
KW_NESTED = "NESTED"i !ident_start { return 'NESTED'; }
KW_ORDINALITY = "ORDINALITY"i !ident_start { return 'ORDINALITY'; }
KW_FOR = "FOR"i !ident_start { return 'FOR'; }
KW_EMPTY = "EMPTY"i !ident_start { return 'EMPTY'; }
KW_ERROR = "ERROR"i !ident_start { return 'ERROR'; }


// MySQL extensions to SQL
OPT_SQL_CALC_FOUND_ROWS = "SQL_CALC_FOUND_ROWS"i
Expand Down
100 changes: 100 additions & 0 deletions pegjs/mysql.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -2645,6 +2645,13 @@ table_base
type: 'dual'
};
}
/ jt:json_table_expr __ alias:alias_clause? {
return {
expr: jt,
as: alias,
...getLocationObject(),
};
}
/ t:table_name __ alias:alias_clause? {
if (t.type === 'var') {
t.as = alias;
Expand Down Expand Up @@ -2688,6 +2695,89 @@ table_base
return result
}

// JSON_TABLE expression
json_table_expr
= KW_JSON_TABLE __ LPAREN __
expr:expr __ COMMA __
path:literal_string __
KW_COLUMNS __ LPAREN __
columns:json_table_column_list __
RPAREN __ RPAREN {
return {
type: 'json_table',
expr: expr,
path: path,
columns: columns,
...getLocationObject(),
};
}

json_table_column_list
= head:json_table_column tail:(__ COMMA __ json_table_column)* {
return createList(head, tail);
}

json_table_column
= name:ident_name __ KW_FOR __ KW_ORDINALITY {
return {
type: 'ordinality',
name: name,
...getLocationObject(),
};
}
/ name:ident_name __ datatype:data_type __ KW_PATH __ path:literal_string __
on_empty:json_table_on_empty? __ on_error:json_table_on_error? {
return {
type: 'column',
name: name,
datatype: datatype,
path: path,
on_empty: on_empty,
on_error: on_error,
...getLocationObject(),
};
}
/ name:ident_name __ datatype:data_type __ KW_EXISTS __ KW_PATH __ path:literal_string {
return {
type: 'exists',
name: name,
datatype: datatype,
path: path,
...getLocationObject(),
};
}
/ KW_NESTED __ KW_PATH? __ path:literal_string __ KW_COLUMNS __ LPAREN __
columns:json_table_column_list __ RPAREN {
return {
type: 'nested',
path: path,
columns: columns,
...getLocationObject(),
};
}

json_table_on_empty
= KW_NULL __ KW_ON __ KW_EMPTY {
return { type: 'null' };
}
/ KW_DEFAULT __ value:literal_string __ KW_ON __ KW_EMPTY {
return { type: 'default', value: value };
}
/ KW_ERROR __ KW_ON __ KW_EMPTY {
return { type: 'error' };
}

json_table_on_error
= KW_NULL __ KW_ON __ KW_ERROR {
return { type: 'null' };
}
/ KW_DEFAULT __ value:literal_string __ KW_ON __ KW_ERROR {
return { type: 'default', value: value };
}
/ KW_ERROR __ KW_ON __ KW_ERROR {
return { type: 'error' };
}

join_op
= KW_LEFT __ KW_OUTER? __ KW_JOIN { return 'LEFT JOIN'; }
/ KW_RIGHT __ KW_OUTER? __ KW_JOIN { return 'RIGHT JOIN'; }
Expand Down Expand Up @@ -4284,6 +4374,16 @@ KW_COMMENT = "COMMENT"i !ident_start { return 'COMMENT'; }
KW_CONSTRAINT = "CONSTRAINT"i !ident_start { return 'CONSTRAINT'; }
KW_REFERENCES = "REFERENCES"i !ident_start { return 'REFERENCES'; }

// JSON_TABLE Keywords
KW_JSON_TABLE = "JSON_TABLE"i !ident_start { return 'JSON_TABLE'; }
KW_PATH = "PATH"i !ident_start { return 'PATH'; }
KW_COLUMNS = "COLUMNS"i !ident_start { return 'COLUMNS'; }
KW_NESTED = "NESTED"i !ident_start { return 'NESTED'; }
KW_ORDINALITY = "ORDINALITY"i !ident_start { return 'ORDINALITY'; }
KW_FOR = "FOR"i !ident_start { return 'FOR'; }
KW_EMPTY = "EMPTY"i !ident_start { return 'EMPTY'; }
KW_ERROR = "ERROR"i !ident_start { return 'ERROR'; }

// MySQL extensions to SQL
OPT_SQL_CALC_FOUND_ROWS = "SQL_CALC_FOUND_ROWS"i
OPT_SQL_CACHE = "SQL_CACHE"i
Expand Down
84 changes: 83 additions & 1 deletion src/tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { columnRefToSQL } from './column'
import { exprToSQL } from './expr'
import { valuesToSQL } from './insert'
import { intervalToSQL } from './interval'
import { commonOptionConnector, commonTypeValue, hasVal, identifierToSql, literalToSQL, toUpper } from './util'
import { commonOptionConnector, commonTypeValue, dataTypeToSQL, hasVal, identifierToSql, literalToSQL, toUpper } from './util'

function unnestToSQL(unnestExpr) {
const { type, as, expr, with_offset: withOffset } = unnestExpr
Expand Down Expand Up @@ -112,6 +112,84 @@ function generateVirtualTable(stmt) {
return `${toUpper(keyword)}(${toUpper(type)}(${generatorSQL}))`
}

function jsonTableOnClauseToSQL(onClause, clauseType) {
const { type, value } = onClause

switch (type) {
case 'null':
return `NULL ON ${clauseType}`
case 'default':
return `DEFAULT ${literalToSQL(value)} ON ${clauseType}`
case 'error':
return `ERROR ON ${clauseType}`
default:
return ''
}
}

function jsonTableColumnToSQL(column) {
const { type, name, datatype, path, on_empty, on_error, columns } = column

switch (type) {
case 'ordinality':
return `${identifierToSql(name)} FOR ORDINALITY`

case 'column':
const result = [identifierToSql(name)]
if (datatype) {
result.push(dataTypeToSQL(datatype))
}
result.push('PATH', literalToSQL(path))

if (on_empty) {
result.push(jsonTableOnClauseToSQL(on_empty, 'EMPTY'))
}
if (on_error) {
result.push(jsonTableOnClauseToSQL(on_error, 'ERROR'))
}

return result.join(' ')

case 'exists':
const existsResult = [identifierToSql(name)]
if (datatype) {
existsResult.push(dataTypeToSQL(datatype))
}
existsResult.push('EXISTS PATH', literalToSQL(path))
return existsResult.join(' ')

case 'nested':
const nestedResult = ['NESTED PATH', literalToSQL(path), 'COLUMNS']
if (columns && columns.length > 0) {
const columnsList = columns.map(jsonTableColumnToSQL).join(', ')
nestedResult.push(`(${columnsList})`)
}
return nestedResult.join(' ')

default:
return ''
}
}

function jsonTableToSQL(jsonTableExpr) {
const { expr, path, columns } = jsonTableExpr

const result = ['JSON_TABLE(']
result.push(exprToSQL(expr))
result.push(',')
result.push(literalToSQL(path))
result.push('COLUMNS')

if (columns && columns.length > 0) {
const columnsList = columns.map(jsonTableColumnToSQL).join(', ')
result.push(`(${columnsList})`)
}

result.push(')')

return result.join(' ')
}

function tableToSQL(tableInfo) {
if (toUpper(tableInfo.type) === 'UNNEST') return unnestToSQL(tableInfo)
const { table, db, as, expr, operator, prefix: prefixStr, schema, server, suffix, tablesample, temporal_table, table_hint, surround = {} } = tableInfo
Expand All @@ -136,6 +214,9 @@ function tableToSQL(tableInfo) {
case 'generator':
tableName = generateVirtualTable(expr)
break
case 'json_table':
tableName = jsonTableToSQL(expr)
break
default:
tableName = exprToSQL(expr)
}
Expand Down Expand Up @@ -223,4 +304,5 @@ export {
tableOptionToSQL,
tableToSQL,
unnestToSQL,
jsonTableToSQL,
}
Loading