This is an automated email from the ASF dual-hosted git repository.
tuichenchuxin 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 cc6d5ebc025 Fix mysql client multi statements option in protocol
(#29688)
cc6d5ebc025 is described below
commit cc6d5ebc025023ab3737bd18ea06add6959bf3ca
Author: ZhangCheng <[email protected]>
AuthorDate: Wed Jan 10 18:39:19 2024 +0800
Fix mysql client multi statements option in protocol (#29688)
* Fix mysql client multi statements option in protocol
* Fix mysql client multi statements option in protocol
* Fix mysql client multi statements option in protocol
* Fix mysql client multi statements option in protocol
* Fix mysql client multi statements option in protocol
* Fix mysql client multi statements option in protocol
* Fix mysql client multi statements option in protocol
* fix
---
.../mysql/constant/MySQLCapabilityFlag.java | 2 +-
.../handshake/MySQLHandshakeResponse41Packet.java | 9 +++++++
.../mysql/constant/MySQLCapabilityFlagTest.java | 2 +-
.../packet/handshake/MySQLHandshakePacketTest.java | 2 +-
.../MySQLHandshakeResponse41PacketTest.java | 19 ++++++++++++++
.../authentication/MySQLAuthenticationEngine.java | 7 +++++-
.../MySQLAuthenticationEngineTest.java | 2 ++
.../e2e/env/runtime/DataSourceEnvironment.java | 4 +--
.../param/array/E2ETestParameterGenerator.java | 7 ++++--
.../cases/dml/dataset/db/delete_with_multiple.xml | 29 ++++++++++++++++++++++
.../resources/cases/dml/dml-integration-delete.xml | 6 +++++
11 files changed, 81 insertions(+), 8 deletions(-)
diff --git
a/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLCapabilityFlag.java
b/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLCapabilityFlag.java
index 6d5eda2f71b..7a1c18c82a8 100644
---
a/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLCapabilityFlag.java
+++
b/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLCapabilityFlag.java
@@ -97,7 +97,7 @@ public enum MySQLCapabilityFlag {
* @return handshake capability flags upper bit
*/
public static int calculateHandshakeCapabilityFlagsUpper() {
- return calculateCapabilityFlags(CLIENT_PLUGIN_AUTH) >> 16;
+ return calculateCapabilityFlags(CLIENT_MULTI_STATEMENTS,
CLIENT_PLUGIN_AUTH) >> 16;
}
/**
diff --git
a/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakeResponse41Packet.java
b/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakeResponse41Packet.java
index 96c1f90bb4d..7d98bc1ee36 100644
---
a/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakeResponse41Packet.java
+++
b/db-protocol/mysql/src/main/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakeResponse41Packet.java
@@ -23,6 +23,7 @@ import lombok.Setter;
import
org.apache.shardingsphere.db.protocol.mysql.constant.MySQLAuthenticationMethod;
import
org.apache.shardingsphere.db.protocol.mysql.constant.MySQLCapabilityFlag;
import org.apache.shardingsphere.db.protocol.mysql.packet.MySQLPacket;
+import
org.apache.shardingsphere.db.protocol.mysql.packet.command.admin.MySQLComSetOptionPacket;
import org.apache.shardingsphere.db.protocol.mysql.payload.MySQLPacketPayload;
/**
@@ -49,8 +50,11 @@ public final class MySQLHandshakeResponse41Packet extends
MySQLPacket {
private String authPluginName;
+ private int multiStatementsOption;
+
public MySQLHandshakeResponse41Packet(final MySQLPacketPayload payload) {
capabilityFlags = payload.readInt4();
+ multiStatementsOption = readMultiStatementsOption(capabilityFlags);
maxPacketSize = payload.readInt4();
characterSet = payload.readInt1();
payload.skipReserved(23);
@@ -60,6 +64,11 @@ public final class MySQLHandshakeResponse41Packet extends
MySQLPacket {
authPluginName = readAuthPluginName(payload);
}
+ private int readMultiStatementsOption(final int capabilityFlags) {
+ return 0 == (capabilityFlags &
MySQLCapabilityFlag.CLIENT_MULTI_STATEMENTS.getValue()) ?
MySQLComSetOptionPacket.MYSQL_OPTION_MULTI_STATEMENTS_OFF
+ : MySQLComSetOptionPacket.MYSQL_OPTION_MULTI_STATEMENTS_ON;
+ }
+
private byte[] readAuthResponse(final MySQLPacketPayload payload) {
if (0 != (capabilityFlags &
MySQLCapabilityFlag.CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA.getValue())) {
return payload.readStringLenencByBytes();
diff --git
a/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLCapabilityFlagTest.java
b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLCapabilityFlagTest.java
index e89c0e9ae44..ebc3cb46e2c 100644
---
a/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLCapabilityFlagTest.java
+++
b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/constant/MySQLCapabilityFlagTest.java
@@ -36,6 +36,6 @@ class MySQLCapabilityFlagTest {
@Test
void assertCalculateHandshakeCapabilityFlagsUpper() {
-
assertThat(MySQLCapabilityFlag.calculateHandshakeCapabilityFlagsUpper(),
is(0x0008));
+
assertThat(MySQLCapabilityFlag.calculateHandshakeCapabilityFlagsUpper(),
is(0x0009));
}
}
diff --git
a/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakePacketTest.java
b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakePacketTest.java
index ff25169d263..f4065216048 100644
---
a/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakePacketTest.java
+++
b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakePacketTest.java
@@ -129,7 +129,7 @@ class MySQLHandshakePacketTest {
verify(payload).writeInt2(MySQLCapabilityFlag.calculateHandshakeCapabilityFlagsLower());
verify(payload).writeInt1(MySQLConstants.DEFAULT_CHARSET.getId());
verify(payload).writeInt2(MySQLStatusFlag.SERVER_STATUS_AUTOCOMMIT.getValue());
-
verify(payload).writeInt2(MySQLCapabilityFlag.CLIENT_PLUGIN_AUTH.getValue() >>
16);
+
verify(payload).writeInt2(MySQLCapabilityFlag.calculateHandshakeCapabilityFlagsUpper());
verify(payload).writeInt1(authPluginData.getAuthenticationPluginData().length +
1);
verify(payload).writeReserved(10);
verify(payload).writeStringNul(new
String(authPluginData.getAuthenticationPluginDataPart2()));
diff --git
a/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakeResponse41PacketTest.java
b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakeResponse41PacketTest.java
index 911071d588b..e0a5ad98ac2 100644
---
a/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakeResponse41PacketTest.java
+++
b/db-protocol/mysql/src/test/java/org/apache/shardingsphere/db/protocol/mysql/packet/handshake/MySQLHandshakeResponse41PacketTest.java
@@ -20,6 +20,7 @@ package
org.apache.shardingsphere.db.protocol.mysql.packet.handshake;
import
org.apache.shardingsphere.db.protocol.mysql.constant.MySQLAuthenticationMethod;
import
org.apache.shardingsphere.db.protocol.mysql.constant.MySQLCapabilityFlag;
import org.apache.shardingsphere.db.protocol.mysql.constant.MySQLConstants;
+import
org.apache.shardingsphere.db.protocol.mysql.packet.command.admin.MySQLComSetOptionPacket;
import org.apache.shardingsphere.db.protocol.mysql.payload.MySQLPacketPayload;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -55,6 +56,24 @@ class MySQLHandshakeResponse41PacketTest {
verify(payload).skipReserved(23);
}
+ @Test
+ void assertNewWithPayloadWithClientMultiStatements() {
+
when(payload.readInt1()).thenReturn(MySQLConstants.DEFAULT_CHARSET.getId());
+
when(payload.readInt4()).thenReturn(MySQLCapabilityFlag.CLIENT_MULTI_STATEMENTS.getValue(),
1000);
+ when(payload.readStringNul()).thenReturn("root", "sharding_db");
+ when(payload.readStringNulByBytes()).thenReturn(new byte[]{1});
+ MySQLHandshakeResponse41Packet actual = new
MySQLHandshakeResponse41Packet(payload);
+ assertThat(actual.getMultiStatementsOption(),
is(MySQLComSetOptionPacket.MYSQL_OPTION_MULTI_STATEMENTS_ON));
+ assertThat(actual.getMaxPacketSize(), is(1000));
+ assertThat(actual.getCharacterSet(),
is(MySQLConstants.DEFAULT_CHARSET.getId()));
+ assertThat(actual.getUsername(), is("root"));
+ assertThat(actual.getAuthResponse(), is(new byte[]{1}));
+ assertThat(actual.getCapabilityFlags(),
is(MySQLCapabilityFlag.CLIENT_MULTI_STATEMENTS.getValue()));
+ assertNull(actual.getDatabase());
+ assertNull(actual.getAuthPluginName());
+ verify(payload).skipReserved(23);
+ }
+
@Test
void assertNewWithPayloadWithAuthPluginName() {
when(payload.readInt1()).thenReturn(MySQLConstants.DEFAULT_CHARSET.getId());
diff --git
a/proxy/frontend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/authentication/MySQLAuthenticationEngine.java
b/proxy/frontend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/authentication/MySQLAuthenticationEngine.java
index c62e37daaa2..31233a864ea 100644
---
a/proxy/frontend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/authentication/MySQLAuthenticationEngine.java
+++
b/proxy/frontend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/frontend/mysql/authentication/MySQLAuthenticationEngine.java
@@ -119,9 +119,10 @@ public final class MySQLAuthenticationEngine implements
AuthenticationEngine {
}
throw new HandshakeException();
}
- String database = handshakeResponsePacket.getDatabase();
authResponse = handshakeResponsePacket.getAuthResponse();
+ setMultiStatementsOption(context, handshakeResponsePacket);
setCharacterSet(context, handshakeResponsePacket);
+ String database = handshakeResponsePacket.getDatabase();
if (!Strings.isNullOrEmpty(database) &&
!ProxyContext.getInstance().databaseExists(database)) {
throw new UnknownDatabaseException(database);
}
@@ -137,6 +138,10 @@ public final class MySQLAuthenticationEngine implements
AuthenticationEngine {
return AuthenticationResultBuilder.finished(username, hostname,
database);
}
+ private void setMultiStatementsOption(final ChannelHandlerContext context,
final MySQLHandshakeResponse41Packet handshakeResponsePacket) {
+
context.channel().attr(MySQLConstants.MYSQL_OPTION_MULTI_STATEMENTS).set(handshakeResponsePacket.getMultiStatementsOption());
+ }
+
private void setCharacterSet(final ChannelHandlerContext context, final
MySQLHandshakeResponse41Packet handshakeResponsePacket) {
MySQLCharacterSet characterSet =
MySQLCharacterSet.findById(handshakeResponsePacket.getCharacterSet());
context.channel().attr(CommonConstants.CHARSET_ATTRIBUTE_KEY).set(characterSet.getCharset());
diff --git
a/proxy/frontend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/authentication/MySQLAuthenticationEngineTest.java
b/proxy/frontend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/authentication/MySQLAuthenticationEngineTest.java
index a922952f079..50148519ad6 100644
---
a/proxy/frontend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/authentication/MySQLAuthenticationEngineTest.java
+++
b/proxy/frontend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/frontend/mysql/authentication/MySQLAuthenticationEngineTest.java
@@ -148,6 +148,7 @@ class MySQLAuthenticationEngineTest {
when(channel.remoteAddress()).thenReturn(new
InetSocketAddress("localhost", 3307));
when(channel.attr(CommonConstants.CHARSET_ATTRIBUTE_KEY)).thenReturn(mock(Attribute.class));
when(channel.attr(MySQLConstants.MYSQL_CHARACTER_SET_ATTRIBUTE_KEY)).thenReturn(mock(Attribute.class));
+
when(channel.attr(MySQLConstants.MYSQL_OPTION_MULTI_STATEMENTS)).thenReturn(mock(Attribute.class));
when(channelHandlerContext.channel()).thenReturn(channel);
when(payload.readInt1()).thenReturn(1);
when(payload.readInt4()).thenReturn(MySQLCapabilityFlag.CLIENT_PLUGIN_AUTH.getValue());
@@ -321,6 +322,7 @@ class MySQLAuthenticationEngineTest {
when(result.attr(CommonConstants.CHARSET_ATTRIBUTE_KEY)).thenReturn(mock(Attribute.class));
when(result.attr(MySQLConstants.MYSQL_CHARACTER_SET_ATTRIBUTE_KEY)).thenReturn(mock(Attribute.class));
when(result.attr(MySQLConstants.MYSQL_SEQUENCE_ID)).thenReturn(mock(Attribute.class));
+
when(result.attr(MySQLConstants.MYSQL_OPTION_MULTI_STATEMENTS)).thenReturn(mock(Attribute.class));
return result;
}
diff --git
a/test/e2e/env/src/test/java/org/apache/shardingsphere/test/e2e/env/runtime/DataSourceEnvironment.java
b/test/e2e/env/src/test/java/org/apache/shardingsphere/test/e2e/env/runtime/DataSourceEnvironment.java
index c715bfc5cc7..ca114712809 100644
---
a/test/e2e/env/src/test/java/org/apache/shardingsphere/test/e2e/env/runtime/DataSourceEnvironment.java
+++
b/test/e2e/env/src/test/java/org/apache/shardingsphere/test/e2e/env/runtime/DataSourceEnvironment.java
@@ -61,7 +61,7 @@ public final class DataSourceEnvironment {
return
"jdbc:h2:mem:test_db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL;USER=root;PASSWORD=Root@123";
case "MySQL":
return
String.format("jdbc:mysql://%s:%s?useSSL=true&requireSSL=true&enabledTLSProtocols=TLSv1.2,TLSv1.3&verifyServerCertificate=false"
- +
"&useServerPrepStmts=true&useLocalSessionState=true&characterEncoding=utf-8",
host, port);
+ +
"&useServerPrepStmts=true&useLocalSessionState=true&characterEncoding=utf-8&allowMultiQueries=true",
host, port);
case "PostgreSQL":
return
String.format("jdbc:postgresql://%s:%s/?ssl=on&sslmode=prefer", host, port);
case "openGauss":
@@ -88,7 +88,7 @@ public final class DataSourceEnvironment {
case "MySQL":
return String.format(
"jdbc:mysql://%s:%s/%s?useSSL=true&requireSSL=true&enabledTLSProtocols=TLSv1.2,TLSv1.3&verifyServerCertificate=false"
- +
"&useServerPrepStmts=true&useLocalSessionState=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true",
+ +
"&useServerPrepStmts=true&useLocalSessionState=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true&allowMultiQueries=true",
host, port, dataSourceName);
case "PostgreSQL":
return
String.format("jdbc:postgresql://%s:%s/%s?ssl=on&sslmode=prefer", host, port,
dataSourceName);
diff --git
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/framework/param/array/E2ETestParameterGenerator.java
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/framework/param/array/E2ETestParameterGenerator.java
index af2fe6a5f75..1145720542a 100644
---
a/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/framework/param/array/E2ETestParameterGenerator.java
+++
b/test/e2e/sql/src/test/java/org/apache/shardingsphere/test/e2e/framework/param/array/E2ETestParameterGenerator.java
@@ -163,14 +163,17 @@ public final class E2ETestParameterGenerator {
private Collection<E2ETestParameter> getCaseTestParameter(final
IntegrationTestCaseContext testCaseContext, final DatabaseType databaseType,
final SQLCommandType sqlCommandType) {
Collection<E2ETestParameter> result = new LinkedList<>();
- for (String adapter : envAdapters) {
- result.addAll(getCaseTestParameter(testCaseContext, adapter,
databaseType, sqlCommandType));
+ for (String each : envAdapters) {
+ result.addAll(getCaseTestParameter(testCaseContext, each,
databaseType, sqlCommandType));
}
return result;
}
private Collection<E2ETestParameter> getCaseTestParameter(final
IntegrationTestCaseContext testCaseContext, final String adapter,
final
DatabaseType databaseType, final SQLCommandType sqlCommandType) {
+ if (null != testCaseContext.getTestCase().getAdapters() &&
!testCaseContext.getTestCase().getAdapters().contains(adapter)) {
+ return Collections.emptyList();
+ }
Collection<String> scenarios = null ==
testCaseContext.getTestCase().getScenarioTypes() ? Collections.emptyList() :
Arrays.asList(testCaseContext.getTestCase().getScenarioTypes().split(","));
return envScenarios.stream().filter(each -> scenarios.isEmpty() ||
scenarios.contains(each))
.map(each -> new CaseTestParameter(testCaseContext, adapter,
each, envMode, databaseType, sqlCommandType)).collect(Collectors.toList());
diff --git
a/test/e2e/sql/src/test/resources/cases/dml/dataset/db/delete_with_multiple.xml
b/test/e2e/sql/src/test/resources/cases/dml/dataset/db/delete_with_multiple.xml
new file mode 100644
index 00000000000..c36bff07b07
--- /dev/null
+++
b/test/e2e/sql/src/test/resources/cases/dml/dataset/db/delete_with_multiple.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ 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.
+ -->
+
+<dataset update-count="38">
+ <metadata data-nodes="db_${0..9}.t_order">
+ <column name="order_id" type="numeric" />
+ <column name="user_id" type="numeric" />
+ <column name="status" type="varchar" />
+ <column name="merchant_id" type="numeric" />
+ <column name="remark" type="varchar" />
+ <column name="creation_date" type="datetime" />
+ </metadata>
+ <row data-node="db_9.t_order" values="2900, 29, init, 19, test,
2017-08-08" />
+ <row data-node="db_9.t_order" values="2901, 29, init, 20, test,
2017-08-08" />
+</dataset>
diff --git
a/test/e2e/sql/src/test/resources/cases/dml/dml-integration-delete.xml
b/test/e2e/sql/src/test/resources/cases/dml/dml-integration-delete.xml
index 937057bb0af..b6f6bcc76c4 100644
--- a/test/e2e/sql/src/test/resources/cases/dml/dml-integration-delete.xml
+++ b/test/e2e/sql/src/test/resources/cases/dml/dml-integration-delete.xml
@@ -66,4 +66,10 @@
<test-case sql="DELETE FROM t_shadow WHERE user_id = ? and order_id in (?,
?)" db-types="PostgreSQL"
scenario-types="shadow,sharding_encrypt_shadow,encrypt_shadow,readwrite_splitting_and_shadow,sharding_and_shadow">
<assertion parameters="0:int, 4:int, 5:int"
expected-data-file="shadow_delete_order_by_user_id.xml" />
</test-case>
+
+ <test-case
+ sql="DELETE FROM t_order WHERE order_id = 1000 AND user_id =
10;DELETE FROM t_order WHERE order_id = 1001 AND user_id = 11;DELETE FROM
t_order WHERE user_id < 29;" db-types="MySQL"
+ scenario-types="db" sql-case-types="LITERAL" adapters="proxy">
+ <assertion expected-data-file="delete_with_multiple.xml" />
+ </test-case>
</integration-test-cases>