@supabase/pg-protocol
Advanced tools
| export {}; |
+23
| "use strict"; | ||
| // file for microbenchmarking | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const buffer_reader_1 = require("./buffer-reader"); | ||
| const LOOPS = 1000; | ||
| let count = 0; | ||
| let start = Date.now(); | ||
| const reader = new buffer_reader_1.BufferReader(); | ||
| const buffer = Buffer.from([33, 33, 33, 33, 33, 33, 33, 0]); | ||
| const run = () => { | ||
| if (count > LOOPS) { | ||
| console.log(Date.now() - start); | ||
| return; | ||
| } | ||
| count++; | ||
| for (let i = 0; i < LOOPS; i++) { | ||
| reader.setBuffer(0, buffer); | ||
| reader.cstring(); | ||
| } | ||
| setImmediate(run); | ||
| }; | ||
| run(); | ||
| //# sourceMappingURL=b.js.map |
| {"version":3,"file":"b.js","sourceRoot":"","sources":["../src/b.ts"],"names":[],"mappings":";AAAA,6BAA6B;;AAE7B,mDAA8C;AAE9C,MAAM,KAAK,GAAG,IAAI,CAAA;AAClB,IAAI,KAAK,GAAG,CAAC,CAAA;AACb,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;AAEtB,MAAM,MAAM,GAAG,IAAI,4BAAY,EAAE,CAAA;AACjC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;AAE3D,MAAM,GAAG,GAAG,GAAG,EAAE;IACf,IAAI,KAAK,GAAG,KAAK,EAAE;QACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAA;QAC/B,OAAM;KACP;IACD,KAAK,EAAE,CAAA;IACP,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;QAC9B,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;QAC3B,MAAM,CAAC,OAAO,EAAE,CAAA;KACjB;IACD,YAAY,CAAC,GAAG,CAAC,CAAA;AACnB,CAAC,CAAA;AAED,GAAG,EAAE,CAAA"} |
| /// <reference types="node" /> | ||
| export declare class BufferReader { | ||
| private offset; | ||
| private buffer; | ||
| private encoding; | ||
| constructor(offset?: number); | ||
| setBuffer(offset: number, buffer: Buffer): void; | ||
| int16(): number; | ||
| byte(): number; | ||
| int32(): number; | ||
| uint32(): number; | ||
| string(length: number): string; | ||
| cstring(): string; | ||
| bytes(length: number): Buffer; | ||
| } |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.BufferReader = void 0; | ||
| const emptyBuffer = Buffer.allocUnsafe(0); | ||
| class BufferReader { | ||
| constructor(offset = 0) { | ||
| this.offset = offset; | ||
| this.buffer = emptyBuffer; | ||
| // TODO(bmc): support non-utf8 encoding? | ||
| this.encoding = 'utf-8'; | ||
| } | ||
| setBuffer(offset, buffer) { | ||
| this.offset = offset; | ||
| this.buffer = buffer; | ||
| } | ||
| int16() { | ||
| const result = this.buffer.readInt16BE(this.offset); | ||
| this.offset += 2; | ||
| return result; | ||
| } | ||
| byte() { | ||
| const result = this.buffer[this.offset]; | ||
| this.offset++; | ||
| return result; | ||
| } | ||
| int32() { | ||
| const result = this.buffer.readInt32BE(this.offset); | ||
| this.offset += 4; | ||
| return result; | ||
| } | ||
| uint32() { | ||
| const result = this.buffer.readUInt32BE(this.offset); | ||
| this.offset += 4; | ||
| return result; | ||
| } | ||
| string(length) { | ||
| const result = this.buffer.toString(this.encoding, this.offset, this.offset + length); | ||
| this.offset += length; | ||
| return result; | ||
| } | ||
| cstring() { | ||
| const start = this.offset; | ||
| let end = start; | ||
| while (this.buffer[end++] !== 0) { } | ||
| this.offset = end; | ||
| return this.buffer.toString(this.encoding, start, end - 1); | ||
| } | ||
| bytes(length) { | ||
| const result = this.buffer.slice(this.offset, this.offset + length); | ||
| this.offset += length; | ||
| return result; | ||
| } | ||
| } | ||
| exports.BufferReader = BufferReader; | ||
| //# sourceMappingURL=buffer-reader.js.map |
| {"version":3,"file":"buffer-reader.js","sourceRoot":"","sources":["../src/buffer-reader.ts"],"names":[],"mappings":";;;AAAA,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAA;AAEzC,MAAa,YAAY;IAMvB,YAAoB,SAAiB,CAAC;QAAlB,WAAM,GAAN,MAAM,CAAY;QAL9B,WAAM,GAAW,WAAW,CAAA;QAEpC,wCAAwC;QAChC,aAAQ,GAAW,OAAO,CAAA;IAEO,CAAC;IAEnC,SAAS,CAAC,MAAc,EAAE,MAAc;QAC7C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;IAEM,KAAK;QACV,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACnD,IAAI,CAAC,MAAM,IAAI,CAAC,CAAA;QAChB,OAAO,MAAM,CAAA;IACf,CAAC;IAEM,IAAI;QACT,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACvC,IAAI,CAAC,MAAM,EAAE,CAAA;QACb,OAAO,MAAM,CAAA;IACf,CAAC;IAEM,KAAK;QACV,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACnD,IAAI,CAAC,MAAM,IAAI,CAAC,CAAA;QAChB,OAAO,MAAM,CAAA;IACf,CAAC;IAEM,MAAM;QACX,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACpD,IAAI,CAAC,MAAM,IAAI,CAAC,CAAA;QAChB,OAAO,MAAM,CAAA;IACf,CAAC;IAEM,MAAM,CAAC,MAAc;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAA;QACrF,IAAI,CAAC,MAAM,IAAI,MAAM,CAAA;QACrB,OAAO,MAAM,CAAA;IACf,CAAC;IAEM,OAAO;QACZ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAA;QACzB,IAAI,GAAG,GAAG,KAAK,CAAA;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,GAAE;QACnC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAA;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,CAAA;IAC5D,CAAC;IAEM,KAAK,CAAC,MAAc;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAA;QACnE,IAAI,CAAC,MAAM,IAAI,MAAM,CAAA;QACrB,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAxDD,oCAwDC"} |
| /// <reference types="node" /> | ||
| export declare class Writer { | ||
| private size; | ||
| private buffer; | ||
| private offset; | ||
| private headerPosition; | ||
| constructor(size?: number); | ||
| private ensure; | ||
| addInt32(num: number): Writer; | ||
| addInt16(num: number): Writer; | ||
| addCString(string: string): Writer; | ||
| addString(string?: string): Writer; | ||
| add(otherBuffer: Buffer): Writer; | ||
| private join; | ||
| flush(code?: number): Buffer; | ||
| } |
| "use strict"; | ||
| //binary data writer tuned for encoding binary specific to the postgres binary protocol | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.Writer = void 0; | ||
| class Writer { | ||
| constructor(size = 256) { | ||
| this.size = size; | ||
| this.offset = 5; | ||
| this.headerPosition = 0; | ||
| this.buffer = Buffer.allocUnsafe(size); | ||
| } | ||
| ensure(size) { | ||
| var remaining = this.buffer.length - this.offset; | ||
| if (remaining < size) { | ||
| var oldBuffer = this.buffer; | ||
| // exponential growth factor of around ~ 1.5 | ||
| // https://stackoverflow.com/questions/2269063/buffer-growth-strategy | ||
| var newSize = oldBuffer.length + (oldBuffer.length >> 1) + size; | ||
| this.buffer = Buffer.allocUnsafe(newSize); | ||
| oldBuffer.copy(this.buffer); | ||
| } | ||
| } | ||
| addInt32(num) { | ||
| this.ensure(4); | ||
| this.buffer[this.offset++] = (num >>> 24) & 0xff; | ||
| this.buffer[this.offset++] = (num >>> 16) & 0xff; | ||
| this.buffer[this.offset++] = (num >>> 8) & 0xff; | ||
| this.buffer[this.offset++] = (num >>> 0) & 0xff; | ||
| return this; | ||
| } | ||
| addInt16(num) { | ||
| this.ensure(2); | ||
| this.buffer[this.offset++] = (num >>> 8) & 0xff; | ||
| this.buffer[this.offset++] = (num >>> 0) & 0xff; | ||
| return this; | ||
| } | ||
| addCString(string) { | ||
| if (!string) { | ||
| this.ensure(1); | ||
| } | ||
| else { | ||
| var len = Buffer.byteLength(string); | ||
| this.ensure(len + 1); // +1 for null terminator | ||
| this.buffer.write(string, this.offset, 'utf-8'); | ||
| this.offset += len; | ||
| } | ||
| this.buffer[this.offset++] = 0; // null terminator | ||
| return this; | ||
| } | ||
| addString(string = '') { | ||
| var len = Buffer.byteLength(string); | ||
| this.ensure(len); | ||
| this.buffer.write(string, this.offset); | ||
| this.offset += len; | ||
| return this; | ||
| } | ||
| add(otherBuffer) { | ||
| this.ensure(otherBuffer.length); | ||
| otherBuffer.copy(this.buffer, this.offset); | ||
| this.offset += otherBuffer.length; | ||
| return this; | ||
| } | ||
| join(code) { | ||
| if (code) { | ||
| this.buffer[this.headerPosition] = code; | ||
| //length is everything in this packet minus the code | ||
| const length = this.offset - (this.headerPosition + 1); | ||
| this.buffer.writeInt32BE(length, this.headerPosition + 1); | ||
| } | ||
| return this.buffer.slice(code ? 0 : 5, this.offset); | ||
| } | ||
| flush(code) { | ||
| var result = this.join(code); | ||
| this.offset = 5; | ||
| this.headerPosition = 0; | ||
| this.buffer = Buffer.allocUnsafe(this.size); | ||
| return result; | ||
| } | ||
| } | ||
| exports.Writer = Writer; | ||
| //# sourceMappingURL=buffer-writer.js.map |
| {"version":3,"file":"buffer-writer.js","sourceRoot":"","sources":["../src/buffer-writer.ts"],"names":[],"mappings":"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"} |
| export {}; |
| "use strict"; | ||
| var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
| function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
| return new (P || (P = Promise))(function (resolve, reject) { | ||
| function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
| function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
| function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
| step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
| }); | ||
| }; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const test_buffers_1 = __importDefault(require("./testing/test-buffers")); | ||
| const buffer_list_1 = __importDefault(require("./testing/buffer-list")); | ||
| const _1 = require("."); | ||
| const assert_1 = __importDefault(require("assert")); | ||
| const stream_1 = require("stream"); | ||
| var authOkBuffer = test_buffers_1.default.authenticationOk(); | ||
| var paramStatusBuffer = test_buffers_1.default.parameterStatus('client_encoding', 'UTF8'); | ||
| var readyForQueryBuffer = test_buffers_1.default.readyForQuery(); | ||
| var backendKeyDataBuffer = test_buffers_1.default.backendKeyData(1, 2); | ||
| var commandCompleteBuffer = test_buffers_1.default.commandComplete('SELECT 3'); | ||
| var parseCompleteBuffer = test_buffers_1.default.parseComplete(); | ||
| var bindCompleteBuffer = test_buffers_1.default.bindComplete(); | ||
| var portalSuspendedBuffer = test_buffers_1.default.portalSuspended(); | ||
| var row1 = { | ||
| name: 'id', | ||
| tableID: 1, | ||
| attributeNumber: 2, | ||
| dataTypeID: 3, | ||
| dataTypeSize: 4, | ||
| typeModifier: 5, | ||
| formatCode: 0, | ||
| }; | ||
| var oneRowDescBuff = test_buffers_1.default.rowDescription([row1]); | ||
| row1.name = 'bang'; | ||
| var twoRowBuf = test_buffers_1.default.rowDescription([ | ||
| row1, | ||
| { | ||
| name: 'whoah', | ||
| tableID: 10, | ||
| attributeNumber: 11, | ||
| dataTypeID: 12, | ||
| dataTypeSize: 13, | ||
| typeModifier: 14, | ||
| formatCode: 0, | ||
| }, | ||
| ]); | ||
| var rowWithBigOids = { | ||
| name: 'bigoid', | ||
| tableID: 3000000001, | ||
| attributeNumber: 2, | ||
| dataTypeID: 3000000003, | ||
| dataTypeSize: 4, | ||
| typeModifier: 5, | ||
| formatCode: 0, | ||
| }; | ||
| var bigOidDescBuff = test_buffers_1.default.rowDescription([rowWithBigOids]); | ||
| var emptyRowFieldBuf = new buffer_list_1.default().addInt16(0).join(true, 'D'); | ||
| var emptyRowFieldBuf = test_buffers_1.default.dataRow([]); | ||
| var oneFieldBuf = new buffer_list_1.default() | ||
| .addInt16(1) // number of fields | ||
| .addInt32(5) // length of bytes of fields | ||
| .addCString('test') | ||
| .join(true, 'D'); | ||
| var oneFieldBuf = test_buffers_1.default.dataRow(['test']); | ||
| var expectedAuthenticationOkayMessage = { | ||
| name: 'authenticationOk', | ||
| length: 8, | ||
| }; | ||
| var expectedParameterStatusMessage = { | ||
| name: 'parameterStatus', | ||
| parameterName: 'client_encoding', | ||
| parameterValue: 'UTF8', | ||
| length: 25, | ||
| }; | ||
| var expectedBackendKeyDataMessage = { | ||
| name: 'backendKeyData', | ||
| processID: 1, | ||
| secretKey: 2, | ||
| }; | ||
| var expectedReadyForQueryMessage = { | ||
| name: 'readyForQuery', | ||
| length: 5, | ||
| status: 'I', | ||
| }; | ||
| var expectedCommandCompleteMessage = { | ||
| name: 'commandComplete', | ||
| length: 13, | ||
| text: 'SELECT 3', | ||
| }; | ||
| var emptyRowDescriptionBuffer = new buffer_list_1.default() | ||
| .addInt16(0) // number of fields | ||
| .join(true, 'T'); | ||
| var expectedEmptyRowDescriptionMessage = { | ||
| name: 'rowDescription', | ||
| length: 6, | ||
| fieldCount: 0, | ||
| fields: [], | ||
| }; | ||
| var expectedOneRowMessage = { | ||
| name: 'rowDescription', | ||
| length: 27, | ||
| fieldCount: 1, | ||
| fields: [ | ||
| { | ||
| name: 'id', | ||
| tableID: 1, | ||
| columnID: 2, | ||
| dataTypeID: 3, | ||
| dataTypeSize: 4, | ||
| dataTypeModifier: 5, | ||
| format: 'text', | ||
| }, | ||
| ], | ||
| }; | ||
| var expectedTwoRowMessage = { | ||
| name: 'rowDescription', | ||
| length: 53, | ||
| fieldCount: 2, | ||
| fields: [ | ||
| { | ||
| name: 'bang', | ||
| tableID: 1, | ||
| columnID: 2, | ||
| dataTypeID: 3, | ||
| dataTypeSize: 4, | ||
| dataTypeModifier: 5, | ||
| format: 'text', | ||
| }, | ||
| { | ||
| name: 'whoah', | ||
| tableID: 10, | ||
| columnID: 11, | ||
| dataTypeID: 12, | ||
| dataTypeSize: 13, | ||
| dataTypeModifier: 14, | ||
| format: 'text', | ||
| }, | ||
| ], | ||
| }; | ||
| var expectedBigOidMessage = { | ||
| name: 'rowDescription', | ||
| length: 31, | ||
| fieldCount: 1, | ||
| fields: [ | ||
| { | ||
| name: 'bigoid', | ||
| tableID: 3000000001, | ||
| columnID: 2, | ||
| dataTypeID: 3000000003, | ||
| dataTypeSize: 4, | ||
| dataTypeModifier: 5, | ||
| format: 'text', | ||
| }, | ||
| ], | ||
| }; | ||
| var emptyParameterDescriptionBuffer = new buffer_list_1.default() | ||
| .addInt16(0) // number of parameters | ||
| .join(true, 't'); | ||
| var oneParameterDescBuf = test_buffers_1.default.parameterDescription([1111]); | ||
| var twoParameterDescBuf = test_buffers_1.default.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, expectedMessage) { | ||
| it('receives and parses ' + expectedMessage.name, () => __awaiter(this, void 0, void 0, function* () { | ||
| const messages = yield parseBuffers([buffer]); | ||
| const [lastMessage] = messages; | ||
| for (const key in expectedMessage) { | ||
| assert_1.default.deepEqual(lastMessage[key], expectedMessage[key]); | ||
| } | ||
| })); | ||
| }; | ||
| var plainPasswordBuffer = test_buffers_1.default.authenticationCleartextPassword(); | ||
| var md5PasswordBuffer = test_buffers_1.default.authenticationMD5Password(); | ||
| var SASLBuffer = test_buffers_1.default.authenticationSASL(); | ||
| var SASLContinueBuffer = test_buffers_1.default.authenticationSASLContinue(); | ||
| var SASLFinalBuffer = test_buffers_1.default.authenticationSASLFinal(); | ||
| var expectedPlainPasswordMessage = { | ||
| name: 'authenticationCleartextPassword', | ||
| }; | ||
| var expectedMD5PasswordMessage = { | ||
| name: 'authenticationMD5Password', | ||
| salt: Buffer.from([1, 2, 3, 4]), | ||
| }; | ||
| var expectedSASLMessage = { | ||
| name: 'authenticationSASL', | ||
| mechanisms: ['SCRAM-SHA-256'], | ||
| }; | ||
| var expectedSASLContinueMessage = { | ||
| name: 'authenticationSASLContinue', | ||
| data: 'data', | ||
| }; | ||
| var expectedSASLFinalMessage = { | ||
| name: 'authenticationSASLFinal', | ||
| data: 'data', | ||
| }; | ||
| var notificationResponseBuffer = test_buffers_1.default.notification(4, 'hi', 'boom'); | ||
| var expectedNotificationResponseMessage = { | ||
| name: 'notification', | ||
| processId: 4, | ||
| channel: 'hi', | ||
| payload: 'boom', | ||
| }; | ||
| const parseBuffers = (buffers) => __awaiter(void 0, void 0, void 0, function* () { | ||
| const stream = new stream_1.PassThrough(); | ||
| for (const buffer of buffers) { | ||
| stream.write(buffer); | ||
| } | ||
| stream.end(); | ||
| const msgs = []; | ||
| yield (0, _1.parse)(stream, (msg) => msgs.push(msg)); | ||
| return msgs; | ||
| }); | ||
| describe('PgPacketStream', function () { | ||
| testForMessage(authOkBuffer, expectedAuthenticationOkayMessage); | ||
| testForMessage(plainPasswordBuffer, expectedPlainPasswordMessage); | ||
| testForMessage(md5PasswordBuffer, expectedMD5PasswordMessage); | ||
| testForMessage(SASLBuffer, expectedSASLMessage); | ||
| testForMessage(SASLContinueBuffer, expectedSASLContinueMessage); | ||
| // this exercises a found bug in the parser: | ||
| // https://github.com/brianc/node-postgres/pull/2210#issuecomment-627626084 | ||
| // and adds a test which is deterministic, rather than relying on network packet chunking | ||
| const extendedSASLContinueBuffer = Buffer.concat([SASLContinueBuffer, Buffer.from([1, 2, 3, 4])]); | ||
| testForMessage(extendedSASLContinueBuffer, expectedSASLContinueMessage); | ||
| testForMessage(SASLFinalBuffer, expectedSASLFinalMessage); | ||
| // this exercises a found bug in the parser: | ||
| // https://github.com/brianc/node-postgres/pull/2210#issuecomment-627626084 | ||
| // and adds a test which is deterministic, rather than relying on network packet chunking | ||
| const extendedSASLFinalBuffer = Buffer.concat([SASLFinalBuffer, Buffer.from([1, 2, 4, 5])]); | ||
| testForMessage(extendedSASLFinalBuffer, expectedSASLFinalMessage); | ||
| testForMessage(paramStatusBuffer, expectedParameterStatusMessage); | ||
| testForMessage(backendKeyDataBuffer, expectedBackendKeyDataMessage); | ||
| testForMessage(readyForQueryBuffer, expectedReadyForQueryMessage); | ||
| testForMessage(commandCompleteBuffer, expectedCommandCompleteMessage); | ||
| testForMessage(notificationResponseBuffer, expectedNotificationResponseMessage); | ||
| testForMessage(test_buffers_1.default.emptyQuery(), { | ||
| name: 'emptyQuery', | ||
| length: 4, | ||
| }); | ||
| testForMessage(Buffer.from([0x6e, 0, 0, 0, 4]), { | ||
| name: 'noData', | ||
| }); | ||
| describe('rowDescription messages', function () { | ||
| testForMessage(emptyRowDescriptionBuffer, expectedEmptyRowDescriptionMessage); | ||
| testForMessage(oneRowDescBuff, expectedOneRowMessage); | ||
| testForMessage(twoRowBuf, expectedTwoRowMessage); | ||
| testForMessage(bigOidDescBuff, expectedBigOidMessage); | ||
| }); | ||
| describe('parameterDescription messages', function () { | ||
| testForMessage(emptyParameterDescriptionBuffer, expectedEmptyParameterDescriptionMessage); | ||
| testForMessage(oneParameterDescBuf, expectedOneParameterMessage); | ||
| testForMessage(twoParameterDescBuf, expectedTwoParameterMessage); | ||
| }); | ||
| describe('parsing rows', function () { | ||
| describe('parsing empty row', function () { | ||
| testForMessage(emptyRowFieldBuf, { | ||
| name: 'dataRow', | ||
| fieldCount: 0, | ||
| }); | ||
| }); | ||
| describe('parsing data row with fields', function () { | ||
| testForMessage(oneFieldBuf, { | ||
| name: 'dataRow', | ||
| fieldCount: 1, | ||
| fields: ['test'], | ||
| }); | ||
| }); | ||
| }); | ||
| describe('notice message', function () { | ||
| // this uses the same logic as error message | ||
| var buff = test_buffers_1.default.notice([{ type: 'C', value: 'code' }]); | ||
| testForMessage(buff, { | ||
| name: 'notice', | ||
| code: 'code', | ||
| }); | ||
| }); | ||
| testForMessage(test_buffers_1.default.error([]), { | ||
| name: 'error', | ||
| }); | ||
| describe('with all the fields', function () { | ||
| var buffer = test_buffers_1.default.error([ | ||
| { | ||
| type: 'S', | ||
| value: 'ERROR', | ||
| }, | ||
| { | ||
| type: 'C', | ||
| value: 'code', | ||
| }, | ||
| { | ||
| type: 'M', | ||
| value: 'message', | ||
| }, | ||
| { | ||
| type: 'D', | ||
| value: 'details', | ||
| }, | ||
| { | ||
| type: 'H', | ||
| value: 'hint', | ||
| }, | ||
| { | ||
| type: 'P', | ||
| value: '100', | ||
| }, | ||
| { | ||
| type: 'p', | ||
| value: '101', | ||
| }, | ||
| { | ||
| type: 'q', | ||
| value: 'query', | ||
| }, | ||
| { | ||
| type: 'W', | ||
| value: 'where', | ||
| }, | ||
| { | ||
| type: 'F', | ||
| value: 'file', | ||
| }, | ||
| { | ||
| type: 'L', | ||
| value: 'line', | ||
| }, | ||
| { | ||
| type: 'R', | ||
| value: 'routine', | ||
| }, | ||
| { | ||
| type: 'Z', | ||
| value: 'alsdkf', | ||
| }, | ||
| ]); | ||
| testForMessage(buffer, { | ||
| name: 'error', | ||
| severity: 'ERROR', | ||
| code: 'code', | ||
| message: 'message', | ||
| detail: 'details', | ||
| hint: 'hint', | ||
| position: '100', | ||
| internalPosition: '101', | ||
| internalQuery: 'query', | ||
| where: 'where', | ||
| file: 'file', | ||
| line: 'line', | ||
| routine: 'routine', | ||
| }); | ||
| }); | ||
| testForMessage(parseCompleteBuffer, { | ||
| name: 'parseComplete', | ||
| }); | ||
| testForMessage(bindCompleteBuffer, { | ||
| name: 'bindComplete', | ||
| }); | ||
| testForMessage(bindCompleteBuffer, { | ||
| name: 'bindComplete', | ||
| }); | ||
| testForMessage(test_buffers_1.default.closeComplete(), { | ||
| name: 'closeComplete', | ||
| }); | ||
| describe('parses portal suspended message', function () { | ||
| testForMessage(portalSuspendedBuffer, { | ||
| name: 'portalSuspended', | ||
| }); | ||
| }); | ||
| describe('parses replication start message', function () { | ||
| testForMessage(Buffer.from([0x57, 0x00, 0x00, 0x00, 0x04]), { | ||
| name: 'replicationStart', | ||
| length: 4, | ||
| }); | ||
| }); | ||
| describe('copy', () => { | ||
| testForMessage(test_buffers_1.default.copyIn(0), { | ||
| name: 'copyInResponse', | ||
| length: 7, | ||
| binary: false, | ||
| columnTypes: [], | ||
| }); | ||
| testForMessage(test_buffers_1.default.copyIn(2), { | ||
| name: 'copyInResponse', | ||
| length: 11, | ||
| binary: false, | ||
| columnTypes: [0, 1], | ||
| }); | ||
| testForMessage(test_buffers_1.default.copyOut(0), { | ||
| name: 'copyOutResponse', | ||
| length: 7, | ||
| binary: false, | ||
| columnTypes: [], | ||
| }); | ||
| testForMessage(test_buffers_1.default.copyOut(3), { | ||
| name: 'copyOutResponse', | ||
| length: 13, | ||
| binary: false, | ||
| columnTypes: [0, 1, 2], | ||
| }); | ||
| testForMessage(test_buffers_1.default.copyDone(), { | ||
| name: 'copyDone', | ||
| length: 4, | ||
| }); | ||
| testForMessage(test_buffers_1.default.copyData(Buffer.from([5, 6, 7])), { | ||
| name: 'copyData', | ||
| length: 7, | ||
| chunk: Buffer.from([5, 6, 7]), | ||
| }); | ||
| }); | ||
| // since the data message on a stream can randomly divide the incomming | ||
| // tcp packets anywhere, we need to make sure we can parse every single | ||
| // split on a tcp message | ||
| describe('split buffer, single message parsing', function () { | ||
| var fullBuffer = test_buffers_1.default.dataRow([null, 'bang', 'zug zug', null, '!']); | ||
| it('parses when full buffer comes in', function () { | ||
| return __awaiter(this, void 0, void 0, function* () { | ||
| const messages = yield parseBuffers([fullBuffer]); | ||
| const message = messages[0]; | ||
| assert_1.default.equal(message.fields.length, 5); | ||
| assert_1.default.equal(message.fields[0], null); | ||
| assert_1.default.equal(message.fields[1], 'bang'); | ||
| assert_1.default.equal(message.fields[2], 'zug zug'); | ||
| assert_1.default.equal(message.fields[3], null); | ||
| assert_1.default.equal(message.fields[4], '!'); | ||
| }); | ||
| }); | ||
| var testMessageReceivedAfterSplitAt = function (split) { | ||
| return __awaiter(this, void 0, void 0, function* () { | ||
| var firstBuffer = Buffer.alloc(fullBuffer.length - split); | ||
| var secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length); | ||
| fullBuffer.copy(firstBuffer, 0, 0); | ||
| fullBuffer.copy(secondBuffer, 0, firstBuffer.length); | ||
| const messages = yield parseBuffers([firstBuffer, secondBuffer]); | ||
| const message = messages[0]; | ||
| assert_1.default.equal(message.fields.length, 5); | ||
| assert_1.default.equal(message.fields[0], null); | ||
| assert_1.default.equal(message.fields[1], 'bang'); | ||
| assert_1.default.equal(message.fields[2], 'zug zug'); | ||
| assert_1.default.equal(message.fields[3], null); | ||
| assert_1.default.equal(message.fields[4], '!'); | ||
| }); | ||
| }; | ||
| it('parses when split in the middle', function () { | ||
| return testMessageReceivedAfterSplitAt(6); | ||
| }); | ||
| it('parses when split at end', function () { | ||
| return testMessageReceivedAfterSplitAt(2); | ||
| }); | ||
| it('parses when split at beginning', function () { | ||
| return Promise.all([ | ||
| testMessageReceivedAfterSplitAt(fullBuffer.length - 2), | ||
| testMessageReceivedAfterSplitAt(fullBuffer.length - 1), | ||
| testMessageReceivedAfterSplitAt(fullBuffer.length - 5), | ||
| ]); | ||
| }); | ||
| }); | ||
| describe('split buffer, multiple message parsing', function () { | ||
| var dataRowBuffer = test_buffers_1.default.dataRow(['!']); | ||
| var readyForQueryBuffer = test_buffers_1.default.readyForQuery(); | ||
| var fullBuffer = Buffer.alloc(dataRowBuffer.length + readyForQueryBuffer.length); | ||
| dataRowBuffer.copy(fullBuffer, 0, 0); | ||
| readyForQueryBuffer.copy(fullBuffer, dataRowBuffer.length, 0); | ||
| var verifyMessages = function (messages) { | ||
| assert_1.default.strictEqual(messages.length, 2); | ||
| assert_1.default.deepEqual(messages[0], { | ||
| name: 'dataRow', | ||
| fieldCount: 1, | ||
| length: 11, | ||
| fields: ['!'], | ||
| }); | ||
| assert_1.default.equal(messages[0].fields[0], '!'); | ||
| assert_1.default.deepEqual(messages[1], { | ||
| name: 'readyForQuery', | ||
| length: 5, | ||
| status: 'I', | ||
| }); | ||
| }; | ||
| // sanity check | ||
| it('receives both messages when packet is not split', function () { | ||
| return __awaiter(this, void 0, void 0, function* () { | ||
| const messages = yield parseBuffers([fullBuffer]); | ||
| verifyMessages(messages); | ||
| }); | ||
| }); | ||
| var splitAndVerifyTwoMessages = function (split) { | ||
| return __awaiter(this, void 0, void 0, function* () { | ||
| var firstBuffer = Buffer.alloc(fullBuffer.length - split); | ||
| var secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length); | ||
| fullBuffer.copy(firstBuffer, 0, 0); | ||
| fullBuffer.copy(secondBuffer, 0, firstBuffer.length); | ||
| const messages = yield parseBuffers([firstBuffer, secondBuffer]); | ||
| verifyMessages(messages); | ||
| }); | ||
| }; | ||
| describe('receives both messages when packet is split', function () { | ||
| it('in the middle', function () { | ||
| return splitAndVerifyTwoMessages(11); | ||
| }); | ||
| it('at the front', function () { | ||
| return Promise.all([ | ||
| splitAndVerifyTwoMessages(fullBuffer.length - 1), | ||
| splitAndVerifyTwoMessages(fullBuffer.length - 4), | ||
| splitAndVerifyTwoMessages(fullBuffer.length - 6), | ||
| ]); | ||
| }); | ||
| it('at the end', function () { | ||
| return Promise.all([splitAndVerifyTwoMessages(8), splitAndVerifyTwoMessages(1)]); | ||
| }); | ||
| }); | ||
| }); | ||
| }); | ||
| //# sourceMappingURL=inbound-parser.test.js.map |
| {"version":3,"file":"inbound-parser.test.js","sourceRoot":"","sources":["../src/inbound-parser.test.ts"],"names":[],"mappings":"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"} |
| /// <reference types="node" /> | ||
| import { DatabaseError } from './messages'; | ||
| import { serialize } from './serializer'; | ||
| import { MessageCallback } from './parser'; | ||
| export declare function parse(stream: NodeJS.ReadableStream, callback: MessageCallback): Promise<void>; | ||
| export { serialize, DatabaseError }; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.DatabaseError = exports.serialize = exports.parse = void 0; | ||
| const messages_1 = require("./messages"); | ||
| Object.defineProperty(exports, "DatabaseError", { enumerable: true, get: function () { return messages_1.DatabaseError; } }); | ||
| const serializer_1 = require("./serializer"); | ||
| Object.defineProperty(exports, "serialize", { enumerable: true, get: function () { return serializer_1.serialize; } }); | ||
| const parser_1 = require("./parser"); | ||
| function parse(stream, callback) { | ||
| const parser = new parser_1.Parser(); | ||
| stream.on('data', (buffer) => parser.parse(buffer, callback)); | ||
| return new Promise((resolve) => stream.on('end', () => resolve())); | ||
| } | ||
| exports.parse = parse; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yCAA0C;AAUtB,8FAVX,wBAAa,OAUW;AATjC,6CAAwC;AAS/B,0FATA,sBAAS,OASA;AARlB,qCAAkD;AAElD,SAAgB,KAAK,CAAC,MAA6B,EAAE,QAAyB;IAC5E,MAAM,MAAM,GAAG,IAAI,eAAM,EAAE,CAAA;IAC3B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAA;IACrE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;AACpE,CAAC;AAJD,sBAIC"} |
| /// <reference types="node" /> | ||
| export declare type Mode = 'text' | 'binary'; | ||
| export declare type MessageName = 'parseComplete' | 'bindComplete' | 'closeComplete' | 'noData' | 'portalSuspended' | 'replicationStart' | 'emptyQuery' | 'copyDone' | 'copyData' | 'rowDescription' | 'parameterDescription' | 'parameterStatus' | 'backendKeyData' | 'notification' | 'readyForQuery' | 'commandComplete' | 'dataRow' | 'copyInResponse' | 'copyOutResponse' | 'authenticationOk' | 'authenticationMD5Password' | 'authenticationCleartextPassword' | 'authenticationSASL' | 'authenticationSASLContinue' | 'authenticationSASLFinal' | 'error' | 'notice'; | ||
| export interface BackendMessage { | ||
| name: MessageName; | ||
| length: number; | ||
| } | ||
| export declare const parseComplete: BackendMessage; | ||
| export declare const bindComplete: BackendMessage; | ||
| export declare const closeComplete: BackendMessage; | ||
| export declare const noData: BackendMessage; | ||
| export declare const portalSuspended: BackendMessage; | ||
| export declare const replicationStart: BackendMessage; | ||
| export declare const emptyQuery: BackendMessage; | ||
| export declare const copyDone: BackendMessage; | ||
| interface NoticeOrError { | ||
| message: string | undefined; | ||
| severity: string | undefined; | ||
| code: string | undefined; | ||
| detail: string | undefined; | ||
| hint: string | undefined; | ||
| position: string | undefined; | ||
| internalPosition: string | undefined; | ||
| internalQuery: string | undefined; | ||
| where: string | undefined; | ||
| schema: string | undefined; | ||
| table: string | undefined; | ||
| column: string | undefined; | ||
| dataType: string | undefined; | ||
| constraint: string | undefined; | ||
| file: string | undefined; | ||
| line: string | undefined; | ||
| routine: string | undefined; | ||
| } | ||
| export declare class DatabaseError extends Error implements NoticeOrError { | ||
| readonly length: number; | ||
| readonly name: MessageName; | ||
| severity: string | undefined; | ||
| code: string | undefined; | ||
| detail: string | undefined; | ||
| hint: string | undefined; | ||
| position: string | undefined; | ||
| internalPosition: string | undefined; | ||
| internalQuery: string | undefined; | ||
| where: string | undefined; | ||
| schema: string | undefined; | ||
| table: string | undefined; | ||
| column: string | undefined; | ||
| dataType: string | undefined; | ||
| constraint: string | undefined; | ||
| file: string | undefined; | ||
| line: string | undefined; | ||
| routine: string | undefined; | ||
| constructor(message: string, length: number, name: MessageName); | ||
| } | ||
| export declare class CopyDataMessage { | ||
| readonly length: number; | ||
| readonly chunk: Buffer; | ||
| readonly name = "copyData"; | ||
| constructor(length: number, chunk: Buffer); | ||
| } | ||
| export declare class CopyResponse { | ||
| readonly length: number; | ||
| readonly name: MessageName; | ||
| readonly binary: boolean; | ||
| readonly columnTypes: number[]; | ||
| constructor(length: number, name: MessageName, binary: boolean, columnCount: number); | ||
| } | ||
| export declare class Field { | ||
| readonly name: string; | ||
| readonly tableID: number; | ||
| readonly columnID: number; | ||
| readonly dataTypeID: number; | ||
| readonly dataTypeSize: number; | ||
| readonly dataTypeModifier: number; | ||
| readonly format: Mode; | ||
| constructor(name: string, tableID: number, columnID: number, dataTypeID: number, dataTypeSize: number, dataTypeModifier: number, format: Mode); | ||
| } | ||
| export declare class RowDescriptionMessage { | ||
| readonly length: number; | ||
| readonly fieldCount: number; | ||
| readonly name: MessageName; | ||
| readonly fields: Field[]; | ||
| constructor(length: number, fieldCount: number); | ||
| } | ||
| export declare class ParameterDescriptionMessage { | ||
| readonly length: number; | ||
| readonly parameterCount: number; | ||
| readonly name: MessageName; | ||
| readonly dataTypeIDs: number[]; | ||
| constructor(length: number, parameterCount: number); | ||
| } | ||
| export declare class ParameterStatusMessage { | ||
| readonly length: number; | ||
| readonly parameterName: string; | ||
| readonly parameterValue: string; | ||
| readonly name: MessageName; | ||
| constructor(length: number, parameterName: string, parameterValue: string); | ||
| } | ||
| export declare class AuthenticationMD5Password implements BackendMessage { | ||
| readonly length: number; | ||
| readonly salt: Buffer; | ||
| readonly name: MessageName; | ||
| constructor(length: number, salt: Buffer); | ||
| } | ||
| export declare class BackendKeyDataMessage { | ||
| readonly length: number; | ||
| readonly processID: number; | ||
| readonly secretKey: number; | ||
| readonly name: MessageName; | ||
| constructor(length: number, processID: number, secretKey: number); | ||
| } | ||
| export declare class NotificationResponseMessage { | ||
| readonly length: number; | ||
| readonly processId: number; | ||
| readonly channel: string; | ||
| readonly payload: string; | ||
| readonly name: MessageName; | ||
| constructor(length: number, processId: number, channel: string, payload: string); | ||
| } | ||
| export declare class ReadyForQueryMessage { | ||
| readonly length: number; | ||
| readonly status: string; | ||
| readonly name: MessageName; | ||
| constructor(length: number, status: string); | ||
| } | ||
| export declare class CommandCompleteMessage { | ||
| readonly length: number; | ||
| readonly text: string; | ||
| readonly name: MessageName; | ||
| constructor(length: number, text: string); | ||
| } | ||
| export declare class DataRowMessage { | ||
| length: number; | ||
| fields: any[]; | ||
| readonly fieldCount: number; | ||
| readonly name: MessageName; | ||
| constructor(length: number, fields: any[]); | ||
| } | ||
| export declare class NoticeMessage implements BackendMessage, NoticeOrError { | ||
| readonly length: number; | ||
| readonly message: string | undefined; | ||
| constructor(length: number, message: string | undefined); | ||
| readonly name = "notice"; | ||
| severity: string | undefined; | ||
| code: string | undefined; | ||
| detail: string | undefined; | ||
| hint: string | undefined; | ||
| position: string | undefined; | ||
| internalPosition: string | undefined; | ||
| internalQuery: string | undefined; | ||
| where: string | undefined; | ||
| schema: string | undefined; | ||
| table: string | undefined; | ||
| column: string | undefined; | ||
| dataType: string | undefined; | ||
| constraint: string | undefined; | ||
| file: string | undefined; | ||
| line: string | undefined; | ||
| routine: string | undefined; | ||
| } | ||
| export {}; |
+160
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.NoticeMessage = exports.DataRowMessage = exports.CommandCompleteMessage = exports.ReadyForQueryMessage = exports.NotificationResponseMessage = exports.BackendKeyDataMessage = exports.AuthenticationMD5Password = exports.ParameterStatusMessage = exports.ParameterDescriptionMessage = exports.RowDescriptionMessage = exports.Field = exports.CopyResponse = exports.CopyDataMessage = exports.DatabaseError = exports.copyDone = exports.emptyQuery = exports.replicationStart = exports.portalSuspended = exports.noData = exports.closeComplete = exports.bindComplete = exports.parseComplete = void 0; | ||
| exports.parseComplete = { | ||
| name: 'parseComplete', | ||
| length: 5, | ||
| }; | ||
| exports.bindComplete = { | ||
| name: 'bindComplete', | ||
| length: 5, | ||
| }; | ||
| exports.closeComplete = { | ||
| name: 'closeComplete', | ||
| length: 5, | ||
| }; | ||
| exports.noData = { | ||
| name: 'noData', | ||
| length: 5, | ||
| }; | ||
| exports.portalSuspended = { | ||
| name: 'portalSuspended', | ||
| length: 5, | ||
| }; | ||
| exports.replicationStart = { | ||
| name: 'replicationStart', | ||
| length: 4, | ||
| }; | ||
| exports.emptyQuery = { | ||
| name: 'emptyQuery', | ||
| length: 4, | ||
| }; | ||
| exports.copyDone = { | ||
| name: 'copyDone', | ||
| length: 4, | ||
| }; | ||
| class DatabaseError extends Error { | ||
| constructor(message, length, name) { | ||
| super(message); | ||
| this.length = length; | ||
| this.name = name; | ||
| } | ||
| } | ||
| exports.DatabaseError = DatabaseError; | ||
| class CopyDataMessage { | ||
| constructor(length, chunk) { | ||
| this.length = length; | ||
| this.chunk = chunk; | ||
| this.name = 'copyData'; | ||
| } | ||
| } | ||
| exports.CopyDataMessage = CopyDataMessage; | ||
| class CopyResponse { | ||
| constructor(length, name, binary, columnCount) { | ||
| this.length = length; | ||
| this.name = name; | ||
| this.binary = binary; | ||
| this.columnTypes = new Array(columnCount); | ||
| } | ||
| } | ||
| exports.CopyResponse = CopyResponse; | ||
| class Field { | ||
| constructor(name, tableID, columnID, dataTypeID, dataTypeSize, dataTypeModifier, format) { | ||
| this.name = name; | ||
| this.tableID = tableID; | ||
| this.columnID = columnID; | ||
| this.dataTypeID = dataTypeID; | ||
| this.dataTypeSize = dataTypeSize; | ||
| this.dataTypeModifier = dataTypeModifier; | ||
| this.format = format; | ||
| } | ||
| } | ||
| exports.Field = Field; | ||
| class RowDescriptionMessage { | ||
| constructor(length, fieldCount) { | ||
| this.length = length; | ||
| this.fieldCount = fieldCount; | ||
| this.name = 'rowDescription'; | ||
| this.fields = new Array(this.fieldCount); | ||
| } | ||
| } | ||
| exports.RowDescriptionMessage = RowDescriptionMessage; | ||
| class ParameterDescriptionMessage { | ||
| constructor(length, parameterCount) { | ||
| this.length = length; | ||
| this.parameterCount = parameterCount; | ||
| this.name = 'parameterDescription'; | ||
| this.dataTypeIDs = new Array(this.parameterCount); | ||
| } | ||
| } | ||
| exports.ParameterDescriptionMessage = ParameterDescriptionMessage; | ||
| class ParameterStatusMessage { | ||
| constructor(length, parameterName, parameterValue) { | ||
| this.length = length; | ||
| this.parameterName = parameterName; | ||
| this.parameterValue = parameterValue; | ||
| this.name = 'parameterStatus'; | ||
| } | ||
| } | ||
| exports.ParameterStatusMessage = ParameterStatusMessage; | ||
| class AuthenticationMD5Password { | ||
| constructor(length, salt) { | ||
| this.length = length; | ||
| this.salt = salt; | ||
| this.name = 'authenticationMD5Password'; | ||
| } | ||
| } | ||
| exports.AuthenticationMD5Password = AuthenticationMD5Password; | ||
| class BackendKeyDataMessage { | ||
| constructor(length, processID, secretKey) { | ||
| this.length = length; | ||
| this.processID = processID; | ||
| this.secretKey = secretKey; | ||
| this.name = 'backendKeyData'; | ||
| } | ||
| } | ||
| exports.BackendKeyDataMessage = BackendKeyDataMessage; | ||
| class NotificationResponseMessage { | ||
| constructor(length, processId, channel, payload) { | ||
| this.length = length; | ||
| this.processId = processId; | ||
| this.channel = channel; | ||
| this.payload = payload; | ||
| this.name = 'notification'; | ||
| } | ||
| } | ||
| exports.NotificationResponseMessage = NotificationResponseMessage; | ||
| class ReadyForQueryMessage { | ||
| constructor(length, status) { | ||
| this.length = length; | ||
| this.status = status; | ||
| this.name = 'readyForQuery'; | ||
| } | ||
| } | ||
| exports.ReadyForQueryMessage = ReadyForQueryMessage; | ||
| class CommandCompleteMessage { | ||
| constructor(length, text) { | ||
| this.length = length; | ||
| this.text = text; | ||
| this.name = 'commandComplete'; | ||
| } | ||
| } | ||
| exports.CommandCompleteMessage = CommandCompleteMessage; | ||
| class DataRowMessage { | ||
| constructor(length, fields) { | ||
| this.length = length; | ||
| this.fields = fields; | ||
| this.name = 'dataRow'; | ||
| this.fieldCount = fields.length; | ||
| } | ||
| } | ||
| exports.DataRowMessage = DataRowMessage; | ||
| class NoticeMessage { | ||
| constructor(length, message) { | ||
| this.length = length; | ||
| this.message = message; | ||
| this.name = 'notice'; | ||
| } | ||
| } | ||
| exports.NoticeMessage = NoticeMessage; | ||
| //# sourceMappingURL=messages.js.map |
| {"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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"} |
| export {}; |
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| const assert_1 = __importDefault(require("assert")); | ||
| const serializer_1 = require("./serializer"); | ||
| const buffer_list_1 = __importDefault(require("./testing/buffer-list")); | ||
| describe('serializer', () => { | ||
| it('builds startup message', function () { | ||
| const actual = serializer_1.serialize.startup({ | ||
| user: 'brian', | ||
| database: 'bang', | ||
| }); | ||
| assert_1.default.deepEqual(actual, new buffer_list_1.default() | ||
| .addInt16(3) | ||
| .addInt16(0) | ||
| .addCString('user') | ||
| .addCString('brian') | ||
| .addCString('database') | ||
| .addCString('bang') | ||
| .addCString('client_encoding') | ||
| .addCString('UTF8') | ||
| .addCString('') | ||
| .join(true)); | ||
| }); | ||
| it('builds password message', function () { | ||
| const actual = serializer_1.serialize.password('!'); | ||
| assert_1.default.deepEqual(actual, new buffer_list_1.default().addCString('!').join(true, 'p')); | ||
| }); | ||
| it('builds request ssl message', function () { | ||
| const actual = serializer_1.serialize.requestSsl(); | ||
| const expected = new buffer_list_1.default().addInt32(80877103).join(true); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| it('builds SASLInitialResponseMessage message', function () { | ||
| const actual = serializer_1.serialize.sendSASLInitialResponseMessage('mech', 'data'); | ||
| assert_1.default.deepEqual(actual, new buffer_list_1.default().addCString('mech').addInt32(4).addString('data').join(true, 'p')); | ||
| }); | ||
| it('builds SCRAMClientFinalMessage message', function () { | ||
| const actual = serializer_1.serialize.sendSCRAMClientFinalMessage('data'); | ||
| assert_1.default.deepEqual(actual, new buffer_list_1.default().addString('data').join(true, 'p')); | ||
| }); | ||
| it('builds query message', function () { | ||
| var txt = 'select * from boom'; | ||
| const actual = serializer_1.serialize.query(txt); | ||
| assert_1.default.deepEqual(actual, new buffer_list_1.default().addCString(txt).join(true, 'Q')); | ||
| }); | ||
| describe('parse message', () => { | ||
| it('builds parse message', function () { | ||
| const actual = serializer_1.serialize.parse({ text: '!' }); | ||
| var expected = new buffer_list_1.default().addCString('').addCString('!').addInt16(0).join(true, 'P'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| it('builds parse message with named query', function () { | ||
| const actual = serializer_1.serialize.parse({ | ||
| name: 'boom', | ||
| text: 'select * from boom', | ||
| types: [], | ||
| }); | ||
| var expected = new buffer_list_1.default().addCString('boom').addCString('select * from boom').addInt16(0).join(true, 'P'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| it('with multiple parameters', function () { | ||
| const actual = serializer_1.serialize.parse({ | ||
| name: 'force', | ||
| text: 'select * from bang where name = $1', | ||
| types: [1, 2, 3, 4], | ||
| }); | ||
| var expected = new buffer_list_1.default() | ||
| .addCString('force') | ||
| .addCString('select * from bang where name = $1') | ||
| .addInt16(4) | ||
| .addInt32(1) | ||
| .addInt32(2) | ||
| .addInt32(3) | ||
| .addInt32(4) | ||
| .join(true, 'P'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| }); | ||
| describe('bind messages', function () { | ||
| it('with no values', function () { | ||
| const actual = serializer_1.serialize.bind(); | ||
| var expectedBuffer = new buffer_list_1.default() | ||
| .addCString('') | ||
| .addCString('') | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .join(true, 'B'); | ||
| assert_1.default.deepEqual(actual, expectedBuffer); | ||
| }); | ||
| it('with named statement, portal, and values', function () { | ||
| const actual = serializer_1.serialize.bind({ | ||
| portal: 'bang', | ||
| statement: 'woo', | ||
| values: ['1', 'hi', null, 'zing'], | ||
| }); | ||
| var expectedBuffer = new buffer_list_1.default() | ||
| .addCString('bang') // portal name | ||
| .addCString('woo') // statement name | ||
| .addInt16(4) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(4) | ||
| .addInt32(1) | ||
| .add(Buffer.from('1')) | ||
| .addInt32(2) | ||
| .add(Buffer.from('hi')) | ||
| .addInt32(-1) | ||
| .addInt32(4) | ||
| .add(Buffer.from('zing')) | ||
| .addInt16(0) | ||
| .join(true, 'B'); | ||
| assert_1.default.deepEqual(actual, expectedBuffer); | ||
| }); | ||
| }); | ||
| it('with custom valueMapper', function () { | ||
| const actual = serializer_1.serialize.bind({ | ||
| portal: 'bang', | ||
| statement: 'woo', | ||
| values: ['1', 'hi', null, 'zing'], | ||
| valueMapper: () => null, | ||
| }); | ||
| var expectedBuffer = new buffer_list_1.default() | ||
| .addCString('bang') // portal name | ||
| .addCString('woo') // statement name | ||
| .addInt16(4) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(4) | ||
| .addInt32(-1) | ||
| .addInt32(-1) | ||
| .addInt32(-1) | ||
| .addInt32(-1) | ||
| .addInt16(0) | ||
| .join(true, 'B'); | ||
| assert_1.default.deepEqual(actual, expectedBuffer); | ||
| }); | ||
| it('with named statement, portal, and buffer value', function () { | ||
| const actual = serializer_1.serialize.bind({ | ||
| portal: 'bang', | ||
| statement: 'woo', | ||
| values: ['1', 'hi', null, Buffer.from('zing', 'utf8')], | ||
| }); | ||
| var expectedBuffer = new buffer_list_1.default() | ||
| .addCString('bang') // portal name | ||
| .addCString('woo') // statement name | ||
| .addInt16(4) // value count | ||
| .addInt16(0) // string | ||
| .addInt16(0) // string | ||
| .addInt16(0) // string | ||
| .addInt16(1) // binary | ||
| .addInt16(4) | ||
| .addInt32(1) | ||
| .add(Buffer.from('1')) | ||
| .addInt32(2) | ||
| .add(Buffer.from('hi')) | ||
| .addInt32(-1) | ||
| .addInt32(4) | ||
| .add(Buffer.from('zing', 'utf-8')) | ||
| .addInt16(0) | ||
| .join(true, 'B'); | ||
| assert_1.default.deepEqual(actual, expectedBuffer); | ||
| }); | ||
| describe('builds execute message', function () { | ||
| it('for unamed portal with no row limit', function () { | ||
| const actual = serializer_1.serialize.execute(); | ||
| var expectedBuffer = new buffer_list_1.default().addCString('').addInt32(0).join(true, 'E'); | ||
| assert_1.default.deepEqual(actual, expectedBuffer); | ||
| }); | ||
| it('for named portal with row limit', function () { | ||
| const actual = serializer_1.serialize.execute({ | ||
| portal: 'my favorite portal', | ||
| rows: 100, | ||
| }); | ||
| var expectedBuffer = new buffer_list_1.default().addCString('my favorite portal').addInt32(100).join(true, 'E'); | ||
| assert_1.default.deepEqual(actual, expectedBuffer); | ||
| }); | ||
| }); | ||
| it('builds flush command', function () { | ||
| const actual = serializer_1.serialize.flush(); | ||
| var expected = new buffer_list_1.default().join(true, 'H'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| it('builds sync command', function () { | ||
| const actual = serializer_1.serialize.sync(); | ||
| var expected = new buffer_list_1.default().join(true, 'S'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| it('builds end command', function () { | ||
| const actual = serializer_1.serialize.end(); | ||
| var expected = Buffer.from([0x58, 0, 0, 0, 4]); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| describe('builds describe command', function () { | ||
| it('describe statement', function () { | ||
| const actual = serializer_1.serialize.describe({ type: 'S', name: 'bang' }); | ||
| var expected = new buffer_list_1.default().addChar('S').addCString('bang').join(true, 'D'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| it('describe unnamed portal', function () { | ||
| const actual = serializer_1.serialize.describe({ type: 'P' }); | ||
| var expected = new buffer_list_1.default().addChar('P').addCString('').join(true, 'D'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| }); | ||
| describe('builds close command', function () { | ||
| it('describe statement', function () { | ||
| const actual = serializer_1.serialize.close({ type: 'S', name: 'bang' }); | ||
| var expected = new buffer_list_1.default().addChar('S').addCString('bang').join(true, 'C'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| it('describe unnamed portal', function () { | ||
| const actual = serializer_1.serialize.close({ type: 'P' }); | ||
| var expected = new buffer_list_1.default().addChar('P').addCString('').join(true, 'C'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| }); | ||
| describe('copy messages', function () { | ||
| it('builds copyFromChunk', () => { | ||
| const actual = serializer_1.serialize.copyData(Buffer.from([1, 2, 3])); | ||
| const expected = new buffer_list_1.default().add(Buffer.from([1, 2, 3])).join(true, 'd'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| it('builds copy fail', () => { | ||
| const actual = serializer_1.serialize.copyFail('err!'); | ||
| const expected = new buffer_list_1.default().addCString('err!').join(true, 'f'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| it('builds copy done', () => { | ||
| const actual = serializer_1.serialize.copyDone(); | ||
| const expected = new buffer_list_1.default().join(true, 'c'); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| }); | ||
| it('builds cancel message', () => { | ||
| const actual = serializer_1.serialize.cancel(3, 4); | ||
| const expected = new buffer_list_1.default().addInt16(1234).addInt16(5678).addInt32(3).addInt32(4).join(true); | ||
| assert_1.default.deepEqual(actual, expected); | ||
| }); | ||
| }); | ||
| //# sourceMappingURL=outbound-serializer.test.js.map |
| {"version":3,"file":"outbound-serializer.test.js","sourceRoot":"","sources":["../src/outbound-serializer.test.ts"],"names":[],"mappings":"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"} |
| /// <reference types="node" /> | ||
| /// <reference types="node" /> | ||
| import { TransformOptions } from 'stream'; | ||
| import { Mode, BackendMessage } from './messages'; | ||
| export declare type Packet = { | ||
| code: number; | ||
| packet: Buffer; | ||
| }; | ||
| declare type StreamOptions = TransformOptions & { | ||
| mode: Mode; | ||
| }; | ||
| export declare type MessageCallback = (msg: BackendMessage) => void; | ||
| export declare class Parser { | ||
| private buffer; | ||
| private bufferLength; | ||
| private bufferOffset; | ||
| private reader; | ||
| private mode; | ||
| constructor(opts?: StreamOptions); | ||
| parse(buffer: Buffer, callback: MessageCallback): void; | ||
| private mergeBuffer; | ||
| private handlePacket; | ||
| private parseReadyForQueryMessage; | ||
| private parseCommandCompleteMessage; | ||
| private parseCopyData; | ||
| private parseCopyInMessage; | ||
| private parseCopyOutMessage; | ||
| private parseCopyMessage; | ||
| private parseNotificationMessage; | ||
| private parseRowDescriptionMessage; | ||
| private parseField; | ||
| private parseParameterDescriptionMessage; | ||
| private parseDataRowMessage; | ||
| private parseParameterStatusMessage; | ||
| private parseBackendKeyData; | ||
| parseAuthenticationResponse(offset: number, length: number, bytes: Buffer): any; | ||
| private parseErrorMessage; | ||
| } | ||
| export {}; |
+304
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.Parser = void 0; | ||
| const messages_1 = require("./messages"); | ||
| const buffer_reader_1 = require("./buffer-reader"); | ||
| // every message is prefixed with a single bye | ||
| const CODE_LENGTH = 1; | ||
| // every message has an int32 length which includes itself but does | ||
| // NOT include the code in the length | ||
| const LEN_LENGTH = 4; | ||
| const HEADER_LENGTH = CODE_LENGTH + LEN_LENGTH; | ||
| const emptyBuffer = Buffer.allocUnsafe(0); | ||
| class Parser { | ||
| constructor(opts) { | ||
| this.buffer = emptyBuffer; | ||
| this.bufferLength = 0; | ||
| this.bufferOffset = 0; | ||
| this.reader = new buffer_reader_1.BufferReader(); | ||
| if ((opts === null || opts === void 0 ? void 0 : opts.mode) === 'binary') { | ||
| throw new Error('Binary mode not supported yet'); | ||
| } | ||
| this.mode = (opts === null || opts === void 0 ? void 0 : opts.mode) || 'text'; | ||
| } | ||
| parse(buffer, callback) { | ||
| this.mergeBuffer(buffer); | ||
| const bufferFullLength = this.bufferOffset + this.bufferLength; | ||
| let offset = this.bufferOffset; | ||
| while (offset + HEADER_LENGTH <= bufferFullLength) { | ||
| // code is 1 byte long - it identifies the message type | ||
| const code = this.buffer[offset]; | ||
| // length is 1 Uint32BE - it is the length of the message EXCLUDING the code | ||
| const length = this.buffer.readUInt32BE(offset + CODE_LENGTH); | ||
| const fullMessageLength = CODE_LENGTH + length; | ||
| if (fullMessageLength + offset <= bufferFullLength) { | ||
| const message = this.handlePacket(offset + HEADER_LENGTH, code, length, this.buffer); | ||
| callback(message); | ||
| offset += fullMessageLength; | ||
| } | ||
| else { | ||
| break; | ||
| } | ||
| } | ||
| if (offset === bufferFullLength) { | ||
| // No more use for the buffer | ||
| this.buffer = emptyBuffer; | ||
| this.bufferLength = 0; | ||
| this.bufferOffset = 0; | ||
| } | ||
| else { | ||
| // Adjust the cursors of remainingBuffer | ||
| this.bufferLength = bufferFullLength - offset; | ||
| this.bufferOffset = offset; | ||
| } | ||
| } | ||
| mergeBuffer(buffer) { | ||
| if (this.bufferLength > 0) { | ||
| const newLength = this.bufferLength + buffer.byteLength; | ||
| const newFullLength = newLength + this.bufferOffset; | ||
| if (newFullLength > this.buffer.byteLength) { | ||
| // We can't concat the new buffer with the remaining one | ||
| let newBuffer; | ||
| if (newLength <= this.buffer.byteLength && this.bufferOffset >= this.bufferLength) { | ||
| // We can move the relevant part to the beginning of the buffer instead of allocating a new buffer | ||
| newBuffer = this.buffer; | ||
| } | ||
| else { | ||
| // Allocate a new larger buffer | ||
| let newBufferLength = this.buffer.byteLength * 2; | ||
| while (newLength >= newBufferLength) { | ||
| newBufferLength *= 2; | ||
| } | ||
| newBuffer = Buffer.allocUnsafe(newBufferLength); | ||
| } | ||
| // Move the remaining buffer to the new one | ||
| this.buffer.copy(newBuffer, 0, this.bufferOffset, this.bufferOffset + this.bufferLength); | ||
| this.buffer = newBuffer; | ||
| this.bufferOffset = 0; | ||
| } | ||
| // Concat the new buffer with the remaining one | ||
| buffer.copy(this.buffer, this.bufferOffset + this.bufferLength); | ||
| this.bufferLength = newLength; | ||
| } | ||
| else { | ||
| this.buffer = buffer; | ||
| this.bufferOffset = 0; | ||
| this.bufferLength = buffer.byteLength; | ||
| } | ||
| } | ||
| handlePacket(offset, code, length, bytes) { | ||
| switch (code) { | ||
| case 50 /* MessageCodes.BindComplete */: | ||
| return messages_1.bindComplete; | ||
| case 49 /* MessageCodes.ParseComplete */: | ||
| return messages_1.parseComplete; | ||
| case 51 /* MessageCodes.CloseComplete */: | ||
| return messages_1.closeComplete; | ||
| case 110 /* MessageCodes.NoData */: | ||
| return messages_1.noData; | ||
| case 115 /* MessageCodes.PortalSuspended */: | ||
| return messages_1.portalSuspended; | ||
| case 99 /* MessageCodes.CopyDone */: | ||
| return messages_1.copyDone; | ||
| case 87 /* MessageCodes.ReplicationStart */: | ||
| return messages_1.replicationStart; | ||
| case 73 /* MessageCodes.EmptyQuery */: | ||
| return messages_1.emptyQuery; | ||
| case 68 /* MessageCodes.DataRow */: | ||
| return this.parseDataRowMessage(offset, length, bytes); | ||
| case 67 /* MessageCodes.CommandComplete */: | ||
| return this.parseCommandCompleteMessage(offset, length, bytes); | ||
| case 90 /* MessageCodes.ReadyForQuery */: | ||
| return this.parseReadyForQueryMessage(offset, length, bytes); | ||
| case 65 /* MessageCodes.NotificationResponse */: | ||
| return this.parseNotificationMessage(offset, length, bytes); | ||
| case 82 /* MessageCodes.AuthenticationResponse */: | ||
| return this.parseAuthenticationResponse(offset, length, bytes); | ||
| case 83 /* MessageCodes.ParameterStatus */: | ||
| return this.parseParameterStatusMessage(offset, length, bytes); | ||
| case 75 /* MessageCodes.BackendKeyData */: | ||
| return this.parseBackendKeyData(offset, length, bytes); | ||
| case 69 /* MessageCodes.ErrorMessage */: | ||
| return this.parseErrorMessage(offset, length, bytes, 'error'); | ||
| case 78 /* MessageCodes.NoticeMessage */: | ||
| return this.parseErrorMessage(offset, length, bytes, 'notice'); | ||
| case 84 /* MessageCodes.RowDescriptionMessage */: | ||
| return this.parseRowDescriptionMessage(offset, length, bytes); | ||
| case 116 /* MessageCodes.ParameterDescriptionMessage */: | ||
| return this.parseParameterDescriptionMessage(offset, length, bytes); | ||
| case 71 /* MessageCodes.CopyIn */: | ||
| return this.parseCopyInMessage(offset, length, bytes); | ||
| case 72 /* MessageCodes.CopyOut */: | ||
| return this.parseCopyOutMessage(offset, length, bytes); | ||
| case 100 /* MessageCodes.CopyData */: | ||
| return this.parseCopyData(offset, length, bytes); | ||
| default: | ||
| return new messages_1.DatabaseError('received invalid response: ' + code.toString(16), length, 'error'); | ||
| } | ||
| } | ||
| parseReadyForQueryMessage(offset, length, bytes) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const status = this.reader.string(1); | ||
| return new messages_1.ReadyForQueryMessage(length, status); | ||
| } | ||
| parseCommandCompleteMessage(offset, length, bytes) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const text = this.reader.cstring(); | ||
| return new messages_1.CommandCompleteMessage(length, text); | ||
| } | ||
| parseCopyData(offset, length, bytes) { | ||
| const chunk = bytes.slice(offset, offset + (length - 4)); | ||
| return new messages_1.CopyDataMessage(length, chunk); | ||
| } | ||
| parseCopyInMessage(offset, length, bytes) { | ||
| return this.parseCopyMessage(offset, length, bytes, 'copyInResponse'); | ||
| } | ||
| parseCopyOutMessage(offset, length, bytes) { | ||
| return this.parseCopyMessage(offset, length, bytes, 'copyOutResponse'); | ||
| } | ||
| parseCopyMessage(offset, length, bytes, messageName) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const isBinary = this.reader.byte() !== 0; | ||
| const columnCount = this.reader.int16(); | ||
| const message = new messages_1.CopyResponse(length, messageName, isBinary, columnCount); | ||
| for (let i = 0; i < columnCount; i++) { | ||
| message.columnTypes[i] = this.reader.int16(); | ||
| } | ||
| return message; | ||
| } | ||
| parseNotificationMessage(offset, length, bytes) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const processId = this.reader.int32(); | ||
| const channel = this.reader.cstring(); | ||
| const payload = this.reader.cstring(); | ||
| return new messages_1.NotificationResponseMessage(length, processId, channel, payload); | ||
| } | ||
| parseRowDescriptionMessage(offset, length, bytes) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const fieldCount = this.reader.int16(); | ||
| const message = new messages_1.RowDescriptionMessage(length, fieldCount); | ||
| for (let i = 0; i < fieldCount; i++) { | ||
| message.fields[i] = this.parseField(); | ||
| } | ||
| return message; | ||
| } | ||
| parseField() { | ||
| const name = this.reader.cstring(); | ||
| const tableID = this.reader.uint32(); | ||
| const columnID = this.reader.int16(); | ||
| const dataTypeID = this.reader.uint32(); | ||
| const dataTypeSize = this.reader.int16(); | ||
| const dataTypeModifier = this.reader.int32(); | ||
| const mode = this.reader.int16() === 0 ? 'text' : 'binary'; | ||
| return new messages_1.Field(name, tableID, columnID, dataTypeID, dataTypeSize, dataTypeModifier, mode); | ||
| } | ||
| parseParameterDescriptionMessage(offset, length, bytes) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const parameterCount = this.reader.int16(); | ||
| const message = new messages_1.ParameterDescriptionMessage(length, parameterCount); | ||
| for (let i = 0; i < parameterCount; i++) { | ||
| message.dataTypeIDs[i] = this.reader.int32(); | ||
| } | ||
| return message; | ||
| } | ||
| parseDataRowMessage(offset, length, bytes) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const fieldCount = this.reader.int16(); | ||
| const fields = new Array(fieldCount); | ||
| for (let i = 0; i < fieldCount; i++) { | ||
| const len = this.reader.int32(); | ||
| // a -1 for length means the value of the field is null | ||
| fields[i] = len === -1 ? null : this.reader.string(len); | ||
| } | ||
| return new messages_1.DataRowMessage(length, fields); | ||
| } | ||
| parseParameterStatusMessage(offset, length, bytes) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const name = this.reader.cstring(); | ||
| const value = this.reader.cstring(); | ||
| return new messages_1.ParameterStatusMessage(length, name, value); | ||
| } | ||
| parseBackendKeyData(offset, length, bytes) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const processID = this.reader.int32(); | ||
| const secretKey = this.reader.int32(); | ||
| return new messages_1.BackendKeyDataMessage(length, processID, secretKey); | ||
| } | ||
| parseAuthenticationResponse(offset, length, bytes) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const code = this.reader.int32(); | ||
| // TODO(bmc): maybe better types here | ||
| const message = { | ||
| name: 'authenticationOk', | ||
| length, | ||
| }; | ||
| switch (code) { | ||
| case 0: // AuthenticationOk | ||
| break; | ||
| case 3: // AuthenticationCleartextPassword | ||
| if (message.length === 8) { | ||
| message.name = 'authenticationCleartextPassword'; | ||
| } | ||
| break; | ||
| case 5: // AuthenticationMD5Password | ||
| if (message.length === 12) { | ||
| message.name = 'authenticationMD5Password'; | ||
| const salt = this.reader.bytes(4); | ||
| return new messages_1.AuthenticationMD5Password(length, salt); | ||
| } | ||
| break; | ||
| case 10: // AuthenticationSASL | ||
| message.name = 'authenticationSASL'; | ||
| message.mechanisms = []; | ||
| let mechanism; | ||
| do { | ||
| mechanism = this.reader.cstring(); | ||
| if (mechanism) { | ||
| message.mechanisms.push(mechanism); | ||
| } | ||
| } while (mechanism); | ||
| break; | ||
| case 11: // AuthenticationSASLContinue | ||
| message.name = 'authenticationSASLContinue'; | ||
| message.data = this.reader.string(length - 8); | ||
| break; | ||
| case 12: // AuthenticationSASLFinal | ||
| message.name = 'authenticationSASLFinal'; | ||
| message.data = this.reader.string(length - 8); | ||
| break; | ||
| default: | ||
| throw new Error('Unknown authenticationOk message type ' + code); | ||
| } | ||
| return message; | ||
| } | ||
| parseErrorMessage(offset, length, bytes, name) { | ||
| this.reader.setBuffer(offset, bytes); | ||
| const fields = {}; | ||
| let fieldType = this.reader.string(1); | ||
| while (fieldType !== '\0') { | ||
| fields[fieldType] = this.reader.cstring(); | ||
| fieldType = this.reader.string(1); | ||
| } | ||
| const messageValue = fields.M; | ||
| const message = name === 'notice' ? new messages_1.NoticeMessage(length, messageValue) : new messages_1.DatabaseError(messageValue, length, name); | ||
| message.severity = fields.S; | ||
| message.code = fields.C; | ||
| message.detail = fields.D; | ||
| message.hint = fields.H; | ||
| message.position = fields.P; | ||
| message.internalPosition = fields.p; | ||
| message.internalQuery = fields.q; | ||
| message.where = fields.W; | ||
| message.schema = fields.s; | ||
| message.table = fields.t; | ||
| message.column = fields.c; | ||
| message.dataType = fields.d; | ||
| message.constraint = fields.n; | ||
| message.file = fields.F; | ||
| message.line = fields.L; | ||
| message.routine = fields.R; | ||
| return message; | ||
| } | ||
| } | ||
| exports.Parser = Parser; | ||
| //# sourceMappingURL=parser.js.map |
| {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"} |
| /// <reference types="node" /> | ||
| declare type ParseOpts = { | ||
| name?: string; | ||
| types?: number[]; | ||
| text: string; | ||
| }; | ||
| declare type ValueMapper = (param: any, index: number) => any; | ||
| declare type BindOpts = { | ||
| portal?: string; | ||
| binary?: boolean; | ||
| statement?: string; | ||
| values?: any[]; | ||
| valueMapper?: ValueMapper; | ||
| }; | ||
| declare type ExecOpts = { | ||
| portal?: string; | ||
| rows?: number; | ||
| }; | ||
| declare type PortalOpts = { | ||
| type: 'S' | 'P'; | ||
| name?: string; | ||
| }; | ||
| declare const serialize: { | ||
| startup: (opts: Record<string, string>) => Buffer; | ||
| password: (password: string) => Buffer; | ||
| requestSsl: () => Buffer; | ||
| sendSASLInitialResponseMessage: (mechanism: string, initialResponse: string) => Buffer; | ||
| sendSCRAMClientFinalMessage: (additionalData: string) => Buffer; | ||
| query: (text: string) => Buffer; | ||
| parse: (query: ParseOpts) => Buffer; | ||
| bind: (config?: BindOpts) => Buffer; | ||
| execute: (config?: ExecOpts) => Buffer; | ||
| describe: (msg: PortalOpts) => Buffer; | ||
| close: (msg: PortalOpts) => Buffer; | ||
| flush: () => Buffer; | ||
| sync: () => Buffer; | ||
| end: () => Buffer; | ||
| copyData: (chunk: Buffer) => Buffer; | ||
| copyDone: () => Buffer; | ||
| copyFail: (message: string) => Buffer; | ||
| cancel: (processID: number, secretKey: number) => Buffer; | ||
| }; | ||
| export { serialize }; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.serialize = void 0; | ||
| const buffer_writer_1 = require("./buffer-writer"); | ||
| const writer = new buffer_writer_1.Writer(); | ||
| const startup = (opts) => { | ||
| // protocol version | ||
| writer.addInt16(3).addInt16(0); | ||
| for (const key of Object.keys(opts)) { | ||
| writer.addCString(key).addCString(opts[key]); | ||
| } | ||
| writer.addCString('client_encoding').addCString('UTF8'); | ||
| var bodyBuffer = writer.addCString('').flush(); | ||
| // this message is sent without a code | ||
| var length = bodyBuffer.length + 4; | ||
| return new buffer_writer_1.Writer().addInt32(length).add(bodyBuffer).flush(); | ||
| }; | ||
| const requestSsl = () => { | ||
| const response = Buffer.allocUnsafe(8); | ||
| response.writeInt32BE(8, 0); | ||
| response.writeInt32BE(80877103, 4); | ||
| return response; | ||
| }; | ||
| const password = (password) => { | ||
| return writer.addCString(password).flush(112 /* code.startup */); | ||
| }; | ||
| const sendSASLInitialResponseMessage = function (mechanism, initialResponse) { | ||
| // 0x70 = 'p' | ||
| writer.addCString(mechanism).addInt32(Buffer.byteLength(initialResponse)).addString(initialResponse); | ||
| return writer.flush(112 /* code.startup */); | ||
| }; | ||
| const sendSCRAMClientFinalMessage = function (additionalData) { | ||
| return writer.addString(additionalData).flush(112 /* code.startup */); | ||
| }; | ||
| const query = (text) => { | ||
| return writer.addCString(text).flush(81 /* code.query */); | ||
| }; | ||
| const emptyArray = []; | ||
| const parse = (query) => { | ||
| // expect something like this: | ||
| // { name: 'queryName', | ||
| // text: 'select * from blah', | ||
| // types: ['int8', 'bool'] } | ||
| // normalize missing query names to allow for null | ||
| const name = query.name || ''; | ||
| if (name.length > 63) { | ||
| /* eslint-disable no-console */ | ||
| console.error('Warning! Postgres only supports 63 characters for query names.'); | ||
| console.error('You supplied %s (%s)', name, name.length); | ||
| console.error('This can cause conflicts and silent errors executing queries'); | ||
| /* eslint-enable no-console */ | ||
| } | ||
| const types = query.types || emptyArray; | ||
| var len = types.length; | ||
| var buffer = writer | ||
| .addCString(name) // name of query | ||
| .addCString(query.text) // actual query text | ||
| .addInt16(len); | ||
| for (var i = 0; i < len; i++) { | ||
| buffer.addInt32(types[i]); | ||
| } | ||
| return writer.flush(80 /* code.parse */); | ||
| }; | ||
| const paramWriter = new buffer_writer_1.Writer(); | ||
| const writeValues = function (values, valueMapper) { | ||
| for (let i = 0; i < values.length; i++) { | ||
| const mappedVal = valueMapper ? valueMapper(values[i], i) : values[i]; | ||
| if (mappedVal == null) { | ||
| // add the param type (string) to the writer | ||
| writer.addInt16(0 /* ParamType.STRING */); | ||
| // write -1 to the param writer to indicate null | ||
| paramWriter.addInt32(-1); | ||
| } | ||
| else if (mappedVal instanceof Buffer) { | ||
| // add the param type (binary) to the writer | ||
| writer.addInt16(1 /* ParamType.BINARY */); | ||
| // add the buffer to the param writer | ||
| paramWriter.addInt32(mappedVal.length); | ||
| paramWriter.add(mappedVal); | ||
| } | ||
| else { | ||
| // add the param type (string) to the writer | ||
| writer.addInt16(0 /* ParamType.STRING */); | ||
| paramWriter.addInt32(Buffer.byteLength(mappedVal)); | ||
| paramWriter.addString(mappedVal); | ||
| } | ||
| } | ||
| }; | ||
| const bind = (config = {}) => { | ||
| // normalize config | ||
| const portal = config.portal || ''; | ||
| const statement = config.statement || ''; | ||
| const binary = config.binary || false; | ||
| const values = config.values || emptyArray; | ||
| const len = values.length; | ||
| writer.addCString(portal).addCString(statement); | ||
| writer.addInt16(len); | ||
| writeValues(values, config.valueMapper); | ||
| writer.addInt16(len); | ||
| writer.add(paramWriter.flush()); | ||
| // format code | ||
| writer.addInt16(binary ? 1 /* ParamType.BINARY */ : 0 /* ParamType.STRING */); | ||
| return writer.flush(66 /* code.bind */); | ||
| }; | ||
| const emptyExecute = Buffer.from([69 /* code.execute */, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00]); | ||
| const execute = (config) => { | ||
| // this is the happy path for most queries | ||
| if (!config || (!config.portal && !config.rows)) { | ||
| return emptyExecute; | ||
| } | ||
| const portal = config.portal || ''; | ||
| const rows = config.rows || 0; | ||
| const portalLength = Buffer.byteLength(portal); | ||
| const len = 4 + portalLength + 1 + 4; | ||
| // one extra bit for code | ||
| const buff = Buffer.allocUnsafe(1 + len); | ||
| buff[0] = 69 /* code.execute */; | ||
| buff.writeInt32BE(len, 1); | ||
| buff.write(portal, 5, 'utf-8'); | ||
| buff[portalLength + 5] = 0; // null terminate portal cString | ||
| buff.writeUInt32BE(rows, buff.length - 4); | ||
| return buff; | ||
| }; | ||
| const cancel = (processID, secretKey) => { | ||
| const buffer = Buffer.allocUnsafe(16); | ||
| buffer.writeInt32BE(16, 0); | ||
| buffer.writeInt16BE(1234, 4); | ||
| buffer.writeInt16BE(5678, 6); | ||
| buffer.writeInt32BE(processID, 8); | ||
| buffer.writeInt32BE(secretKey, 12); | ||
| return buffer; | ||
| }; | ||
| const cstringMessage = (code, string) => { | ||
| const stringLen = Buffer.byteLength(string); | ||
| const len = 4 + stringLen + 1; | ||
| // one extra bit for code | ||
| const buffer = Buffer.allocUnsafe(1 + len); | ||
| buffer[0] = code; | ||
| buffer.writeInt32BE(len, 1); | ||
| buffer.write(string, 5, 'utf-8'); | ||
| buffer[len] = 0; // null terminate cString | ||
| return buffer; | ||
| }; | ||
| const emptyDescribePortal = writer.addCString('P').flush(68 /* code.describe */); | ||
| const emptyDescribeStatement = writer.addCString('S').flush(68 /* code.describe */); | ||
| const describe = (msg) => { | ||
| return msg.name | ||
| ? cstringMessage(68 /* code.describe */, `${msg.type}${msg.name || ''}`) | ||
| : msg.type === 'P' | ||
| ? emptyDescribePortal | ||
| : emptyDescribeStatement; | ||
| }; | ||
| const close = (msg) => { | ||
| const text = `${msg.type}${msg.name || ''}`; | ||
| return cstringMessage(67 /* code.close */, text); | ||
| }; | ||
| const copyData = (chunk) => { | ||
| return writer.add(chunk).flush(100 /* code.copyFromChunk */); | ||
| }; | ||
| const copyFail = (message) => { | ||
| return cstringMessage(102 /* code.copyFail */, message); | ||
| }; | ||
| const codeOnlyBuffer = (code) => Buffer.from([code, 0x00, 0x00, 0x00, 0x04]); | ||
| const flushBuffer = codeOnlyBuffer(72 /* code.flush */); | ||
| const syncBuffer = codeOnlyBuffer(83 /* code.sync */); | ||
| const endBuffer = codeOnlyBuffer(88 /* code.end */); | ||
| const copyDoneBuffer = codeOnlyBuffer(99 /* code.copyDone */); | ||
| const serialize = { | ||
| startup, | ||
| password, | ||
| requestSsl, | ||
| sendSASLInitialResponseMessage, | ||
| sendSCRAMClientFinalMessage, | ||
| query, | ||
| parse, | ||
| bind, | ||
| execute, | ||
| describe, | ||
| close, | ||
| flush: () => flushBuffer, | ||
| sync: () => syncBuffer, | ||
| end: () => endBuffer, | ||
| copyData, | ||
| copyDone: () => copyDoneBuffer, | ||
| copyFail, | ||
| cancel, | ||
| }; | ||
| exports.serialize = serialize; | ||
| //# sourceMappingURL=serializer.js.map |
| {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"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"} |
| # pg-protocol | ||
| Low level postgres wire protocol parser and serializer written in Typescript. Used by node-postgres. Needs more documentation. :smile: |
+25
| // file for microbenchmarking | ||
| import { BufferReader } from './buffer-reader' | ||
| const LOOPS = 1000 | ||
| let count = 0 | ||
| let start = Date.now() | ||
| const reader = new BufferReader() | ||
| const buffer = Buffer.from([33, 33, 33, 33, 33, 33, 33, 0]) | ||
| const run = () => { | ||
| if (count > LOOPS) { | ||
| console.log(Date.now() - start) | ||
| return | ||
| } | ||
| count++ | ||
| for (let i = 0; i < LOOPS; i++) { | ||
| reader.setBuffer(0, buffer) | ||
| reader.cstring() | ||
| } | ||
| setImmediate(run) | ||
| } | ||
| run() |
| const emptyBuffer = Buffer.allocUnsafe(0) | ||
| export class BufferReader { | ||
| private buffer: Buffer = emptyBuffer | ||
| // TODO(bmc): support non-utf8 encoding? | ||
| private encoding: string = 'utf-8' | ||
| constructor(private offset: number = 0) {} | ||
| public setBuffer(offset: number, buffer: Buffer): void { | ||
| this.offset = offset | ||
| this.buffer = buffer | ||
| } | ||
| public int16(): number { | ||
| const result = this.buffer.readInt16BE(this.offset) | ||
| this.offset += 2 | ||
| return result | ||
| } | ||
| public byte(): number { | ||
| const result = this.buffer[this.offset] | ||
| this.offset++ | ||
| return result | ||
| } | ||
| public int32(): number { | ||
| const result = this.buffer.readInt32BE(this.offset) | ||
| this.offset += 4 | ||
| return result | ||
| } | ||
| public uint32(): number { | ||
| const result = this.buffer.readUInt32BE(this.offset) | ||
| this.offset += 4 | ||
| return result | ||
| } | ||
| public string(length: number): string { | ||
| const result = this.buffer.toString(this.encoding, this.offset, this.offset + length) | ||
| this.offset += length | ||
| return result | ||
| } | ||
| public cstring(): string { | ||
| const start = this.offset | ||
| let end = start | ||
| while (this.buffer[end++] !== 0) {} | ||
| this.offset = end | ||
| return this.buffer.toString(this.encoding, start, end - 1) | ||
| } | ||
| public bytes(length: number): Buffer { | ||
| const result = this.buffer.slice(this.offset, this.offset + length) | ||
| this.offset += length | ||
| return result | ||
| } | ||
| } |
| //binary data writer tuned for encoding binary specific to the postgres binary protocol | ||
| export class Writer { | ||
| private buffer: Buffer | ||
| private offset: number = 5 | ||
| private headerPosition: number = 0 | ||
| constructor(private size = 256) { | ||
| this.buffer = Buffer.allocUnsafe(size) | ||
| } | ||
| private ensure(size: number): void { | ||
| var remaining = this.buffer.length - this.offset | ||
| if (remaining < size) { | ||
| var oldBuffer = this.buffer | ||
| // exponential growth factor of around ~ 1.5 | ||
| // https://stackoverflow.com/questions/2269063/buffer-growth-strategy | ||
| var newSize = oldBuffer.length + (oldBuffer.length >> 1) + size | ||
| this.buffer = Buffer.allocUnsafe(newSize) | ||
| oldBuffer.copy(this.buffer) | ||
| } | ||
| } | ||
| public addInt32(num: number): Writer { | ||
| this.ensure(4) | ||
| this.buffer[this.offset++] = (num >>> 24) & 0xff | ||
| this.buffer[this.offset++] = (num >>> 16) & 0xff | ||
| this.buffer[this.offset++] = (num >>> 8) & 0xff | ||
| this.buffer[this.offset++] = (num >>> 0) & 0xff | ||
| return this | ||
| } | ||
| public addInt16(num: number): Writer { | ||
| this.ensure(2) | ||
| this.buffer[this.offset++] = (num >>> 8) & 0xff | ||
| this.buffer[this.offset++] = (num >>> 0) & 0xff | ||
| return this | ||
| } | ||
| public addCString(string: string): Writer { | ||
| if (!string) { | ||
| this.ensure(1) | ||
| } else { | ||
| var len = Buffer.byteLength(string) | ||
| this.ensure(len + 1) // +1 for null terminator | ||
| this.buffer.write(string, this.offset, 'utf-8') | ||
| this.offset += len | ||
| } | ||
| this.buffer[this.offset++] = 0 // null terminator | ||
| return this | ||
| } | ||
| public addString(string: string = ''): Writer { | ||
| var len = Buffer.byteLength(string) | ||
| this.ensure(len) | ||
| this.buffer.write(string, this.offset) | ||
| this.offset += len | ||
| return this | ||
| } | ||
| public add(otherBuffer: Buffer): Writer { | ||
| this.ensure(otherBuffer.length) | ||
| otherBuffer.copy(this.buffer, this.offset) | ||
| this.offset += otherBuffer.length | ||
| return this | ||
| } | ||
| private join(code?: number): Buffer { | ||
| if (code) { | ||
| this.buffer[this.headerPosition] = code | ||
| //length is everything in this packet minus the code | ||
| const length = this.offset - (this.headerPosition + 1) | ||
| this.buffer.writeInt32BE(length, this.headerPosition + 1) | ||
| } | ||
| return this.buffer.slice(code ? 0 : 5, this.offset) | ||
| } | ||
| public flush(code?: number): Buffer { | ||
| var result = this.join(code) | ||
| this.offset = 5 | ||
| this.headerPosition = 0 | ||
| this.buffer = Buffer.allocUnsafe(this.size) | ||
| return result | ||
| } | ||
| } |
| import buffers from './testing/test-buffers' | ||
| import BufferList from './testing/buffer-list' | ||
| import { parse } from '.' | ||
| import assert from 'assert' | ||
| import { PassThrough } from 'stream' | ||
| import { BackendMessage } from './messages' | ||
| var authOkBuffer = buffers.authenticationOk() | ||
| var paramStatusBuffer = buffers.parameterStatus('client_encoding', 'UTF8') | ||
| var readyForQueryBuffer = buffers.readyForQuery() | ||
| var backendKeyDataBuffer = buffers.backendKeyData(1, 2) | ||
| var commandCompleteBuffer = buffers.commandComplete('SELECT 3') | ||
| var parseCompleteBuffer = buffers.parseComplete() | ||
| var bindCompleteBuffer = buffers.bindComplete() | ||
| var portalSuspendedBuffer = buffers.portalSuspended() | ||
| var row1 = { | ||
| name: 'id', | ||
| tableID: 1, | ||
| attributeNumber: 2, | ||
| dataTypeID: 3, | ||
| dataTypeSize: 4, | ||
| typeModifier: 5, | ||
| formatCode: 0, | ||
| } | ||
| var oneRowDescBuff = buffers.rowDescription([row1]) | ||
| row1.name = 'bang' | ||
| var twoRowBuf = buffers.rowDescription([ | ||
| row1, | ||
| { | ||
| name: 'whoah', | ||
| tableID: 10, | ||
| attributeNumber: 11, | ||
| dataTypeID: 12, | ||
| dataTypeSize: 13, | ||
| typeModifier: 14, | ||
| formatCode: 0, | ||
| }, | ||
| ]) | ||
| var rowWithBigOids = { | ||
| name: 'bigoid', | ||
| tableID: 3000000001, | ||
| attributeNumber: 2, | ||
| dataTypeID: 3000000003, | ||
| dataTypeSize: 4, | ||
| typeModifier: 5, | ||
| formatCode: 0, | ||
| } | ||
| var bigOidDescBuff = buffers.rowDescription([rowWithBigOids]) | ||
| var emptyRowFieldBuf = new BufferList().addInt16(0).join(true, 'D') | ||
| var emptyRowFieldBuf = buffers.dataRow([]) | ||
| var oneFieldBuf = new BufferList() | ||
| .addInt16(1) // number of fields | ||
| .addInt32(5) // length of bytes of fields | ||
| .addCString('test') | ||
| .join(true, 'D') | ||
| var oneFieldBuf = buffers.dataRow(['test']) | ||
| var expectedAuthenticationOkayMessage = { | ||
| name: 'authenticationOk', | ||
| length: 8, | ||
| } | ||
| var expectedParameterStatusMessage = { | ||
| name: 'parameterStatus', | ||
| parameterName: 'client_encoding', | ||
| parameterValue: 'UTF8', | ||
| length: 25, | ||
| } | ||
| var expectedBackendKeyDataMessage = { | ||
| name: 'backendKeyData', | ||
| processID: 1, | ||
| secretKey: 2, | ||
| } | ||
| var expectedReadyForQueryMessage = { | ||
| name: 'readyForQuery', | ||
| length: 5, | ||
| status: 'I', | ||
| } | ||
| var expectedCommandCompleteMessage = { | ||
| name: 'commandComplete', | ||
| length: 13, | ||
| text: 'SELECT 3', | ||
| } | ||
| var emptyRowDescriptionBuffer = new BufferList() | ||
| .addInt16(0) // number of fields | ||
| .join(true, 'T') | ||
| var expectedEmptyRowDescriptionMessage = { | ||
| name: 'rowDescription', | ||
| length: 6, | ||
| fieldCount: 0, | ||
| fields: [], | ||
| } | ||
| var expectedOneRowMessage = { | ||
| name: 'rowDescription', | ||
| length: 27, | ||
| fieldCount: 1, | ||
| fields: [ | ||
| { | ||
| name: 'id', | ||
| tableID: 1, | ||
| columnID: 2, | ||
| dataTypeID: 3, | ||
| dataTypeSize: 4, | ||
| dataTypeModifier: 5, | ||
| format: 'text', | ||
| }, | ||
| ], | ||
| } | ||
| var expectedTwoRowMessage = { | ||
| name: 'rowDescription', | ||
| length: 53, | ||
| fieldCount: 2, | ||
| fields: [ | ||
| { | ||
| name: 'bang', | ||
| tableID: 1, | ||
| columnID: 2, | ||
| dataTypeID: 3, | ||
| dataTypeSize: 4, | ||
| dataTypeModifier: 5, | ||
| format: 'text', | ||
| }, | ||
| { | ||
| name: 'whoah', | ||
| tableID: 10, | ||
| columnID: 11, | ||
| dataTypeID: 12, | ||
| dataTypeSize: 13, | ||
| dataTypeModifier: 14, | ||
| format: 'text', | ||
| }, | ||
| ], | ||
| } | ||
| var expectedBigOidMessage = { | ||
| name: 'rowDescription', | ||
| length: 31, | ||
| fieldCount: 1, | ||
| fields: [ | ||
| { | ||
| name: 'bigoid', | ||
| tableID: 3000000001, | ||
| columnID: 2, | ||
| dataTypeID: 3000000003, | ||
| dataTypeSize: 4, | ||
| dataTypeModifier: 5, | ||
| format: 'text', | ||
| }, | ||
| ], | ||
| } | ||
| 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('receives and parses ' + expectedMessage.name, async () => { | ||
| const messages = await parseBuffers([buffer]) | ||
| const [lastMessage] = messages | ||
| for (const key in expectedMessage) { | ||
| assert.deepEqual((lastMessage as any)[key], expectedMessage[key]) | ||
| } | ||
| }) | ||
| } | ||
| var plainPasswordBuffer = buffers.authenticationCleartextPassword() | ||
| var md5PasswordBuffer = buffers.authenticationMD5Password() | ||
| var SASLBuffer = buffers.authenticationSASL() | ||
| var SASLContinueBuffer = buffers.authenticationSASLContinue() | ||
| var SASLFinalBuffer = buffers.authenticationSASLFinal() | ||
| var expectedPlainPasswordMessage = { | ||
| name: 'authenticationCleartextPassword', | ||
| } | ||
| var expectedMD5PasswordMessage = { | ||
| name: 'authenticationMD5Password', | ||
| salt: Buffer.from([1, 2, 3, 4]), | ||
| } | ||
| var expectedSASLMessage = { | ||
| name: 'authenticationSASL', | ||
| mechanisms: ['SCRAM-SHA-256'], | ||
| } | ||
| var expectedSASLContinueMessage = { | ||
| name: 'authenticationSASLContinue', | ||
| data: 'data', | ||
| } | ||
| var expectedSASLFinalMessage = { | ||
| name: 'authenticationSASLFinal', | ||
| data: 'data', | ||
| } | ||
| var notificationResponseBuffer = buffers.notification(4, 'hi', 'boom') | ||
| var expectedNotificationResponseMessage = { | ||
| name: 'notification', | ||
| processId: 4, | ||
| channel: 'hi', | ||
| payload: 'boom', | ||
| } | ||
| const parseBuffers = async (buffers: Buffer[]): Promise<BackendMessage[]> => { | ||
| const stream = new PassThrough() | ||
| for (const buffer of buffers) { | ||
| stream.write(buffer) | ||
| } | ||
| stream.end() | ||
| const msgs: BackendMessage[] = [] | ||
| await parse(stream, (msg) => msgs.push(msg)) | ||
| return msgs | ||
| } | ||
| describe('PgPacketStream', function () { | ||
| testForMessage(authOkBuffer, expectedAuthenticationOkayMessage) | ||
| testForMessage(plainPasswordBuffer, expectedPlainPasswordMessage) | ||
| testForMessage(md5PasswordBuffer, expectedMD5PasswordMessage) | ||
| testForMessage(SASLBuffer, expectedSASLMessage) | ||
| testForMessage(SASLContinueBuffer, expectedSASLContinueMessage) | ||
| // this exercises a found bug in the parser: | ||
| // https://github.com/brianc/node-postgres/pull/2210#issuecomment-627626084 | ||
| // and adds a test which is deterministic, rather than relying on network packet chunking | ||
| const extendedSASLContinueBuffer = Buffer.concat([SASLContinueBuffer, Buffer.from([1, 2, 3, 4])]) | ||
| testForMessage(extendedSASLContinueBuffer, expectedSASLContinueMessage) | ||
| testForMessage(SASLFinalBuffer, expectedSASLFinalMessage) | ||
| // this exercises a found bug in the parser: | ||
| // https://github.com/brianc/node-postgres/pull/2210#issuecomment-627626084 | ||
| // and adds a test which is deterministic, rather than relying on network packet chunking | ||
| const extendedSASLFinalBuffer = Buffer.concat([SASLFinalBuffer, Buffer.from([1, 2, 4, 5])]) | ||
| testForMessage(extendedSASLFinalBuffer, expectedSASLFinalMessage) | ||
| testForMessage(paramStatusBuffer, expectedParameterStatusMessage) | ||
| testForMessage(backendKeyDataBuffer, expectedBackendKeyDataMessage) | ||
| testForMessage(readyForQueryBuffer, expectedReadyForQueryMessage) | ||
| testForMessage(commandCompleteBuffer, expectedCommandCompleteMessage) | ||
| testForMessage(notificationResponseBuffer, expectedNotificationResponseMessage) | ||
| testForMessage(buffers.emptyQuery(), { | ||
| name: 'emptyQuery', | ||
| length: 4, | ||
| }) | ||
| testForMessage(Buffer.from([0x6e, 0, 0, 0, 4]), { | ||
| name: 'noData', | ||
| }) | ||
| describe('rowDescription messages', function () { | ||
| testForMessage(emptyRowDescriptionBuffer, expectedEmptyRowDescriptionMessage) | ||
| testForMessage(oneRowDescBuff, expectedOneRowMessage) | ||
| testForMessage(twoRowBuf, expectedTwoRowMessage) | ||
| testForMessage(bigOidDescBuff, expectedBigOidMessage) | ||
| }) | ||
| describe('parameterDescription messages', function () { | ||
| testForMessage(emptyParameterDescriptionBuffer, expectedEmptyParameterDescriptionMessage) | ||
| testForMessage(oneParameterDescBuf, expectedOneParameterMessage) | ||
| testForMessage(twoParameterDescBuf, expectedTwoParameterMessage) | ||
| }) | ||
| describe('parsing rows', function () { | ||
| describe('parsing empty row', function () { | ||
| testForMessage(emptyRowFieldBuf, { | ||
| name: 'dataRow', | ||
| fieldCount: 0, | ||
| }) | ||
| }) | ||
| describe('parsing data row with fields', function () { | ||
| testForMessage(oneFieldBuf, { | ||
| name: 'dataRow', | ||
| fieldCount: 1, | ||
| fields: ['test'], | ||
| }) | ||
| }) | ||
| }) | ||
| describe('notice message', function () { | ||
| // this uses the same logic as error message | ||
| var buff = buffers.notice([{ type: 'C', value: 'code' }]) | ||
| testForMessage(buff, { | ||
| name: 'notice', | ||
| code: 'code', | ||
| }) | ||
| }) | ||
| testForMessage(buffers.error([]), { | ||
| name: 'error', | ||
| }) | ||
| describe('with all the fields', function () { | ||
| var buffer = buffers.error([ | ||
| { | ||
| type: 'S', | ||
| value: 'ERROR', | ||
| }, | ||
| { | ||
| type: 'C', | ||
| value: 'code', | ||
| }, | ||
| { | ||
| type: 'M', | ||
| value: 'message', | ||
| }, | ||
| { | ||
| type: 'D', | ||
| value: 'details', | ||
| }, | ||
| { | ||
| type: 'H', | ||
| value: 'hint', | ||
| }, | ||
| { | ||
| type: 'P', | ||
| value: '100', | ||
| }, | ||
| { | ||
| type: 'p', | ||
| value: '101', | ||
| }, | ||
| { | ||
| type: 'q', | ||
| value: 'query', | ||
| }, | ||
| { | ||
| type: 'W', | ||
| value: 'where', | ||
| }, | ||
| { | ||
| type: 'F', | ||
| value: 'file', | ||
| }, | ||
| { | ||
| type: 'L', | ||
| value: 'line', | ||
| }, | ||
| { | ||
| type: 'R', | ||
| value: 'routine', | ||
| }, | ||
| { | ||
| type: 'Z', // ignored | ||
| value: 'alsdkf', | ||
| }, | ||
| ]) | ||
| testForMessage(buffer, { | ||
| name: 'error', | ||
| severity: 'ERROR', | ||
| code: 'code', | ||
| message: 'message', | ||
| detail: 'details', | ||
| hint: 'hint', | ||
| position: '100', | ||
| internalPosition: '101', | ||
| internalQuery: 'query', | ||
| where: 'where', | ||
| file: 'file', | ||
| line: 'line', | ||
| routine: 'routine', | ||
| }) | ||
| }) | ||
| testForMessage(parseCompleteBuffer, { | ||
| name: 'parseComplete', | ||
| }) | ||
| testForMessage(bindCompleteBuffer, { | ||
| name: 'bindComplete', | ||
| }) | ||
| testForMessage(bindCompleteBuffer, { | ||
| name: 'bindComplete', | ||
| }) | ||
| testForMessage(buffers.closeComplete(), { | ||
| name: 'closeComplete', | ||
| }) | ||
| describe('parses portal suspended message', function () { | ||
| testForMessage(portalSuspendedBuffer, { | ||
| name: 'portalSuspended', | ||
| }) | ||
| }) | ||
| describe('parses replication start message', function () { | ||
| testForMessage(Buffer.from([0x57, 0x00, 0x00, 0x00, 0x04]), { | ||
| name: 'replicationStart', | ||
| length: 4, | ||
| }) | ||
| }) | ||
| describe('copy', () => { | ||
| testForMessage(buffers.copyIn(0), { | ||
| name: 'copyInResponse', | ||
| length: 7, | ||
| binary: false, | ||
| columnTypes: [], | ||
| }) | ||
| testForMessage(buffers.copyIn(2), { | ||
| name: 'copyInResponse', | ||
| length: 11, | ||
| binary: false, | ||
| columnTypes: [0, 1], | ||
| }) | ||
| testForMessage(buffers.copyOut(0), { | ||
| name: 'copyOutResponse', | ||
| length: 7, | ||
| binary: false, | ||
| columnTypes: [], | ||
| }) | ||
| testForMessage(buffers.copyOut(3), { | ||
| name: 'copyOutResponse', | ||
| length: 13, | ||
| binary: false, | ||
| columnTypes: [0, 1, 2], | ||
| }) | ||
| testForMessage(buffers.copyDone(), { | ||
| name: 'copyDone', | ||
| length: 4, | ||
| }) | ||
| testForMessage(buffers.copyData(Buffer.from([5, 6, 7])), { | ||
| name: 'copyData', | ||
| length: 7, | ||
| chunk: Buffer.from([5, 6, 7]), | ||
| }) | ||
| }) | ||
| // since the data message on a stream can randomly divide the incomming | ||
| // tcp packets anywhere, we need to make sure we can parse every single | ||
| // split on a tcp message | ||
| describe('split buffer, single message parsing', function () { | ||
| var fullBuffer = buffers.dataRow([null, 'bang', 'zug zug', null, '!']) | ||
| it('parses when full buffer comes in', async function () { | ||
| const messages = await parseBuffers([fullBuffer]) | ||
| const message = messages[0] as any | ||
| assert.equal(message.fields.length, 5) | ||
| assert.equal(message.fields[0], null) | ||
| assert.equal(message.fields[1], 'bang') | ||
| assert.equal(message.fields[2], 'zug zug') | ||
| assert.equal(message.fields[3], null) | ||
| assert.equal(message.fields[4], '!') | ||
| }) | ||
| var testMessageReceivedAfterSplitAt = async function (split: number) { | ||
| var firstBuffer = Buffer.alloc(fullBuffer.length - split) | ||
| var secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length) | ||
| fullBuffer.copy(firstBuffer, 0, 0) | ||
| fullBuffer.copy(secondBuffer, 0, firstBuffer.length) | ||
| const messages = await parseBuffers([firstBuffer, secondBuffer]) | ||
| const message = messages[0] as any | ||
| assert.equal(message.fields.length, 5) | ||
| assert.equal(message.fields[0], null) | ||
| assert.equal(message.fields[1], 'bang') | ||
| assert.equal(message.fields[2], 'zug zug') | ||
| assert.equal(message.fields[3], null) | ||
| assert.equal(message.fields[4], '!') | ||
| } | ||
| it('parses when split in the middle', function () { | ||
| return testMessageReceivedAfterSplitAt(6) | ||
| }) | ||
| it('parses when split at end', function () { | ||
| return testMessageReceivedAfterSplitAt(2) | ||
| }) | ||
| it('parses when split at beginning', function () { | ||
| return Promise.all([ | ||
| testMessageReceivedAfterSplitAt(fullBuffer.length - 2), | ||
| testMessageReceivedAfterSplitAt(fullBuffer.length - 1), | ||
| testMessageReceivedAfterSplitAt(fullBuffer.length - 5), | ||
| ]) | ||
| }) | ||
| }) | ||
| describe('split buffer, multiple message parsing', function () { | ||
| var dataRowBuffer = buffers.dataRow(['!']) | ||
| var readyForQueryBuffer = buffers.readyForQuery() | ||
| var fullBuffer = Buffer.alloc(dataRowBuffer.length + readyForQueryBuffer.length) | ||
| dataRowBuffer.copy(fullBuffer, 0, 0) | ||
| readyForQueryBuffer.copy(fullBuffer, dataRowBuffer.length, 0) | ||
| var verifyMessages = function (messages: any[]) { | ||
| assert.strictEqual(messages.length, 2) | ||
| assert.deepEqual(messages[0], { | ||
| name: 'dataRow', | ||
| fieldCount: 1, | ||
| length: 11, | ||
| fields: ['!'], | ||
| }) | ||
| assert.equal(messages[0].fields[0], '!') | ||
| assert.deepEqual(messages[1], { | ||
| name: 'readyForQuery', | ||
| length: 5, | ||
| status: 'I', | ||
| }) | ||
| } | ||
| // sanity check | ||
| it('receives both messages when packet is not split', async function () { | ||
| const messages = await parseBuffers([fullBuffer]) | ||
| verifyMessages(messages) | ||
| }) | ||
| var splitAndVerifyTwoMessages = async function (split: number) { | ||
| var firstBuffer = Buffer.alloc(fullBuffer.length - split) | ||
| var secondBuffer = Buffer.alloc(fullBuffer.length - firstBuffer.length) | ||
| fullBuffer.copy(firstBuffer, 0, 0) | ||
| fullBuffer.copy(secondBuffer, 0, firstBuffer.length) | ||
| const messages = await parseBuffers([firstBuffer, secondBuffer]) | ||
| verifyMessages(messages) | ||
| } | ||
| describe('receives both messages when packet is split', function () { | ||
| it('in the middle', function () { | ||
| return splitAndVerifyTwoMessages(11) | ||
| }) | ||
| it('at the front', function () { | ||
| return Promise.all([ | ||
| splitAndVerifyTwoMessages(fullBuffer.length - 1), | ||
| splitAndVerifyTwoMessages(fullBuffer.length - 4), | ||
| splitAndVerifyTwoMessages(fullBuffer.length - 6), | ||
| ]) | ||
| }) | ||
| it('at the end', function () { | ||
| return Promise.all([splitAndVerifyTwoMessages(8), splitAndVerifyTwoMessages(1)]) | ||
| }) | ||
| }) | ||
| }) | ||
| }) |
+11
| import { DatabaseError } from './messages' | ||
| import { serialize } from './serializer' | ||
| import { Parser, MessageCallback } from './parser' | ||
| export function parse(stream: NodeJS.ReadableStream, callback: MessageCallback): Promise<void> { | ||
| const parser = new Parser() | ||
| stream.on('data', (buffer: Buffer) => parser.parse(buffer, callback)) | ||
| return new Promise((resolve) => stream.on('end', () => resolve())) | ||
| } | ||
| export { serialize, DatabaseError } |
+262
| export type Mode = 'text' | 'binary' | ||
| export type MessageName = | ||
| | 'parseComplete' | ||
| | 'bindComplete' | ||
| | 'closeComplete' | ||
| | 'noData' | ||
| | 'portalSuspended' | ||
| | 'replicationStart' | ||
| | 'emptyQuery' | ||
| | 'copyDone' | ||
| | 'copyData' | ||
| | 'rowDescription' | ||
| | 'parameterDescription' | ||
| | 'parameterStatus' | ||
| | 'backendKeyData' | ||
| | 'notification' | ||
| | 'readyForQuery' | ||
| | 'commandComplete' | ||
| | 'dataRow' | ||
| | 'copyInResponse' | ||
| | 'copyOutResponse' | ||
| | 'authenticationOk' | ||
| | 'authenticationMD5Password' | ||
| | 'authenticationCleartextPassword' | ||
| | 'authenticationSASL' | ||
| | 'authenticationSASLContinue' | ||
| | 'authenticationSASLFinal' | ||
| | 'error' | ||
| | 'notice' | ||
| export interface BackendMessage { | ||
| name: MessageName | ||
| length: number | ||
| } | ||
| export const parseComplete: BackendMessage = { | ||
| name: 'parseComplete', | ||
| length: 5, | ||
| } | ||
| export const bindComplete: BackendMessage = { | ||
| name: 'bindComplete', | ||
| length: 5, | ||
| } | ||
| export const closeComplete: BackendMessage = { | ||
| name: 'closeComplete', | ||
| length: 5, | ||
| } | ||
| export const noData: BackendMessage = { | ||
| name: 'noData', | ||
| length: 5, | ||
| } | ||
| export const portalSuspended: BackendMessage = { | ||
| name: 'portalSuspended', | ||
| length: 5, | ||
| } | ||
| export const replicationStart: BackendMessage = { | ||
| name: 'replicationStart', | ||
| length: 4, | ||
| } | ||
| export const emptyQuery: BackendMessage = { | ||
| name: 'emptyQuery', | ||
| length: 4, | ||
| } | ||
| export const copyDone: BackendMessage = { | ||
| name: 'copyDone', | ||
| length: 4, | ||
| } | ||
| interface NoticeOrError { | ||
| message: string | undefined | ||
| severity: string | undefined | ||
| code: string | undefined | ||
| detail: string | undefined | ||
| hint: string | undefined | ||
| position: string | undefined | ||
| internalPosition: string | undefined | ||
| internalQuery: string | undefined | ||
| where: string | undefined | ||
| schema: string | undefined | ||
| table: string | undefined | ||
| column: string | undefined | ||
| dataType: string | undefined | ||
| constraint: string | undefined | ||
| file: string | undefined | ||
| line: string | undefined | ||
| routine: string | undefined | ||
| } | ||
| export class DatabaseError extends Error implements NoticeOrError { | ||
| public severity: string | undefined | ||
| public code: string | undefined | ||
| public detail: string | undefined | ||
| public hint: string | undefined | ||
| public position: string | undefined | ||
| public internalPosition: string | undefined | ||
| public internalQuery: string | undefined | ||
| public where: string | undefined | ||
| public schema: string | undefined | ||
| public table: string | undefined | ||
| public column: string | undefined | ||
| public dataType: string | undefined | ||
| public constraint: string | undefined | ||
| public file: string | undefined | ||
| public line: string | undefined | ||
| public routine: string | undefined | ||
| constructor( | ||
| message: string, | ||
| public readonly length: number, | ||
| public readonly name: MessageName | ||
| ) { | ||
| super(message) | ||
| } | ||
| } | ||
| export class CopyDataMessage { | ||
| public readonly name = 'copyData' | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly chunk: Buffer | ||
| ) {} | ||
| } | ||
| export class CopyResponse { | ||
| public readonly columnTypes: number[] | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly name: MessageName, | ||
| public readonly binary: boolean, | ||
| columnCount: number | ||
| ) { | ||
| this.columnTypes = new Array(columnCount) | ||
| } | ||
| } | ||
| export class Field { | ||
| constructor( | ||
| public readonly name: string, | ||
| public readonly tableID: number, | ||
| public readonly columnID: number, | ||
| public readonly dataTypeID: number, | ||
| public readonly dataTypeSize: number, | ||
| public readonly dataTypeModifier: number, | ||
| public readonly format: Mode | ||
| ) {} | ||
| } | ||
| export class RowDescriptionMessage { | ||
| public readonly name: MessageName = 'rowDescription' | ||
| public readonly fields: Field[] | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly fieldCount: number | ||
| ) { | ||
| this.fields = new Array(this.fieldCount) | ||
| } | ||
| } | ||
| export class ParameterDescriptionMessage { | ||
| public readonly name: 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 = 'parameterStatus' | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly parameterName: string, | ||
| public readonly parameterValue: string | ||
| ) {} | ||
| } | ||
| export class AuthenticationMD5Password implements BackendMessage { | ||
| public readonly name: MessageName = 'authenticationMD5Password' | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly salt: Buffer | ||
| ) {} | ||
| } | ||
| export class BackendKeyDataMessage { | ||
| public readonly name: MessageName = 'backendKeyData' | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly processID: number, | ||
| public readonly secretKey: number | ||
| ) {} | ||
| } | ||
| export class NotificationResponseMessage { | ||
| public readonly name: MessageName = 'notification' | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly processId: number, | ||
| public readonly channel: string, | ||
| public readonly payload: string | ||
| ) {} | ||
| } | ||
| export class ReadyForQueryMessage { | ||
| public readonly name: MessageName = 'readyForQuery' | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly status: string | ||
| ) {} | ||
| } | ||
| export class CommandCompleteMessage { | ||
| public readonly name: MessageName = 'commandComplete' | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly text: string | ||
| ) {} | ||
| } | ||
| export class DataRowMessage { | ||
| public readonly fieldCount: number | ||
| public readonly name: MessageName = 'dataRow' | ||
| constructor( | ||
| public length: number, | ||
| public fields: any[] | ||
| ) { | ||
| this.fieldCount = fields.length | ||
| } | ||
| } | ||
| export class NoticeMessage implements BackendMessage, NoticeOrError { | ||
| constructor( | ||
| public readonly length: number, | ||
| public readonly message: string | undefined | ||
| ) {} | ||
| public readonly name = 'notice' | ||
| public severity: string | undefined | ||
| public code: string | undefined | ||
| public detail: string | undefined | ||
| public hint: string | undefined | ||
| public position: string | undefined | ||
| public internalPosition: string | undefined | ||
| public internalQuery: string | undefined | ||
| public where: string | undefined | ||
| public schema: string | undefined | ||
| public table: string | undefined | ||
| public column: string | undefined | ||
| public dataType: string | undefined | ||
| public constraint: string | undefined | ||
| public file: string | undefined | ||
| public line: string | undefined | ||
| public routine: string | undefined | ||
| } |
| import assert from 'assert' | ||
| import { serialize } from './serializer' | ||
| import BufferList from './testing/buffer-list' | ||
| describe('serializer', () => { | ||
| it('builds startup message', function () { | ||
| const actual = serialize.startup({ | ||
| user: 'brian', | ||
| database: 'bang', | ||
| }) | ||
| assert.deepEqual( | ||
| actual, | ||
| new BufferList() | ||
| .addInt16(3) | ||
| .addInt16(0) | ||
| .addCString('user') | ||
| .addCString('brian') | ||
| .addCString('database') | ||
| .addCString('bang') | ||
| .addCString('client_encoding') | ||
| .addCString('UTF8') | ||
| .addCString('') | ||
| .join(true) | ||
| ) | ||
| }) | ||
| it('builds password message', function () { | ||
| const actual = serialize.password('!') | ||
| assert.deepEqual(actual, new BufferList().addCString('!').join(true, 'p')) | ||
| }) | ||
| it('builds request ssl message', function () { | ||
| const actual = serialize.requestSsl() | ||
| const expected = new BufferList().addInt32(80877103).join(true) | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| it('builds SASLInitialResponseMessage message', function () { | ||
| const actual = serialize.sendSASLInitialResponseMessage('mech', 'data') | ||
| assert.deepEqual(actual, new BufferList().addCString('mech').addInt32(4).addString('data').join(true, 'p')) | ||
| }) | ||
| it('builds SCRAMClientFinalMessage message', function () { | ||
| const actual = serialize.sendSCRAMClientFinalMessage('data') | ||
| assert.deepEqual(actual, new BufferList().addString('data').join(true, 'p')) | ||
| }) | ||
| it('builds query message', function () { | ||
| var txt = 'select * from boom' | ||
| const actual = serialize.query(txt) | ||
| assert.deepEqual(actual, new BufferList().addCString(txt).join(true, 'Q')) | ||
| }) | ||
| describe('parse message', () => { | ||
| it('builds parse message', function () { | ||
| const actual = serialize.parse({ text: '!' }) | ||
| var expected = new BufferList().addCString('').addCString('!').addInt16(0).join(true, 'P') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| it('builds parse message with named query', function () { | ||
| const actual = serialize.parse({ | ||
| name: 'boom', | ||
| text: 'select * from boom', | ||
| types: [], | ||
| }) | ||
| var expected = new BufferList().addCString('boom').addCString('select * from boom').addInt16(0).join(true, 'P') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| it('with multiple parameters', function () { | ||
| const actual = serialize.parse({ | ||
| name: 'force', | ||
| text: 'select * from bang where name = $1', | ||
| types: [1, 2, 3, 4], | ||
| }) | ||
| var expected = new BufferList() | ||
| .addCString('force') | ||
| .addCString('select * from bang where name = $1') | ||
| .addInt16(4) | ||
| .addInt32(1) | ||
| .addInt32(2) | ||
| .addInt32(3) | ||
| .addInt32(4) | ||
| .join(true, 'P') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| }) | ||
| describe('bind messages', function () { | ||
| it('with no values', function () { | ||
| const actual = serialize.bind() | ||
| var expectedBuffer = new BufferList() | ||
| .addCString('') | ||
| .addCString('') | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .join(true, 'B') | ||
| assert.deepEqual(actual, expectedBuffer) | ||
| }) | ||
| it('with named statement, portal, and values', function () { | ||
| const actual = serialize.bind({ | ||
| portal: 'bang', | ||
| statement: 'woo', | ||
| values: ['1', 'hi', null, 'zing'], | ||
| }) | ||
| var expectedBuffer = new BufferList() | ||
| .addCString('bang') // portal name | ||
| .addCString('woo') // statement name | ||
| .addInt16(4) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(4) | ||
| .addInt32(1) | ||
| .add(Buffer.from('1')) | ||
| .addInt32(2) | ||
| .add(Buffer.from('hi')) | ||
| .addInt32(-1) | ||
| .addInt32(4) | ||
| .add(Buffer.from('zing')) | ||
| .addInt16(0) | ||
| .join(true, 'B') | ||
| assert.deepEqual(actual, expectedBuffer) | ||
| }) | ||
| }) | ||
| it('with custom valueMapper', function () { | ||
| const actual = serialize.bind({ | ||
| portal: 'bang', | ||
| statement: 'woo', | ||
| values: ['1', 'hi', null, 'zing'], | ||
| valueMapper: () => null, | ||
| }) | ||
| var expectedBuffer = new BufferList() | ||
| .addCString('bang') // portal name | ||
| .addCString('woo') // statement name | ||
| .addInt16(4) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(0) | ||
| .addInt16(4) | ||
| .addInt32(-1) | ||
| .addInt32(-1) | ||
| .addInt32(-1) | ||
| .addInt32(-1) | ||
| .addInt16(0) | ||
| .join(true, 'B') | ||
| assert.deepEqual(actual, expectedBuffer) | ||
| }) | ||
| it('with named statement, portal, and buffer value', function () { | ||
| const actual = serialize.bind({ | ||
| portal: 'bang', | ||
| statement: 'woo', | ||
| values: ['1', 'hi', null, Buffer.from('zing', 'utf8')], | ||
| }) | ||
| var expectedBuffer = new BufferList() | ||
| .addCString('bang') // portal name | ||
| .addCString('woo') // statement name | ||
| .addInt16(4) // value count | ||
| .addInt16(0) // string | ||
| .addInt16(0) // string | ||
| .addInt16(0) // string | ||
| .addInt16(1) // binary | ||
| .addInt16(4) | ||
| .addInt32(1) | ||
| .add(Buffer.from('1')) | ||
| .addInt32(2) | ||
| .add(Buffer.from('hi')) | ||
| .addInt32(-1) | ||
| .addInt32(4) | ||
| .add(Buffer.from('zing', 'utf-8')) | ||
| .addInt16(0) | ||
| .join(true, 'B') | ||
| assert.deepEqual(actual, expectedBuffer) | ||
| }) | ||
| describe('builds execute message', function () { | ||
| it('for unamed portal with no row limit', function () { | ||
| const actual = serialize.execute() | ||
| var expectedBuffer = new BufferList().addCString('').addInt32(0).join(true, 'E') | ||
| assert.deepEqual(actual, expectedBuffer) | ||
| }) | ||
| it('for named portal with row limit', function () { | ||
| const actual = serialize.execute({ | ||
| portal: 'my favorite portal', | ||
| rows: 100, | ||
| }) | ||
| var expectedBuffer = new BufferList().addCString('my favorite portal').addInt32(100).join(true, 'E') | ||
| assert.deepEqual(actual, expectedBuffer) | ||
| }) | ||
| }) | ||
| it('builds flush command', function () { | ||
| const actual = serialize.flush() | ||
| var expected = new BufferList().join(true, 'H') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| it('builds sync command', function () { | ||
| const actual = serialize.sync() | ||
| var expected = new BufferList().join(true, 'S') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| it('builds end command', function () { | ||
| const actual = serialize.end() | ||
| var expected = Buffer.from([0x58, 0, 0, 0, 4]) | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| describe('builds describe command', function () { | ||
| it('describe statement', function () { | ||
| const actual = serialize.describe({ type: 'S', name: 'bang' }) | ||
| var expected = new BufferList().addChar('S').addCString('bang').join(true, 'D') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| it('describe unnamed portal', function () { | ||
| const actual = serialize.describe({ type: 'P' }) | ||
| var expected = new BufferList().addChar('P').addCString('').join(true, 'D') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| }) | ||
| describe('builds close command', function () { | ||
| it('describe statement', function () { | ||
| const actual = serialize.close({ type: 'S', name: 'bang' }) | ||
| var expected = new BufferList().addChar('S').addCString('bang').join(true, 'C') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| it('describe unnamed portal', function () { | ||
| const actual = serialize.close({ type: 'P' }) | ||
| var expected = new BufferList().addChar('P').addCString('').join(true, 'C') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| }) | ||
| describe('copy messages', function () { | ||
| it('builds copyFromChunk', () => { | ||
| const actual = serialize.copyData(Buffer.from([1, 2, 3])) | ||
| const expected = new BufferList().add(Buffer.from([1, 2, 3])).join(true, 'd') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| it('builds copy fail', () => { | ||
| const actual = serialize.copyFail('err!') | ||
| const expected = new BufferList().addCString('err!').join(true, 'f') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| it('builds copy done', () => { | ||
| const actual = serialize.copyDone() | ||
| const expected = new BufferList().join(true, 'c') | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| }) | ||
| it('builds cancel message', () => { | ||
| const actual = serialize.cancel(3, 4) | ||
| const expected = new BufferList().addInt16(1234).addInt16(5678).addInt32(3).addInt32(4).join(true) | ||
| assert.deepEqual(actual, expected) | ||
| }) | ||
| }) |
+388
| import { TransformOptions } from 'stream' | ||
| import { | ||
| Mode, | ||
| bindComplete, | ||
| parseComplete, | ||
| closeComplete, | ||
| noData, | ||
| portalSuspended, | ||
| copyDone, | ||
| replicationStart, | ||
| emptyQuery, | ||
| ReadyForQueryMessage, | ||
| CommandCompleteMessage, | ||
| CopyDataMessage, | ||
| CopyResponse, | ||
| NotificationResponseMessage, | ||
| RowDescriptionMessage, | ||
| ParameterDescriptionMessage, | ||
| Field, | ||
| DataRowMessage, | ||
| ParameterStatusMessage, | ||
| BackendKeyDataMessage, | ||
| DatabaseError, | ||
| BackendMessage, | ||
| MessageName, | ||
| AuthenticationMD5Password, | ||
| NoticeMessage, | ||
| } from './messages' | ||
| import { BufferReader } from './buffer-reader' | ||
| // every message is prefixed with a single bye | ||
| const CODE_LENGTH = 1 | ||
| // every message has an int32 length which includes itself but does | ||
| // NOT include the code in the length | ||
| const LEN_LENGTH = 4 | ||
| const HEADER_LENGTH = CODE_LENGTH + LEN_LENGTH | ||
| export type Packet = { | ||
| code: number | ||
| packet: Buffer | ||
| } | ||
| const emptyBuffer = Buffer.allocUnsafe(0) | ||
| type StreamOptions = TransformOptions & { | ||
| mode: Mode | ||
| } | ||
| const enum MessageCodes { | ||
| DataRow = 0x44, // D | ||
| ParseComplete = 0x31, // 1 | ||
| BindComplete = 0x32, // 2 | ||
| CloseComplete = 0x33, // 3 | ||
| CommandComplete = 0x43, // C | ||
| ReadyForQuery = 0x5a, // Z | ||
| NoData = 0x6e, // n | ||
| NotificationResponse = 0x41, // A | ||
| AuthenticationResponse = 0x52, // R | ||
| ParameterStatus = 0x53, // S | ||
| BackendKeyData = 0x4b, // K | ||
| ErrorMessage = 0x45, // E | ||
| NoticeMessage = 0x4e, // N | ||
| RowDescriptionMessage = 0x54, // T | ||
| ParameterDescriptionMessage = 0x74, // t | ||
| PortalSuspended = 0x73, // s | ||
| ReplicationStart = 0x57, // W | ||
| EmptyQuery = 0x49, // I | ||
| CopyIn = 0x47, // G | ||
| CopyOut = 0x48, // H | ||
| CopyDone = 0x63, // c | ||
| CopyData = 0x64, // d | ||
| } | ||
| export type MessageCallback = (msg: BackendMessage) => void | ||
| export class Parser { | ||
| private buffer: Buffer = emptyBuffer | ||
| private bufferLength: number = 0 | ||
| private bufferOffset: number = 0 | ||
| private reader = new BufferReader() | ||
| private mode: Mode | ||
| constructor(opts?: StreamOptions) { | ||
| if (opts?.mode === 'binary') { | ||
| throw new Error('Binary mode not supported yet') | ||
| } | ||
| this.mode = opts?.mode || 'text' | ||
| } | ||
| public parse(buffer: Buffer, callback: MessageCallback) { | ||
| this.mergeBuffer(buffer) | ||
| const bufferFullLength = this.bufferOffset + this.bufferLength | ||
| let offset = this.bufferOffset | ||
| while (offset + HEADER_LENGTH <= bufferFullLength) { | ||
| // code is 1 byte long - it identifies the message type | ||
| const code = this.buffer[offset] | ||
| // length is 1 Uint32BE - it is the length of the message EXCLUDING the code | ||
| const length = this.buffer.readUInt32BE(offset + CODE_LENGTH) | ||
| const fullMessageLength = CODE_LENGTH + length | ||
| if (fullMessageLength + offset <= bufferFullLength) { | ||
| const message = this.handlePacket(offset + HEADER_LENGTH, code, length, this.buffer) | ||
| callback(message) | ||
| offset += fullMessageLength | ||
| } else { | ||
| break | ||
| } | ||
| } | ||
| if (offset === bufferFullLength) { | ||
| // No more use for the buffer | ||
| this.buffer = emptyBuffer | ||
| this.bufferLength = 0 | ||
| this.bufferOffset = 0 | ||
| } else { | ||
| // Adjust the cursors of remainingBuffer | ||
| this.bufferLength = bufferFullLength - offset | ||
| this.bufferOffset = offset | ||
| } | ||
| } | ||
| private mergeBuffer(buffer: Buffer): void { | ||
| if (this.bufferLength > 0) { | ||
| const newLength = this.bufferLength + buffer.byteLength | ||
| const newFullLength = newLength + this.bufferOffset | ||
| if (newFullLength > this.buffer.byteLength) { | ||
| // We can't concat the new buffer with the remaining one | ||
| let newBuffer: Buffer | ||
| if (newLength <= this.buffer.byteLength && this.bufferOffset >= this.bufferLength) { | ||
| // We can move the relevant part to the beginning of the buffer instead of allocating a new buffer | ||
| newBuffer = this.buffer | ||
| } else { | ||
| // Allocate a new larger buffer | ||
| let newBufferLength = this.buffer.byteLength * 2 | ||
| while (newLength >= newBufferLength) { | ||
| newBufferLength *= 2 | ||
| } | ||
| newBuffer = Buffer.allocUnsafe(newBufferLength) | ||
| } | ||
| // Move the remaining buffer to the new one | ||
| this.buffer.copy(newBuffer, 0, this.bufferOffset, this.bufferOffset + this.bufferLength) | ||
| this.buffer = newBuffer | ||
| this.bufferOffset = 0 | ||
| } | ||
| // Concat the new buffer with the remaining one | ||
| buffer.copy(this.buffer, this.bufferOffset + this.bufferLength) | ||
| this.bufferLength = newLength | ||
| } else { | ||
| this.buffer = buffer | ||
| this.bufferOffset = 0 | ||
| this.bufferLength = buffer.byteLength | ||
| } | ||
| } | ||
| private handlePacket(offset: number, code: number, length: number, bytes: Buffer): BackendMessage { | ||
| switch (code) { | ||
| case MessageCodes.BindComplete: | ||
| return bindComplete | ||
| case MessageCodes.ParseComplete: | ||
| return parseComplete | ||
| case MessageCodes.CloseComplete: | ||
| return closeComplete | ||
| case MessageCodes.NoData: | ||
| return noData | ||
| case MessageCodes.PortalSuspended: | ||
| return portalSuspended | ||
| case MessageCodes.CopyDone: | ||
| return copyDone | ||
| case MessageCodes.ReplicationStart: | ||
| return replicationStart | ||
| case MessageCodes.EmptyQuery: | ||
| return emptyQuery | ||
| case MessageCodes.DataRow: | ||
| return this.parseDataRowMessage(offset, length, bytes) | ||
| case MessageCodes.CommandComplete: | ||
| return this.parseCommandCompleteMessage(offset, length, bytes) | ||
| case MessageCodes.ReadyForQuery: | ||
| return this.parseReadyForQueryMessage(offset, length, bytes) | ||
| case MessageCodes.NotificationResponse: | ||
| return this.parseNotificationMessage(offset, length, bytes) | ||
| case MessageCodes.AuthenticationResponse: | ||
| return this.parseAuthenticationResponse(offset, length, bytes) | ||
| case MessageCodes.ParameterStatus: | ||
| return this.parseParameterStatusMessage(offset, length, bytes) | ||
| case MessageCodes.BackendKeyData: | ||
| return this.parseBackendKeyData(offset, length, bytes) | ||
| case MessageCodes.ErrorMessage: | ||
| return this.parseErrorMessage(offset, length, bytes, 'error') | ||
| case MessageCodes.NoticeMessage: | ||
| return this.parseErrorMessage(offset, length, bytes, '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: | ||
| return this.parseCopyOutMessage(offset, length, bytes) | ||
| case MessageCodes.CopyData: | ||
| return this.parseCopyData(offset, length, bytes) | ||
| default: | ||
| return new DatabaseError('received invalid response: ' + code.toString(16), length, 'error') | ||
| } | ||
| } | ||
| private parseReadyForQueryMessage(offset: number, length: number, bytes: Buffer) { | ||
| this.reader.setBuffer(offset, bytes) | ||
| const status = this.reader.string(1) | ||
| return new ReadyForQueryMessage(length, status) | ||
| } | ||
| private parseCommandCompleteMessage(offset: number, length: number, bytes: Buffer) { | ||
| this.reader.setBuffer(offset, bytes) | ||
| const text = this.reader.cstring() | ||
| return new CommandCompleteMessage(length, text) | ||
| } | ||
| private parseCopyData(offset: number, length: number, bytes: Buffer) { | ||
| const chunk = bytes.slice(offset, offset + (length - 4)) | ||
| return new CopyDataMessage(length, chunk) | ||
| } | ||
| private parseCopyInMessage(offset: number, length: number, bytes: Buffer) { | ||
| return this.parseCopyMessage(offset, length, bytes, 'copyInResponse') | ||
| } | ||
| private parseCopyOutMessage(offset: number, length: number, bytes: Buffer) { | ||
| return this.parseCopyMessage(offset, length, bytes, 'copyOutResponse') | ||
| } | ||
| private parseCopyMessage(offset: number, length: number, bytes: Buffer, messageName: MessageName) { | ||
| this.reader.setBuffer(offset, bytes) | ||
| const isBinary = this.reader.byte() !== 0 | ||
| const columnCount = this.reader.int16() | ||
| const message = new CopyResponse(length, messageName, isBinary, columnCount) | ||
| for (let i = 0; i < columnCount; i++) { | ||
| message.columnTypes[i] = this.reader.int16() | ||
| } | ||
| return message | ||
| } | ||
| private parseNotificationMessage(offset: number, length: number, bytes: Buffer) { | ||
| this.reader.setBuffer(offset, bytes) | ||
| const processId = this.reader.int32() | ||
| const channel = this.reader.cstring() | ||
| const payload = this.reader.cstring() | ||
| return new NotificationResponseMessage(length, processId, channel, payload) | ||
| } | ||
| private parseRowDescriptionMessage(offset: number, length: number, bytes: Buffer) { | ||
| this.reader.setBuffer(offset, bytes) | ||
| const fieldCount = this.reader.int16() | ||
| const message = new RowDescriptionMessage(length, fieldCount) | ||
| for (let i = 0; i < fieldCount; i++) { | ||
| message.fields[i] = this.parseField() | ||
| } | ||
| return message | ||
| } | ||
| private parseField(): Field { | ||
| const name = this.reader.cstring() | ||
| const tableID = this.reader.uint32() | ||
| const columnID = this.reader.int16() | ||
| const dataTypeID = this.reader.uint32() | ||
| const dataTypeSize = this.reader.int16() | ||
| const dataTypeModifier = this.reader.int32() | ||
| const mode = this.reader.int16() === 0 ? 'text' : 'binary' | ||
| 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() | ||
| const fields: any[] = new Array(fieldCount) | ||
| for (let i = 0; i < fieldCount; i++) { | ||
| const len = this.reader.int32() | ||
| // a -1 for length means the value of the field is null | ||
| fields[i] = len === -1 ? null : this.reader.string(len) | ||
| } | ||
| return new DataRowMessage(length, fields) | ||
| } | ||
| private parseParameterStatusMessage(offset: number, length: number, bytes: Buffer) { | ||
| this.reader.setBuffer(offset, bytes) | ||
| const name = this.reader.cstring() | ||
| const value = this.reader.cstring() | ||
| return new ParameterStatusMessage(length, name, value) | ||
| } | ||
| private parseBackendKeyData(offset: number, length: number, bytes: Buffer) { | ||
| this.reader.setBuffer(offset, bytes) | ||
| const processID = this.reader.int32() | ||
| const secretKey = this.reader.int32() | ||
| return new BackendKeyDataMessage(length, processID, secretKey) | ||
| } | ||
| public parseAuthenticationResponse(offset: number, length: number, bytes: Buffer) { | ||
| this.reader.setBuffer(offset, bytes) | ||
| const code = this.reader.int32() | ||
| // TODO(bmc): maybe better types here | ||
| const message: BackendMessage & any = { | ||
| name: 'authenticationOk', | ||
| length, | ||
| } | ||
| switch (code) { | ||
| case 0: // AuthenticationOk | ||
| break | ||
| case 3: // AuthenticationCleartextPassword | ||
| if (message.length === 8) { | ||
| message.name = 'authenticationCleartextPassword' | ||
| } | ||
| break | ||
| case 5: // AuthenticationMD5Password | ||
| if (message.length === 12) { | ||
| message.name = 'authenticationMD5Password' | ||
| const salt = this.reader.bytes(4) | ||
| return new AuthenticationMD5Password(length, salt) | ||
| } | ||
| break | ||
| case 10: // AuthenticationSASL | ||
| message.name = 'authenticationSASL' | ||
| message.mechanisms = [] | ||
| let mechanism: string | ||
| do { | ||
| mechanism = this.reader.cstring() | ||
| if (mechanism) { | ||
| message.mechanisms.push(mechanism) | ||
| } | ||
| } while (mechanism) | ||
| break | ||
| case 11: // AuthenticationSASLContinue | ||
| message.name = 'authenticationSASLContinue' | ||
| message.data = this.reader.string(length - 8) | ||
| break | ||
| case 12: // AuthenticationSASLFinal | ||
| message.name = 'authenticationSASLFinal' | ||
| message.data = this.reader.string(length - 8) | ||
| break | ||
| default: | ||
| throw new Error('Unknown authenticationOk message type ' + code) | ||
| } | ||
| return message | ||
| } | ||
| private parseErrorMessage(offset: number, length: number, bytes: Buffer, name: MessageName) { | ||
| this.reader.setBuffer(offset, bytes) | ||
| const fields: Record<string, string> = {} | ||
| let fieldType = this.reader.string(1) | ||
| while (fieldType !== '\0') { | ||
| fields[fieldType] = this.reader.cstring() | ||
| fieldType = this.reader.string(1) | ||
| } | ||
| const messageValue = fields.M | ||
| const message = | ||
| name === 'notice' ? new NoticeMessage(length, messageValue) : new DatabaseError(messageValue, length, name) | ||
| message.severity = fields.S | ||
| message.code = fields.C | ||
| message.detail = fields.D | ||
| message.hint = fields.H | ||
| message.position = fields.P | ||
| message.internalPosition = fields.p | ||
| message.internalQuery = fields.q | ||
| message.where = fields.W | ||
| message.schema = fields.s | ||
| message.table = fields.t | ||
| message.column = fields.c | ||
| message.dataType = fields.d | ||
| message.constraint = fields.n | ||
| message.file = fields.F | ||
| message.line = fields.L | ||
| message.routine = fields.R | ||
| return message | ||
| } | ||
| } |
| import { Writer } from './buffer-writer' | ||
| const enum code { | ||
| startup = 0x70, | ||
| query = 0x51, | ||
| parse = 0x50, | ||
| bind = 0x42, | ||
| execute = 0x45, | ||
| flush = 0x48, | ||
| sync = 0x53, | ||
| end = 0x58, | ||
| close = 0x43, | ||
| describe = 0x44, | ||
| copyFromChunk = 0x64, | ||
| copyDone = 0x63, | ||
| copyFail = 0x66, | ||
| } | ||
| const writer = new Writer() | ||
| const startup = (opts: Record<string, string>): Buffer => { | ||
| // protocol version | ||
| writer.addInt16(3).addInt16(0) | ||
| for (const key of Object.keys(opts)) { | ||
| writer.addCString(key).addCString(opts[key]) | ||
| } | ||
| writer.addCString('client_encoding').addCString('UTF8') | ||
| var bodyBuffer = writer.addCString('').flush() | ||
| // this message is sent without a code | ||
| var length = bodyBuffer.length + 4 | ||
| return new Writer().addInt32(length).add(bodyBuffer).flush() | ||
| } | ||
| const requestSsl = (): Buffer => { | ||
| const response = Buffer.allocUnsafe(8) | ||
| response.writeInt32BE(8, 0) | ||
| response.writeInt32BE(80877103, 4) | ||
| return response | ||
| } | ||
| const password = (password: string): Buffer => { | ||
| return writer.addCString(password).flush(code.startup) | ||
| } | ||
| const sendSASLInitialResponseMessage = function (mechanism: string, initialResponse: string): Buffer { | ||
| // 0x70 = 'p' | ||
| writer.addCString(mechanism).addInt32(Buffer.byteLength(initialResponse)).addString(initialResponse) | ||
| return writer.flush(code.startup) | ||
| } | ||
| const sendSCRAMClientFinalMessage = function (additionalData: string): Buffer { | ||
| return writer.addString(additionalData).flush(code.startup) | ||
| } | ||
| const query = (text: string): Buffer => { | ||
| return writer.addCString(text).flush(code.query) | ||
| } | ||
| type ParseOpts = { | ||
| name?: string | ||
| types?: number[] | ||
| text: string | ||
| } | ||
| const emptyArray: any[] = [] | ||
| const parse = (query: ParseOpts): Buffer => { | ||
| // expect something like this: | ||
| // { name: 'queryName', | ||
| // text: 'select * from blah', | ||
| // types: ['int8', 'bool'] } | ||
| // normalize missing query names to allow for null | ||
| const name = query.name || '' | ||
| if (name.length > 63) { | ||
| /* eslint-disable no-console */ | ||
| console.error('Warning! Postgres only supports 63 characters for query names.') | ||
| console.error('You supplied %s (%s)', name, name.length) | ||
| console.error('This can cause conflicts and silent errors executing queries') | ||
| /* eslint-enable no-console */ | ||
| } | ||
| const types = query.types || emptyArray | ||
| var len = types.length | ||
| var buffer = writer | ||
| .addCString(name) // name of query | ||
| .addCString(query.text) // actual query text | ||
| .addInt16(len) | ||
| for (var i = 0; i < len; i++) { | ||
| buffer.addInt32(types[i]) | ||
| } | ||
| return writer.flush(code.parse) | ||
| } | ||
| type ValueMapper = (param: any, index: number) => any | ||
| type BindOpts = { | ||
| portal?: string | ||
| binary?: boolean | ||
| statement?: string | ||
| values?: any[] | ||
| // optional map from JS value to postgres value per parameter | ||
| valueMapper?: ValueMapper | ||
| } | ||
| const paramWriter = new Writer() | ||
| // make this a const enum so typescript will inline the value | ||
| const enum ParamType { | ||
| STRING = 0, | ||
| BINARY = 1, | ||
| } | ||
| const writeValues = function (values: any[], valueMapper?: ValueMapper): void { | ||
| for (let i = 0; i < values.length; i++) { | ||
| const mappedVal = valueMapper ? valueMapper(values[i], i) : values[i] | ||
| if (mappedVal == null) { | ||
| // add the param type (string) to the writer | ||
| writer.addInt16(ParamType.STRING) | ||
| // write -1 to the param writer to indicate null | ||
| paramWriter.addInt32(-1) | ||
| } else if (mappedVal instanceof Buffer) { | ||
| // add the param type (binary) to the writer | ||
| writer.addInt16(ParamType.BINARY) | ||
| // add the buffer to the param writer | ||
| paramWriter.addInt32(mappedVal.length) | ||
| paramWriter.add(mappedVal) | ||
| } else { | ||
| // add the param type (string) to the writer | ||
| writer.addInt16(ParamType.STRING) | ||
| paramWriter.addInt32(Buffer.byteLength(mappedVal)) | ||
| paramWriter.addString(mappedVal) | ||
| } | ||
| } | ||
| } | ||
| const bind = (config: BindOpts = {}): Buffer => { | ||
| // normalize config | ||
| const portal = config.portal || '' | ||
| const statement = config.statement || '' | ||
| const binary = config.binary || false | ||
| const values = config.values || emptyArray | ||
| const len = values.length | ||
| writer.addCString(portal).addCString(statement) | ||
| writer.addInt16(len) | ||
| writeValues(values, config.valueMapper) | ||
| writer.addInt16(len) | ||
| writer.add(paramWriter.flush()) | ||
| // format code | ||
| writer.addInt16(binary ? ParamType.BINARY : ParamType.STRING) | ||
| return writer.flush(code.bind) | ||
| } | ||
| type ExecOpts = { | ||
| portal?: string | ||
| rows?: number | ||
| } | ||
| const emptyExecute = Buffer.from([code.execute, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00]) | ||
| const execute = (config?: ExecOpts): Buffer => { | ||
| // this is the happy path for most queries | ||
| if (!config || (!config.portal && !config.rows)) { | ||
| return emptyExecute | ||
| } | ||
| const portal = config.portal || '' | ||
| const rows = config.rows || 0 | ||
| const portalLength = Buffer.byteLength(portal) | ||
| const len = 4 + portalLength + 1 + 4 | ||
| // one extra bit for code | ||
| const buff = Buffer.allocUnsafe(1 + len) | ||
| buff[0] = code.execute | ||
| buff.writeInt32BE(len, 1) | ||
| buff.write(portal, 5, 'utf-8') | ||
| buff[portalLength + 5] = 0 // null terminate portal cString | ||
| buff.writeUInt32BE(rows, buff.length - 4) | ||
| return buff | ||
| } | ||
| const cancel = (processID: number, secretKey: number): Buffer => { | ||
| const buffer = Buffer.allocUnsafe(16) | ||
| buffer.writeInt32BE(16, 0) | ||
| buffer.writeInt16BE(1234, 4) | ||
| buffer.writeInt16BE(5678, 6) | ||
| buffer.writeInt32BE(processID, 8) | ||
| buffer.writeInt32BE(secretKey, 12) | ||
| return buffer | ||
| } | ||
| type PortalOpts = { | ||
| type: 'S' | 'P' | ||
| name?: string | ||
| } | ||
| const cstringMessage = (code: code, string: string): Buffer => { | ||
| const stringLen = Buffer.byteLength(string) | ||
| const len = 4 + stringLen + 1 | ||
| // one extra bit for code | ||
| const buffer = Buffer.allocUnsafe(1 + len) | ||
| buffer[0] = code | ||
| buffer.writeInt32BE(len, 1) | ||
| buffer.write(string, 5, 'utf-8') | ||
| buffer[len] = 0 // null terminate cString | ||
| return buffer | ||
| } | ||
| const emptyDescribePortal = writer.addCString('P').flush(code.describe) | ||
| const emptyDescribeStatement = writer.addCString('S').flush(code.describe) | ||
| const describe = (msg: PortalOpts): Buffer => { | ||
| return msg.name | ||
| ? cstringMessage(code.describe, `${msg.type}${msg.name || ''}`) | ||
| : msg.type === 'P' | ||
| ? emptyDescribePortal | ||
| : emptyDescribeStatement | ||
| } | ||
| const close = (msg: PortalOpts): Buffer => { | ||
| const text = `${msg.type}${msg.name || ''}` | ||
| return cstringMessage(code.close, text) | ||
| } | ||
| const copyData = (chunk: Buffer): Buffer => { | ||
| return writer.add(chunk).flush(code.copyFromChunk) | ||
| } | ||
| const copyFail = (message: string): Buffer => { | ||
| return cstringMessage(code.copyFail, message) | ||
| } | ||
| const codeOnlyBuffer = (code: code): Buffer => Buffer.from([code, 0x00, 0x00, 0x00, 0x04]) | ||
| const flushBuffer = codeOnlyBuffer(code.flush) | ||
| const syncBuffer = codeOnlyBuffer(code.sync) | ||
| const endBuffer = codeOnlyBuffer(code.end) | ||
| const copyDoneBuffer = codeOnlyBuffer(code.copyDone) | ||
| const serialize = { | ||
| startup, | ||
| password, | ||
| requestSsl, | ||
| sendSASLInitialResponseMessage, | ||
| sendSCRAMClientFinalMessage, | ||
| query, | ||
| parse, | ||
| bind, | ||
| execute, | ||
| describe, | ||
| close, | ||
| flush: () => flushBuffer, | ||
| sync: () => syncBuffer, | ||
| end: () => endBuffer, | ||
| copyData, | ||
| copyDone: () => copyDoneBuffer, | ||
| copyFail, | ||
| cancel, | ||
| } | ||
| export { serialize } |
| export default class BufferList { | ||
| constructor(public buffers: Buffer[] = []) {} | ||
| public add(buffer: Buffer, front?: boolean) { | ||
| this.buffers[front ? 'unshift' : 'push'](buffer) | ||
| return this | ||
| } | ||
| public addInt16(val: number, front?: boolean) { | ||
| return this.add(Buffer.from([val >>> 8, val >>> 0]), front) | ||
| } | ||
| public getByteLength() { | ||
| return this.buffers.reduce(function (previous, current) { | ||
| return previous + current.length | ||
| }, 0) | ||
| } | ||
| public addInt32(val: number, first?: boolean) { | ||
| return this.add( | ||
| Buffer.from([(val >>> 24) & 0xff, (val >>> 16) & 0xff, (val >>> 8) & 0xff, (val >>> 0) & 0xff]), | ||
| first | ||
| ) | ||
| } | ||
| public addCString(val: string, front?: boolean) { | ||
| var len = Buffer.byteLength(val) | ||
| var buffer = Buffer.alloc(len + 1) | ||
| buffer.write(val) | ||
| buffer[len] = 0 | ||
| return this.add(buffer, front) | ||
| } | ||
| public addString(val: string, front?: boolean) { | ||
| var len = Buffer.byteLength(val) | ||
| var buffer = Buffer.alloc(len) | ||
| buffer.write(val) | ||
| return this.add(buffer, front) | ||
| } | ||
| public addChar(char: string, first?: boolean) { | ||
| return this.add(Buffer.from(char, 'utf8'), first) | ||
| } | ||
| public addByte(byte: number) { | ||
| return this.add(Buffer.from([byte])) | ||
| } | ||
| public join(appendLength?: boolean, char?: string): Buffer { | ||
| var length = this.getByteLength() | ||
| if (appendLength) { | ||
| this.addInt32(length + 4, true) | ||
| return this.join(false, char) | ||
| } | ||
| if (char) { | ||
| this.addChar(char, true) | ||
| length++ | ||
| } | ||
| var result = Buffer.alloc(length) | ||
| var index = 0 | ||
| this.buffers.forEach(function (buffer) { | ||
| buffer.copy(result, index, 0) | ||
| index += buffer.length | ||
| }) | ||
| return result | ||
| } | ||
| } |
| // https://www.postgresql.org/docs/current/protocol-message-formats.html | ||
| import BufferList from './buffer-list' | ||
| const buffers = { | ||
| readyForQuery: function () { | ||
| return new BufferList().add(Buffer.from('I')).join(true, 'Z') | ||
| }, | ||
| authenticationOk: function () { | ||
| return new BufferList().addInt32(0).join(true, 'R') | ||
| }, | ||
| authenticationCleartextPassword: function () { | ||
| return new BufferList().addInt32(3).join(true, 'R') | ||
| }, | ||
| authenticationMD5Password: function () { | ||
| return new BufferList() | ||
| .addInt32(5) | ||
| .add(Buffer.from([1, 2, 3, 4])) | ||
| .join(true, 'R') | ||
| }, | ||
| authenticationSASL: function () { | ||
| return new BufferList().addInt32(10).addCString('SCRAM-SHA-256').addCString('').join(true, 'R') | ||
| }, | ||
| authenticationSASLContinue: function () { | ||
| return new BufferList().addInt32(11).addString('data').join(true, 'R') | ||
| }, | ||
| authenticationSASLFinal: function () { | ||
| return new BufferList().addInt32(12).addString('data').join(true, 'R') | ||
| }, | ||
| parameterStatus: function (name: string, value: string) { | ||
| return new BufferList().addCString(name).addCString(value).join(true, 'S') | ||
| }, | ||
| backendKeyData: function (processID: number, secretKey: number) { | ||
| return new BufferList().addInt32(processID).addInt32(secretKey).join(true, 'K') | ||
| }, | ||
| commandComplete: function (string: string) { | ||
| return new BufferList().addCString(string).join(true, 'C') | ||
| }, | ||
| rowDescription: function (fields: any[]) { | ||
| fields = fields || [] | ||
| var buf = new BufferList() | ||
| buf.addInt16(fields.length) | ||
| fields.forEach(function (field) { | ||
| buf | ||
| .addCString(field.name) | ||
| .addInt32(field.tableID || 0) | ||
| .addInt16(field.attributeNumber || 0) | ||
| .addInt32(field.dataTypeID || 0) | ||
| .addInt16(field.dataTypeSize || 0) | ||
| .addInt32(field.typeModifier || 0) | ||
| .addInt16(field.formatCode || 0) | ||
| }) | ||
| 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() | ||
| buf.addInt16(columns.length) | ||
| columns.forEach(function (col) { | ||
| if (col == null) { | ||
| buf.addInt32(-1) | ||
| } else { | ||
| var strBuf = Buffer.from(col, 'utf8') | ||
| buf.addInt32(strBuf.length) | ||
| buf.add(strBuf) | ||
| } | ||
| }) | ||
| return buf.join(true, 'D') | ||
| }, | ||
| error: function (fields: any) { | ||
| return buffers.errorOrNotice(fields).join(true, 'E') | ||
| }, | ||
| notice: function (fields: any) { | ||
| return buffers.errorOrNotice(fields).join(true, 'N') | ||
| }, | ||
| errorOrNotice: function (fields: any) { | ||
| fields = fields || [] | ||
| var buf = new BufferList() | ||
| fields.forEach(function (field: any) { | ||
| buf.addChar(field.type) | ||
| buf.addCString(field.value) | ||
| }) | ||
| return buf.add(Buffer.from([0])) // terminator | ||
| }, | ||
| parseComplete: function () { | ||
| return new BufferList().join(true, '1') | ||
| }, | ||
| bindComplete: function () { | ||
| return new BufferList().join(true, '2') | ||
| }, | ||
| notification: function (id: number, channel: string, payload: string) { | ||
| return new BufferList().addInt32(id).addCString(channel).addCString(payload).join(true, 'A') | ||
| }, | ||
| emptyQuery: function () { | ||
| return new BufferList().join(true, 'I') | ||
| }, | ||
| portalSuspended: function () { | ||
| return new BufferList().join(true, 's') | ||
| }, | ||
| closeComplete: function () { | ||
| return new BufferList().join(true, '3') | ||
| }, | ||
| copyIn: function (cols: number) { | ||
| const list = new BufferList() | ||
| // text mode | ||
| .addByte(0) | ||
| // column count | ||
| .addInt16(cols) | ||
| for (let i = 0; i < cols; i++) { | ||
| list.addInt16(i) | ||
| } | ||
| return list.join(true, 'G') | ||
| }, | ||
| copyOut: function (cols: number) { | ||
| const list = new BufferList() | ||
| // text mode | ||
| .addByte(0) | ||
| // column count | ||
| .addInt16(cols) | ||
| for (let i = 0; i < cols; i++) { | ||
| list.addInt16(i) | ||
| } | ||
| return list.join(true, 'H') | ||
| }, | ||
| copyData: function (bytes: Buffer) { | ||
| return new BufferList().add(bytes).join(true, 'd') | ||
| }, | ||
| copyDone: function () { | ||
| return new BufferList().join(true, 'c') | ||
| }, | ||
| } | ||
| export default buffers |
| declare module 'chunky' |
+29
-7
| { | ||
| "name": "@supabase/pg-protocol", | ||
| "version": "0.0.0", | ||
| "main": "index.js", | ||
| "version": "1.8.0", | ||
| "description": "The postgres client/server binary protocol, implemented in TypeScript", | ||
| "main": "dist/index.js", | ||
| "types": "dist/index.d.ts", | ||
| "license": "MIT", | ||
| "devDependencies": { | ||
| "@types/chai": "^4.2.7", | ||
| "@types/mocha": "^10.0.7", | ||
| "@types/node": "^12.12.21", | ||
| "chai": "^4.2.0", | ||
| "chunky": "^0.0.0", | ||
| "mocha": "^10.5.2", | ||
| "ts-node": "^8.5.4", | ||
| "typescript": "^4.0.3" | ||
| }, | ||
| "scripts": { | ||
| "test": "echo \"Error: no test specified\" && exit 1" | ||
| "test": "mocha dist/**/*.test.js", | ||
| "build": "tsc", | ||
| "build:watch": "tsc --watch", | ||
| "prepublish": "yarn build", | ||
| "pretest": "yarn build" | ||
| }, | ||
| "keywords": [], | ||
| "author": "", | ||
| "license": "ISC", | ||
| "description": "" | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git://github.com/supabase/node-postgres.git", | ||
| "directory": "packages/pg-protocol" | ||
| }, | ||
| "files": [ | ||
| "/dist/*{js,ts,map}", | ||
| "/src" | ||
| ] | ||
| } |
-1
| console.log() |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
Trivial Package
Supply chain riskPackages less than 10 lines of code are easily copied into your own project and may not warrant the additional supply chain risk of an external dependency.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
187211
75085.14%41
1950%3804
380300%1
-66.67%0
-100%4
Infinity%8
Infinity%6
500%