This is an automated email from the ASF dual-hosted git repository.
strongduanmu 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 81994d66d72 Fix Oracle DML scalar subqueries and system datetime
functions (#39710)
81994d66d72 is described below
commit 81994d66d7258ed533667e1c20c27ae4a512e989
Author: ZhangCheng <[email protected]>
AuthorDate: Thu Sep 3 19:15:58 2026 +0800
Fix Oracle DML scalar subqueries and system datetime functions (#39710)
* Fix Oracle DML parser
* Preserve bare function syntax in SQL node converter
* Limit bare function conversion to Oracle system functions
---
.../segment/expression/impl/FunctionConverter.java | 9 ++
.../expression/impl/FunctionConverterTest.java | 24 +++++
.../src/main/antlr4/imports/oracle/DMLStatement.g4 | 4 +-
.../visitor/statement/OracleStatementVisitor.java | 10 ++
.../statement/type/OracleDMLStatementVisitor.java | 25 +++--
.../type/OracleDMLStatementVisitorTest.java | 103 +++++++++++++++++++++
.../parser/src/main/resources/case/dml/delete.xml | 2 +-
.../parser/src/main/resources/case/dml/insert.xml | 4 +-
.../parser/src/main/resources/case/dml/select.xml | 46 +++++++--
.../main/resources/sql/supported/dml/select.xml | 3 +-
10 files changed, 201 insertions(+), 29 deletions(-)
diff --git
a/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverter.java
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverter.java
index 1a69b1faad1..72c75de1df4 100644
---
a/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverter.java
+++
b/kernel/sql-federation/compiler/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverter.java
@@ -66,6 +66,9 @@ public final class FunctionConverter {
if ("OVER".equalsIgnoreCase(functionName.getSimple())) {
return WindowFunctionConverter.convert(segment);
}
+ if (isSystemDateTimeFunctionWithoutParentheses(segment)) {
+ return functionName;
+ }
List<SqlOperator> functions = new LinkedList<>();
SqlStdOperatorTable.instance().lookupOperatorOverloads(functionName,
null, SqlSyntax.FUNCTION, functions, SqlNameMatchers.withCaseSensitive(false));
if (!functions.isEmpty() && segment.getWindow().isPresent()) {
@@ -79,6 +82,12 @@ public final class FunctionConverter {
return new SqlBasicCall(operator,
getFunctionParameters(segment.getParameters()), SqlParserPos.ZERO);
}
+ private static boolean isSystemDateTimeFunctionWithoutParentheses(final
FunctionSegment segment) {
+ String functionName = segment.getFunctionName();
+ return null == segment.getOwner() && segment.getParameters().isEmpty()
&& segment.getText().equalsIgnoreCase(functionName)
+ && ("SYSDATE".equalsIgnoreCase(functionName) ||
"SYSTIMESTAMP".equalsIgnoreCase(functionName));
+ }
+
private static List<String> getQualifiedFunctionNames(final
FunctionSegment segment) {
List<String> result = null == segment.getOwner() ? new LinkedList<>()
: OwnerConverter.convert(segment.getOwner());
result.add(segment.getFunctionName());
diff --git
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverterTest.java
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverterTest.java
index f15dfdb8ec6..56d6232957c 100644
---
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverterTest.java
+++
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverterTest.java
@@ -61,6 +61,30 @@ class FunctionConverterTest {
assertThat(actual.getSimple(), is("CURRENT_USER"));
}
+ @Test
+ void assertConvertSysdateWithoutParentheses() {
+ FunctionSegment segment = new FunctionSegment(0, 0, "SYSDATE",
"SYSDATE");
+ assertThat(FunctionConverter.convert(segment),
isA(SqlIdentifier.class));
+ }
+
+ @Test
+ void assertConvertSystimestampWithoutParentheses() {
+ FunctionSegment segment = new FunctionSegment(0, 0, "SYSTIMESTAMP",
"SYSTIMESTAMP");
+ assertThat(FunctionConverter.convert(segment),
isA(SqlIdentifier.class));
+ }
+
+ @Test
+ void assertConvertFunctionWithParentheses() {
+ FunctionSegment segment = new FunctionSegment(0, 0, "SYSDATE",
"SYSDATE()");
+ assertThat(FunctionConverter.convert(segment),
isA(SqlBasicCall.class));
+ }
+
+ @Test
+ void assertConvertOtherFunctionWithoutParentheses() {
+ FunctionSegment segment = new FunctionSegment(0, 0, "CUSTOM_FUNC",
"CUSTOM_FUNC");
+ assertThat(FunctionConverter.convert(segment),
isA(SqlBasicCall.class));
+ }
+
@Test
void assertConvertDelegatesToTrimFunctionConverter() {
FunctionSegment segment = new FunctionSegment(0, 0, "TRIM", "TRIM");
diff --git
a/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/DMLStatement.g4
b/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/DMLStatement.g4
index 745c3392bcb..054e3e5cdd3 100644
---
a/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/DMLStatement.g4
+++
b/parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/DMLStatement.g4
@@ -816,7 +816,7 @@ mergeAssignment
;
mergeAssignmentValue
- : expr | DEFAULT
+ : expr | LP_ selectSubquery RP_ | DEFAULT
;
deleteWhereClause
@@ -832,7 +832,7 @@ mergeInsertColumn
;
mergeColumnValue
- : VALUES LP_ (expr | DEFAULT) (COMMA_ (expr | DEFAULT))* RP_
+ : VALUES LP_ mergeAssignmentValue (COMMA_ mergeAssignmentValue)* RP_
;
errorLoggingClause
diff --git
a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/OracleStatementVisitor.java
b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/OracleStatementVisitor.java
index 31688e4c7bf..44de9435938 100644
---
a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/OracleStatementVisitor.java
+++
b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/OracleStatementVisitor.java
@@ -504,6 +504,9 @@ public abstract class OracleStatementVisitor extends
OracleStatementBaseVisitor<
@Override
public final ASTNode visitColumnName(final ColumnNameContext ctx) {
+ if (isSystemDateTimeFunction(ctx)) {
+ return new FunctionSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), ctx.name().getText(), getOriginalText(ctx));
+ }
if (SequenceFunction.valueFrom(ctx.name().getText()).isPresent()) {
return createSequenceFunction(ctx);
}
@@ -523,6 +526,13 @@ public abstract class OracleStatementVisitor extends
OracleStatementBaseVisitor<
return result;
}
+ private boolean isSystemDateTimeFunction(final ColumnNameContext ctx) {
+ if (null != ctx.owner() || null != ctx.nestedItem() &&
!ctx.nestedItem().isEmpty()) {
+ return false;
+ }
+ return "SYSDATE".equalsIgnoreCase(ctx.name().getText()) ||
"SYSTIMESTAMP".equalsIgnoreCase(ctx.name().getText());
+ }
+
private FunctionSegment createSequenceFunction(final ColumnNameContext
ctx) {
FunctionSegment result = new
FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(),
ctx.name().getText(), getOriginalText(ctx));
OwnerContext owner = ctx.owner();
diff --git
a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
index 15c1df850fa..5859d542aa9 100644
---
a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
+++
b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
@@ -330,14 +330,10 @@ public final class OracleDMLStatementVisitor extends
OracleStatementVisitor impl
SubquerySegment subquerySegment = new
SubquerySegment(ctx.selectSubquery().start.getStartIndex(),
ctx.selectSubquery().stop.getStopIndex(),
(SelectStatement) visit(ctx.selectSubquery()),
getOriginalText(ctx.selectSubquery()));
SubqueryExpressionSegment value = new
SubqueryExpressionSegment(subquerySegment);
- ColumnAssignmentSegment result = new
ColumnAssignmentSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), columnSegments, value);
- result.getColumns().add(column);
- return result;
+ return new ColumnAssignmentSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), columnSegments, value);
}
CommonExpressionSegment value = new
CommonExpressionSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), ctx.DEFAULT().getText());
- ColumnAssignmentSegment result = new
ColumnAssignmentSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), columnSegments, value);
- result.getColumns().add(column);
- return result;
+ return new ColumnAssignmentSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), columnSegments, value);
}
private ColumnAssignmentSegment
createAssignmentSegmentFromMultiColumnAssignment(final
UpdateSetColumnClauseContext ctx) {
@@ -358,16 +354,12 @@ public final class OracleDMLStatementVisitor extends
OracleStatementVisitor impl
columnSegments.add(column);
if (null != ctx.expr()) {
ExpressionSegment value = (ExpressionSegment) visit(ctx.expr());
- ColumnAssignmentSegment result = new
ColumnAssignmentSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), columnSegments, value);
- result.getColumns().add(column);
- return result;
+ return new ColumnAssignmentSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), columnSegments, value);
} else {
SubquerySegment subquerySegment = new
SubquerySegment(ctx.selectSubquery().start.getStartIndex(),
ctx.selectSubquery().stop.getStopIndex(),
(SelectStatement) visit(ctx.selectSubquery()),
getOriginalText(ctx.selectSubquery()));
SubqueryExpressionSegment value = new
SubqueryExpressionSegment(subquerySegment);
- ColumnAssignmentSegment result = new
ColumnAssignmentSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), columnSegments, value);
- result.getColumns().add(column);
- return result;
+ return new ColumnAssignmentSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), columnSegments, value);
}
}
@@ -1679,8 +1671,8 @@ public final class OracleDMLStatementVisitor extends
OracleStatementVisitor impl
public ASTNode visitMergeColumnValue(final MergeColumnValueContext ctx) {
CollectionValue<InsertValuesSegment> result = new CollectionValue<>();
List<ExpressionSegment> segments = new LinkedList<>();
- for (ExprContext each : ctx.expr()) {
- segments.add(null == each ? new
CommonExpressionSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), ctx.getText()) : (ExpressionSegment) visit(each));
+ for (MergeAssignmentValueContext each : ctx.mergeAssignmentValue()) {
+ segments.add((ExpressionSegment) visit(each));
}
result.getValue().add(new
InsertValuesSegment(ctx.LP_().getSymbol().getStartIndex(),
ctx.RP_().getSymbol().getStopIndex(), segments));
return result;
@@ -1773,6 +1765,11 @@ public final class OracleDMLStatementVisitor extends
OracleStatementVisitor impl
@Override
public ASTNode visitMergeAssignmentValue(final MergeAssignmentValueContext
ctx) {
+ if (null != ctx.selectSubquery()) {
+ SelectStatement selectStatement = (SelectStatement)
visit(ctx.selectSubquery());
+ SubquerySegment subquerySegment = new
SubquerySegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(),
selectStatement, getOriginalText(ctx));
+ return new SubqueryExpressionSegment(subquerySegment);
+ }
ExprContext expr = ctx.expr();
return null == expr ? new
CommonExpressionSegment(ctx.getStart().getStartIndex(),
ctx.getStop().getStopIndex(), ctx.getText()) : visit(expr);
}
diff --git
a/parser/sql/engine/dialect/oracle/src/test/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitorTest.java
b/parser/sql/engine/dialect/oracle/src/test/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitorTest.java
new file mode 100644
index 00000000000..7f83dbd5825
--- /dev/null
+++
b/parser/sql/engine/dialect/oracle/src/test/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitorTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.sql.parser.engine.oracle.visitor.statement.type;
+
+import org.apache.shardingsphere.sql.parser.engine.api.CacheOption;
+import org.apache.shardingsphere.sql.parser.engine.api.SQLParserEngine;
+import
org.apache.shardingsphere.sql.parser.engine.api.SQLStatementVisitorEngine;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.MergeStatement;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.UpdateStatement;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isA;
+
+class OracleDMLStatementVisitorTest {
+
+ private static final CacheOption CACHE_OPTION = new CacheOption(128,
1024L);
+
+ @Test
+ void assertVisitMergeUpdateWithScalarSubquery() {
+ MergeStatement actual = parseMerge("MERGE INTO t_user target USING
(SELECT ? user_id FROM DUAL) source ON (target.user_id = source.user_id) "
+ + "WHEN MATCHED THEN UPDATE SET target.email = (SELECT
MAX(u.email) FROM t_user u WHERE u.user_id < ?)");
+ ExpressionSegment actualValue =
actual.getUpdate().get().getAssignment().get().getAssignments().iterator().next().getValue();
+ assertThat(actualValue, isA(SubqueryExpressionSegment.class));
+ assertThat(actualValue.getText(), is("(SELECT MAX(u.email) FROM t_user
u WHERE u.user_id < ?)"));
+ assertThat(actual.getParameterCount(), is(2));
+ }
+
+ @Test
+ void assertVisitMergeInsertWithScalarSubquery() {
+ MergeStatement actual = parseMerge("MERGE INTO t_user target USING
(SELECT ? user_id FROM DUAL) source ON (target.user_id = source.user_id) "
+ + "WHEN NOT MATCHED THEN INSERT (user_id, email) VALUES
(source.user_id, (SELECT MAX(u.email) FROM t_user u WHERE u.user_id < ?))");
+ ExpressionSegment actualValue =
actual.getInsert().get().getValues().iterator().next().getValues().get(1);
+ assertThat(actualValue, isA(SubqueryExpressionSegment.class));
+ assertThat(actualValue.getText(), is("(SELECT MAX(u.email) FROM t_user
u WHERE u.user_id < ?)"));
+ assertThat(actual.getParameterCount(), is(2));
+ }
+
+ @Test
+ void assertVisitSystemDateTimeFunctions() {
+ MergeStatement actual = parseMerge("MERGE INTO t_user target USING
(SELECT ? user_id FROM DUAL) source ON (target.user_id = source.user_id) "
+ + "WHEN MATCHED THEN UPDATE SET target.creation_date = SYSDATE
"
+ + "WHEN NOT MATCHED THEN INSERT (user_id, creation_date)
VALUES (source.user_id, CAST(SYSTIMESTAMP AS TIMESTAMP))");
+ ExpressionSegment actualSysdate =
actual.getUpdate().get().getAssignment().get().getAssignments().iterator().next().getValue();
+ FunctionSegment actualCast = (FunctionSegment)
actual.getInsert().get().getValues().iterator().next().getValues().get(1);
+ assertThat(actualSysdate, isA(FunctionSegment.class));
+ assertThat(((FunctionSegment) actualSysdate).getFunctionName(),
is("SYSDATE"));
+ assertThat(actualCast.getParameters().iterator().next(),
isA(FunctionSegment.class));
+ assertThat(((FunctionSegment)
actualCast.getParameters().iterator().next()).getFunctionName(),
is("SYSTIMESTAMP"));
+ }
+
+ @Test
+ void assertVisitQuotedSystemDateTimeColumn() {
+ MergeStatement actual = parseMerge("MERGE INTO t_user target USING
(SELECT ? user_id FROM DUAL) source ON (target.user_id = source.user_id) "
+ + "WHEN MATCHED THEN UPDATE SET target.creation_date =
\"SYSDATE\"");
+
assertThat(actual.getUpdate().get().getAssignment().get().getAssignments().iterator().next().getValue(),
isA(ColumnSegment.class));
+ }
+
+ @Test
+ void assertVisitUpdateAssignmentWithScalarSubquery() {
+ UpdateStatement actual = parseUpdate("UPDATE t_order SET status =
(SELECT ? FROM DUAL) WHERE order_id = ?");
+
assertThat(actual.getAssignment().get().getAssignments().iterator().next().getColumns().size(),
is(1));
+
assertThat(actual.getAssignment().get().getAssignments().iterator().next().getValue(),
isA(SubqueryExpressionSegment.class));
+ }
+
+ @Test
+ void assertVisitUpdateValueAssignment() {
+ UpdateStatement actual = parseUpdate("UPDATE ot1 SET VALUE(ot1.x) =
t1(20) WHERE VALUE(ot1.x) = t1(10)");
+
assertThat(actual.getAssignment().get().getAssignments().iterator().next().getColumns().size(),
is(1));
+ }
+
+ private MergeStatement parseMerge(final String sql) {
+ return (MergeStatement) parse(sql);
+ }
+
+ private UpdateStatement parseUpdate(final String sql) {
+ return (UpdateStatement) parse(sql);
+ }
+
+ private Object parse(final String sql) {
+ return new SQLStatementVisitorEngine("Oracle").visit(new
SQLParserEngine("Oracle", CACHE_OPTION).parse(sql, false));
+ }
+}
diff --git a/test/it/parser/src/main/resources/case/dml/delete.xml
b/test/it/parser/src/main/resources/case/dml/delete.xml
index 16d8d19e03e..2065465739c 100644
--- a/test/it/parser/src/main/resources/case/dml/delete.xml
+++ b/test/it/parser/src/main/resources/case/dml/delete.xml
@@ -762,7 +762,7 @@
</left>
<operator><</operator>
<right>
- <column name="SYSDATE" start-index="87"
stop-index="93" />
+ <function function-name="SYSDATE"
text="SYSDATE" start-index="87" stop-index="93" />
</right>
</binary-operation-expression>
</right>
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 2605405fcb9..8f4bd5d3263 100644
--- a/test/it/parser/src/main/resources/case/dml/insert.xml
+++ b/test/it/parser/src/main/resources/case/dml/insert.xml
@@ -2232,7 +2232,7 @@
<literal-expression value="[email protected]"
start-index="133" stop-index="154" />
</assignment-value>
<assignment-value>
- <column name="sysdate" start-index="157" stop-index="163"
/>
+ <function function-name="sysdate" text="sysdate"
start-index="157" stop-index="163" />
</assignment-value>
<assignment-value>
<literal-expression value="PU_CLERK" start-index="166"
stop-index="175" />
@@ -2915,7 +2915,7 @@
<literal-expression value="500 Oracle Parkway"
start-index="60" stop-index="79" literal-start-index="59"
literal-stop-index="79" />
</assignment-value>
<assignment-value>
- <column name="sysdate" start-index="81" stop-index="87"
literal-start-index="81" literal-stop-index="87" />
+ <function function-name="sysdate" text="sysdate"
start-index="81" stop-index="87" literal-start-index="81"
literal-stop-index="87" />
</assignment-value>
</value>
</values>
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 5b9b8b9fbb5..de2fdafbdc3 100644
--- a/test/it/parser/src/main/resources/case/dml/select.xml
+++ b/test/it/parser/src/main/resources/case/dml/select.xml
@@ -6174,7 +6174,7 @@
<parameter>
<binary-operation-expression start-index="50"
stop-index="66" literal-start-index="50" literal-stop-index="66">
<left>
- <column name="SYSDATE" start-index="50"
stop-index="56" literal-start-index="50" literal-stop-index="56" />
+ <function function-name="SYSDATE"
text="SYSDATE" start-index="50" stop-index="56" literal-start-index="50"
literal-stop-index="56" />
</left>
<operator>-</operator>
<right>
@@ -6196,7 +6196,7 @@
<parameter>
<binary-operation-expression start-index="126"
stop-index="142" literal-start-index="126" literal-stop-index="142">
<left>
- <column name="SYSDATE" start-index="126"
stop-index="132" literal-start-index="126" literal-stop-index="132" />
+ <function function-name="SYSDATE"
text="SYSDATE" start-index="126" stop-index="132" literal-start-index="126"
literal-stop-index="132" />
</left>
<operator>-</operator>
<right>
@@ -6218,7 +6218,7 @@
<parameter>
<binary-operation-expression start-index="196"
stop-index="212" literal-start-index="196" literal-stop-index="212">
<left>
- <column name="SYSDATE" start-index="196"
stop-index="202" literal-start-index="196" literal-stop-index="202" />
+ <function function-name="SYSDATE"
text="SYSDATE" start-index="196" stop-index="202" literal-start-index="196"
literal-stop-index="202" />
</left>
<operator>-</operator>
<right>
@@ -6240,7 +6240,7 @@
<parameter>
<binary-operation-expression start-index="267"
stop-index="283" literal-start-index="267" literal-stop-index="283">
<left>
- <column name="SYSDATE" start-index="267"
stop-index="273" literal-start-index="267" literal-stop-index="273" />
+ <function function-name="SYSDATE"
text="SYSDATE" start-index="267" stop-index="273" literal-start-index="267"
literal-stop-index="273" />
</left>
<operator>-</operator>
<right>
@@ -6262,7 +6262,7 @@
<parameter>
<binary-operation-expression start-index="338"
stop-index="354" literal-start-index="338" literal-stop-index="354">
<left>
- <column name="SYSDATE" start-index="338"
stop-index="344" literal-start-index="338" literal-stop-index="344" />
+ <function function-name="SYSDATE"
text="SYSDATE" start-index="338" stop-index="344" literal-start-index="338"
literal-stop-index="344" />
</left>
<operator>-</operator>
<right>
@@ -6284,7 +6284,7 @@
<parameter>
<binary-operation-expression start-index="408"
stop-index="424" literal-start-index="408" literal-stop-index="424">
<left>
- <column name="SYSDATE" start-index="408"
stop-index="414" literal-start-index="408" literal-stop-index="414" />
+ <function function-name="SYSDATE"
text="SYSDATE" start-index="408" stop-index="414" literal-start-index="408"
literal-stop-index="414" />
</left>
<operator>-</operator>
<right>
@@ -6780,7 +6780,35 @@
</projections>
</select>
- <select sql-case-id="select_projection_with_parameter" parameters="'OK'">
+ <select sql-case-id="select_projection_with_parameter_oracle"
parameters="'OK'">
+ <projections start-index="7" stop-index="81" literal-stop-index="84">
+ <expression-projection text="1" start-index="7" stop-index="13"
alias="id">
+ <expr>
+ <literal-expression value="1" start-index="7"
stop-index="7" />
+ </expr>
+ </expression-projection>
+ <parameter-marker-expression parameter-index="0" start-index="16"
stop-index="26" literal-stop-index="29" />
+ <expression-projection text="SYSDATE" start-index="29"
stop-index="50" literal-start-index="32" literal-stop-index="53"
alias="create_time">
+ <expr>
+ <function function-name="SYSDATE" text="SYSDATE"
start-index="29" stop-index="35" literal-start-index="32"
literal-stop-index="38" />
+ </expr>
+ </expression-projection>
+ <expression-projection text="TRUNC(SYSDATE)" start-index="53"
stop-index="81" literal-start-index="56" literal-stop-index="84"
alias="create_date">
+ <expr>
+ <function function-name="TRUNC" start-index="53"
stop-index="66" literal-start-index="56" literal-stop-index="69"
text="TRUNC(SYSDATE)">
+ <parameter>
+ <function function-name="SYSDATE" text="SYSDATE"
start-index="59" stop-index="65" literal-start-index="62"
literal-stop-index="68" />
+ </parameter>
+ </function>
+ </expr>
+ </expression-projection>
+ </projections>
+ <from>
+ <simple-table name="DUAL" start-index="88" stop-index="91"
literal-start-index="91" literal-stop-index="94" />
+ </from>
+ </select>
+
+ <select sql-case-id="select_projection_with_parameter_firebird"
parameters="'OK'">
<projections start-index="7" stop-index="81" literal-stop-index="84">
<expression-projection text="1" start-index="7" stop-index="13"
alias="id">
<expr>
@@ -7423,7 +7451,7 @@
<parameter>
<binary-operation-expression start-index="25"
stop-index="43" literal-start-index="25" literal-stop-index="43">
<left>
- <column name="SYSDATE" start-index="25"
stop-index="31" literal-start-index="25" literal-stop-index="31" />
+ <function function-name="SYSDATE"
text="SYSDATE" start-index="25" stop-index="31" literal-start-index="25"
literal-stop-index="31" />
</left>
<operator>-</operator>
<right>
@@ -11065,7 +11093,7 @@
<column name="END_TIME"
start-index="51" stop-index="58" />
</parameter>
<parameter>
- <column name="sysdate"
start-index="61" stop-index="67" />
+ <function
function-name="sysdate" text="sysdate" start-index="61" stop-index="67" />
</parameter>
</function>
</left>
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 b996e738a5a..3c7107c13f2 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
@@ -223,7 +223,8 @@
<sql-case id="select_positional_parameter_type_cast_money" value="SELECT
$1::money" db-types="PostgreSQL,openGauss" case-types="Placeholder" />
<sql-case id="select_string_constant_type_cast" value="SELECT int4 '1',
money '2'" db-types="PostgreSQL,openGauss" />
<sql-case id="select_constant_with_nested_type_cast" value="SELECT
CAST(MONEY '1' AS VARCHAR)::CHAR(10)::VARCHAR::CHAR(4)"
db-types="PostgreSQL,openGauss" />
- <sql-case id="select_projection_with_parameter" value="SELECT 1 AS id, ?
AS status, SYSDATE AS create_time, TRUNC(SYSDATE) AS create_date FROM DUAL"
db-types="Oracle,Firebird" case-types="PLACEHOLDER" />
+ <sql-case id="select_projection_with_parameter_oracle" value="SELECT 1 AS
id, ? AS status, SYSDATE AS create_time, TRUNC(SYSDATE) AS create_date FROM
DUAL" db-types="Oracle" case-types="PLACEHOLDER" />
+ <sql-case id="select_projection_with_parameter_firebird" value="SELECT 1
AS id, ? AS status, SYSDATE AS create_time, TRUNC(SYSDATE) AS create_date FROM
DUAL" db-types="Firebird" case-types="PLACEHOLDER" />
<sql-case id="select_with_chinese_comma" value="SELECT 1, 2,3 FROM DUAL"
db-types="Oracle" />
<sql-case id="select_with_chinese_whitespace" value="SELECT 1, 2,3 FROM
DUAL" db-types="Oracle" />
<sql-case id="select_with_auto_keyword" value="SELECT * FROM t_auto WHERE
auto = ?" db-types="MySQL"/>