Skip to content

Commit

Permalink
Support parsing SQL Server SELECT name, sql (#29627)
Browse files Browse the repository at this point in the history
* draft

* Support parsing SQL Server SELECT name, sql

* remove test parser

* fix test error

* fix code style check

* fix code style

* fix code style
  • Loading branch information
yydeng626 authored Jan 5, 2024
1 parent c2cb6db commit 55065b7
Show file tree
Hide file tree
Showing 21 changed files with 447 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ unreservedWord
| DATA_RETENTION | TEMPORAL_HISTORY_RETENTION | EDITION | MIXED_PAGE_ALLOCATION | DISABLED | ALLOWED | HADR | MULTI_USER | RESTRICTED_USER | SINGLE_USER | OFFLINE | EMERGENCY | SUSPEND | DATE_CORRELATION_OPTIMIZATION
| ELASTIC_POOL | SERVICE_OBJECTIVE | DATABASE_NAME | ALLOW_CONNECTIONS | GEO | NAMED | DATEFIRST | BACKUP_STORAGE_REDUNDANCY | FORCE_FAILOVER_ALLOW_DATA_LOSS | SECONDARY | FAILOVER | DEFAULT_FULLTEXT_LANGUAGE
| DEFAULT_LANGUAGE | INLINE | NESTED_TRIGGERS | TRANSFORM_NOISE_WORDS | TWO_DIGIT_YEAR_CUTOFF | PERSISTENT_LOG_BUFFER | DIRECTORY_NAME | DATEFORMAT | DELAYED_DURABILITY | TRANSFER | SCHEMA | PASSWORD | AUTHORIZATION
| MEMBER | SEARCH | TEXT | SECOND | PRECISION | VIEWS
| MEMBER | SEARCH | TEXT | SECOND | PRECISION | VIEWS | PROVIDER
;

databaseName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ grammar DMLStatement;
import BaseRule;

insert
: withClause? INSERT top? INTO? tableName (AS? alias)? (insertDefaultValue | insertValuesClause | insertSelectClause)
: withClause? INSERT top? INTO? tableName (AS? alias)? (insertDefaultValue | insertValuesClause | insertSelectClause | insertExecClause)
;

insertDefaultValue
Expand All @@ -35,6 +35,14 @@ insertSelectClause
: columnNames? outputClause? select
;

insertExecClause
: columnNames? exec
;

exec
: (EXEC | EXECUTE) procedureName (expr (COMMA_ expr)*)?
;

update
: withClause? UPDATE top? tableReferences setAssignmentsClause whereClause? (OPTION queryHint)?
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -692,3 +692,6 @@ WITHOUT
: W I T H O U T
;

APPLY
: A P P L Y
;
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@
import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.ViewNameContext;
import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.WhereClauseContext;
import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.WithClauseContext;
import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.InsertExecClauseContext;
import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.ExecContext;
import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.ProcedureNameContext;
import org.apache.shardingsphere.sql.parser.sql.common.enums.AggregationType;
import org.apache.shardingsphere.sql.parser.sql.common.enums.JoinType;
import org.apache.shardingsphere.sql.parser.sql.common.enums.OrderDirection;
Expand All @@ -115,6 +118,7 @@
import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.constraint.ConstraintSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.index.IndexNameSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.index.IndexSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.routine.FunctionNameSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.ColumnAssignmentSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.InsertValuesSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.assignment.SetAssignmentSegment;
Expand Down Expand Up @@ -181,6 +185,7 @@
import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.OtherLiteralValue;
import org.apache.shardingsphere.sql.parser.sql.common.value.literal.impl.StringLiteralValue;
import org.apache.shardingsphere.sql.parser.sql.common.value.parametermarker.ParameterMarkerValue;
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.sqlserver.exec.ExecSegment;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.ddl.SQLServerCreateTableStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.dml.SQLServerDeleteStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.dml.SQLServerInsertStatement;
Expand Down Expand Up @@ -914,6 +919,8 @@ public ASTNode visitInsert(final InsertContext ctx) {
result = (SQLServerInsertStatement) visit(ctx.insertDefaultValue());
} else if (null != ctx.insertValuesClause()) {
result = (SQLServerInsertStatement) visit(ctx.insertValuesClause());
} else if (null != ctx.insertExecClause()) {
result = (SQLServerInsertStatement) visit(ctx.insertExecClause());
} else {
result = (SQLServerInsertStatement) visit(ctx.insertSelectClause());
}
Expand All @@ -935,6 +942,39 @@ public ASTNode visitInsertDefaultValue(final InsertDefaultValueContext ctx) {
return result;
}

@Override
public ASTNode visitInsertExecClause(final InsertExecClauseContext ctx) {
SQLServerInsertStatement result = new SQLServerInsertStatement();
result.setInsertColumns(createInsertColumns(ctx.columnNames(), ctx.start.getStartIndex()));
result.setExecSegment((ExecSegment) visit(ctx.exec()));
return result;
}

@Override
public ASTNode visitExec(final ExecContext ctx) {
ExecSegment result = new ExecSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex());
if (null != ctx.procedureName()) {
result.setProcedureName((FunctionNameSegment) visitProcedureName(ctx.procedureName()));
}
if (null != ctx.expr()) {
Collection<ExpressionSegment> items = new LinkedList<>();
for (ExprContext each : ctx.expr()) {
items.add((ExpressionSegment) visit(each));
}
result.getExpressionSegments().addAll(items);
}
return result;
}

@Override
public ASTNode visitProcedureName(final ProcedureNameContext ctx) {
FunctionNameSegment result = new FunctionNameSegment(ctx.name().start.getStartIndex(), ctx.name().stop.getStopIndex(), (IdentifierValue) visit(ctx.name()));
if (null != ctx.owner()) {
result.setOwner(new OwnerSegment(ctx.owner().start.getStartIndex(), ctx.owner().stop.getStopIndex(), (IdentifierValue) visit(ctx.owner())));
}
return result;
}

@Override
public ASTNode visitOutputClause(final OutputClauseContext ctx) {
OutputSegment result = new OutputSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
*/
public enum JoinType {

INNER, FULL, CROSS, LEFT, RIGHT, COMMA
INNER, FULL, CROSS, LEFT, RIGHT, COMMA, APPLY
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.oracle.table.MultiTableConditionalIntoSegment;
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.oracle.table.MultiTableInsertIntoSegment;
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.oracle.table.MultiTableInsertType;
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.sqlserver.exec.ExecSegment;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dml.MySQLInsertStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.opengauss.dml.OpenGaussInsertStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.oracle.dml.OracleInsertStatement;
Expand Down Expand Up @@ -295,4 +296,29 @@ public static void setWhereSegment(final InsertStatement insertStatement, final
((OracleInsertStatement) insertStatement).setWhere(whereSegment);
}
}

/**
* Get execute segment.
*
* @param insertStatement insert statement
* @return execute segment
*/
public static Optional<ExecSegment> getExecSegment(final InsertStatement insertStatement) {
if (insertStatement instanceof SQLServerInsertStatement) {
return ((SQLServerInsertStatement) insertStatement).getExecSegment();
}
return Optional.empty();
}

/**
* Set execute segment.
*
* @param insertStatement insert statement
* @param execSegment execute segment
*/
public static void setExecSegment(final InsertStatement insertStatement, final ExecSegment execSegment) {
if (insertStatement instanceof SQLServerInsertStatement) {
((SQLServerInsertStatement) insertStatement).setExecSegment(execSegment);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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.sql.dialect.segment.sqlserver.exec;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.apache.shardingsphere.sql.parser.sql.common.segment.SQLSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.routine.FunctionNameSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;

import java.util.Collection;
import java.util.LinkedList;

/**
* Execute segment.
*/
@RequiredArgsConstructor
@Getter
public final class ExecSegment implements SQLSegment {

private final int startIndex;

private final int stopIndex;

@Setter
private FunctionNameSegment procedureName;

private final Collection<ExpressionSegment> expressionSegments = new LinkedList<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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.sql.dialect.statement.sqlserver.dml;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.CallStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.SQLServerStatement;

import java.util.List;

/**
* SQLServer call statement.
*/
@AllArgsConstructor
@NoArgsConstructor
@Getter
public final class SQLServerCallStatement extends CallStatement implements SQLServerStatement {

private String procedureName;

private List<ExpressionSegment> parameters;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.OutputSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WithSegment;
import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.InsertStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.sqlserver.exec.ExecSegment;
import org.apache.shardingsphere.sql.parser.sql.dialect.statement.sqlserver.SQLServerStatement;

import java.util.Optional;
Expand All @@ -35,6 +36,8 @@ public final class SQLServerInsertStatement extends InsertStatement implements S

private OutputSegment outputSegment;

private ExecSegment execSegment;

/**
* Get with segment.
*
Expand All @@ -52,4 +55,13 @@ public Optional<WithSegment> getWithSegment() {
public Optional<OutputSegment> getOutputSegment() {
return Optional.ofNullable(outputSegment);
}

/**
* Get execute segment.
*
* @return execute segment.
*/
public Optional<ExecSegment> getExecSegment() {
return Optional.ofNullable(execSegment);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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.insert;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.sqlserver.exec.ExecSegment;
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.expression.ExpressionAssert;
import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.owner.OwnerAssert;
import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.exec.ExpectedExecClause;
import org.hamcrest.CoreMatchers;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* Insert execute clause assert.
**/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class InsertExecClauseAssert {

/**
* Assert actual execute segment is correct with expected execute clause.
*
* @param assertContext assert context
* @param actual actual execute segment
* @param expected expected execute clause
*/
public static void assertIs(final SQLCaseAssertContext assertContext, final ExecSegment actual, final ExpectedExecClause expected) {
assertThat(assertContext.getText("exec procedure name assertion error: "), actual.getProcedureName().getIdentifier().getValue(), CoreMatchers.is(expected.getName()));
if (null == expected.getOwner()) {
assertFalse(actual.getProcedureName().getOwner().isPresent(), assertContext.getText("Actual owner should not exist."));
} else {
assertTrue(actual.getProcedureName().getOwner().isPresent(), assertContext.getText("Actual owner should exist."));
OwnerAssert.assertIs(assertContext, actual.getProcedureName().getOwner().get(), expected.getOwner());
}
if (null == expected.getParameters()) {
assertThat(assertContext.getText("exec procedure parameters assertion error: "), actual.getExpressionSegments().size(), CoreMatchers.is(expected.getParameters().size()));
} else {
int count = 0;
for (ExpressionSegment expressionSegment : actual.getExpressionSegments()) {
ExpressionAssert.assertExpression(assertContext, expressionSegment, expected.getParameters().get(count));
count++;
}
}
SQLSegmentAssert.assertIs(assertContext, actual, expected);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.oracle.table.MultiTableConditionalIntoSegment;
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.oracle.table.MultiTableInsertIntoSegment;
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.oracle.table.MultiTableInsertType;
import org.apache.shardingsphere.sql.parser.sql.dialect.segment.sqlserver.exec.ExecSegment;
import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.SQLCaseAssertContext;
import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.insert.InsertExecClauseAssert;
import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.insert.InsertColumnsClauseAssert;
import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.insert.InsertValuesClauseAssert;
import org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.insert.MultiTableConditionalIntoClauseAssert;
Expand Down Expand Up @@ -77,6 +79,7 @@ public static void assertIs(final SQLCaseAssertContext assertContext, final Inse
assertMultiTableInsertIntoClause(assertContext, actual, expected);
assertMultiTableConditionalIntoClause(assertContext, actual, expected);
assertReturningClause(assertContext, actual, expected);
assertInsertExecClause(assertContext, actual, expected);
}

private static void assertTable(final SQLCaseAssertContext assertContext, final InsertStatement actual, final InsertStatementTestCase expected) {
Expand Down Expand Up @@ -195,4 +198,14 @@ private static void assertReturningClause(final SQLCaseAssertContext assertConte
ReturningClauseAssert.assertIs(assertContext, returningSegment.get(), expected.getReturningClause());
}
}

private static void assertInsertExecClause(final SQLCaseAssertContext assertContext, final InsertStatement actual, final InsertStatementTestCase expected) {
Optional<ExecSegment> execSegment = InsertStatementHandler.getExecSegment(actual);
if (null == expected.getExecClause()) {
assertFalse(execSegment.isPresent(), assertContext.getText("Actual exec segment should not exist."));
} else {
assertTrue(execSegment.isPresent(), assertContext.getText("Actual exec segment should exist."));
InsertExecClauseAssert.assertIs(assertContext, execSegment.get(), expected.getExecClause());
}
}
}
Loading

0 comments on commit 55065b7

Please sign in to comment.