This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new 1a8590e0b22 branch-4.0: [fix](protocol) Support CLIENT_DEPRECATE_EOF 
to fix empty result with MySQL driver 9.5.0 #61050 (#61062)
1a8590e0b22 is described below

commit 1a8590e0b227ee9a43430244215394e99201d7af
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Mar 6 13:18:11 2026 +0800

    branch-4.0: [fix](protocol) Support CLIENT_DEPRECATE_EOF to fix empty 
result with MySQL driver 9.5.0 #61050 (#61062)
    
    Cherry-picked from #61050
    
    Co-authored-by: Mingyu Chen (Rayner) <[email protected]>
---
 .../org/apache/doris/mysql/MysqlCapability.java    |   7 +-
 .../java/org/apache/doris/mysql/MysqlOkPacket.java |   9 +-
 .../doris/mysql/MysqlResultSetEndPacket.java       |  61 +++++++++++
 .../java/org/apache/doris/qe/ConnectProcessor.java |  19 +++-
 .../java/org/apache/doris/qe/FEOpExecutor.java     |   4 +
 .../java/org/apache/doris/qe/StmtExecutor.java     |  49 +++++----
 .../apache/doris/mysql/MysqlCapabilityTest.java    |   3 +-
 .../org/apache/doris/mysql/MysqlOkPacketTest.java  |  23 +++-
 .../doris/mysql/MysqlResultSetEndPacketTest.java   | 120 +++++++++++++++++++++
 gensrc/thrift/FrontendService.thrift               |   2 +
 10 files changed, 266 insertions(+), 31 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCapability.java 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCapability.java
index cbfa88038be..d58f046eb53 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCapability.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCapability.java
@@ -74,13 +74,14 @@ public class MysqlCapability {
 
     private static final int DEFAULT_FLAGS = 
Flag.CLIENT_PROTOCOL_41.getFlagBit()
             | Flag.CLIENT_CONNECT_WITH_DB.getFlagBit() | 
Flag.CLIENT_SECURE_CONNECTION.getFlagBit()
-            | Flag.CLIENT_PLUGIN_AUTH.getFlagBit() | 
Flag.CLIENT_LOCAL_FILES.getFlagBit() | Flag.CLIENT_LONG_FLAG
-            .getFlagBit();
+            | Flag.CLIENT_PLUGIN_AUTH.getFlagBit() | 
Flag.CLIENT_LOCAL_FILES.getFlagBit()
+            | Flag.CLIENT_LONG_FLAG.getFlagBit() | 
Flag.CLIENT_DEPRECATE_EOF.getFlagBit();
 
     private static final int SSL_FLAGS = Flag.CLIENT_PROTOCOL_41.getFlagBit()
             | Flag.CLIENT_CONNECT_WITH_DB.getFlagBit() | 
Flag.CLIENT_SECURE_CONNECTION.getFlagBit()
             | Flag.CLIENT_PLUGIN_AUTH.getFlagBit() | 
Flag.CLIENT_LOCAL_FILES.getFlagBit()
-            | Flag.CLIENT_LONG_FLAG.getFlagBit() | 
Flag.CLIENT_SSL.getFlagBit();
+            | Flag.CLIENT_LONG_FLAG.getFlagBit() | Flag.CLIENT_SSL.getFlagBit()
+            | Flag.CLIENT_DEPRECATE_EOF.getFlagBit();
 
     public static final MysqlCapability DEFAULT_CAPABILITY = new 
MysqlCapability(DEFAULT_FLAGS);
     public static final MysqlCapability SSL_CAPABILITY = new 
MysqlCapability(SSL_FLAGS);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlOkPacket.java 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlOkPacket.java
index 778dfd8c3c4..4fa80102317 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlOkPacket.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlOkPacket.java
@@ -59,8 +59,13 @@ public class MysqlOkPacket extends MysqlPacket {
             // if ((STATUS_FLAGS & 
MysqlStatusFlag.SERVER_SESSION_STATE_CHANGED) != 0) {
             // }
         } else {
-            if (!Strings.isNullOrEmpty(infoMessage)) {
-                // NOTE: in datasheet, use EOF string, but in the code, mysql 
use length encoded string
+            // Always write the info field as a length-encoded string.
+            // When CLIENT_DEPRECATE_EOF is negotiated, the driver's 
OkPacket.parse()
+            // unconditionally reads STRING_LENENC for info, so an empty 
string must
+            // still be written (as a single 0x00 byte representing length 0).
+            if (Strings.isNullOrEmpty(infoMessage)) {
+                serializer.writeVInt(0);
+            } else {
                 serializer.writeLenEncodedString(infoMessage);
             }
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlResultSetEndPacket.java 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlResultSetEndPacket.java
new file mode 100644
index 00000000000..5543b85c361
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlResultSetEndPacket.java
@@ -0,0 +1,61 @@
+// 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.doris.mysql;
+
+import org.apache.doris.qe.QueryState;
+
+/**
+ * MySQL OK packet with 0xFE header, used as the end-of-result-set marker
+ * when CLIENT_DEPRECATE_EOF is set.
+ *
+ * When CLIENT_DEPRECATE_EOF capability is negotiated, the traditional EOF 
packet (0xFE, ≤5 bytes)
+ * is replaced by an OK packet that also uses 0xFE as its header byte but has 
a payload larger
+ * than 5 bytes. This is called a "ResultSet OK" packet in the MySQL protocol 
documentation.
+ *
+ * See: 
https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html
+ */
+public class MysqlResultSetEndPacket extends MysqlPacket {
+    // 0xFE header to distinguish from regular OK (0x00)
+    private static final int RESULTSET_OK_INDICATOR = 0xFE;
+    private static final long AFFECTED_ROWS = 0;
+    private static final long LAST_INSERT_ID = 0;
+
+    private int serverStatus = 0;
+    private int warningCount = 0;
+
+    public MysqlResultSetEndPacket(QueryState state) {
+        this.serverStatus = state.serverStatus;
+    }
+
+    @Override
+    public void writeTo(MysqlSerializer serializer) {
+        // header: 0xFE (same as EOF, but the payload length > 5 distinguishes 
it)
+        serializer.writeInt1(RESULTSET_OK_INDICATOR);
+        // affected_rows: int<lenenc>
+        serializer.writeVInt(AFFECTED_ROWS);
+        // last_insert_id: int<lenenc>
+        serializer.writeVInt(LAST_INSERT_ID);
+        // status_flags: int<2>
+        serializer.writeInt2(serverStatus);
+        // warnings: int<2>
+        serializer.writeInt2(warningCount);
+        // info: string<lenenc> (empty string, written as a single 0x00 byte 
for length 0)
+        // The driver's OkPacket.parse() unconditionally reads this field.
+        serializer.writeVInt(0);
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java
index 99527e99f2c..4811f911f17 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java
@@ -44,6 +44,7 @@ import org.apache.doris.metric.MetricRepo;
 import org.apache.doris.mysql.MysqlChannel;
 import org.apache.doris.mysql.MysqlCommand;
 import org.apache.doris.mysql.MysqlPacket;
+import org.apache.doris.mysql.MysqlResultSetEndPacket;
 import org.apache.doris.mysql.MysqlSerializer;
 import org.apache.doris.mysql.MysqlServerStatusFlag;
 import org.apache.doris.nereids.SqlCacheContext;
@@ -557,7 +558,17 @@ public abstract class ConnectProcessor {
     // only Mysql protocol
     protected ByteBuffer getResultPacket() {
         Preconditions.checkState(connectType.equals(ConnectType.MYSQL));
-        MysqlPacket packet = ctx.getState().toResponsePacket();
+        MysqlPacket packet;
+        // When CLIENT_DEPRECATE_EOF is set and the state is EOF (end of 
result set),
+        // we need to send a "ResultSet OK" packet (0xFE header with payload > 
5 bytes)
+        // instead of the traditional EOF packet. This is required by the 
MySQL protocol
+        // and expected by MySQL Connector/J 9.5.0+.
+        if (ctx.getState().getStateType() == QueryState.MysqlStateType.EOF
+                && ctx.getMysqlChannel().clientDeprecatedEOF()) {
+            packet = new MysqlResultSetEndPacket(ctx.getState());
+        } else {
+            packet = ctx.getState().toResponsePacket();
+        }
         if (packet == null) {
             // possible two cases:
             // 1. handler has send request
@@ -647,6 +658,12 @@ public abstract class ConnectProcessor {
         // set compute group
         
ctx.setComputeGroup(Env.getCurrentEnv().getAuth().getComputeGroup(ctx.getQualifiedUser()));
 
+        // Propagate the client's CLIENT_DEPRECATE_EOF capability to the proxy 
channel.
+        // This ensures the master generates packets matching the original 
client's protocol.
+        if (request.isSetClientDeprecatedEOF() && 
request.isClientDeprecatedEOF()) {
+            ctx.getMysqlChannel().setClientDeprecatedEOF();
+        }
+
         ctx.setThreadLocalInfo();
         StmtExecutor executor = null;
         try {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/FEOpExecutor.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/FEOpExecutor.java
index 9dcd379f913..6a461cb5c94 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/FEOpExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/FEOpExecutor.java
@@ -206,6 +206,10 @@ public class FEOpExecutor {
             }
         }
 
+        // Propagate the client's CLIENT_DEPRECATE_EOF capability so the 
master FE
+        // generates packets matching the original client's protocol 
expectations.
+        
params.setClientDeprecatedEOF(ctx.getMysqlChannel().clientDeprecatedEOF());
+
         return params;
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
index 2c8d095c45f..3a7f4976dce 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
@@ -67,7 +67,6 @@ import org.apache.doris.mysql.FieldInfo;
 import org.apache.doris.mysql.MysqlChannel;
 import org.apache.doris.mysql.MysqlCommand;
 import org.apache.doris.mysql.MysqlEofPacket;
-import org.apache.doris.mysql.MysqlOkPacket;
 import org.apache.doris.mysql.MysqlSerializer;
 import org.apache.doris.mysql.ProxyMysqlChannel;
 import org.apache.doris.nereids.NereidsPlanner;
@@ -1538,11 +1537,15 @@ public class StmtExecutor {
             }
             context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
         }
-        // send EOF
-        serializer.reset();
-        MysqlEofPacket eofPacket = new MysqlEofPacket(context.getState());
-        eofPacket.writeTo(serializer);
-        context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
+        // When CLIENT_DEPRECATE_EOF is set, the server should not send the 
intermediate
+        // EOF packet after column definitions. The client will go directly 
from column
+        // definitions to reading data rows.
+        if (!context.getMysqlChannel().clientDeprecatedEOF()) {
+            serializer.reset();
+            MysqlEofPacket eofPacket = new MysqlEofPacket(context.getState());
+            eofPacket.writeTo(serializer);
+            context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
+        }
     }
 
     private List<PrimitiveType> exprToStringType(List<Expr> exprs) {
@@ -1584,15 +1587,15 @@ public class StmtExecutor {
                 serializer.writeField(colNames.get(i), Type.STRING);
                 
context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
             }
-            serializer.reset();
+            // When CLIENT_DEPRECATE_EOF is set, no EOF/OK packet should be 
sent after
+            // parameter definitions. The driver knows how many params to 
expect from the
+            // prepare OK packet and simply stops reading after that count.
             if (!context.getMysqlChannel().clientDeprecatedEOF()) {
+                serializer.reset();
                 MysqlEofPacket eofPacket = new 
MysqlEofPacket(context.getState());
                 eofPacket.writeTo(serializer);
-            } else {
-                MysqlOkPacket okPacket = new MysqlOkPacket(context.getState());
-                okPacket.writeTo(serializer);
+                
context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
             }
-            context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
         }
         if (numColumns > 0) {
             for (Slot slot : output) {
@@ -1611,15 +1614,15 @@ public class StmtExecutor {
                 }
                 
context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
             }
-            serializer.reset();
+            // When CLIENT_DEPRECATE_EOF is set, no EOF/OK packet should be 
sent after
+            // column definitions. The driver knows how many columns to expect 
from the
+            // prepare OK packet and simply stops reading after that count.
             if (!context.getMysqlChannel().clientDeprecatedEOF()) {
+                serializer.reset();
                 MysqlEofPacket eofPacket = new 
MysqlEofPacket(context.getState());
                 eofPacket.writeTo(serializer);
-            } else {
-                MysqlOkPacket okPacket = new MysqlOkPacket(context.getState());
-                okPacket.writeTo(serializer);
+                
context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
             }
-            context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
         }
         context.getMysqlChannel().flush();
         context.getState().setNoop();
@@ -1668,11 +1671,15 @@ public class StmtExecutor {
                 
context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
             }
         }
-        // send EOF
-        serializer.reset();
-        MysqlEofPacket eofPacket = new MysqlEofPacket(context.getState());
-        eofPacket.writeTo(serializer);
-        context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
+        // When CLIENT_DEPRECATE_EOF is set, the server should not send the 
intermediate
+        // EOF packet after column definitions. The client will go directly 
from column
+        // definitions to reading data rows.
+        if (!context.getMysqlChannel().clientDeprecatedEOF()) {
+            serializer.reset();
+            MysqlEofPacket eofPacket = new MysqlEofPacket(context.getState());
+            eofPacket.writeTo(serializer);
+            context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
+        }
     }
 
     public void sendResultSet(ResultSet resultSet) throws IOException {
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlCapabilityTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlCapabilityTest.java
index f3b4385b960..78197804b63 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlCapabilityTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlCapabilityTest.java
@@ -44,8 +44,9 @@ public class MysqlCapabilityTest {
     public void testDefaultFlags() {
         MysqlCapability capability = MysqlCapability.DEFAULT_CAPABILITY;
         Assert.assertEquals("CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | 
CLIENT_LOCAL_FILES | CLIENT_PROTOCOL_41"
-                + " | CLIENT_SECURE_CONNECTION | CLIENT_PLUGIN_AUTH",
+                + " | CLIENT_SECURE_CONNECTION | CLIENT_PLUGIN_AUTH | 
CLIENT_DEPRECATE_EOF",
                 capability.toString());
         Assert.assertTrue(capability.supportClientLocalFile());
+        Assert.assertTrue(capability.isDeprecatedEOF());
     }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlOkPacketTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlOkPacketTest.java
index 6cb157ee252..9fe47adbf5e 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlOkPacketTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlOkPacketTest.java
@@ -56,10 +56,27 @@ public class MysqlOkPacketTest {
         // assert warnings, int2: 0
         Assert.assertEquals(0x00, MysqlProto.readInt2(buffer));
 
-        // assert info, eof string: "OK"
-        // Assert.assertEquals("OK", new 
String(MysqlProto.readEofString(buffer)));
-
+        // When infoMessage is empty, an empty len-encoded string (0x00) 
should still be written.
+        // This is required because OkPacket.parse() in MySQL Connector/J 
unconditionally reads
+        // STRING_LENENC for info. Without this byte, the driver throws
+        // ArrayIndexOutOfBoundsException when CLIENT_DEPRECATE_EOF is 
negotiated.
+        Assert.assertEquals(0x00, MysqlProto.readVInt(buffer));
         Assert.assertEquals(0, buffer.remaining());
     }
 
+    @Test
+    public void testWritePayloadSizeGreaterThan5() {
+        // When CLIENT_DEPRECATE_EOF is negotiated, the driver distinguishes 
between
+        // EOF packets (payload <= 5) and ResultSet OK packets (payload > 5).
+        // MysqlOkPacket payload must be > 5 to avoid being misidentified as 
EOF.
+        // Payload: 0x00(1) + affected_rows(1) + last_insert_id(1) + status(2) 
+ warnings(2) + info_len(1) = 8
+        MysqlOkPacket packet = new MysqlOkPacket(new QueryState());
+        MysqlSerializer serializer = MysqlSerializer.newInstance(capability);
+        packet.writeTo(serializer);
+
+        ByteBuffer buffer = serializer.toByteBuffer();
+        int payloadLength = buffer.remaining();
+        Assert.assertTrue("OK packet payload should be > 5 for 
CLIENT_DEPRECATE_EOF compatibility, got: "
+                + payloadLength, payloadLength > 5);
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlResultSetEndPacketTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlResultSetEndPacketTest.java
new file mode 100644
index 00000000000..8dc0d18877f
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/MysqlResultSetEndPacketTest.java
@@ -0,0 +1,120 @@
+// 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.doris.mysql;
+
+import org.apache.doris.qe.QueryState;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+public class MysqlResultSetEndPacketTest {
+    private MysqlCapability capability;
+
+    @Before
+    public void setUp() {
+        capability = new 
MysqlCapability(MysqlCapability.Flag.CLIENT_PROTOCOL_41.getFlagBit());
+    }
+
+    @Test
+    public void testWriteHeader() {
+        // The ResultSet OK packet must start with 0xFE (same as EOF)
+        MysqlResultSetEndPacket packet = new MysqlResultSetEndPacket(new 
QueryState());
+        MysqlSerializer serializer = MysqlSerializer.newInstance(capability);
+        packet.writeTo(serializer);
+
+        ByteBuffer buffer = serializer.toByteBuffer();
+
+        // assert header: 0xFE
+        Assert.assertEquals(0xFE, MysqlProto.readInt1(buffer));
+    }
+
+    @Test
+    public void testWriteFields() {
+        // Verify all fields are written correctly
+        MysqlResultSetEndPacket packet = new MysqlResultSetEndPacket(new 
QueryState());
+        MysqlSerializer serializer = MysqlSerializer.newInstance(capability);
+        packet.writeTo(serializer);
+
+        ByteBuffer buffer = serializer.toByteBuffer();
+
+        // header: 0xFE
+        Assert.assertEquals(0xFE, MysqlProto.readInt1(buffer));
+
+        // affected_rows: int<lenenc> = 0
+        Assert.assertEquals(0, MysqlProto.readVInt(buffer));
+
+        // last_insert_id: int<lenenc> = 0
+        Assert.assertEquals(0, MysqlProto.readVInt(buffer));
+
+        // status_flags: int<2> = 0
+        Assert.assertEquals(0, MysqlProto.readInt2(buffer));
+
+        // warnings: int<2> = 0
+        Assert.assertEquals(0, MysqlProto.readInt2(buffer));
+
+        // info: string<lenenc> (empty, length = 0)
+        Assert.assertEquals(0, MysqlProto.readVInt(buffer));
+
+        // no remaining bytes
+        Assert.assertEquals(0, buffer.remaining());
+    }
+
+    @Test
+    public void testPayloadSizeGreaterThan5() {
+        // When CLIENT_DEPRECATE_EOF is negotiated, the MySQL driver uses 
isResultSetOKPacket()
+        // to detect end-of-result-set. This method requires:
+        //   (byteBuffer[0] & 0xff) == 0xFE && payloadLength > 5
+        // The traditional EOF packet has payloadLength == 5, so the ResultSet 
OK packet
+        // MUST have payloadLength > 5 to be correctly identified.
+        MysqlResultSetEndPacket packet = new MysqlResultSetEndPacket(new 
QueryState());
+        MysqlSerializer serializer = MysqlSerializer.newInstance(capability);
+        packet.writeTo(serializer);
+
+        ByteBuffer buffer = serializer.toByteBuffer();
+        int payloadLength = buffer.remaining();
+
+        // Payload: 0xFE(1) + affected_rows(1) + last_insert_id(1) + status(2) 
+ warnings(2) + info(1) = 8
+        Assert.assertTrue("ResultSet OK packet payload must be > 5 for 
isResultSetOKPacket(), got: "
+                + payloadLength, payloadLength > 5);
+    }
+
+    @Test
+    public void testDiffersFromEofPacket() {
+        // A traditional EOF packet has exactly 5 bytes payload.
+        // The ResultSet OK packet must have > 5 bytes to be distinguishable.
+        MysqlEofPacket eofPacket = new MysqlEofPacket(new QueryState());
+        MysqlSerializer eofSerializer = 
MysqlSerializer.newInstance(capability);
+        eofPacket.writeTo(eofSerializer);
+        int eofPayloadLength = eofSerializer.toByteBuffer().remaining();
+
+        MysqlResultSetEndPacket rsEndPacket = new MysqlResultSetEndPacket(new 
QueryState());
+        MysqlSerializer rsEndSerializer = 
MysqlSerializer.newInstance(capability);
+        rsEndPacket.writeTo(rsEndSerializer);
+        int rsEndPayloadLength = rsEndSerializer.toByteBuffer().remaining();
+
+        // EOF payload should be <= 5
+        Assert.assertTrue("EOF packet payload should be <= 5, got: " + 
eofPayloadLength,
+                eofPayloadLength <= 5);
+        // ResultSet OK payload should be > 5
+        Assert.assertTrue("ResultSet OK packet payload should be > 5, got: " + 
rsEndPayloadLength,
+                rsEndPayloadLength > 5);
+    }
+}
diff --git a/gensrc/thrift/FrontendService.thrift 
b/gensrc/thrift/FrontendService.thrift
index 3eb10c8de5f..fed7476a9c0 100644
--- a/gensrc/thrift/FrontendService.thrift
+++ b/gensrc/thrift/FrontendService.thrift
@@ -400,6 +400,8 @@ struct TMasterOpRequest {
 
     // temporary table
     1002: optional string sessionId
+    // propagate client's CLIENT_DEPRECATE_EOF capability for proxy forwarding
+    1003: optional bool clientDeprecatedEOF
 }
 
 struct TColumnDefinition {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to