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();
         }

Reply via email to