From fe8c41b086c9e2068454d993c46f3d2f9fec8ea9 Mon Sep 17 00:00:00 2001 From: Jackie Yan Date: Tue, 23 Sep 2025 22:41:01 +0800 Subject: [PATCH 1/5] optimize MySQL INSERT INTO VALUES AS row_alias parse SQLStatement --- .../main/antlr4/imports/mysql/DMLStatement.g4 | 20 +- .../statement/MySQLStatementVisitor.java | 83 ++++++++- .../dml/assignment/RowAliasSegment.java | 52 ++++++ .../dml/assignment/ValueReferenceSegment.java | 52 ++++++ .../statement/type/dml/InsertStatement.java | 12 ++ .../assignment/RowAliasSegmentAssert.java | 61 ++++++ .../ValueReferenceSegmentAssert.java | 55 ++++++ .../standard/type/InsertStatementAssert.java | 13 ++ .../impl/assignment/ExpectedRowAlias.java | 43 +++++ .../assignment/ExpectedValueReference.java | 52 ++++++ .../dml/standard/InsertStatementTestCase.java | 4 + .../src/main/resources/case/dml/insert.xml | 175 ++++++++++++++++-- .../resources/sql/supported/dml/insert.xml | 7 +- 13 files changed, 595 insertions(+), 34 deletions(-) create mode 100644 parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/assignment/RowAliasSegment.java create mode 100644 parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/assignment/ValueReferenceSegment.java create mode 100644 test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/RowAliasSegmentAssert.java create mode 100644 test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/ValueReferenceSegmentAssert.java create mode 100644 test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/assignment/ExpectedRowAlias.java create mode 100644 test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/assignment/ExpectedValueReference.java diff --git a/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/DMLStatement.g4 b/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/DMLStatement.g4 index a8941a1c35ed6..ae04961951e79 100644 --- a/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/DMLStatement.g4 +++ b/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/DMLStatement.g4 @@ -20,9 +20,11 @@ grammar DMLStatement; import BaseRule; insert - : INSERT insertSpecification INTO? tableName partitionNames? (insertValuesClause | setAssignmentsClause | insertSelectClause) onDuplicateKeyClause? returningClause? + : INSERT insertSpecification INTO? tableName partitionNames? insertBody onDuplicateKeyClause? returningClause? ; +insertBody : insertValuesClause | setAssignmentsClause valueReference? | insertSelectClause valueReference? ; + insertSpecification : (LOW_PRIORITY | DELAYED | HIGH_PRIORITY)? IGNORE? ; @@ -47,8 +49,12 @@ insertSelectClause : valueReference? (LP_ fields? RP_)? (LP_ select RP_ | select) ; +rowAlias + : AS alias derivedColumns? + ; + onDuplicateKeyClause - : (AS identifier derivedColumns?)? ON DUPLICATE KEY UPDATE assignment (COMMA_ assignment)* + : ON DUPLICATE KEY UPDATE assignment (COMMA_ assignment)* ; valueReference @@ -88,7 +94,15 @@ assignment ; setAssignmentsClause - : SET assignment (COMMA_ assignment)* + : SET assignmentList setRowAlias? + ; + +assignmentList + : assignment (COMMA_ assignment)* + ; + +setRowAlias + : AS alias derivedColumns? ; assignmentValues diff --git a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java index 033890a175451..5cf592ad867c0 100644 --- a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java +++ b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java @@ -73,6 +73,7 @@ import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.HexadecimalLiteralsContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.IdentifierContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.IndexNameContext; +import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.InsertBodyContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.InsertContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.InsertIdentifierContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.InsertSelectClauseContext; @@ -114,7 +115,9 @@ import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ReplaceContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ReplaceSelectClauseContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ReplaceValuesClauseContext; +import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.RowAliasContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.RowConstructorListContext; +import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ValueReferenceContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectSpecificationContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectWithIntoContext; @@ -169,6 +172,7 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ColumnAssignmentSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.InsertValuesSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.SetAssignmentSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ValueReferenceSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.InsertColumnsSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.OnDuplicateKeyColumnsSegment; @@ -1460,22 +1464,52 @@ public final ASTNode visitOrderByItem(final OrderByItemContext ctx) { @Override public ASTNode visitInsert(final InsertContext ctx) { // TODO :FIXME, since there is no segment for insertValuesClause, InsertStatement is created by sub rule. + InsertStatement result = (InsertStatement) visit(ctx.insertBody()); + if (null != ctx.onDuplicateKeyClause()) { + result.setOnDuplicateKeyColumns((OnDuplicateKeyColumnsSegment) visit(ctx.onDuplicateKeyClause())); + } + result.setTable((SimpleTableSegment) visit(ctx.tableName())); + result.addParameterMarkers(getParameterMarkerSegments()); + if (null != ctx.returningClause()) { + result.setReturning((ReturningSegment) visit(ctx.returningClause())); + } + return result; + } + + @Override + public ASTNode visitInsertBody(final InsertBodyContext ctx) { InsertStatement result; if (null != ctx.insertValuesClause()) { result = (InsertStatement) visit(ctx.insertValuesClause()); } else if (null != ctx.insertSelectClause()) { result = (InsertStatement) visit(ctx.insertSelectClause()); + if (null != ctx.valueReference()) { + result.setValueReference((ValueReferenceSegment) visit(ctx.valueReference())); + } } else { result = new InsertStatement(databaseType); result.setSetAssignment((SetAssignmentSegment) visit(ctx.setAssignmentsClause())); - } - if (null != ctx.onDuplicateKeyClause()) { - result.setOnDuplicateKeyColumns((OnDuplicateKeyColumnsSegment) visit(ctx.onDuplicateKeyClause())); - } - result.setTable((SimpleTableSegment) visit(ctx.tableName())); - result.addParameterMarkers(getParameterMarkerSegments()); - if (null != ctx.returningClause()) { - result.setReturning((ReturningSegment) visit(ctx.returningClause())); + if (null != ctx.valueReference()) { + result.setValueReference((ValueReferenceSegment) visit(ctx.valueReference())); + } else { + if (null != ctx.setAssignmentsClause().setRowAlias()) { + AliasSegment alias = (AliasSegment) visit(ctx.setAssignmentsClause().setRowAlias().alias()); + Collection derivedColumns = null; + if (null != ctx.setAssignmentsClause().setRowAlias().derivedColumns()) { + derivedColumns = new LinkedList<>(); + for (AliasContext each : ctx.setAssignmentsClause().setRowAlias().derivedColumns().alias()) { + AliasSegment aliasSegment = (AliasSegment) visit(each); + ColumnSegment column = new ColumnSegment(each.getStart().getStartIndex(), each.getStop().getStopIndex(), aliasSegment.getIdentifier()); + derivedColumns.add(column); + } + } + ValueReferenceSegment valueReference = new ValueReferenceSegment( + ctx.setAssignmentsClause().setRowAlias().getStart().getStartIndex(), + ctx.setAssignmentsClause().setRowAlias().getStop().getStopIndex(), + alias, derivedColumns); + result.setValueReference(valueReference); + } + } } return result; } @@ -1515,6 +1549,12 @@ public ASTNode visitInsertValuesClause(final InsertValuesClauseContext ctx) { result.setInsertColumns(new InsertColumnsSegment(ctx.start.getStartIndex() - 1, ctx.start.getStartIndex() - 1, Collections.emptyList())); } result.getValues().addAll(createInsertValuesSegments(ctx.assignmentValues())); + + if (null != ctx.valueReference()) { + ValueReferenceSegment valueRef = (ValueReferenceSegment) visit(ctx.valueReference()); + result.setValueReference(valueRef); + } + return result; } @@ -1526,6 +1566,26 @@ private Collection createInsertValuesSegments(final Collect return result; } + @Override + public ASTNode visitRowAlias(final RowAliasContext ctx) { + return new CommonExpressionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.getText()); + } + + @Override + public ASTNode visitValueReference(final ValueReferenceContext ctx) { + AliasSegment alias = (AliasSegment) visit(ctx.alias()); + Collection derivedColumns = null; + if (null != ctx.derivedColumns()) { + derivedColumns = new LinkedList<>(); + for (AliasContext each : ctx.derivedColumns().alias()) { + AliasSegment aliasSegment = (AliasSegment) visit(each); + ColumnSegment column = new ColumnSegment(each.getStart().getStartIndex(), each.getStop().getStopIndex(), aliasSegment.getIdentifier()); + derivedColumns.add(column); + } + } + return new ValueReferenceSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), alias, derivedColumns); + } + @Override public ASTNode visitOnDuplicateKeyClause(final OnDuplicateKeyClauseContext ctx) { Collection columns = new LinkedList<>(); @@ -1625,10 +1685,13 @@ public ASTNode visitUpdate(final UpdateContext ctx) { @Override public ASTNode visitSetAssignmentsClause(final SetAssignmentsClauseContext ctx) { Collection assignments = new LinkedList<>(); - for (AssignmentContext each : ctx.assignment()) { + for (AssignmentContext each : ctx.assignmentList().assignment()) { assignments.add((ColumnAssignmentSegment) visit(each)); } - return new SetAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), assignments); + SetAssignmentSegment setAssignment = new SetAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), assignments); + + + return setAssignment; } @Override diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/assignment/RowAliasSegment.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/assignment/RowAliasSegment.java new file mode 100644 index 0000000000000..cc7f6ba8f3d8f --- /dev/null +++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/assignment/RowAliasSegment.java @@ -0,0 +1,52 @@ +/* + * 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.statement.core.segment.dml.assignment; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.shardingsphere.sql.parser.statement.core.segment.SQLSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.AliasSegment; + +import java.util.Collection; +import java.util.Optional; + +/** + * Row alias segment for INSERT INTO VALUES AS row_alias syntax. + */ +@RequiredArgsConstructor +@Getter +public final class RowAliasSegment implements SQLSegment { + + private final int startIndex; + + private final int stopIndex; + + private final AliasSegment alias; + + private final Collection derivedColumns; + + /** + * Get derived columns. + * + * @return derived columns + */ + public Optional> getDerivedColumns() { + return Optional.ofNullable(derivedColumns); + } +} diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/assignment/ValueReferenceSegment.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/assignment/ValueReferenceSegment.java new file mode 100644 index 0000000000000..1f4553af7977f --- /dev/null +++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/assignment/ValueReferenceSegment.java @@ -0,0 +1,52 @@ +/* + * 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.statement.core.segment.dml.assignment; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.shardingsphere.sql.parser.statement.core.segment.SQLSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.AliasSegment; + +import java.util.Collection; +import java.util.Optional; + +/** + * Value reference segment for INSERT INTO VALUES AS alias syntax. + */ +@RequiredArgsConstructor +@Getter +public final class ValueReferenceSegment implements SQLSegment { + + private final int startIndex; + + private final int stopIndex; + + private final AliasSegment alias; + + private final Collection derivedColumns; + + /** + * Get derived columns. + * + * @return derived columns + */ + public Optional> getDerivedColumns() { + return Optional.ofNullable(derivedColumns); + } +} diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dml/InsertStatement.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dml/InsertStatement.java index 9a69da2dd56c0..5e47138b0bbe7 100644 --- a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dml/InsertStatement.java +++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dml/InsertStatement.java @@ -23,6 +23,7 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.ReturningSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.InsertValuesSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.SetAssignmentSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ValueReferenceSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.InsertColumnsSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.OnDuplicateKeyColumnsSegment; @@ -62,6 +63,8 @@ public final class InsertStatement extends DMLStatement { private OnDuplicateKeyColumnsSegment onDuplicateKeyColumns; + private ValueReferenceSegment valueReference; + private ReturningSegment returning; private OutputSegment output; @@ -135,6 +138,15 @@ public Optional getOnDuplicateKeyColumns() { return Optional.ofNullable(onDuplicateKeyColumns); } + /** + * Get value reference. + * + * @return value reference + */ + public Optional getValueReference() { + return Optional.ofNullable(valueReference); + } + /** * Get set assignment. * diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/RowAliasSegmentAssert.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/RowAliasSegmentAssert.java new file mode 100644 index 0000000000000..4813a9becbab1 --- /dev/null +++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/RowAliasSegmentAssert.java @@ -0,0 +1,61 @@ +/* + * 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.test.it.sql.parser.internal.asserts.segment.assignment; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.RowAliasSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; +import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.SQLCaseAssertContext; +import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.column.ColumnAssert; +import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.assignment.ExpectedRowAlias; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Row alias segment assert. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RowAliasSegmentAssert { + + /** + * Assert actual row alias segment is correct with expected row alias. + * + * @param assertContext assert context + * @param actual actual row alias segment + * @param expected expected row alias + */ + public static void assertIs(final SQLCaseAssertContext assertContext, final RowAliasSegment actual, final ExpectedRowAlias expected) { + assertThat(assertContext.getText("Row alias name assertion error: "), actual.getAlias().getIdentifier().getValue(), is(expected.getAlias())); + if (null != expected.getDerivedColumns() && !expected.getDerivedColumns().isEmpty()) { + assertThat(assertContext.getText("Row alias derived columns size assertion error: "), + actual.getDerivedColumns().isPresent(), is(true)); + assertThat(assertContext.getText("Row alias derived columns size assertion error: "), + actual.getDerivedColumns().get().size(), is(expected.getDerivedColumns().size())); + int count = 0; + for (ColumnSegment each : actual.getDerivedColumns().get()) { + ColumnAssert.assertIs(assertContext, each, expected.getDerivedColumns().get(count)); + count++; + } + } else { + assertThat(assertContext.getText("Row alias derived columns assertion error: "), + actual.getDerivedColumns().isPresent(), is(false)); + } + } +} diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/ValueReferenceSegmentAssert.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/ValueReferenceSegmentAssert.java new file mode 100644 index 0000000000000..f9760ee4f5845 --- /dev/null +++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/ValueReferenceSegmentAssert.java @@ -0,0 +1,55 @@ +/* + * 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.test.it.sql.parser.internal.asserts.segment.assignment; + +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ValueReferenceSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; +import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.SQLCaseAssertContext; +import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.SQLSegmentAssert; +import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.column.ColumnAssert; +import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.assignment.ExpectedValueReference; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Value reference segment assert. + */ +public final class ValueReferenceSegmentAssert { + + /** + * Assert actual value reference segment is correct with expected value reference. + * + * @param assertContext assert context + * @param actual actual value reference segment + * @param expected expected value reference + */ + public static void assertIs(final SQLCaseAssertContext assertContext, final ValueReferenceSegment actual, final ExpectedValueReference expected) { + assertThat(assertContext.getText("Value reference name assertion error: "), actual.getAlias().getIdentifier().getValue(), is(expected.getAlias())); + SQLSegmentAssert.assertIs(assertContext, actual, expected); + if (expected.getDerivedColumns().isPresent() && actual.getDerivedColumns().isPresent()) { + assertThat(assertContext.getText("Value reference derived columns size assertion error: "), + actual.getDerivedColumns().get().size(), is(expected.getDerivedColumns().get().size())); + int index = 0; + for (ColumnSegment each : actual.getDerivedColumns().get()) { + ColumnAssert.assertIs(assertContext, each, expected.getDerivedColumns().get().get(index)); + index++; + } + } + } +} diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dml/standard/type/InsertStatementAssert.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dml/standard/type/InsertStatementAssert.java index 6e8cf0873174c..a53269f08123f 100644 --- a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dml/standard/type/InsertStatementAssert.java +++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dml/standard/type/InsertStatementAssert.java @@ -21,6 +21,7 @@ import lombok.NoArgsConstructor; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.ReturningSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.SetAssignmentSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ValueReferenceSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.OnDuplicateKeyColumnsSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.exec.ExecSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment; @@ -41,6 +42,7 @@ import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.insert.MultiTableConditionalIntoClauseAssert; import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.insert.MultiTableInsertIntoClauseAssert; import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.insert.OnDuplicateKeyColumnsAssert; +import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.assignment.ValueReferenceSegmentAssert; import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.output.OutputClauseAssert; import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.parameter.ParameterMarkerAssert; import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.returning.ReturningClauseAssert; @@ -77,6 +79,7 @@ public static void assertIs(final SQLCaseAssertContext assertContext, final Inse assertSetClause(assertContext, actual, expected); assertInsertSelectClause(assertContext, actual, expected); assertOnDuplicateKeyColumns(assertContext, actual, expected); + assertValueReference(assertContext, actual, expected); assertWithClause(assertContext, actual, expected); assertOutputClause(assertContext, actual, expected); assertMultiTableInsertType(assertContext, actual, expected); @@ -154,6 +157,16 @@ private static void assertOnDuplicateKeyColumns(final SQLCaseAssertContext asser } } + private static void assertValueReference(final SQLCaseAssertContext assertContext, final InsertStatement actual, final InsertStatementTestCase expected) { + Optional valueReferenceSegment = actual.getValueReference(); + if (null == expected.getValueReference()) { + assertFalse(valueReferenceSegment.isPresent(), assertContext.getText("Actual value reference segment should not exist.")); + } else { + assertTrue(valueReferenceSegment.isPresent(), assertContext.getText("Actual value reference segment should exist.")); + ValueReferenceSegmentAssert.assertIs(assertContext, valueReferenceSegment.get(), expected.getValueReference()); + } + } + private static void assertWithClause(final SQLCaseAssertContext assertContext, final InsertStatement actual, final InsertStatementTestCase expected) { Optional withSegment = actual.getWith(); if (null == expected.getWithClause()) { diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/assignment/ExpectedRowAlias.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/assignment/ExpectedRowAlias.java new file mode 100644 index 0000000000000..054b2ddb039f9 --- /dev/null +++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/assignment/ExpectedRowAlias.java @@ -0,0 +1,43 @@ +/* + * 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.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.assignment; + +import lombok.Getter; +import lombok.Setter; +import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.AbstractExpectedSQLSegment; +import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.column.ExpectedColumn; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import java.util.LinkedList; +import java.util.List; + +/** + * Expected row alias. + */ +@Getter +@Setter +public final class ExpectedRowAlias extends AbstractExpectedSQLSegment { + + @XmlElement + private String alias; + + @XmlElementWrapper(name = "derived-columns") + @XmlElement(name = "column") + private final List derivedColumns = new LinkedList<>(); +} diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/assignment/ExpectedValueReference.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/assignment/ExpectedValueReference.java new file mode 100644 index 0000000000000..7071734e2f081 --- /dev/null +++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/assignment/ExpectedValueReference.java @@ -0,0 +1,52 @@ +/* + * 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.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.assignment; + +import lombok.Getter; +import lombok.Setter; +import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.AbstractExpectedSQLSegment; +import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.column.ExpectedColumn; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +/** + * Expected value reference. + */ +@Getter +@Setter +public final class ExpectedValueReference extends AbstractExpectedSQLSegment { + + @XmlAttribute + private String alias; + + @XmlElement(name = "derived-column") + private List derivedColumns = new LinkedList<>(); + + /** + * Get derived columns. + * + * @return derived columns + */ + public Optional> getDerivedColumns() { + return derivedColumns.isEmpty() ? Optional.empty() : Optional.of(derivedColumns); + } +} diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/statement/dml/standard/InsertStatementTestCase.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/statement/dml/standard/InsertStatementTestCase.java index f94b8e57faece..6b36007aea1e6 100644 --- a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/statement/dml/standard/InsertStatementTestCase.java +++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/statement/dml/standard/InsertStatementTestCase.java @@ -31,6 +31,7 @@ import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.insert.ExpectedMultiTableInsertType; import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.insert.ExpectedOnDuplicateKeyColumns; import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.insert.ExpectedReturningClause; +import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.assignment.ExpectedValueReference; import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.output.ExpectedOutputClause; import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.set.ExpectedSetClause; import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.table.ExpectedSimpleTable; @@ -67,6 +68,9 @@ public final class InsertStatementTestCase extends SQLParserTestCase { @XmlElement(name = "on-duplicate-key-columns") private ExpectedOnDuplicateKeyColumns onDuplicateKeyColumns; + @XmlElement(name = "value-reference") + private ExpectedValueReference valueReference; + @XmlElement(name = "with") private ExpectedWithClause withClause; 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 c05597e7b6e31..8be1af6844113 100644 --- a/test/it/parser/src/main/resources/case/dml/insert.xml +++ b/test/it/parser/src/main/resources/case/dml/insert.xml @@ -490,7 +490,7 @@ - + @@ -504,7 +504,8 @@ - + + @@ -4178,35 +4179,169 @@ - + + +
+ + + + + + + + + + + + + + +
- + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ - + - + - + - + - - - + + + + - - + - - - - - - - + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 7a9fa17c77702..f31e49825b537 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 @@ -150,7 +150,12 @@ - + + + + + + From dd0f02af0279ea99a650b7efc1afe8bdbaf7a339 Mon Sep 17 00:00:00 2001 From: Jackie Yan Date: Wed, 24 Sep 2025 18:18:45 +0800 Subject: [PATCH 2/5] apply spotless --- .../mysql/visitor/statement/MySQLStatementVisitor.java | 7 +++---- .../segment/assignment/ValueReferenceSegmentAssert.java | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java index 5cf592ad867c0..ffa7eb6a32f5c 100644 --- a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java +++ b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java @@ -1504,9 +1504,9 @@ public ASTNode visitInsertBody(final InsertBodyContext ctx) { } } ValueReferenceSegment valueReference = new ValueReferenceSegment( - ctx.setAssignmentsClause().setRowAlias().getStart().getStartIndex(), - ctx.setAssignmentsClause().setRowAlias().getStop().getStopIndex(), - alias, derivedColumns); + ctx.setAssignmentsClause().setRowAlias().getStart().getStartIndex(), + ctx.setAssignmentsClause().setRowAlias().getStop().getStopIndex(), + alias, derivedColumns); result.setValueReference(valueReference); } } @@ -1690,7 +1690,6 @@ public ASTNode visitSetAssignmentsClause(final SetAssignmentsClauseContext ctx) } SetAssignmentSegment setAssignment = new SetAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), assignments); - return setAssignment; } diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/ValueReferenceSegmentAssert.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/ValueReferenceSegmentAssert.java index f9760ee4f5845..97e64cd79f7de 100644 --- a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/ValueReferenceSegmentAssert.java +++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/assignment/ValueReferenceSegmentAssert.java @@ -43,7 +43,7 @@ public static void assertIs(final SQLCaseAssertContext assertContext, final Valu assertThat(assertContext.getText("Value reference name assertion error: "), actual.getAlias().getIdentifier().getValue(), is(expected.getAlias())); SQLSegmentAssert.assertIs(assertContext, actual, expected); if (expected.getDerivedColumns().isPresent() && actual.getDerivedColumns().isPresent()) { - assertThat(assertContext.getText("Value reference derived columns size assertion error: "), + assertThat(assertContext.getText("Value reference derived columns size assertion error: "), actual.getDerivedColumns().get().size(), is(expected.getDerivedColumns().get().size())); int index = 0; for (ColumnSegment each : actual.getDerivedColumns().get()) { From 0661e49847ff6a2044252c528587590785e3973f Mon Sep 17 00:00:00 2001 From: Jackie Yan Date: Wed, 24 Sep 2025 18:22:48 +0800 Subject: [PATCH 3/5] fix checkstyle --- .../statement/MySQLStatementVisitor.java | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java index ffa7eb6a32f5c..433418d1447ba 100644 --- a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java +++ b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java @@ -123,6 +123,7 @@ import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectWithIntoContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SeparatorNameContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SetAssignmentsClauseContext; +import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SetRowAliasContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ShorthandRegularFunctionContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SimpleExprContext; import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SingleTableClauseContext; @@ -1491,24 +1492,9 @@ public ASTNode visitInsertBody(final InsertBodyContext ctx) { result.setSetAssignment((SetAssignmentSegment) visit(ctx.setAssignmentsClause())); if (null != ctx.valueReference()) { result.setValueReference((ValueReferenceSegment) visit(ctx.valueReference())); - } else { - if (null != ctx.setAssignmentsClause().setRowAlias()) { - AliasSegment alias = (AliasSegment) visit(ctx.setAssignmentsClause().setRowAlias().alias()); - Collection derivedColumns = null; - if (null != ctx.setAssignmentsClause().setRowAlias().derivedColumns()) { - derivedColumns = new LinkedList<>(); - for (AliasContext each : ctx.setAssignmentsClause().setRowAlias().derivedColumns().alias()) { - AliasSegment aliasSegment = (AliasSegment) visit(each); - ColumnSegment column = new ColumnSegment(each.getStart().getStartIndex(), each.getStop().getStopIndex(), aliasSegment.getIdentifier()); - derivedColumns.add(column); - } - } - ValueReferenceSegment valueReference = new ValueReferenceSegment( - ctx.setAssignmentsClause().setRowAlias().getStart().getStartIndex(), - ctx.setAssignmentsClause().setRowAlias().getStop().getStopIndex(), - alias, derivedColumns); - result.setValueReference(valueReference); - } + } + if (null == ctx.valueReference() && null != ctx.setAssignmentsClause().setRowAlias()) { + result.setValueReference(createValueReferenceFromSetRowAlias(ctx.setAssignmentsClause().setRowAlias())); } } return result; @@ -1530,6 +1516,20 @@ public ASTNode visitInsertSelectClause(final InsertSelectClauseContext ctx) { return result; } + private ValueReferenceSegment createValueReferenceFromSetRowAlias(final SetRowAliasContext ctx) { + AliasSegment alias = (AliasSegment) visit(ctx.alias()); + Collection derivedColumns = null; + if (null != ctx.derivedColumns()) { + derivedColumns = new LinkedList<>(); + for (AliasContext each : ctx.derivedColumns().alias()) { + AliasSegment aliasSegment = (AliasSegment) visit(each); + ColumnSegment column = new ColumnSegment(each.getStart().getStartIndex(), each.getStop().getStopIndex(), aliasSegment.getIdentifier()); + derivedColumns.add(column); + } + } + return new ValueReferenceSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), alias, derivedColumns); + } + private SubquerySegment createInsertSelectSegment(final InsertSelectClauseContext ctx) { SelectStatement selectStatement = (SelectStatement) visit(ctx.select()); selectStatement.addParameterMarkers(getParameterMarkerSegments()); @@ -1689,7 +1689,6 @@ public ASTNode visitSetAssignmentsClause(final SetAssignmentsClauseContext ctx) assignments.add((ColumnAssignmentSegment) visit(each)); } SetAssignmentSegment setAssignment = new SetAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), assignments); - return setAssignment; } From f00652db54eb8ed6861da15a7d9ade60fe1984f5 Mon Sep 17 00:00:00 2001 From: Jackie Yan Date: Sat, 27 Sep 2025 13:49:16 +0800 Subject: [PATCH 4/5] optimize MySQL INSERT AS syntax implementation --- .../main/antlr4/imports/mysql/DMLStatement.g4 | 6 +++++- .../statement/MySQLStatementVisitor.java | 18 +++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/DMLStatement.g4 b/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/DMLStatement.g4 index ae04961951e79..42a3d086a71f1 100644 --- a/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/DMLStatement.g4 +++ b/parser/sql/engine/dialect/mysql/src/main/antlr4/imports/mysql/DMLStatement.g4 @@ -23,7 +23,11 @@ insert : INSERT insertSpecification INTO? tableName partitionNames? insertBody onDuplicateKeyClause? returningClause? ; -insertBody : insertValuesClause | setAssignmentsClause valueReference? | insertSelectClause valueReference? ; +insertBody + : insertValuesClause + | setAssignmentsClause valueReference? + | insertSelectClause valueReference? + ; insertSpecification : (LOW_PRIORITY | DELAYED | HIGH_PRIORITY)? IGNORE? diff --git a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java index 433418d1447ba..1fbe3435db82b 100644 --- a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java +++ b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java @@ -173,6 +173,7 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ColumnAssignmentSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.InsertValuesSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.SetAssignmentSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.RowAliasSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ValueReferenceSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment; import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.InsertColumnsSegment; @@ -1549,12 +1550,10 @@ public ASTNode visitInsertValuesClause(final InsertValuesClauseContext ctx) { result.setInsertColumns(new InsertColumnsSegment(ctx.start.getStartIndex() - 1, ctx.start.getStartIndex() - 1, Collections.emptyList())); } result.getValues().addAll(createInsertValuesSegments(ctx.assignmentValues())); - if (null != ctx.valueReference()) { ValueReferenceSegment valueRef = (ValueReferenceSegment) visit(ctx.valueReference()); result.setValueReference(valueRef); } - return result; } @@ -1568,7 +1567,17 @@ private Collection createInsertValuesSegments(final Collect @Override public ASTNode visitRowAlias(final RowAliasContext ctx) { - return new CommonExpressionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.getText()); + AliasSegment alias = (AliasSegment) visit(ctx.alias()); + Collection derivedColumns = null; + if (null != ctx.derivedColumns()) { + derivedColumns = new LinkedList<>(); + for (AliasContext each : ctx.derivedColumns().alias()) { + AliasSegment aliasSegment = (AliasSegment) visit(each); + ColumnSegment column = new ColumnSegment(each.getStart().getStartIndex(), each.getStop().getStopIndex(), aliasSegment.getIdentifier()); + derivedColumns.add(column); + } + } + return new RowAliasSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), alias, derivedColumns); } @Override @@ -1688,8 +1697,7 @@ public ASTNode visitSetAssignmentsClause(final SetAssignmentsClauseContext ctx) for (AssignmentContext each : ctx.assignmentList().assignment()) { assignments.add((ColumnAssignmentSegment) visit(each)); } - SetAssignmentSegment setAssignment = new SetAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), assignments); - return setAssignment; + return new SetAssignmentSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), assignments); } @Override From a112d66ec385ed0f171ee37396f86c46ab6a5a0b Mon Sep 17 00:00:00 2001 From: Jackie Yan Date: Fri, 19 Dec 2025 18:33:50 +0800 Subject: [PATCH 5/5] fix: MySQL parser compilation errors in visitInsertBody method --- .../mysql/visitor/statement/MySQLStatementVisitor.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java index 6d2ccbae91875..dcf94f8489274 100644 --- a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java +++ b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java @@ -1489,6 +1489,7 @@ public ASTNode visitInsert(final InsertContext ctx) { if (null != ctx.onDuplicateKeyClause()) { result.setOnDuplicateKeyColumns((OnDuplicateKeyColumnsSegment) visit(ctx.onDuplicateKeyClause())); } + result.setIgnore(null != ctx.insertSpecification().IGNORE()); result.setTable((SimpleTableSegment) visit(ctx.tableName())); result.addParameterMarkers(getParameterMarkerSegments()); if (null != ctx.returningClause()) { @@ -1517,15 +1518,6 @@ public ASTNode visitInsertBody(final InsertBodyContext ctx) { result.setValueReference(createValueReferenceFromSetRowAlias(ctx.setAssignmentsClause().setRowAlias())); } } - if (null != ctx.onDuplicateKeyClause()) { - result.setOnDuplicateKeyColumns((OnDuplicateKeyColumnsSegment) visit(ctx.onDuplicateKeyClause())); - } - result.setIgnore(null != ctx.insertSpecification().IGNORE()); - result.setTable((SimpleTableSegment) visit(ctx.tableName())); - result.addParameterMarkers(getParameterMarkerSegments()); - if (null != ctx.returningClause()) { - result.setReturning((ReturningSegment) visit(ctx.returningClause())); - } return result; }