You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by du...@apache.org on 2025/04/24 09:11:36 UTC

(shardingsphere) branch master updated: Support Oracle json_object function parsing (#35238)

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 1f25074bc30 Support Oracle json_object function parsing (#35238)
1f25074bc30 is described below

commit 1f25074bc30ee581b53e7026e2903b70317cbbd3
Author: ZhangCheng <ch...@apache.org>
AuthorDate: Thu Apr 24 17:11:29 2025 +0800

    Support Oracle json_object function parsing (#35238)
    
    * Support Oracle json_object function parsing
    
    * Support Oracle json_object function parsing
    
    * Support Oracle json_object function parsing
---
 .../src/main/antlr4/imports/oracle/BaseRule.g4     | 22 +++++++++++++++++-
 .../src/main/antlr4/imports/oracle/Keyword.g4      |  4 ++++
 .../main/antlr4/imports/oracle/OracleKeyword.g4    |  4 ++++
 .../visitor/statement/OracleStatementVisitor.java  | 16 ++++++++++++-
 .../resources/case/dml/select-special-function.xml | 26 ++++++++++++++++++++++
 .../sql/supported/dml/select-special-function.xml  |  1 +
 6 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4 b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4
index 2c59db05818..7403ba133a1 100644
--- a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4
+++ b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/BaseRule.g4
@@ -550,7 +550,27 @@ leadLagInfo
 
 specialFunction
     : castFunction | charFunction | extractFunction | formatFunction | firstOrLastValueFunction | trimFunction | featureFunction
-    | setFunction | translateFunction | cursorFunction | toDateFunction | approxRank | wmConcatFunction | predictionCostFunction
+    | setFunction | translateFunction | cursorFunction | toDateFunction | approxRank | wmConcatFunction | predictionCostFunction | jsonObjectFunction
+    ;
+
+jsonObjectFunction
+    : JSON_OBJECT LP_ jsonObjectContent RP_
+    ;
+
+jsonObjectContent
+    : jsonObjectKeyValue (COMMA_ jsonObjectKeyValue)* jsonOnNullClause? jsonReturnClause?
+    ;
+
+jsonOnNullClause
+    : (NULL | ABSENT) ON NULL
+    ;
+
+jsonReturnClause
+    : RETURNING VARCHAR2 (LP_ INTEGER_ ( BYTE | CHAR)? RP_)?
+    ;
+    
+jsonObjectKeyValue
+    : (KEY? expr VALUE expr) (FORMAT JSON)?
     ;
 
 predictionCostFunction
diff --git a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/Keyword.g4 b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/Keyword.g4
index fa46ae24e9a..ec2091e6892 100644
--- a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/Keyword.g4
+++ b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/Keyword.g4
@@ -1140,6 +1140,10 @@ JSONPRINT
     : J S O N P R I N T
     ;
 
+JSON_OBJECT
+    : J S O N UL_ O B J E C T
+    ;
+
 LINESIZE
     : L I N E S I Z E
     ;
diff --git a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/OracleKeyword.g4 b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/OracleKeyword.g4
index 5fd42845599..f9f3d2fad5e 100644
--- a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/OracleKeyword.g4
+++ b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/OracleKeyword.g4
@@ -19,6 +19,10 @@ lexer grammar OracleKeyword;
 
 import Alphabet;
 
+ABSENT
+    : A B S E N T
+    ;
+
 BEQUEATH
     : B E Q U E A T H
     ;
diff --git a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/OracleStatementVisitor.java b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/OracleStatementVisitor.java
index 688b79209f8..125ce772a0c 100644
--- a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/OracleStatementVisitor.java
+++ b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/OracleStatementVisitor.java
@@ -60,6 +60,8 @@ import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IndexT
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IntervalDayToSecondExpressionContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IntervalExpressionContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.IntervalYearToMonthExpressionContext;
+import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.JsonObjectFunctionContext;
+import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.JsonObjectKeyValueContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.LiteralsContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.NullValueLiteralsContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.NumberLiteralsContext;
@@ -1051,9 +1053,21 @@ public abstract class OracleStatementVisitor extends OracleStatementBaseVisitor<
         if (null != ctx.predictionCostFunction()) {
             return visit(ctx.predictionCostFunction());
         }
+        if (null != ctx.jsonObjectFunction()) {
+            return visit(ctx.jsonObjectFunction());
+        }
         throw new IllegalStateException(
                 "SpecialFunctionContext must have castFunction, charFunction, extractFunction, formatFunction, firstOrLastValueFunction, "
-                        + "trimFunction, toDateFunction, approxCount, predictionCostFunction or featureFunction.");
+                        + "trimFunction, toDateFunction, approxCount, predictionCostFunction, jsonObjectFunction or featureFunction.");
+    }
+    
+    @Override
+    public ASTNode visitJsonObjectFunction(final JsonObjectFunctionContext ctx) {
+        FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.JSON_OBJECT().getText(), getOriginalText(ctx));
+        for (JsonObjectKeyValueContext each : ctx.jsonObjectContent().jsonObjectKeyValue()) {
+            result.getParameters().addAll(getExpressions(each.expr()));
+        }
+        return result;
     }
     
     @Override
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 b22f2d84522..dfe451a1e12 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
@@ -5229,4 +5229,30 @@
             </expression-projection>
         </projections>
     </select>
+
+    <select sql-case-id="select_with_json_object_function">
+        <projections start-index="7" stop-index="67">
+            <expression-projection text="JSON_OBJECT('name' VALUE 'John', 'age' VALUE 30)" alias="json_data" start-index="7" stop-index="67">
+                <expr start-index="7" stop-index="54">
+                    <function function-name="JSON_OBJECT" text="JSON_OBJECT('name' VALUE 'John', 'age' VALUE 30)" start-index="7" stop-index="54">
+                        <parameter start-index="19" stop-index="24">
+                            <literal-expression value="name" start-index="19" stop-index="24"/>
+                        </parameter>
+                        <parameter start-index="32" stop-index="37">
+                            <literal-expression value="John" start-index="32" stop-index="37"/>
+                        </parameter>
+                        <parameter start-index="40" stop-index="44">
+                            <literal-expression value="age" start-index="40" stop-index="44"/>
+                        </parameter>
+                        <parameter start-index="52" stop-index="53">
+                            <literal-expression value="30" start-index="52" stop-index="53"/>
+                        </parameter>
+                    </function>
+                </expr>
+            </expression-projection>
+        </projections>
+        <from start-index="74" stop-index="77">
+            <simple-table name="DUAL" start-index="74" stop-index="77"/>
+        </from>
+    </select>
 </sql-parser-test-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 8e0bc506dc2..786224cf5b2 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
@@ -302,4 +302,5 @@
     <sql-case id="select_percent_rank" value="SELECT PERCENT_RANK() OVER (ORDER BY salary) FROM employees;" db-types="MySQL" />
     <sql-case id="select_pi" value="SELECT PI()" db-types="MySQL" />
     <sql-case id="select_regexp" value="SELECT 'a' REGEXP '^[a-d]'" db-types="MySQL" />
+    <sql-case id="select_with_json_object_function" value="SELECT JSON_OBJECT('name' VALUE 'John', 'age' VALUE 30) AS json_data FROM DUAL" db-types="Oracle" />
 </sql-cases>