@@ -99,14 +99,14 @@ func forwardOnePacket(destIO, srcIO *pnet.PacketIO, flush bool) (data []byte, er
9999
100100func (cp * CmdProcessor ) forwardUntilResultEnd (clientIO , backendIO * pnet.PacketIO , request []byte ) (uint16 , error ) {
101101 var serverStatus uint16
102- err := backendIO .ForwardUntil (clientIO , func (firstByte byte , length int ) bool {
102+ err := backendIO .ForwardUntil (clientIO , func (firstByte byte , length int ) ( end , needData bool ) {
103103 switch {
104104 case pnet .IsErrorPacket (firstByte ):
105- return true
105+ return true , true
106106 case cp .capability & pnet .ClientDeprecateEOF == 0 :
107- return pnet .IsEOFPacket (firstByte , length )
107+ return pnet .IsEOFPacket (firstByte , length ), true
108108 default :
109- return pnet .IsResultSetOKPacket (firstByte , length )
109+ return pnet .IsResultSetOKPacket (firstByte , length ), true
110110 }
111111 }, func (response []byte ) error {
112112 switch {
@@ -119,7 +119,7 @@ func (cp *CmdProcessor) forwardUntilResultEnd(clientIO, backendIO *pnet.PacketIO
119119 serverStatus = cp .handleEOFPacket (request , response )
120120 return clientIO .Flush ()
121121 default :
122- serverStatus = cp .handleOKPacket (request , response ). Status
122+ serverStatus = cp .handleOKPacket (request , response )
123123 return clientIO .Flush ()
124124 }
125125 })
@@ -146,9 +146,14 @@ func (cp *CmdProcessor) forwardPrepareCmd(clientIO, backendIO *pnet.PacketIO) er
146146 expectedPackets ++
147147 }
148148 }
149- for i := 0 ; i < expectedPackets ; i ++ {
150- // Ignore this status because PREPARE doesn't affect status.
151- if _ , err = forwardOnePacket (clientIO , backendIO , false ); err != nil {
149+ // Ignore this status because PREPARE doesn't affect status.
150+ if expectedPackets > 0 {
151+ i := 0
152+ err = backendIO .ForwardUntil (clientIO , func (firstByte byte , firstPktLen int ) (end , needData bool ) {
153+ i ++
154+ return i >= expectedPackets , false
155+ }, nil )
156+ if err != nil {
152157 return err
153158 }
154159 }
@@ -175,26 +180,35 @@ func (cp *CmdProcessor) forwardFieldListCmd(clientIO, backendIO *pnet.PacketIO,
175180
176181func (cp * CmdProcessor ) forwardQueryCmd (clientIO , backendIO * pnet.PacketIO , request []byte ) error {
177182 for {
178- response , err := forwardOnePacket (clientIO , backendIO , false )
179- if err != nil {
180- return err
181- }
182183 var serverStatus uint16
183- switch response [0 ] {
184- case mysql .OKHeader :
185- rs := cp .handleOKPacket (request , response )
186- serverStatus , err = rs .Status , clientIO .Flush ()
187- case mysql .ErrHeader :
188- if err := clientIO .Flush (); err != nil {
189- return err
184+ var first byte
185+ err := backendIO .ForwardUntil (clientIO , func (firstByte byte , _ int ) (end , needData bool ) {
186+ first = firstByte
187+ switch firstByte {
188+ case mysql .OKHeader , mysql .ErrHeader :
189+ return true , true
190+ default :
191+ return true , false
190192 }
191- // Subsequent statements won't be executed even if it's a multi-statement.
192- return cp .handleErrorPacket (response )
193- case mysql .LocalInFileHeader :
194- serverStatus , err = cp .forwardLoadInFile (clientIO , backendIO , request )
195- default :
196- serverStatus , err = cp .forwardResultSet (clientIO , backendIO , request )
197- }
193+ }, func (response []byte ) error {
194+ var err error
195+ switch first {
196+ case mysql .OKHeader :
197+ status := cp .handleOKPacket (request , response )
198+ serverStatus , err = status , clientIO .Flush ()
199+ case mysql .ErrHeader :
200+ if err = clientIO .Flush (); err != nil {
201+ return err
202+ }
203+ // Subsequent statements won't be executed even if it's a multi-statement.
204+ return cp .handleErrorPacket (response )
205+ case mysql .LocalInFileHeader :
206+ serverStatus , err = cp .forwardLoadInFile (clientIO , backendIO , request )
207+ default :
208+ serverStatus , err = cp .forwardResultSet (clientIO , backendIO , request )
209+ }
210+ return err
211+ })
198212 if err != nil {
199213 return err
200214 }
@@ -213,11 +227,14 @@ func (cp *CmdProcessor) forwardLoadInFile(clientIO, backendIO *pnet.PacketIO, re
213227 // The client sends file data until an empty packet.
214228 for {
215229 var data []byte
216- // The file may be large, so always flush it .
217- if data , err = forwardOnePacket (backendIO , clientIO , true ); err != nil {
230+ // Do not call PacketIO.ForwardUntil. It peeks 5 bytes but there may be only 4 bytes here .
231+ if data , err = forwardOnePacket (backendIO , clientIO , false ); err != nil {
218232 return
219233 }
220234 if len (data ) == 0 {
235+ if err := backendIO .Flush (); err != nil {
236+ return 0 , err
237+ }
221238 break
222239 }
223240 }
@@ -227,8 +244,7 @@ func (cp *CmdProcessor) forwardLoadInFile(clientIO, backendIO *pnet.PacketIO, re
227244 }
228245 switch response [0 ] {
229246 case mysql .OKHeader :
230- rs := cp .handleOKPacket (request , response )
231- return rs .Status , nil
247+ return cp .handleOKPacket (request , response ), nil
232248 case mysql .ErrHeader :
233249 return serverStatus , cp .handleErrorPacket (response )
234250 }
@@ -238,22 +254,22 @@ func (cp *CmdProcessor) forwardLoadInFile(clientIO, backendIO *pnet.PacketIO, re
238254
239255func (cp * CmdProcessor ) forwardResultSet (clientIO , backendIO * pnet.PacketIO , request []byte ) (uint16 , error ) {
240256 if cp .capability & pnet .ClientDeprecateEOF == 0 {
241- var response [] byte
257+ var serverStatus uint16
242258 // read columns
243- for {
244- var err error
245- if response , err = forwardOnePacket (clientIO , backendIO , false ); err != nil {
246- return 0 , err
247- }
248- if pnet .IsEOFPacket (response [0 ], len (response )) {
249- break
259+ err := backendIO .ForwardUntil (clientIO , func (firstByte byte , firstPktLen int ) (end , needData bool ) {
260+ return pnet .IsEOFPacket (firstByte , firstPktLen ), true
261+ }, func (response []byte ) error {
262+ serverStatus = binary .LittleEndian .Uint16 (response [3 :])
263+ // If a cursor exists, only columns are sent this time. The client will then send COM_STMT_FETCH to fetch rows.
264+ // Otherwise, columns and rows are both sent once.
265+ if serverStatus & mysql .ServerStatusCursorExists > 0 {
266+ serverStatus = cp .handleEOFPacket (request , response )
267+ return clientIO .Flush ()
250268 }
251- }
252- serverStatus := binary .LittleEndian .Uint16 (response [3 :])
253- // If a cursor exists, only columns are sent this time. The client will then send COM_STMT_FETCH to fetch rows.
254- // Otherwise, columns and rows are both sent once.
255- if serverStatus & mysql .ServerStatusCursorExists > 0 {
256- return cp .handleEOFPacket (request , response ), clientIO .Flush ()
269+ return nil
270+ })
271+ if err != nil {
272+ return serverStatus , err
257273 }
258274 }
259275 // Deprecate EOF or no cursor.
0 commit comments