Skip to content

Commit c2a168f

Browse files
committed
fix(parser): handle exceptions within handlePacket
Exception occuring within the handlePacket will bubble up to pg as uncatchables exceptions errors. Adding a try/catch and returning an handled error allow the caller program to catch such exceptions and decide what to do with them. Fixes brianc#2653
1 parent a3fefe3 commit c2a168f

File tree

2 files changed

+78
-47
lines changed

2 files changed

+78
-47
lines changed

packages/pg-protocol/src/messages.ts

+26
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,32 @@ export class DatabaseError extends Error implements NoticeOrError {
120120
}
121121
}
122122

123+
export class ParserError extends Error implements NoticeOrError {
124+
public severity: string | undefined
125+
public code: string | undefined
126+
public detail: string | undefined
127+
public hint: string | undefined
128+
public position: string | undefined
129+
public internalPosition: string | undefined
130+
public internalQuery: string | undefined
131+
public where: string | undefined
132+
public schema: string | undefined
133+
public table: string | undefined
134+
public column: string | undefined
135+
public dataType: string | undefined
136+
public constraint: string | undefined
137+
public file: string | undefined
138+
public line: string | undefined
139+
public routine: string | undefined
140+
constructor(
141+
message: string,
142+
public readonly length: number,
143+
public readonly name: MessageName
144+
) {
145+
super(message)
146+
}
147+
}
148+
123149
export class CopyDataMessage {
124150
public readonly name = 'copyData'
125151
constructor(

packages/pg-protocol/src/parser.ts

+52-47
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
MessageName,
2626
AuthenticationMD5Password,
2727
NoticeMessage,
28+
ParserError,
2829
} from './messages'
2930
import { BufferReader } from './buffer-reader'
3031

@@ -152,53 +153,57 @@ export class Parser {
152153
}
153154

154155
private handlePacket(offset: number, code: number, length: number, bytes: Buffer): BackendMessage {
155-
switch (code) {
156-
case MessageCodes.BindComplete:
157-
return bindComplete
158-
case MessageCodes.ParseComplete:
159-
return parseComplete
160-
case MessageCodes.CloseComplete:
161-
return closeComplete
162-
case MessageCodes.NoData:
163-
return noData
164-
case MessageCodes.PortalSuspended:
165-
return portalSuspended
166-
case MessageCodes.CopyDone:
167-
return copyDone
168-
case MessageCodes.ReplicationStart:
169-
return replicationStart
170-
case MessageCodes.EmptyQuery:
171-
return emptyQuery
172-
case MessageCodes.DataRow:
173-
return this.parseDataRowMessage(offset, length, bytes)
174-
case MessageCodes.CommandComplete:
175-
return this.parseCommandCompleteMessage(offset, length, bytes)
176-
case MessageCodes.ReadyForQuery:
177-
return this.parseReadyForQueryMessage(offset, length, bytes)
178-
case MessageCodes.NotificationResponse:
179-
return this.parseNotificationMessage(offset, length, bytes)
180-
case MessageCodes.AuthenticationResponse:
181-
return this.parseAuthenticationResponse(offset, length, bytes)
182-
case MessageCodes.ParameterStatus:
183-
return this.parseParameterStatusMessage(offset, length, bytes)
184-
case MessageCodes.BackendKeyData:
185-
return this.parseBackendKeyData(offset, length, bytes)
186-
case MessageCodes.ErrorMessage:
187-
return this.parseErrorMessage(offset, length, bytes, 'error')
188-
case MessageCodes.NoticeMessage:
189-
return this.parseErrorMessage(offset, length, bytes, 'notice')
190-
case MessageCodes.RowDescriptionMessage:
191-
return this.parseRowDescriptionMessage(offset, length, bytes)
192-
case MessageCodes.ParameterDescriptionMessage:
193-
return this.parseParameterDescriptionMessage(offset, length, bytes)
194-
case MessageCodes.CopyIn:
195-
return this.parseCopyInMessage(offset, length, bytes)
196-
case MessageCodes.CopyOut:
197-
return this.parseCopyOutMessage(offset, length, bytes)
198-
case MessageCodes.CopyData:
199-
return this.parseCopyData(offset, length, bytes)
200-
default:
201-
return new DatabaseError('received invalid response: ' + code.toString(16), length, 'error')
156+
try {
157+
switch (code) {
158+
case MessageCodes.BindComplete:
159+
return bindComplete
160+
case MessageCodes.ParseComplete:
161+
return parseComplete
162+
case MessageCodes.CloseComplete:
163+
return closeComplete
164+
case MessageCodes.NoData:
165+
return noData
166+
case MessageCodes.PortalSuspended:
167+
return portalSuspended
168+
case MessageCodes.CopyDone:
169+
return copyDone
170+
case MessageCodes.ReplicationStart:
171+
return replicationStart
172+
case MessageCodes.EmptyQuery:
173+
return emptyQuery
174+
case MessageCodes.DataRow:
175+
return this.parseDataRowMessage(offset, length, bytes)
176+
case MessageCodes.CommandComplete:
177+
return this.parseCommandCompleteMessage(offset, length, bytes)
178+
case MessageCodes.ReadyForQuery:
179+
return this.parseReadyForQueryMessage(offset, length, bytes)
180+
case MessageCodes.NotificationResponse:
181+
return this.parseNotificationMessage(offset, length, bytes)
182+
case MessageCodes.AuthenticationResponse:
183+
return this.parseAuthenticationResponse(offset, length, bytes)
184+
case MessageCodes.ParameterStatus:
185+
return this.parseParameterStatusMessage(offset, length, bytes)
186+
case MessageCodes.BackendKeyData:
187+
return this.parseBackendKeyData(offset, length, bytes)
188+
case MessageCodes.ErrorMessage:
189+
return this.parseErrorMessage(offset, length, bytes, 'error')
190+
case MessageCodes.NoticeMessage:
191+
return this.parseErrorMessage(offset, length, bytes, 'notice')
192+
case MessageCodes.RowDescriptionMessage:
193+
return this.parseRowDescriptionMessage(offset, length, bytes)
194+
case MessageCodes.ParameterDescriptionMessage:
195+
return this.parseParameterDescriptionMessage(offset, length, bytes)
196+
case MessageCodes.CopyIn:
197+
return this.parseCopyInMessage(offset, length, bytes)
198+
case MessageCodes.CopyOut:
199+
return this.parseCopyOutMessage(offset, length, bytes)
200+
case MessageCodes.CopyData:
201+
return this.parseCopyData(offset, length, bytes)
202+
default:
203+
return new DatabaseError('received invalid response: ' + code.toString(16), length, 'error')
204+
}
205+
} catch (error) {
206+
return new ParserError(`unexpected error handling packet: ${error}`, length, 'error')
202207
}
203208
}
204209

0 commit comments

Comments
 (0)