@@ -85,34 +85,28 @@ func zCompress(src []byte, dst io.Writer) error {
8585 return nil
8686}
8787
88- type decompressor struct {
89- mc * mysqlConn
90- // read buffer (FIFO).
91- // We can not reuse already-read buffer until dropping Go 1.20 support.
92- // It is because of database/mysql's weired behavior.
93- // See https://github.com/go-sql-driver/mysql/issues/1435
94- bytesBuf []byte
88+ type compIO struct {
89+ mc * mysqlConn
90+ buff bytes.Buffer
9591}
9692
97- func newDecompressor (mc * mysqlConn ) * decompressor {
98- return & decompressor {
93+ func newCompIO (mc * mysqlConn ) * compIO {
94+ return & compIO {
9995 mc : mc ,
10096 }
10197}
10298
103- func (c * decompressor ) readNext (need int ) ([]byte , error ) {
104- for len ( c . bytesBuf ) < need {
99+ func (c * compIO ) readNext (need int ) ([]byte , error ) {
100+ for c . buff . Len ( ) < need {
105101 if err := c .uncompressPacket (); err != nil {
106102 return nil , err
107103 }
108104 }
109-
110- data := c .bytesBuf [:need :need ] // prevent caller writes into r.bytesBuf
111- c .bytesBuf = c .bytesBuf [need :]
112- return data , nil
105+ data := c .buff .Next (need )
106+ return data [:need :need ], nil // prevent caller writes into c.buff
113107}
114108
115- func (c * decompressor ) uncompressPacket () error {
109+ func (c * compIO ) uncompressPacket () error {
116110 header , err := c .mc .buf .readNext (7 ) // size of compressed header
117111 if err != nil {
118112 return err
@@ -147,41 +141,37 @@ func (c *decompressor) uncompressPacket() error {
147141 // if payload is uncompressed, its length will be specified as zero, and its
148142 // true length is contained in comprLength
149143 if uncompressedLength == 0 {
150- c .bytesBuf = append ( c . bytesBuf , comprData ... )
144+ c .buff . Write ( comprData )
151145 return nil
152146 }
153147
154148 // use existing capacity in bytesBuf if possible
155- offset := len (c .bytesBuf )
156- if cap (c .bytesBuf )- offset < uncompressedLength {
157- old := c .bytesBuf
158- c .bytesBuf = make ([]byte , offset , offset + uncompressedLength )
159- copy (c .bytesBuf , old )
160- }
161-
162- lenRead , err := zDecompress (comprData , c .bytesBuf [offset :offset + uncompressedLength ])
149+ c .buff .Grow (uncompressedLength )
150+ dec := c .buff .AvailableBuffer ()[:uncompressedLength ]
151+ lenRead , err := zDecompress (comprData , dec )
163152 if err != nil {
164153 return err
165154 }
166155 if lenRead != uncompressedLength {
167156 return fmt .Errorf ("invalid compressed packet: uncompressed length in header is %d, actual %d" ,
168157 uncompressedLength , lenRead )
169158 }
170- c .bytesBuf = c . bytesBuf [: offset + uncompressedLength ]
159+ c .buff . Write ( dec ) // fast copy. See bytes.Buffer.AvailableBuffer() doc.
171160 return nil
172161}
173162
174163const maxPayloadLen = maxPacketSize - 4
175164
176- // writeCompressed sends one or some packets with compression.
165+ // writePackets sends one or some packets with compression.
177166// Use this instead of mc.netConn.Write() when mc.compress is true.
178- func (mc * mysqlConn ) writeCompressed (packets []byte ) (int , error ) {
167+ func (c * compIO ) writePackets (packets []byte ) (int , error ) {
179168 totalBytes := len (packets )
180169 dataLen := len (packets )
181170 blankHeader := make ([]byte , 7 )
182- var buf bytes. Buffer
171+ buf := & c . buff
183172
184173 for dataLen > 0 {
174+ buf .Reset ()
185175 payloadLen := dataLen
186176 if payloadLen > maxPayloadLen {
187177 payloadLen = maxPayloadLen
@@ -200,10 +190,10 @@ func (mc *mysqlConn) writeCompressed(packets []byte) (int, error) {
200190 }
201191 uncompressedLen = 0
202192 } else {
203- zCompress (payload , & buf )
193+ zCompress (payload , buf )
204194 }
205195
206- if err := mc .writeCompressedPacket (buf .Bytes (), uncompressedLen ); err != nil {
196+ if err := c .writeCompressedPacket (buf .Bytes (), uncompressedLen ); err != nil {
207197 return 0 , err
208198 }
209199 dataLen -= payloadLen
@@ -216,7 +206,8 @@ func (mc *mysqlConn) writeCompressed(packets []byte) (int, error) {
216206
217207// writeCompressedPacket writes a compressed packet with header.
218208// data should start with 7 size space for header followed by payload.
219- func (mc * mysqlConn ) writeCompressedPacket (data []byte , uncompressedLen int ) error {
209+ func (c * compIO ) writeCompressedPacket (data []byte , uncompressedLen int ) error {
210+ mc := c .mc
220211 comprLength := len (data ) - 7
221212 if debugTrace {
222213 fmt .Printf (
0 commit comments