This is an automated email from the ASF dual-hosted git repository.
duanzhengqiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new a9cc7717c7c Support parsing SQL Server open json function (#29721)
a9cc7717c7c is described below
commit a9cc7717c7c74bebdaa8cd894306ae2a937d0047
Author: LotusMoon <[email protected]>
AuthorDate: Mon Jan 15 13:56:15 2024 +0800
Support parsing SQL Server open json function (#29721)
* Support parsing SQL Server open json function
* Fix spotless check
* Change the traversal object to each
---
.../src/main/antlr4/imports/sqlserver/BaseRule.g4 | 20 +++-
.../antlr4/imports/sqlserver/SQLServerKeyword.g4 | 4 +
.../statement/SQLServerStatementVisitor.java | 17 ++++
.../parser/src/main/resources/case/dml/insert.xml | 36 +++++++
.../src/main/resources/case/dml/select-join.xml | 103 +++++++++++++++++++++
.../resources/case/dml/select-special-function.xml | 34 +++++++
.../parser/src/main/resources/case/dml/select.xml | 37 ++++++++
.../main/resources/sql/supported/dml/insert.xml | 2 +
.../resources/sql/supported/dml/select-join.xml | 1 +
.../sql/supported/dml/select-special-function.xml | 2 +
.../main/resources/sql/supported/dml/select.xml | 1 +
11 files changed, 253 insertions(+), 4 deletions(-)
diff --git
a/parser/sql/dialect/sqlserver/src/main/antlr4/imports/sqlserver/BaseRule.g4
b/parser/sql/dialect/sqlserver/src/main/antlr4/imports/sqlserver/BaseRule.g4
index 0435185f4e8..4c2ff0fa375 100644
--- a/parser/sql/dialect/sqlserver/src/main/antlr4/imports/sqlserver/BaseRule.g4
+++ b/parser/sql/dialect/sqlserver/src/main/antlr4/imports/sqlserver/BaseRule.g4
@@ -120,7 +120,7 @@ unreservedWord
| DATA_RETENTION | TEMPORAL_HISTORY_RETENTION | EDITION |
MIXED_PAGE_ALLOCATION | DISABLED | ALLOWED | HADR | MULTI_USER |
RESTRICTED_USER | SINGLE_USER | OFFLINE | EMERGENCY | SUSPEND |
DATE_CORRELATION_OPTIMIZATION
| ELASTIC_POOL | SERVICE_OBJECTIVE | DATABASE_NAME | ALLOW_CONNECTIONS |
GEO | NAMED | DATEFIRST | BACKUP_STORAGE_REDUNDANCY |
FORCE_FAILOVER_ALLOW_DATA_LOSS | SECONDARY | FAILOVER |
DEFAULT_FULLTEXT_LANGUAGE
| DEFAULT_LANGUAGE | INLINE | NESTED_TRIGGERS | TRANSFORM_NOISE_WORDS |
TWO_DIGIT_YEAR_CUTOFF | PERSISTENT_LOG_BUFFER | DIRECTORY_NAME | DATEFORMAT |
DELAYED_DURABILITY | TRANSFER | SCHEMA | PASSWORD | AUTHORIZATION
- | MEMBER | SEARCH | TEXT | SECOND | PRECISION | VIEWS | PROVIDER | COLUMNS
| SUBSTRING | RETURNS | SIZE
+ | MEMBER | SEARCH | TEXT | SECOND | PRECISION | VIEWS | PROVIDER | COLUMNS
| SUBSTRING | RETURNS | SIZE | CONTAINS | MONTH
;
databaseName
@@ -221,12 +221,12 @@ primaryKey
// TODO comb expr
expr
- : expr andOperator expr
+ : booleanPrimary
+ | expr andOperator expr
| expr orOperator expr
| expr distinctFrom expr
| notOperator expr
| LP_ expr RP_
- | booleanPrimary
;
andOperator
@@ -311,7 +311,7 @@ distinct
;
specialFunction
- : castFunction | charFunction | convertFunction
+ : castFunction | charFunction | convertFunction | openJsonFunction
;
castFunction
@@ -326,6 +326,18 @@ charFunction
: CHAR LP_ expr (COMMA_ expr)* (USING ignoredIdentifier)? RP_
;
+openJsonFunction
+ : OPENJSON LP_ expr (COMMA_ expr)? RP_ openJsonWithclause?
+ ;
+
+openJsonWithclause
+ : WITH LP_ jsonColumnDefinition (COMMA_ jsonColumnDefinition)* RP_
+ ;
+
+jsonColumnDefinition
+ : columnName dataType expr? (AS JSON)?
+ ;
+
regularFunction
: regularFunctionName LP_ (expr (COMMA_ expr)* | ASTERISK_)? RP_
;
diff --git
a/parser/sql/dialect/sqlserver/src/main/antlr4/imports/sqlserver/SQLServerKeyword.g4
b/parser/sql/dialect/sqlserver/src/main/antlr4/imports/sqlserver/SQLServerKeyword.g4
index bfd69964552..d176b7cd77c 100644
---
a/parser/sql/dialect/sqlserver/src/main/antlr4/imports/sqlserver/SQLServerKeyword.g4
+++
b/parser/sql/dialect/sqlserver/src/main/antlr4/imports/sqlserver/SQLServerKeyword.g4
@@ -1942,3 +1942,7 @@ AUTO_DROP
PERSIST_SAMPLE_PERCENT
: P E R S I S T UL_ S A M P L E UL_ P E R C E N T
;
+
+OPENJSON
+ : O P E N J S O N
+ ;
diff --git
a/parser/sql/dialect/sqlserver/src/main/java/org/apache/shardingsphere/sql/parser/sqlserver/visitor/statement/SQLServerStatementVisitor.java
b/parser/sql/dialect/sqlserver/src/main/java/org/apache/shardingsphere/sql/parser/sqlserver/visitor/statement/SQLServerStatementVisitor.java
index f6d395657c4..3833d90d45f 100644
---
a/parser/sql/dialect/sqlserver/src/main/java/org/apache/shardingsphere/sql/parser/sqlserver/visitor/statement/SQLServerStatementVisitor.java
+++
b/parser/sql/dialect/sqlserver/src/main/java/org/apache/shardingsphere/sql/parser/sqlserver/visitor/statement/SQLServerStatementVisitor.java
@@ -116,6 +116,7 @@ import
org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.Sam
import
org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.InsertExecClauseContext;
import
org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.ExecContext;
import
org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.ProcedureNameContext;
+import
org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.OpenJsonFunctionContext;
import
org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.TableHintLimitedContext;
import org.apache.shardingsphere.sql.parser.sql.common.enums.AggregationType;
import org.apache.shardingsphere.sql.parser.sql.common.enums.JoinType;
@@ -207,6 +208,7 @@ import
org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.segm
import
org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.segment.StatisticsDimension;
import
org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.segment.StatisticsOptionSegment;
import
org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.segment.StatisticsStrategySegment;
+
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
@@ -569,6 +571,9 @@ public abstract class SQLServerStatementVisitor extends
SQLServerStatementBaseVi
if (null != ctx.columnName()) {
return visit(ctx.columnName());
}
+ if (null != ctx.LP_() && 1 == ctx.expr().size()) {
+ return visit(ctx.expr(0));
+ }
return visitRemainSimpleExpr(ctx);
}
@@ -653,6 +658,9 @@ public abstract class SQLServerStatementVisitor extends
SQLServerStatementBaseVi
if (null != ctx.charFunction()) {
return visit(ctx.charFunction());
}
+ if (null != ctx.openJsonFunction()) {
+ return visit(ctx.openJsonFunction());
+ }
return new FunctionSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), ctx.getChild(0).getChild(0).getText(),
getOriginalText(ctx));
}
@@ -687,6 +695,15 @@ public abstract class SQLServerStatementVisitor extends
SQLServerStatementBaseVi
return new FunctionSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), ctx.CHAR().getText(), getOriginalText(ctx));
}
+ @Override
+ public final ASTNode visitOpenJsonFunction(final OpenJsonFunctionContext
ctx) {
+ FunctionSegment result = new
FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(),
ctx.OPENJSON().getText(), getOriginalText(ctx));
+ for (ExprContext each : ctx.expr()) {
+ result.getParameters().add((ExpressionSegment) visit(each));
+ }
+ return result;
+ }
+
@Override
public final ASTNode visitRegularFunction(final RegularFunctionContext
ctx) {
FunctionSegment result = new
FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(),
ctx.regularFunctionName().getText(), getOriginalText(ctx));
diff --git a/test/it/parser/src/main/resources/case/dml/insert.xml
b/test/it/parser/src/main/resources/case/dml/insert.xml
index dd0b2f1be81..f2b33ed0d0b 100644
--- a/test/it/parser/src/main/resources/case/dml/insert.xml
+++ b/test/it/parser/src/main/resources/case/dml/insert.xml
@@ -2952,6 +2952,42 @@
</values>
</insert>
+ <insert sql-case-id="insert_with_nchar_4">
+ <table name="@table1" start-index="7" stop-index="13"/>
+ <columns start-index="15" stop-index="32">
+ <column name="c2" start-index="16" stop-index="17"/>
+ <column name="is_transient" start-index="20" stop-index="31"/>
+ </columns>
+ <values>
+ <value>
+ <assignment-value>
+ <literal-expression value="sample durable"
start-index="42" stop-index="58"/>
+ </assignment-value>
+ <assignment-value>
+ <literal-expression value="0" start-index="61"
stop-index="61"/>
+ </assignment-value>
+ </value>
+ </values>
+ </insert>
+
+ <insert sql-case-id="insert_with_nchar_5">
+ <table name="@table1" start-index="7" stop-index="13"/>
+ <columns start-index="15" stop-index="32">
+ <column name="c2" start-index="16" stop-index="17"/>
+ <column name="is_transient" start-index="20" stop-index="31"/>
+ </columns>
+ <values>
+ <value>
+ <assignment-value>
+ <literal-expression value="sample non-durable"
start-index="42" stop-index="62"/>
+ </assignment-value>
+ <assignment-value>
+ <literal-expression value="1" start-index="65"
stop-index="65"/>
+ </assignment-value>
+ </value>
+ </values>
+ </insert>
+
<insert sql-case-id="insert_with_data_base_name">
<table name="VariableTest" start-index="12" stop-index="46">
<owner name="dbo" start-index="31" stop-index="33">
diff --git a/test/it/parser/src/main/resources/case/dml/select-join.xml
b/test/it/parser/src/main/resources/case/dml/select-join.xml
index 84a575c1436..5d288fca063 100644
--- a/test/it/parser/src/main/resources/case/dml/select-join.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-join.xml
@@ -1368,4 +1368,107 @@
</expr>
</where>
</select>
+
+ <select sql-case-id="select_cross_apply_join_with_open_json_function">
+ <projections start-index="7" stop-index="339">
+ <column-projection name="reason" start-index="7" stop-index="12"/>
+ <column-projection name="score" start-index="15" stop-index="19"/>
+ <expression-projection text="JSON_VALUE(details,
'$.implementationDetails.script')" start-index="22" stop-index="83"
alias="script">
+ <expr>
+ <function text="JSON_VALUE(details,
'$.implementationDetails.script')" function-name="JSON_VALUE" start-index="31"
stop-index="83">
+ <parameter>
+ <column name="details" start-index="42"
stop-index="48"/>
+ </parameter>
+ <parameter>
+ <literal-expression
value="$.implementationDetails.script" start-index="51" stop-index="82"/>
+ </parameter>
+ </function>
+ </expr>
+ </expression-projection>
+ <shorthand-projection name="*" start-index="86" stop-index="103">
+ <owner name="planForceDetails" start-index="86"
stop-index="101"/>
+ </shorthand-projection>
+ <expression-projection start-index="106" stop-index="255"
text="regressedPlanExecutionCount + recommendedPlanExecutionCount) *
(regressedPlanCpuTimeAverage - recommendedPlanCpuTimeAverage)/100000"
alias="estimated_gain">
+ <expr>
+ <binary-operation-expression start-index="123"
stop-index="255">
+ <left>
+ <binary-operation-expression start-index="123"
stop-index="247">
+ <operator>*</operator>
+ <left>
+ <binary-operation-expression
start-index="124" stop-index="182">
+ <left>
+ <column
name="regressedPlanExecutionCount" start-index="124" stop-index="150"/>
+ </left>
+ <right>
+ <column
name="recommendedPlanExecutionCount" start-index="154" stop-index="182"/>
+ </right>
+ <operator>+</operator>
+ </binary-operation-expression>
+ </left>
+ <right>
+ <binary-operation-expression
start-index="188" stop-index="246">
+ <left>
+ <column
name="regressedPlanCpuTimeAverage" start-index="188" stop-index="214"/>
+ </left>
+ <right>
+ <column
name="recommendedPlanCpuTimeAverage" start-index="218" stop-index="246"/>
+ </right>
+ <operator>-</operator>
+ </binary-operation-expression>
+ </right>
+ </binary-operation-expression>
+ </left>
+ <right>
+ <literal-expression value="1000000"
start-index="249" stop-index="255"/>
+ </right>
+ <operator>/</operator>
+ </binary-operation-expression>
+ </expr>
+ </expression-projection>
+ <expression-projection text="IIF(regressedPlanErrorCount >
recommendedPlanErrorCount, 'YES','NO')" start-index="258" stop-index="339"
alias="error_prone">
+ <expr>
+ <function text="IIF(regressedPlanErrorCount >
recommendedPlanErrorCount, 'YES','NO')" start-index="272" stop-index="339"
function-name="IIF">
+ <parameter>
+ <binary-operation-expression start-index="276"
stop-index="326">
+ <left>
+ <column name="regressedPlanErrorCount"
start-index="276" stop-index="298"/>
+ </left>
+ <right>
+ <column name="recommendedPlanErrorCount"
start-index="302" stop-index="326"/>
+ </right>
+ <operator>></operator>
+ </binary-operation-expression>
+ </parameter>
+ <parameter>
+ <literal-expression value="YES" start-index="329"
stop-index="333"/>
+ </parameter>
+ <parameter>
+ <literal-expression value="NO" start-index="335"
stop-index="338"/>
+ </parameter>
+ </function>
+ </expr>
+ </expression-projection>
+ </projections>
+ <from start-index="346" stop-index="770">
+ <join-table join-type="CROSS">
+ <left>
+ <simple-table name="dm_db_tuning_recommendations"
start-index="346" stop-index="377">
+ <owner name="sys" start-index="346" stop-index="348"/>
+ </simple-table>
+ </left>
+ <right>
+ <function-table start-index="391" stop-index="750"
table-alias="planForceDetails">
+ <table-function function-name="OPENJSON"
text="OPENJSON (Details, '$.planForceDetails') WITH ([query_id] int
'$.queryId', regressedPlanId int '$.regressedPlanId', recommendedPlanId int
'$.recommendedPlanId', regressedPlanErrorCount int, recommendedPlanErrorCount
int, regressedPlanExecutionCount int, regressedPlanCpuTimeAverage float,
recommendedPlanExecutionCount int, recommendedPlanCpuTimeAverage float)">
+ <parameter>
+ <column name="Details" start-index="401"
stop-index="407"/>
+ </parameter>
+ <parameter>
+ <literal-expression value="$.planForceDetails"
start-index="410" stop-index="429"/>
+ </parameter>
+ </table-function>
+ </function-table>
+ </right>
+ </join-table>
+ </from>
+ </select>
</sql-parser-test-cases>
diff --git
a/test/it/parser/src/main/resources/case/dml/select-special-function.xml
b/test/it/parser/src/main/resources/case/dml/select-special-function.xml
index 9704599ec4b..9a3c2294499 100644
--- a/test/it/parser/src/main/resources/case/dml/select-special-function.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-special-function.xml
@@ -629,4 +629,38 @@
<expression-item expression="COUNT(*)" order-direction="DESC"
start-index="147" stop-index="154"/>
</order-by>
</select>
+
+ <select sql-case-id="select_from_open_json_function">
+ <projections start-index="7" stop-index="7">
+ <shorthand-projection start-index="7" stop-index="7"/>
+ </projections>
+ <from start-index="14" stop-index="101">
+ <function-table start-index="14" stop-index="102"
table-alias="months">
+ <table-function text="OPENJSON(@array) WITH ( month
VARCHAR(3), temp int, month_id tinyint '$.sql:identity()')"
function-name="OPENJSON">
+ <parameter>
+ <column name="@array" start-index="23"
stop-index="28"/>
+ </parameter>
+ </table-function>
+ </function-table>
+ </from>
+ </select>
+
+ <select sql-case-id="select_from_open_json_function_with_path">
+ <projections start-index="7" stop-index="18">
+ <column-projection name="key" start-index="7" stop-index="11"
start-delimiter='[' end-delimiter=']'/>
+ <column-projection name="value" start-index="14" stop-index="18"/>
+ </projections>
+ <from start-index="25" stop-index="64">
+ <function-table start-index="25" stop-index="64">
+ <table-function
text="OPENJSON(@json,'$.path.to."sub-object"')"
function-name="OPENJSON">
+ <parameter>
+ <column name="@json" start-index="34" stop-index="38"/>
+ </parameter>
+ <parameter>
+ <literal-expression
value="$.path.to."sub-object"" start-index="40" stop-index="63"/>
+ </parameter>
+ </table-function>
+ </function-table>
+ </from>
+ </select>
</sql-parser-test-cases>
diff --git a/test/it/parser/src/main/resources/case/dml/select.xml
b/test/it/parser/src/main/resources/case/dml/select.xml
index 74af7bda52a..1cd9add7632 100644
--- a/test/it/parser/src/main/resources/case/dml/select.xml
+++ b/test/it/parser/src/main/resources/case/dml/select.xml
@@ -8137,4 +8137,41 @@
</expression-projection>
</projections>
</select>
+
+ <select sql-case-id="select_with_contains_function">
+ <projections start-index="7" stop-index="16">
+ <column-projection name="product_id" start-index="7"
stop-index="16"/>
+ </projections>
+ <from start-index="23" stop-index="30">
+ <simple-table name="products" start-index="23" stop-index="30"/>
+ </from>
+ <where start-index="32" stop-index="157">
+ <expr>
+ <binary-operation-expression start-index="38" stop-index="157">
+ <left>
+ <function text="CONTAINS(product_description,
'"Snap Happy 100EZ" OR FORMSOF(THESAURUS,"Snap Happy") OR
"100EZ"')" function-name="CONTAINS" start-index="38" stop-index="134">
+ <parameter>
+ <column name="product_description"
start-index="47" stop-index="65"/>
+ </parameter>
+ <parameter>
+ <literal-expression value=""Snap Happy
100EZ" OR FORMSOF(THESAURUS,"Snap Happy") OR "100EZ""
start-index="68" stop-index="133"/>
+ </parameter>
+ </function>
+ </left>
+ <operator>AND</operator>
+ <right>
+ <binary-operation-expression start-index="140"
stop-index="157">
+ <left>
+ <column name="product_cost" start-index="140"
stop-index="151"/>
+ </left>
+ <right>
+ <literal-expression value="200"
start-index="155" stop-index="157"/>
+ </right>
+ <operator><</operator>
+ </binary-operation-expression>
+ </right>
+ </binary-operation-expression>
+ </expr>
+ </where>
+ </select>
</sql-parser-test-cases>
diff --git a/test/it/parser/src/main/resources/sql/supported/dml/insert.xml
b/test/it/parser/src/main/resources/sql/supported/dml/insert.xml
index bab46d33867..9b3f5949bb4 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/insert.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/insert.xml
@@ -106,6 +106,8 @@
<sql-case id="insert_with_nchar_1" value="INSERT INTO dbo.T1 VALUES (1,
N'Natalia')" db-types="SQLServer"/>
<sql-case id="insert_with_nchar_2" value="INSERT INTO dbo.T1 VALUES (2,
N'Mark')" db-types="SQLServer"/>
<sql-case id="insert_with_nchar_3" value="INSERT INTO dbo.T1 VALUES (3,
N'Randolph')" db-types="SQLServer"/>
+ <sql-case id="insert_with_nchar_4" value="INSERT @table1 (c2,
is_transient) VALUES (N'sample durable', 0)" db-types="SQLServer"/>
+ <sql-case id="insert_with_nchar_5" value="INSERT @table1 (c2,
is_transient) VALUES (N'sample non-durable', 1)" db-types="SQLServer"/>
<sql-case id="insert_with_batch_nchar" value="INSERT INTO
TestSchema.Employees (Name, Location) VALUES (N'Jared', N'Australia'),
(N'Nikita', N'India'), (N'Tom', N'Germany')" db-types="SQLServer"/>
<sql-case id="insert_with_data_base_name" value="INSERT INTO
AdventureWorks2022.dbo.VariableTest(Col1) VALUES('$(tablename)')"
db-types="SQLServer"/>
<sql-case id="insert_with_exec" value="INSERT INTO iris_rx_data
("Sepal.Length", "Sepal.Width", "Petal.Length",
"Petal.Width" , "Species") EXECUTE
sp_execute_external_script @language = N'R' , @script = N'iris_data <-
iris'" db-types="SQLServer"/>
diff --git
a/test/it/parser/src/main/resources/sql/supported/dml/select-join.xml
b/test/it/parser/src/main/resources/sql/supported/dml/select-join.xml
index be02e203615..053f0290cbd 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/select-join.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/select-join.xml
@@ -42,4 +42,5 @@
<sql-case id="select_cross_join_schema_table" value="SELECT s.ticket,
s.customer, r.store FROM dbo.Sales AS s CROSS JOIN dbo.Returns AS r WHERE
s.ticket = r.ticket AND s.type = 'toy' AND r.date = '2016-05-11'"
db-types="SQLServer"/>
<sql-case id="select_with_multi_join_01" value="SELECT
tat.transaction_begin_time, getdate() AS 'current time', es.program_name,
es.login_time, es.session_id, tst.open_transaction_count, eib.event_info FROM
sys.dm_tran_active_transactions tat JOIN sys.dm_tran_session_transactions tst
ON tat.transaction_id=tst.transaction_id JOIN sys.dm_exec_sessions es ON
tst.session_id=es.session_id CROSS APPLY
sys.dm_exec_input_buffer(es.session_id, NULL) eib WHERE es.is_user_process = 1
ORDER BY t [...]
<sql-case id="select_with_multi_join_02" value="SELECT text, 'DBCC
FREEPROCCACHE (0x' + CONVERT(VARCHAR (512), plan_handle, 2) + ')' AS
dbcc_freeproc_command FROM sys.dm_exec_cached_plans CROSS APPLY
sys.dm_exec_query_plan(plan_handle) CROSS APPLY
sys.dm_exec_sql_text(plan_handle) WHERE text LIKE '%person.person%'"
db-types="SQLServer"/>
+ <sql-case id="select_cross_apply_join_with_open_json_function"
value="SELECT reason, score, script = JSON_VALUE(details,
'$.implementationDetails.script'), planForceDetails.*, estimated_gain =
(regressedPlanExecutionCount + recommendedPlanExecutionCount) *
(regressedPlanCpuTimeAverage - recommendedPlanCpuTimeAverage)/1000000,
error_prone = IIF(regressedPlanErrorCount > recommendedPlanErrorCount,
'YES','NO') FROM sys.dm_db_tuning_recommendations CROSS APPLY OPENJSON
(Details, '$.planF [...]
</sql-cases>
diff --git
a/test/it/parser/src/main/resources/sql/supported/dml/select-special-function.xml
b/test/it/parser/src/main/resources/sql/supported/dml/select-special-function.xml
index 382afdca059..6b81fe723e1 100644
---
a/test/it/parser/src/main/resources/sql/supported/dml/select-special-function.xml
+++
b/test/it/parser/src/main/resources/sql/supported/dml/select-special-function.xml
@@ -45,4 +45,6 @@
<sql-case id="select_set_function" value="SELECT customer_id,
SET(cust_address_ntab) address FROM customers_demo ORDER BY customer_id;"
db-types="Oracle" />
<sql-case id="select_pivot" value="SELECT * FROM (SELECT * FROM sales)
PIVOT (SUM(amount) FOR month IN ('Jan', 'Feb'))" db-types="Oracle"/>
<sql-case id="select_string_split_function" value="SELECT value as tag,
COUNT(*) AS [number_of_articles] FROM Product CROSS APPLY STRING_SPLIT(Tags,
',') GROUP BY value HAVING COUNT(*) > 2 ORDER BY COUNT(*) DESC"
db-types="SQLServer"/>
+ <sql-case id="select_from_open_json_function" value="SELECT * FROM
OPENJSON(@array) WITH ( month VARCHAR(3), temp int, month_id tinyint
'$.sql:identity()') as months" db-types="SQLServer"/>
+ <sql-case id="select_from_open_json_function_with_path" value="SELECT
[key], value FROM OPENJSON(@json,'$.path.to."sub-object"')"
db-types="SQLServer"/>
</sql-cases>
diff --git a/test/it/parser/src/main/resources/sql/supported/dml/select.xml
b/test/it/parser/src/main/resources/sql/supported/dml/select.xml
index 6156dd62151..a75ed268f28 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/select.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/select.xml
@@ -247,4 +247,5 @@
<sql-case id="select_with_not_distinct_from" value="SELECT * FROM
#SampleTempTable WHERE id IS NOT DISTINCT FROM NULL" db-types="SQLServer"/>
<sql-case id="select_with_distinct_from" value="SELECT * FROM
#SampleTempTable WHERE id IS DISTINCT FROM 17;" db-types="SQLServer"/>
<sql-case id="select_with_database_files" value="SELECT name, size / 128.0
- CAST(FILEPROPERTY(name, 'SpaceUsed') AS INT) / 128.0 AS AvailableSpaceInMB
FROM sys.database_files" db-types="SQLServer"/>
+ <sql-case id="select_with_contains_function" value="SELECT product_id FROM
products WHERE CONTAINS(product_description, '"Snap Happy 100EZ" OR
FORMSOF(THESAURUS,"Snap Happy") OR "100EZ"') AND
product_cost < 200" db-types="SQLServer"/>
</sql-cases>