From 967acfae4db32582c73dd4079ca4f4b51641cc81 Mon Sep 17 00:00:00 2001 From: Jackie Yan Date: Thu, 7 Aug 2025 20:17:25 +0800 Subject: [PATCH 1/4] Support grant statement SQL bind --- .../infra/binder/engine/SQLBindEngine.java | 5 + .../statement/dcl/GrantStatementBinder.java | 63 +++++++++++++ .../engine/type/DCLStatementBindEngine.java | 43 +++++++++ .../dcl/GrantStatementBinderTest.java | 92 +++++++++++++++++++ .../src/test/resources/cases/dcl/grant.xml | 28 ++++++ .../src/test/resources/sqls/dcl/grant.xml | 21 +++++ 6 files changed, 252 insertions(+) create mode 100644 infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinder.java create mode 100644 infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/type/DCLStatementBindEngine.java create mode 100644 infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinderTest.java create mode 100644 test/it/binder/src/test/resources/cases/dcl/grant.xml create mode 100644 test/it/binder/src/test/resources/sqls/dcl/grant.xml diff --git a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/SQLBindEngine.java b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/SQLBindEngine.java index b68a3eda60ccf..b548c4419a3da 100644 --- a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/SQLBindEngine.java +++ b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/SQLBindEngine.java @@ -22,6 +22,7 @@ import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; import org.apache.shardingsphere.infra.binder.engine.type.DALStatementBindEngine; +import org.apache.shardingsphere.infra.binder.engine.type.DCLStatementBindEngine; import org.apache.shardingsphere.infra.binder.engine.type.DDLStatementBindEngine; import org.apache.shardingsphere.infra.binder.engine.type.DMLStatementBindEngine; import org.apache.shardingsphere.infra.database.core.spi.DatabaseTypedSPILoader; @@ -30,6 +31,7 @@ import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData; import org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement; import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dal.DALStatement; +import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.DCLStatement; import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.DDLStatement; import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.DMLStatement; @@ -75,6 +77,9 @@ private SQLStatement bind(final SQLStatement sqlStatement) { if (sqlStatement instanceof DDLStatement) { return new DDLStatementBindEngine().bind((DDLStatement) sqlStatement, binderContext); } + if (sqlStatement instanceof DCLStatement) { + return new DCLStatementBindEngine().bind((DCLStatement) sqlStatement, binderContext); + } if (sqlStatement instanceof DALStatement) { return new DALStatementBindEngine().bind((DALStatement) sqlStatement, binderContext); } diff --git a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinder.java b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinder.java new file mode 100644 index 0000000000000..6e02e0d9fa7d6 --- /dev/null +++ b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinder.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.shardingsphere.infra.binder.engine.statement.dcl; + +import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import org.apache.shardingsphere.infra.binder.engine.segment.dml.from.context.TableSegmentBinderContext; +import org.apache.shardingsphere.infra.binder.engine.segment.dml.from.type.SimpleTableSegmentBinder; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinder; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementCopyUtils; +import org.apache.shardingsphere.infra.database.core.type.DatabaseType; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment; +import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.GrantStatement; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Grant statement binder. + */ +public final class GrantStatementBinder implements SQLStatementBinder { + + @Override + public GrantStatement bind(final GrantStatement sqlStatement, final SQLStatementBinderContext binderContext) { + Collection tables = sqlStatement.getTables(); + if (tables.isEmpty()) { + return sqlStatement; + } + Multimap tableBinderContexts = LinkedHashMultimap.create(); + Collection boundTables = new ArrayList<>(); + for (SimpleTableSegment each : tables) { + boundTables.add(SimpleTableSegmentBinder.bind(each, binderContext, tableBinderContexts)); + } + return copyGrantStatement(sqlStatement, boundTables); + } + + private GrantStatement copyGrantStatement(final GrantStatement sqlStatement, final Collection tables) { + if (tables.equals(sqlStatement.getTables())) { + return sqlStatement; + } + GrantStatement result = new GrantStatement(sqlStatement.getDatabaseType()); + result.getTables().addAll(tables); + SQLStatementCopyUtils.copyAttributes(sqlStatement, result); + return result; + } +} diff --git a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/type/DCLStatementBindEngine.java b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/type/DCLStatementBindEngine.java new file mode 100644 index 0000000000000..196f74a97409f --- /dev/null +++ b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/type/DCLStatementBindEngine.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.infra.binder.engine.type; + +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.infra.binder.engine.statement.dcl.GrantStatementBinder; +import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.DCLStatement; +import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.GrantStatement; + +/** + * DCL statement bind engine. + */ +public final class DCLStatementBindEngine { + + /** + * Bind DCL statement. + * + * @param statement to be bound DCL statement + * @param binderContext binder context + * @return bound DCL statement + */ + public DCLStatement bind(final DCLStatement statement, final SQLStatementBinderContext binderContext) { + if (statement instanceof GrantStatement) { + return new GrantStatementBinder().bind((GrantStatement) statement, binderContext); + } + return statement; + } +} diff --git a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinderTest.java b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinderTest.java new file mode 100644 index 0000000000000..f2a80a137567f --- /dev/null +++ b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinderTest.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.shardingsphere.infra.binder.engine.statement.dcl; + +import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; +import org.apache.shardingsphere.infra.database.core.type.DatabaseType; +import org.apache.shardingsphere.infra.hint.HintValueContext; +import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData; +import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase; +import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema; +import org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable; +import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment; +import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableNameSegment; +import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.GrantStatement; +import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Collection; +import java.util.Collections; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class GrantStatementBinderTest { + + private final DatabaseType databaseType = TypedSPILoader.getService(DatabaseType.class, "FIXTURE"); + + @Mock + private ShardingSphereMetaData metaData; + + @Mock + private ShardingSphereDatabase database; + + @Mock + private ShardingSphereSchema schema; + + @Mock + private ShardingSphereTable table; + + @Test + void assertBind() { + when(metaData.containsDatabase("foo_db")).thenReturn(true); + when(metaData.getDatabase("foo_db")).thenReturn(database); + when(database.containsSchema("foo_db")).thenReturn(true); + when(database.getSchema("foo_db")).thenReturn(schema); + when(schema.containsTable("test_table")).thenReturn(true); + when(schema.getTable("test_table")).thenReturn(table); + when(table.getAllColumns()).thenReturn(Collections.emptyList()); + HintValueContext hintValueContext = new HintValueContext(); + hintValueContext.setSkipMetadataValidate(true); + SimpleTableSegment tableSegment = new SimpleTableSegment(new TableNameSegment(0, 0, new IdentifierValue("test_table"))); + GrantStatement original = new GrantStatement(databaseType); + original.getTables().add(tableSegment); + SQLStatementBinderContext binderContext = new SQLStatementBinderContext(metaData, "foo_db", hintValueContext, original); + GrantStatement actual = new GrantStatementBinder().bind(original, binderContext); + Collection actualTables = actual.getTables(); + assertThat(actualTables.size(), is(1)); + assertThat(actualTables.iterator().next().getTableName().getIdentifier().getValue(), is("test_table")); + } + + @Test + void assertBindWithEmptyTables() { + GrantStatement original = new GrantStatement(databaseType); + HintValueContext hintValueContext = new HintValueContext(); + hintValueContext.setSkipMetadataValidate(true); + SQLStatementBinderContext binderContext = new SQLStatementBinderContext(metaData, "foo_db", hintValueContext, original); + GrantStatement actual = new GrantStatementBinder().bind(original, binderContext); + Collection actualTables = actual.getTables(); + assertThat(actualTables.size(), is(0)); + } +} diff --git a/test/it/binder/src/test/resources/cases/dcl/grant.xml b/test/it/binder/src/test/resources/cases/dcl/grant.xml new file mode 100644 index 0000000000000..a20b46d224685 --- /dev/null +++ b/test/it/binder/src/test/resources/cases/dcl/grant.xml @@ -0,0 +1,28 @@ + + + + + + + + + + +
+
+
diff --git a/test/it/binder/src/test/resources/sqls/dcl/grant.xml b/test/it/binder/src/test/resources/sqls/dcl/grant.xml new file mode 100644 index 0000000000000..557e3db966dc9 --- /dev/null +++ b/test/it/binder/src/test/resources/sqls/dcl/grant.xml @@ -0,0 +1,21 @@ + + + + + + From 8cd06a746a83f173b88517aa2aec5437729bdba5 Mon Sep 17 00:00:00 2001 From: Jackie Yan Date: Thu, 7 Aug 2025 20:23:55 +0800 Subject: [PATCH 2/4] fix checkstyle --- .../infra/binder/engine/statement/dcl/GrantStatementBinder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinder.java b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinder.java index 6e02e0d9fa7d6..28c988b982fb4 100644 --- a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinder.java +++ b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/statement/dcl/GrantStatementBinder.java @@ -25,7 +25,6 @@ import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinder; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext; import org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementCopyUtils; -import org.apache.shardingsphere.infra.database.core.type.DatabaseType; import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment; import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.GrantStatement; From a6146d57d145a54262f2351ae59777616491ae1a Mon Sep 17 00:00:00 2001 From: Jackie Yan Date: Fri, 8 Aug 2025 23:12:26 +0800 Subject: [PATCH 3/4] resolve conflict --- .../infra/binder/engine/type/DCLStatementBindEngine.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/type/DCLStatementBindEngine.java b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/type/DCLStatementBindEngine.java index c14a067fc693c..7c71af57399c3 100644 --- a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/type/DCLStatementBindEngine.java +++ b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/type/DCLStatementBindEngine.java @@ -39,10 +39,10 @@ public final class DCLStatementBindEngine { public DCLStatement bind(final DCLStatement statement, final SQLStatementBinderContext binderContext) { if (statement instanceof RevokeStatement) { return new RevokeStatementBinder().bind((RevokeStatement) statement, binderContext); + } if (statement instanceof GrantStatement) { return new GrantStatementBinder().bind((GrantStatement) statement, binderContext); } - return statement; - } + return statement; } } From 5eff598a41c9835bac28c1a839b000864dc870d5 Mon Sep 17 00:00:00 2001 From: Jackie Yan Date: Fri, 8 Aug 2025 23:14:24 +0800 Subject: [PATCH 4/4] update release notes --- RELEASE-NOTES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index d26aa0c2ec11c..2b1dbf8f8a7f5 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -118,6 +118,7 @@ 1. SQL Binder: Support Comment statement SQL bind - [#36012](https://github.com/apache/shardingsphere/pull/36012) 1. SQL Binder: Support Prepare statement SQL bind - [#36064](https://github.com/apache/shardingsphere/pull/36064) 1. SQL Binder: Support Revoke statement SQL bind - [#36124](https://github.com/apache/shardingsphere/pull/36124) +1. SQL Binder: Support Grant statement SQL bind - [#36207](https://github.com/apache/shardingsphere/pull/36207) 1. SQL Binder: Add alter table metadata check - [#35877](https://github.com/apache/shardingsphere/pull/35877) 1. SQL Router: Add check for select with union all routing to multi data sources - [#35037](https://github.com/apache/shardingsphere/pull/35037) 1. SQL Router: Improve support for executing tableless SQL with single data source - [#35659](https://github.com/apache/shardingsphere/pull/35659)