diff --git a/packages/pg-protocol/src/inbound-parser.test.ts b/packages/pg-protocol/src/inbound-parser.test.ts index 3fcbe410a..364bd8d95 100644 --- a/packages/pg-protocol/src/inbound-parser.test.ts +++ b/packages/pg-protocol/src/inbound-parser.test.ts @@ -144,6 +144,35 @@ var expectedTwoRowMessage = { ], } +var emptyParameterDescriptionBuffer = new BufferList() + .addInt16(0) // number of parameters + .join(true, 't') + +var oneParameterDescBuf = buffers.parameterDescription([1111]) + +var twoParameterDescBuf = buffers.parameterDescription([2222, 3333]) + +var expectedEmptyParameterDescriptionMessage = { + name: 'parameterDescription', + length: 6, + parameterCount: 0, + dataTypeIDs: [], +} + +var expectedOneParameterMessage = { + name: 'parameterDescription', + length: 10, + parameterCount: 1, + dataTypeIDs: [1111], +} + +var expectedTwoParameterMessage = { + name: 'parameterDescription', + length: 14, + parameterCount: 2, + dataTypeIDs: [2222, 3333], +} + var testForMessage = function (buffer: Buffer, expectedMessage: any) { it('recieves and parses ' + expectedMessage.name, async () => { const messages = await parseBuffers([buffer]) @@ -245,6 +274,12 @@ describe('PgPacketStream', function () { testForMessage(twoRowBuf, expectedTwoRowMessage) }) + describe('parameterDescription messages', function () { + testForMessage(emptyParameterDescriptionBuffer, expectedEmptyParameterDescriptionMessage) + testForMessage(oneParameterDescBuf, expectedOneParameterMessage) + testForMessage(twoParameterDescBuf, expectedTwoParameterMessage) + }) + describe('parsing rows', function () { describe('parsing empty row', function () { testForMessage(emptyRowFieldBuf, { diff --git a/packages/pg-protocol/src/messages.ts b/packages/pg-protocol/src/messages.ts index 03c2f61ea..982186c25 100644 --- a/packages/pg-protocol/src/messages.ts +++ b/packages/pg-protocol/src/messages.ts @@ -11,6 +11,7 @@ export const enum MessageName { copyDone = 'copyDone', copyData = 'copyData', rowDescription = 'rowDescription', + parameterDescription = 'parameterDescription', parameterStatus = 'parameterStatus', backendKeyData = 'backendKeyData', notification = 'notification', @@ -153,6 +154,14 @@ export class RowDescriptionMessage { } } +export class ParameterDescriptionMessage { + public readonly name: MessageName = MessageName.parameterDescription + public readonly dataTypeIDs: number[] + constructor(public readonly length: number, public readonly parameterCount: number) { + this.dataTypeIDs = new Array(this.parameterCount) + } +} + export class ParameterStatusMessage { public readonly name: MessageName = MessageName.parameterStatus constructor( diff --git a/packages/pg-protocol/src/parser.ts b/packages/pg-protocol/src/parser.ts index a00dabec9..087da9ec0 100644 --- a/packages/pg-protocol/src/parser.ts +++ b/packages/pg-protocol/src/parser.ts @@ -15,6 +15,7 @@ import { CopyResponse, NotificationResponseMessage, RowDescriptionMessage, + ParameterDescriptionMessage, Field, DataRowMessage, ParameterStatusMessage, @@ -62,6 +63,7 @@ const enum MessageCodes { ErrorMessage = 0x45, // E NoticeMessage = 0x4e, // N RowDescriptionMessage = 0x54, // T + ParameterDescriptionMessage = 0x74, // t PortalSuspended = 0x73, // s ReplicationStart = 0x57, // W EmptyQuery = 0x49, // I @@ -188,6 +190,8 @@ export class Parser { return this.parseErrorMessage(offset, length, bytes, MessageName.notice) case MessageCodes.RowDescriptionMessage: return this.parseRowDescriptionMessage(offset, length, bytes) + case MessageCodes.ParameterDescriptionMessage: + return this.parseParameterDescriptionMessage(offset, length, bytes) case MessageCodes.CopyIn: return this.parseCopyInMessage(offset, length, bytes) case MessageCodes.CopyOut: @@ -264,6 +268,16 @@ export class Parser { return new Field(name, tableID, columnID, dataTypeID, dataTypeSize, dataTypeModifier, mode) } + private parseParameterDescriptionMessage(offset: number, length: number, bytes: Buffer) { + this.reader.setBuffer(offset, bytes) + const parameterCount = this.reader.int16() + const message = new ParameterDescriptionMessage(length, parameterCount) + for (let i = 0; i < parameterCount; i++) { + message.dataTypeIDs[i] = this.reader.int32() + } + return message + } + private parseDataRowMessage(offset: number, length: number, bytes: Buffer) { this.reader.setBuffer(offset, bytes) const fieldCount = this.reader.int16() diff --git a/packages/pg-protocol/src/testing/test-buffers.ts b/packages/pg-protocol/src/testing/test-buffers.ts index 19ba16cce..e0a04a758 100644 --- a/packages/pg-protocol/src/testing/test-buffers.ts +++ b/packages/pg-protocol/src/testing/test-buffers.ts @@ -62,6 +62,16 @@ const buffers = { return buf.join(true, 'T') }, + parameterDescription: function (dataTypeIDs: number[]) { + dataTypeIDs = dataTypeIDs || [] + var buf = new BufferList() + buf.addInt16(dataTypeIDs.length) + dataTypeIDs.forEach(function (dataTypeID) { + buf.addInt32(dataTypeID) + }) + return buf.join(true, 't') + }, + dataRow: function (columns: any[]) { columns = columns || [] var buf = new BufferList()