Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for WithSegment #28555

Merged
merged 1 commit into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* 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.sqlfederation.compiler.converter.segment.with;

import org.apache.calcite.sql.SqlIdentifier;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.SqlNodeList;
import org.apache.calcite.sql.SqlWithItem;
import org.apache.calcite.sql.SqlWith;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WithSegment;
import org.apache.shardingsphere.sqlfederation.compiler.converter.segment.expression.ExpressionConverter;
import org.apache.shardingsphere.sqlfederation.compiler.converter.statement.select.SelectStatementConverter;

import java.util.Collection;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* With converter.
*/
public final class WithConverter {

/**
* Convert the given WithSegment and query into an SqlNodeList.
*
* @param withSegment with segment
* @param query SqlNode
* @return SqlNodeList
*/
public Optional<SqlNodeList> convert(final WithSegment withSegment, final SqlNode query) {
SqlIdentifier name = new SqlIdentifier(withSegment.getCommonTableExpressions().iterator().next().getIdentifier().getValue(), SqlParserPos.ZERO);
SqlNode selectSubquery = new SelectStatementConverter().convert(withSegment.getCommonTableExpressions().iterator().next().getSubquery().getSelect());
ExpressionConverter converter = new ExpressionConverter();
Collection<ColumnSegment> collectionColumns = withSegment.getCommonTableExpressions().iterator().next().getColumns();
Collection<SqlNode> convertedColumns;
SqlNodeList columns = null;
if (!collectionColumns.isEmpty()) {
convertedColumns = collectionColumns.stream().map(converter::convert).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
columns = new SqlNodeList(convertedColumns, SqlParserPos.ZERO);
}
SqlWithItem sqlWithItem = new SqlWithItem(SqlParserPos.ZERO, name, columns, selectSubquery);
SqlNodeList sqlWithItems = new SqlNodeList(SqlParserPos.ZERO);
sqlWithItems.add(sqlWithItem);
SqlWith sqlWith = new SqlWith(SqlParserPos.ZERO, sqlWithItems, query);
SqlNodeList result = new SqlNodeList(SqlParserPos.ZERO);
result.add(sqlWith);
return Optional.of(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
import org.apache.calcite.sql.SqlOrderBy;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.pagination.limit.LimitSegment;
import org.apache.shardingsphere.sql.parser.sql.common.segment.generic.WithSegment;
import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.DeleteStatement;
import org.apache.shardingsphere.sql.parser.sql.dialect.handler.dml.DeleteStatementHandler;
import org.apache.shardingsphere.sqlfederation.compiler.converter.segment.from.TableConverter;
import org.apache.shardingsphere.sqlfederation.compiler.converter.segment.limit.PaginationValueSQLConverter;
import org.apache.shardingsphere.sqlfederation.compiler.converter.segment.orderby.OrderByConverter;
import org.apache.shardingsphere.sqlfederation.compiler.converter.segment.where.WhereConverter;
import org.apache.shardingsphere.sqlfederation.compiler.converter.segment.with.WithConverter;
import org.apache.shardingsphere.sqlfederation.compiler.converter.statement.SQLStatementConverter;

import java.util.Optional;
Expand All @@ -41,7 +43,7 @@ public final class DeleteStatementConverter implements SQLStatementConverter<Del

@Override
public SqlNode convert(final DeleteStatement deleteStatement) {
SqlDelete sqlDelete = convertDelete(deleteStatement);
SqlNode sqlDelete = convertDelete(deleteStatement);
SqlNodeList orderBy = DeleteStatementHandler.getOrderBySegment(deleteStatement).flatMap(optional -> new OrderByConverter().convert(optional)).orElse(SqlNodeList.EMPTY);
Optional<LimitSegment> limit = DeleteStatementHandler.getLimitSegment(deleteStatement);
if (limit.isPresent()) {
Expand All @@ -52,10 +54,15 @@ public SqlNode convert(final DeleteStatement deleteStatement) {
return orderBy.isEmpty() ? sqlDelete : new SqlOrderBy(SqlParserPos.ZERO, sqlDelete, orderBy, null, null);
}

private SqlDelete convertDelete(final DeleteStatement deleteStatement) {
private SqlNode convertDelete(final DeleteStatement deleteStatement) {
SqlNode deleteTable = new TableConverter().convert(deleteStatement.getTable()).orElseThrow(IllegalStateException::new);
SqlNode condition = deleteStatement.getWhere().flatMap(optional -> new WhereConverter().convert(optional)).orElse(null);
SqlIdentifier alias = deleteStatement.getTable().getAliasName().map(optional -> new SqlIdentifier(optional, SqlParserPos.ZERO)).orElse(null);
return new SqlDelete(SqlParserPos.ZERO, deleteTable, condition, null, alias);
SqlDelete sqlDelete = new SqlDelete(SqlParserPos.ZERO, deleteTable, condition, null, alias);
Optional<WithSegment> with = DeleteStatementHandler.getWithSegment(deleteStatement);
if (with.isPresent()) {
return new WithConverter().convert(DeleteStatementHandler.getWithSegment(deleteStatement).get(), sqlDelete).get();
}
return sqlDelete;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private static class TestCaseArgumentsProvider implements ArgumentsProvider {

@Override
public Stream<? extends Arguments> provideArguments(final ExtensionContext extensionContext) {
return getTestParameters("MySQL", "PostgreSQL", "openGauss", "Oracle").stream();
return getTestParameters("MySQL", "PostgreSQL", "openGauss", "Oracle", "SQLServer").stream();
}

private Collection<Arguments> getTestParameters(final String... databaseTypes) {
Expand Down
8 changes: 6 additions & 2 deletions test/it/optimizer/src/test/resources/converter/delete.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
<test-cases sql-case-id="delete_with_schema" expected-sql="DELETE FROM &quot;db1&quot;.&quot;t_order&quot;" db-types="PostgreSQL, openGauss"/>
<test-cases sql-case-id="delete_with_order_by_row_count" expected-sql="DELETE FROM `t_order` WHERE `order_id` = 1000 AND `user_id` = 1001 AND `status` = 'init' ORDER BY `order_id` LIMIT 10" db-types="MySQL" sql-case-types="LITERAL" />
<test-cases sql-case-id="delete_with_order_by_row_count" expected-sql="DELETE FROM `t_order` WHERE `order_id` = ? AND `user_id` = ? AND `status` = ? ORDER BY `order_id` LIMIT ?" db-types="MySQL" sql-case-types="PLACEHOLDER" />
<test-cases sql-case-id="delete_with_alias" expected-sql="DELETE FROM `t_order` AS `o` AS `o` WHERE `status` = 'init'" db-types="MySQL,SQLServer" sql-case-types="LITERAL" />
<test-cases sql-case-id="delete_with_alias" expected-sql="DELETE FROM `t_order` AS `o` AS `o` WHERE `status` = ?" db-types="MySQL,SQLServer" sql-case-types="PLACEHOLDER" />
<test-cases sql-case-id="delete_with_alias" expected-sql="DELETE FROM `t_order` AS `o` AS `o` WHERE `status` = 'init'" db-types="MySQL" sql-case-types="LITERAL" />
<test-cases sql-case-id="delete_with_alias" expected-sql="DELETE FROM [t_order] AS [o] AS [o] WHERE [status] = 'init'" db-types="SQLServer" sql-case-types="LITERAL" />
<test-cases sql-case-id="delete_with_alias" expected-sql="DELETE FROM `t_order` AS `o` AS `o` WHERE `status` = ?" db-types="MySQL" sql-case-types="PLACEHOLDER" />
<test-cases sql-case-id="delete_with_alias" expected-sql="DELETE FROM [t_order] AS [o] AS [o] WHERE [status] = ?" db-types="SQLServer" sql-case-types="PLACEHOLDER" />
<test-cases sql-case-id="delete_with_with_clause" expected-sql="(WITH [cte] ([order_id], [user_id]) AS (SELECT [order_id], [user_id] FROM [t_order]) DELETE FROM ([cte], [t_order]) WHERE [t_order].[order_id] = [cte].[order_id])" db-types="SQLServer" />
<test-cases sql-case-id="delete_without_columns_with_with_clause" expected-sql="(WITH [cte] AS (SELECT [order_id], [user_id] FROM [t_order]) DELETE FROM ([cte], [t_order]) WHERE [t_order].[order_id] = [cte].[order_id])" db-types="SQLServer" />
</sql-node-converter-test-cases>