This is an automated email from the ASF dual-hosted git repository.
zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new b2badcd4394 Throw NPE when INSERT column and values mismatch (#19039)
b2badcd4394 is described below
commit b2badcd43948fcf6aa5ea46cacda509ed6eaa6da
Author: Ziyuan Han <[email protected]>
AuthorDate: Wed Jul 13 11:48:49 2022 +0800
Throw NPE when INSERT column and values mismatch (#19039)
* Throw NPE when INSERT column and values mismatch
---
.../mysql/constant/MySQLServerErrorCode.java | 2 ++
.../postgresql/constant/PostgreSQLErrorCode.java | 1 +
.../impl/InsertClauseShardingConditionEngine.java | 10 ++++--
.../InsertClauseShardingConditionEngineTest.java | 14 ++++++++
.../infra/exception/ColumnMismatchException.java | 42 ++++++++++++++++++++++
.../frontend/mysql/err/MySQLErrPacketFactory.java | 4 +++
.../postgresql/err/PostgreSQLErrPacketFactory.java | 4 +++
7 files changed, 75 insertions(+), 2 deletions(-)
diff --git
a/shardingsphere-db-protocol/shardingsphere-db-protocol-mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLServerErrorCode.java
b/shardingsphere-db-protocol/shardingsphere-db-protocol-mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLServerErrorCode.java
index d0da0e258fe..dfc570763ad 100644
---
a/shardingsphere-db-protocol/shardingsphere-db-protocol-mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLServerErrorCode.java
+++
b/shardingsphere-db-protocol/shardingsphere-db-protocol-mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLServerErrorCode.java
@@ -58,6 +58,8 @@ public enum MySQLServerErrorCode implements SQLErrorCode {
ER_UNKNOWN_CHARACTER_SET(1115, "42000", "Unknown character set: '%s'"),
+ ER_MISMATCH_COLUMN_COUNT(1136, "21S01", "Column count doesn't match value
count at row %d"),
+
ER_ERROR_ON_MODIFYING_GTID_EXECUTED_TABLE(3176, "HY000",
"Please do not modify the %s table with an XA transaction. This is
an internal system table used to store GTIDs for committed transactions. "
+ "Although modifying it can lead to an inconsistent GTID
state, if necessary you can modify it with a non-XA transaction.");
diff --git
a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLErrorCode.java
b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLErrorCode.java
index 4cb9f187cc7..1e312e3ca3e 100644
---
a/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLErrorCode.java
+++
b/shardingsphere-db-protocol/shardingsphere-db-protocol-postgresql/src/main/java/org/apache/shardingsphere/db/protocol/postgresql/constant/PostgreSQLErrorCode.java
@@ -49,6 +49,7 @@ public enum PostgreSQLErrorCode {
FEATURE_NOT_SUPPORTED("0A000", "feature_not_supported"),
DUPLICATE_DATABASE("42P04", "Database '%s' already exists"),
INVALID_AUTHORIZATION_SPECIFICATION("28000",
"invalid_authorization_specification"),
+ ER_MISMATCH_COLUMN_COUNT("42601", "syntax_error"),
INVALID_PARAMETER_VALUE("22023", "invalid_parameter_value"),
INVALID_PASSWORD("28P01", "invalid_password"),
INVALID_CATALOG_NAME("3D000", "invalid_catalog_name"),
diff --git
a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/impl/InsertClauseShardingConditionEngine.java
b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/impl/InsertClauseShardingConditionEngine.java
index 97e4319e6d2..f347607aeba 100644
---
a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/impl/InsertClauseShardingConditionEngine.java
+++
b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/impl/InsertClauseShardingConditionEngine.java
@@ -25,6 +25,7 @@ import
org.apache.shardingsphere.infra.binder.statement.dml.InsertStatementConte
import
org.apache.shardingsphere.infra.binder.statement.dml.SelectStatementContext;
import org.apache.shardingsphere.infra.datetime.DatetimeService;
import org.apache.shardingsphere.infra.datetime.DatetimeServiceFactory;
+import org.apache.shardingsphere.infra.exception.ColumnMismatchException;
import org.apache.shardingsphere.infra.exception.ShardingSphereException;
import
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
import
org.apache.shardingsphere.sharding.route.engine.condition.ExpressionConditionUtils;
@@ -72,8 +73,9 @@ public final class InsertClauseShardingConditionEngine
implements ShardingCondit
Collection<String> columnNames = getColumnNames(sqlStatementContext);
List<InsertValueContext> insertValueContexts =
sqlStatementContext.getInsertValueContexts();
List<ShardingCondition> result = new
ArrayList<>(insertValueContexts.size());
+ int row = 0;
for (InsertValueContext each : insertValueContexts) {
- result.add(createShardingCondition(tableName,
columnNames.iterator(), each, parameters));
+ result.add(createShardingCondition(tableName,
columnNames.iterator(), each, parameters, ++row));
}
return result;
}
@@ -88,10 +90,14 @@ public final class InsertClauseShardingConditionEngine
implements ShardingCondit
return insertStatementContext.getColumnNames();
}
- private ShardingCondition createShardingCondition(final String tableName,
final Iterator<String> columnNames, final InsertValueContext
insertValueContext, final List<Object> parameters) {
+ private ShardingCondition createShardingCondition(final String tableName,
final Iterator<String> columnNames, final InsertValueContext insertValueContext,
+ final List<Object>
parameters, final int row) {
ShardingCondition result = new ShardingCondition();
DatetimeService datetimeService = null;
for (ExpressionSegment each :
insertValueContext.getValueExpressions()) {
+ if (!columnNames.hasNext()) {
+ throw new ColumnMismatchException(row);
+ }
Optional<String> shardingColumn =
shardingRule.findShardingColumn(columnNames.next(), tableName);
if (!shardingColumn.isPresent()) {
continue;
diff --git
a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/InsertClauseShardingConditionEngineTest.java
b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/InsertClauseShardingConditionEngineTest.java
index fe659775967..a468c738352 100644
---
a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/InsertClauseShardingConditionEngineTest.java
+++
b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/route/engine/condition/engine/InsertClauseShardingConditionEngineTest.java
@@ -21,6 +21,7 @@ import
org.apache.shardingsphere.infra.binder.segment.insert.keygen.GeneratedKey
import
org.apache.shardingsphere.infra.binder.segment.insert.values.InsertSelectContext;
import
org.apache.shardingsphere.infra.binder.segment.insert.values.InsertValueContext;
import
org.apache.shardingsphere.infra.binder.statement.dml.InsertStatementContext;
+import org.apache.shardingsphere.infra.exception.ColumnMismatchException;
import
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
import
org.apache.shardingsphere.sharding.route.engine.condition.ShardingCondition;
import
org.apache.shardingsphere.sharding.route.engine.condition.engine.impl.InsertClauseShardingConditionEngine;
@@ -38,6 +39,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@@ -107,6 +109,18 @@ public final class InsertClauseShardingConditionEngineTest
{
assertThat(shardingConditions.get(0).getValues().size(), is(1));
}
+ @Test(expected = ColumnMismatchException.class)
+ public void
assertCreateShardingConditionsInsertStatementWithMismatchColumns() {
+
when(insertStatementContext.getInsertValueContexts()).thenReturn(Collections.singletonList(createInsertValueContextWithMultiAssignments()));
+ when(shardingRule.findShardingColumn(any(),
any())).thenReturn(Optional.of("foo_sharding_col"));
+
when(insertStatementContext.getColumnNames()).thenReturn(Collections.singletonList("foo_col1"));
+
shardingConditionEngine.createShardingConditions(insertStatementContext,
Collections.emptyList());
+ }
+
+ private InsertValueContext createInsertValueContextWithMultiAssignments() {
+ return new InsertValueContext(Arrays.asList(new
LiteralExpressionSegment(0, 10, "1"), new LiteralExpressionSegment(0, 10,
"1")), Collections.emptyList(), 0);
+ }
+
@Test
public void
assertCreateShardingConditionsInsertStatementWithGeneratedKeyContextUsingCommonExpressionSegmentNow()
{
when(insertStatementContext.getInsertValueContexts()).thenReturn(Collections.singletonList(createInsertValueContextAsCommonExpressionSegmentWithNow()));
diff --git
a/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/exception/ColumnMismatchException.java
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/exception/ColumnMismatchException.java
new file mode 100644
index 00000000000..dfea6225b8b
--- /dev/null
+++
b/shardingsphere-infra/shardingsphere-infra-common/src/main/java/org/apache/shardingsphere/infra/exception/ColumnMismatchException.java
@@ -0,0 +1,42 @@
+/*
+ * 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.exception;
+
+import lombok.Getter;
+
+@Getter
+public final class ColumnMismatchException extends ShardingSphereException {
+
+ private static final long serialVersionUID = 5676889868213244575L;
+
+ private static final String DEFAULT_MSG = "INSERT has more expressions
than target columns";
+
+ private final int row;
+
+ private final String message;
+
+ public ColumnMismatchException(final int row, final String message) {
+ super(message);
+ this.row = row;
+ this.message = message;
+ }
+
+ public ColumnMismatchException(final int row) {
+ this(row, DEFAULT_MSG);
+ }
+}
diff --git
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/err/MySQLErrPacketFactory.java
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/err/MySQLErrPacketFactory.java
index 1b431f600c9..7f5cae40bb8 100644
---
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/err/MySQLErrPacketFactory.java
+++
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/err/MySQLErrPacketFactory.java
@@ -25,6 +25,7 @@ import
org.apache.shardingsphere.db.protocol.error.CommonErrorCode;
import
org.apache.shardingsphere.db.protocol.mysql.constant.MySQLServerErrorCode;
import
org.apache.shardingsphere.db.protocol.mysql.packet.generic.MySQLErrPacket;
import
org.apache.shardingsphere.infra.config.exception.ShardingSphereConfigurationException;
+import org.apache.shardingsphere.infra.exception.ColumnMismatchException;
import org.apache.shardingsphere.infra.exception.DatabaseNotExistedException;
import org.apache.shardingsphere.proxy.backend.exception.CircuitBreakException;
import
org.apache.shardingsphere.proxy.backend.exception.DBCreateExistsException;
@@ -74,6 +75,9 @@ public final class MySQLErrPacketFactory {
if (cause instanceof TableModifyInTransactionException) {
return new MySQLErrPacket(1,
MySQLServerErrorCode.ER_ERROR_ON_MODIFYING_GTID_EXECUTED_TABLE,
((TableModifyInTransactionException) cause).getTableName());
}
+ if (cause instanceof ColumnMismatchException) {
+ return new MySQLErrPacket(1,
MySQLServerErrorCode.ER_MISMATCH_COLUMN_COUNT, ((ColumnMismatchException)
cause).getRow());
+ }
if (cause instanceof UnknownDatabaseException) {
return new MySQLErrPacket(1, MySQLServerErrorCode.ER_BAD_DB_ERROR,
((UnknownDatabaseException) cause).getDatabaseName());
}
diff --git
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/err/PostgreSQLErrPacketFactory.java
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/err/PostgreSQLErrPacketFactory.java
index 88adb3ce263..e5dfe98f88c 100644
---
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/err/PostgreSQLErrPacketFactory.java
+++
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-postgresql/src/main/java/org/apache/shardingsphere/proxy/frontend/postgresql/err/PostgreSQLErrPacketFactory.java
@@ -23,6 +23,7 @@ import lombok.NoArgsConstructor;
import
org.apache.shardingsphere.db.protocol.postgresql.constant.PostgreSQLErrorCode;
import
org.apache.shardingsphere.db.protocol.postgresql.constant.PostgreSQLMessageSeverityLevel;
import
org.apache.shardingsphere.db.protocol.postgresql.packet.generic.PostgreSQLErrorResponsePacket;
+import org.apache.shardingsphere.infra.exception.ColumnMismatchException;
import
org.apache.shardingsphere.proxy.backend.exception.DBCreateExistsException;
import
org.apache.shardingsphere.proxy.backend.exception.InTransactionException;
import
org.apache.shardingsphere.proxy.backend.exception.UnsupportedUpdateOperationException;
@@ -57,6 +58,9 @@ public final class PostgreSQLErrPacketFactory {
if (cause instanceof SQLException) {
return createErrorResponsePacket((SQLException) cause);
}
+ if (cause instanceof ColumnMismatchException) {
+ return
PostgreSQLErrorResponsePacket.newBuilder(PostgreSQLMessageSeverityLevel.ERROR,
PostgreSQLErrorCode.ER_MISMATCH_COLUMN_COUNT, cause.getMessage()).build();
+ }
if (cause instanceof InvalidAuthorizationSpecificationException) {
return
PostgreSQLErrorResponsePacket.newBuilder(PostgreSQLMessageSeverityLevel.FATAL,
PostgreSQLErrorCode.INVALID_AUTHORIZATION_SPECIFICATION,
cause.getMessage()).build();
}