Skip to content

Commit 7c6914f

Browse files
committed
Fix error handling for exceptions on values parsing.
- Fix: Avoid connection leaks by ensuring parse closure on error. - Refactor: Move `Writer` instantiation to improve isolation and prevent state reuse issues.
1 parent ecff60d commit 7c6914f

File tree

2 files changed

+23
-13
lines changed

2 files changed

+23
-13
lines changed

packages/pg-protocol/src/serializer.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,8 @@ const enum code {
1616
copyFail = 0x66,
1717
}
1818

19-
const writer = new Writer()
20-
2119
const startup = (opts: Record<string, string>): Buffer => {
20+
const writer = new Writer()
2221
// protocol version
2322
writer.addInt16(3).addInt16(0)
2423
for (const key of Object.keys(opts)) {
@@ -43,22 +42,24 @@ const requestSsl = (): Buffer => {
4342
}
4443

4544
const password = (password: string): Buffer => {
46-
return writer.addCString(password).flush(code.startup)
45+
return new Writer().addCString(password).flush(code.startup)
4746
}
4847

4948
const sendSASLInitialResponseMessage = function (mechanism: string, initialResponse: string): Buffer {
49+
const writer = new Writer()
50+
5051
// 0x70 = 'p'
5152
writer.addCString(mechanism).addInt32(Buffer.byteLength(initialResponse)).addString(initialResponse)
5253

5354
return writer.flush(code.startup)
5455
}
5556

5657
const sendSCRAMClientFinalMessage = function (additionalData: string): Buffer {
57-
return writer.addString(additionalData).flush(code.startup)
58+
return new Writer().addString(additionalData).flush(code.startup)
5859
}
5960

6061
const query = (text: string): Buffer => {
61-
return writer.addCString(text).flush(code.query)
62+
return new Writer().addCString(text).flush(code.query)
6263
}
6364

6465
type ParseOpts = {
@@ -70,6 +71,7 @@ type ParseOpts = {
7071
const emptyArray: any[] = []
7172

7273
const parse = (query: ParseOpts): Buffer => {
74+
const writer = new Writer()
7375
// expect something like this:
7476
// { name: 'queryName',
7577
// text: 'select * from blah',
@@ -110,15 +112,15 @@ type BindOpts = {
110112
valueMapper?: ValueMapper
111113
}
112114

113-
const paramWriter = new Writer()
114-
115115
// make this a const enum so typescript will inline the value
116116
const enum ParamType {
117117
STRING = 0,
118118
BINARY = 1,
119119
}
120120

121-
const writeValues = function (values: any[], valueMapper?: ValueMapper): void {
121+
const writeValues = function (writer: Writer, values: any[], valueMapper?: ValueMapper): Buffer {
122+
const paramWriter = new Writer()
123+
122124
for (let i = 0; i < values.length; i++) {
123125
const mappedVal = valueMapper ? valueMapper(values[i], i) : values[i]
124126
if (mappedVal == null) {
@@ -139,9 +141,13 @@ const writeValues = function (values: any[], valueMapper?: ValueMapper): void {
139141
paramWriter.addString(mappedVal)
140142
}
141143
}
144+
145+
return paramWriter.flush()
142146
}
143147

144148
const bind = (config: BindOpts = {}): Buffer => {
149+
const writer = new Writer()
150+
145151
// normalize config
146152
const portal = config.portal || ''
147153
const statement = config.statement || ''
@@ -152,10 +158,10 @@ const bind = (config: BindOpts = {}): Buffer => {
152158
writer.addCString(portal).addCString(statement)
153159
writer.addInt16(len)
154160

155-
writeValues(values, config.valueMapper)
161+
const paramValues = writeValues(writer, values, config.valueMapper)
156162

157163
writer.addInt16(len)
158-
writer.add(paramWriter.flush())
164+
writer.add(paramValues)
159165

160166
// all results use the same format code
161167
writer.addInt16(1)
@@ -219,8 +225,8 @@ const cstringMessage = (code: code, string: string): Buffer => {
219225
return buffer
220226
}
221227

222-
const emptyDescribePortal = writer.addCString('P').flush(code.describe)
223-
const emptyDescribeStatement = writer.addCString('S').flush(code.describe)
228+
const emptyDescribePortal = new Writer().addCString('P').flush(code.describe)
229+
const emptyDescribeStatement = new Writer().addCString('S').flush(code.describe)
224230

225231
const describe = (msg: PortalOpts): Buffer => {
226232
return msg.name
@@ -236,7 +242,7 @@ const close = (msg: PortalOpts): Buffer => {
236242
}
237243

238244
const copyData = (chunk: Buffer): Buffer => {
239-
return writer.add(chunk).flush(code.copyFromChunk)
245+
return new Writer().add(chunk).flush(code.copyFromChunk)
240246
}
241247

242248
const copyFail = (message: string): Buffer => {

packages/pg/lib/query.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ class Query extends EventEmitter {
228228
valueMapper: utils.prepareValue,
229229
})
230230
} catch (err) {
231+
// we should close parse to avoid leaking connections
232+
connection.close({ type: 'S', name: this.name })
233+
connection.sync()
234+
231235
this.handleError(err, connection)
232236
return
233237
}

0 commit comments

Comments
 (0)