This is an automated email from the ASF dual-hosted git repository.

zhaojinchao 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 7e886d48bed Optimize the SQL parsing in Oracle support merge into 
select. (#28247)
7e886d48bed is described below

commit 7e886d48bed08a9caa4a44c712d5272994819824
Author: Cong Hu <[email protected]>
AuthorDate: Thu Aug 24 17:46:32 2023 +0800

    Optimize the SQL parsing in Oracle support merge into select. (#28247)
---
 .../statement/SQLStatementContextFactory.java      |   5 +
 .../statement/dml/MergeStatementContext.java       |  33 +++++++
 .../src/main/antlr4/imports/oracle/DMLStatement.g4 |   2 +-
 .../statement/type/OracleDMLStatementVisitor.java  |  13 ++-
 .../parser/src/main/resources/case/dml/merge.xml   | 102 +++++++++++++++++++++
 .../src/main/resources/sql/supported/dml/merge.xml |   1 +
 6 files changed, 153 insertions(+), 3 deletions(-)

diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/SQLStatementContextFactory.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/SQLStatementContextFactory.java
index 95dde06e49f..22bf72d0906 100644
--- 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/SQLStatementContextFactory.java
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/SQLStatementContextFactory.java
@@ -59,6 +59,7 @@ import 
org.apache.shardingsphere.infra.binder.context.statement.dal.ShowCreateTa
 import 
org.apache.shardingsphere.infra.binder.context.statement.dal.ShowIndexStatementContext;
 import 
org.apache.shardingsphere.infra.binder.context.statement.dal.ShowTableStatusStatementContext;
 import 
org.apache.shardingsphere.infra.binder.context.statement.dal.ShowTablesStatementContext;
+import 
org.apache.shardingsphere.infra.binder.context.statement.dml.MergeStatementContext;
 import 
org.apache.shardingsphere.infra.binder.context.statement.dcl.DenyUserStatementContext;
 import 
org.apache.shardingsphere.infra.binder.context.statement.dml.SelectStatementContext;
 import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
@@ -109,6 +110,7 @@ import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQ
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLLoadDataStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLLoadXMLStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.opengauss.ddl.OpenGaussCursorStatement;
+import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.oracle.dml.OracleMergeStatement;
 import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.dcl.SQLServerDenyUserStatement;
 
 import java.util.List;
@@ -173,6 +175,9 @@ public final class SQLStatementContextFactory {
         if (sqlStatement instanceof MySQLLoadXMLStatement) {
             return new LoadXMLStatementContext((MySQLLoadXMLStatement) 
sqlStatement);
         }
+        if (sqlStatement instanceof OracleMergeStatement) {
+            return new MergeStatementContext((OracleMergeStatement) 
sqlStatement);
+        }
         throw new UnsupportedSQLOperationException(String.format("Unsupported 
SQL statement `%s`", sqlStatement.getClass().getSimpleName()));
     }
     
diff --git 
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/MergeStatementContext.java
 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/MergeStatementContext.java
new file mode 100644
index 00000000000..40ab28d71d2
--- /dev/null
+++ 
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/statement/dml/MergeStatementContext.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.shardingsphere.infra.binder.context.statement.dml;
+
+import lombok.Getter;
+import 
org.apache.shardingsphere.infra.binder.context.statement.CommonSQLStatementContext;
+import 
org.apache.shardingsphere.sql.parser.sql.dialect.statement.oracle.dml.OracleMergeStatement;
+
+/**
+ * Load xml statement context.
+ */
+@Getter
+public final class MergeStatementContext extends CommonSQLStatementContext {
+    
+    public MergeStatementContext(final OracleMergeStatement sqlStatement) {
+        super(sqlStatement);
+    }
+}
diff --git 
a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/DMLStatement.g4 
b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/DMLStatement.g4
index 30859d8b31c..2f230d27517 100644
--- a/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/DMLStatement.g4
+++ b/parser/sql/dialect/oracle/src/main/antlr4/imports/oracle/DMLStatement.g4
@@ -719,7 +719,7 @@ hint
     ;
 
 intoClause
-    : INTO (tableName | viewName) alias?
+    : INTO (tableName | viewName | subquery) alias?
     ;
 
 usingClause
diff --git 
a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
 
b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
index 006199edca8..e1f1e4ff065 100644
--- 
a/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
+++ 
b/parser/sql/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
@@ -1135,7 +1135,7 @@ public final class OracleDMLStatementVisitor extends 
OracleStatementVisitor impl
     @Override
     public ASTNode visitMerge(final MergeContext ctx) {
         OracleMergeStatement result = new OracleMergeStatement();
-        result.setTarget((SimpleTableSegment) visit(ctx.intoClause()));
+        result.setTarget((TableSegment) visit(ctx.intoClause()));
         result.setSource((TableSegment) visit(ctx.usingClause()));
         result.setExpr((ExpressionSegment) visit(ctx.usingClause().expr()));
         if (null != ctx.mergeUpdateClause()) {
@@ -1194,7 +1194,16 @@ public final class OracleDMLStatementVisitor extends 
OracleStatementVisitor impl
             }
             return result;
         }
-        SimpleTableSegment result = (SimpleTableSegment) visit(ctx.viewName());
+        if (null != ctx.viewName()) {
+            SimpleTableSegment result = (SimpleTableSegment) 
visit(ctx.viewName());
+            if (null != ctx.alias()) {
+                result.setAlias((AliasSegment) visit(ctx.alias()));
+            }
+            return result;
+        }
+        OracleSelectStatement subquery = (OracleSelectStatement) 
visit(ctx.subquery());
+        SubquerySegment subquerySegment = new 
SubquerySegment(ctx.subquery().start.getStartIndex(), 
ctx.subquery().stop.getStopIndex(), subquery);
+        SubqueryTableSegment result = new 
SubqueryTableSegment(subquerySegment);
         if (null != ctx.alias()) {
             result.setAlias((AliasSegment) visit(ctx.alias()));
         }
diff --git a/test/it/parser/src/main/resources/case/dml/merge.xml 
b/test/it/parser/src/main/resources/case/dml/merge.xml
index 34425e915c9..62800c80341 100644
--- a/test/it/parser/src/main/resources/case/dml/merge.xml
+++ b/test/it/parser/src/main/resources/case/dml/merge.xml
@@ -293,4 +293,106 @@
             </where>
         </insert>
     </merge>
+    <merge sql-case-id="merge_into_select">
+        <target>
+            <subquery-table alias="D">
+                <subquery>
+                    <select>
+                        <projections start-index="19" stop-index="19" >
+                            <shorthand-projection start-index="19" 
stop-index="19" />
+                        </projections>
+                        <from>
+                            <simple-table name="bonuses" start-index="26" 
stop-index="32" />
+                        </from>
+                        <where start-index="34" stop-index="57">
+                            <expr>
+                                <binary-operation-expression start-index="40" 
stop-index="57">
+                                    <left>
+                                        <column name="department_id" 
start-index="40" stop-index="52" />
+                                    </left>
+                                    <operator>=</operator>
+                                    <right>
+                                        <literal-expression value="80" 
start-index="56" stop-index="57" />
+                                    </right>
+                                </binary-operation-expression>
+                            </expr>
+                        </where>
+                    </select>
+                </subquery>
+            </subquery-table>
+        </target>
+        <source>
+            <subquery-table alias="S">
+                <subquery>
+                    <select>
+                        <from>
+                            <simple-table name="employees" start-index="116" 
stop-index="124" />
+                        </from>
+                        <projections start-index="76" stop-index="109">
+                            <column-projection name="employee_id" 
start-index="76" stop-index="86" />
+                            <column-projection name="salary" start-index="89" 
stop-index="94" />
+                            <column-projection name="department_id" 
start-index="97" stop-index="109" />
+                        </projections>
+                        <where start-index="126" stop-index="149">
+                            <expr>
+                                <binary-operation-expression start-index="132" 
stop-index="149">
+                                    <left>
+                                        <column name="department_id" 
start-index="132" stop-index="144" />
+                                    </left>
+                                    <operator>=</operator>
+                                    <right>
+                                        <literal-expression value="80" 
start-index="148" stop-index="149" />
+                                    </right>
+                                </binary-operation-expression>
+                            </expr>
+                        </where>
+                    </select>
+                </subquery>
+            </subquery-table>
+        </source>
+        <expr>
+            <binary-operation-expression start-index="158" stop-index="186">
+                <left>
+                    <column name="employee_id" start-index="158" 
stop-index="170">
+                        <owner name="D" start-index="158" stop-index="158" />
+                    </column>
+                </left>
+                <operator>=</operator>
+                <right>
+                    <column name="employee_id" start-index="174" 
stop-index="186">
+                        <owner name="S" start-index="174" stop-index="174" />
+                    </column>
+                </right>
+            </binary-operation-expression>
+        </expr>
+        <update>
+            <set start-index="218" stop-index="249">
+                <assignment start-index="218" stop-index="249">
+                    <column name="bonus" start-index="218" stop-index="224">
+                        <owner name="D" start-index="218" stop-index="218" />
+                    </column>
+                    <assignment-value>
+                        <literal-expression value="D.bonus + S.salary*.01" 
start-index="228" stop-index="249" />
+                    </assignment-value>
+                </assignment>
+            </set>
+        </update>
+        <delete>
+            <where start-index="251" stop-index="280">
+                <expr>
+                    <binary-operation-expression start-index="265" 
stop-index="279">
+                        <left>
+                            <column name="salary" start-index="265" 
stop-index="272">
+                                <owner name="S" start-index="265" 
stop-index="265" />
+                            </column>
+                        </left>
+                        <operator>&gt;</operator>
+                        <right>
+                            <literal-expression value="8000" start-index="276" 
stop-index="279" />
+                        </right>
+                    </binary-operation-expression>
+                </expr>
+            </where>
+        </delete>
+    </merge>
 </sql-parser-test-cases>
diff --git a/test/it/parser/src/main/resources/sql/supported/dml/merge.xml 
b/test/it/parser/src/main/resources/sql/supported/dml/merge.xml
index ca9d0e8d79b..de66626b021 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/merge.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/merge.xml
@@ -22,4 +22,5 @@
     <sql-case id="merge_update_table" value="MERGE INTO people_target pt USING 
people_source ps ON (pt.person_id = ps.person_id) WHEN MATCHED THEN UPDATE SET 
pt.first_name = ps.first_name, pt.last_name = ps.last_name, pt.title = 
ps.title" db-types="Oracle" />
     <sql-case id="merge_update_table_with_delete" value="MERGE INTO bonuses D 
USING (SELECT employee_id, salary, department_id FROM employees WHERE 
department_id = 80) S ON (D.employee_id = S.employee_id) WHEN MATCHED THEN 
UPDATE SET D.bonus = D.bonus + S.salary*.01 DELETE WHERE (S.salary > 8000)" 
db-types="Oracle" />
     <sql-case id="merge_update_and_insert_table" value="MERGE INTO bonuses D   
 USING (SELECT employee_id, salary, department_id FROM hr.employees    WHERE 
department_id = 80) S    ON (D.employee_id = S.employee_id)    WHEN MATCHED 
THEN UPDATE SET D.bonus = D.bonus + S.salary*.01      DELETE WHERE (S.salary = 
8000)    WHEN NOT MATCHED THEN INSERT (D.employee_id, D.bonus)      VALUES 
(S.employee_id, S.salary*.01)      WHERE (S.salary &lt;= 8000);"  
db-types="Oracle" />
+    <sql-case id="merge_into_select" value="MERGE INTO (SELECT * FROM bonuses 
WHERE department_id = 80) D USING (SELECT employee_id, salary, department_id 
FROM employees WHERE department_id = 80) S ON (D.employee_id = S.employee_id) 
WHEN MATCHED THEN UPDATE SET D.bonus = D.bonus + S.salary*.01 DELETE WHERE 
(S.salary > 8000)" db-types="Oracle" />
 </sql-cases>

Reply via email to