postgrejs 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/CHANGELOG.md +814 -0
  2. package/LICENSE +21 -0
  3. package/README.md +200 -0
  4. package/cjs/connection/bind-param.js +10 -0
  5. package/cjs/connection/connection.js +279 -0
  6. package/cjs/connection/cursor.js +93 -0
  7. package/cjs/connection/intl-connection.js +243 -0
  8. package/cjs/connection/pool.js +226 -0
  9. package/cjs/connection/portal.js +148 -0
  10. package/cjs/connection/prepared-statement.js +217 -0
  11. package/cjs/constants.js +250 -0
  12. package/cjs/data-type-map.js +119 -0
  13. package/cjs/data-types/bool-type.js +27 -0
  14. package/cjs/data-types/box-type.js +52 -0
  15. package/cjs/data-types/bytea-type.js +29 -0
  16. package/cjs/data-types/char-type.js +27 -0
  17. package/cjs/data-types/circle-type.js +48 -0
  18. package/cjs/data-types/date-type.js +67 -0
  19. package/cjs/data-types/float4-type.js +25 -0
  20. package/cjs/data-types/float8-type.js +25 -0
  21. package/cjs/data-types/int2-type.js +26 -0
  22. package/cjs/data-types/int2-vector-type.js +38 -0
  23. package/cjs/data-types/int4-type.js +26 -0
  24. package/cjs/data-types/int8-type.js +31 -0
  25. package/cjs/data-types/json-type.js +38 -0
  26. package/cjs/data-types/jsonb-type.js +42 -0
  27. package/cjs/data-types/lseg-type.js +52 -0
  28. package/cjs/data-types/numeric-type.js +125 -0
  29. package/cjs/data-types/oid-type.js +32 -0
  30. package/cjs/data-types/point-type.js +39 -0
  31. package/cjs/data-types/time-type.js +54 -0
  32. package/cjs/data-types/timestamp-type.js +81 -0
  33. package/cjs/data-types/timestamptz-type.js +73 -0
  34. package/cjs/data-types/uuid-type.js +39 -0
  35. package/cjs/data-types/varchar-type.js +27 -0
  36. package/cjs/index.js +41 -0
  37. package/cjs/interfaces/command-result.js +2 -0
  38. package/cjs/interfaces/data-mapping-options.js +2 -0
  39. package/cjs/interfaces/data-type.js +2 -0
  40. package/cjs/interfaces/database-connection-params.js +2 -0
  41. package/cjs/interfaces/field-info.js +2 -0
  42. package/cjs/interfaces/query-options.js +2 -0
  43. package/cjs/interfaces/query-result.js +2 -0
  44. package/cjs/interfaces/script-execute-options.js +2 -0
  45. package/cjs/interfaces/script-result.js +2 -0
  46. package/cjs/interfaces/statement-prepare-options.js +2 -0
  47. package/cjs/package.json +3 -0
  48. package/cjs/protocol/backend.js +256 -0
  49. package/cjs/protocol/buffer-reader.js +78 -0
  50. package/cjs/protocol/database-error.js +17 -0
  51. package/cjs/protocol/frontend.js +218 -0
  52. package/cjs/protocol/pg-socket.js +345 -0
  53. package/cjs/protocol/protocol.js +71 -0
  54. package/cjs/protocol/sasl.js +108 -0
  55. package/cjs/protocol/smart-buffer.js +195 -0
  56. package/cjs/safe-event-emitter.js +17 -0
  57. package/cjs/types.js +2 -0
  58. package/cjs/util/array-calculatedim.js +19 -0
  59. package/cjs/util/bigint-methods.js +42 -0
  60. package/cjs/util/config-from-env.js +30 -0
  61. package/cjs/util/connection-config.js +65 -0
  62. package/cjs/util/convert-row-to-object.js +13 -0
  63. package/cjs/util/decode-binaryarray.js +39 -0
  64. package/cjs/util/encode-binaryarray.js +45 -0
  65. package/cjs/util/escape-literal.js +27 -0
  66. package/cjs/util/fast-parseint.js +32 -0
  67. package/cjs/util/get-parsers.js +42 -0
  68. package/cjs/util/parse-array.js +61 -0
  69. package/cjs/util/parse-datetime.js +38 -0
  70. package/cjs/util/parse-row.js +11 -0
  71. package/cjs/util/parse-time.js +29 -0
  72. package/cjs/util/stringify-arrayliteral.js +38 -0
  73. package/cjs/util/stringify-for-sql.js +30 -0
  74. package/cjs/util/wrap-row-description.js +35 -0
  75. package/esm/connection/bind-param.js +6 -0
  76. package/esm/connection/connection.js +275 -0
  77. package/esm/connection/cursor.js +86 -0
  78. package/esm/connection/intl-connection.js +238 -0
  79. package/esm/connection/pool.js +222 -0
  80. package/esm/connection/portal.js +144 -0
  81. package/esm/connection/prepared-statement.js +213 -0
  82. package/esm/constants.js +247 -0
  83. package/esm/data-type-map.js +115 -0
  84. package/esm/data-types/bool-type.js +24 -0
  85. package/esm/data-types/box-type.js +49 -0
  86. package/esm/data-types/bytea-type.js +23 -0
  87. package/esm/data-types/char-type.js +24 -0
  88. package/esm/data-types/circle-type.js +45 -0
  89. package/esm/data-types/date-type.js +64 -0
  90. package/esm/data-types/float4-type.js +22 -0
  91. package/esm/data-types/float8-type.js +22 -0
  92. package/esm/data-types/int2-type.js +23 -0
  93. package/esm/data-types/int2-vector-type.js +35 -0
  94. package/esm/data-types/int4-type.js +23 -0
  95. package/esm/data-types/int8-type.js +28 -0
  96. package/esm/data-types/json-type.js +35 -0
  97. package/esm/data-types/jsonb-type.js +39 -0
  98. package/esm/data-types/lseg-type.js +49 -0
  99. package/esm/data-types/numeric-type.js +121 -0
  100. package/esm/data-types/oid-type.js +29 -0
  101. package/esm/data-types/point-type.js +36 -0
  102. package/esm/data-types/time-type.js +51 -0
  103. package/esm/data-types/timestamp-type.js +78 -0
  104. package/esm/data-types/timestamptz-type.js +70 -0
  105. package/esm/data-types/uuid-type.js +36 -0
  106. package/esm/data-types/varchar-type.js +24 -0
  107. package/esm/index.js +25 -0
  108. package/esm/interfaces/command-result.js +1 -0
  109. package/esm/interfaces/data-mapping-options.js +1 -0
  110. package/esm/interfaces/data-type.js +1 -0
  111. package/esm/interfaces/database-connection-params.js +1 -0
  112. package/esm/interfaces/field-info.js +1 -0
  113. package/esm/interfaces/query-options.js +1 -0
  114. package/esm/interfaces/query-result.js +1 -0
  115. package/esm/interfaces/script-execute-options.js +1 -0
  116. package/esm/interfaces/script-result.js +1 -0
  117. package/esm/interfaces/statement-prepare-options.js +1 -0
  118. package/esm/protocol/backend.js +252 -0
  119. package/esm/protocol/buffer-reader.js +74 -0
  120. package/esm/protocol/database-error.js +13 -0
  121. package/esm/protocol/frontend.js +214 -0
  122. package/esm/protocol/pg-socket.js +338 -0
  123. package/esm/protocol/protocol.js +68 -0
  124. package/esm/protocol/sasl.js +102 -0
  125. package/esm/protocol/smart-buffer.js +168 -0
  126. package/esm/safe-event-emitter.js +13 -0
  127. package/esm/types.js +1 -0
  128. package/esm/util/array-calculatedim.js +15 -0
  129. package/esm/util/bigint-methods.js +37 -0
  130. package/esm/util/config-from-env.js +26 -0
  131. package/esm/util/connection-config.js +57 -0
  132. package/esm/util/convert-row-to-object.js +9 -0
  133. package/esm/util/decode-binaryarray.js +35 -0
  134. package/esm/util/encode-binaryarray.js +41 -0
  135. package/esm/util/escape-literal.js +23 -0
  136. package/esm/util/fast-parseint.js +28 -0
  137. package/esm/util/get-parsers.js +38 -0
  138. package/esm/util/parse-array.js +57 -0
  139. package/esm/util/parse-datetime.js +34 -0
  140. package/esm/util/parse-row.js +7 -0
  141. package/esm/util/parse-time.js +25 -0
  142. package/esm/util/stringify-arrayliteral.js +34 -0
  143. package/esm/util/stringify-for-sql.js +25 -0
  144. package/esm/util/wrap-row-description.js +31 -0
  145. package/package.json +54 -0
  146. package/typings/connection/bind-param.d.ts +6 -0
  147. package/typings/connection/connection.d.ts +110 -0
  148. package/typings/connection/cursor.d.ts +25 -0
  149. package/typings/connection/intl-connection.d.ts +40 -0
  150. package/typings/connection/pool.d.ts +52 -0
  151. package/typings/connection/portal.d.ts +23 -0
  152. package/typings/connection/prepared-statement.d.ts +27 -0
  153. package/typings/constants.d.ts +130 -0
  154. package/typings/data-type-map.d.ts +11 -0
  155. package/typings/data-types/bool-type.d.ts +3 -0
  156. package/typings/data-types/box-type.d.ts +3 -0
  157. package/typings/data-types/bytea-type.d.ts +3 -0
  158. package/typings/data-types/char-type.d.ts +3 -0
  159. package/typings/data-types/circle-type.d.ts +3 -0
  160. package/typings/data-types/date-type.d.ts +3 -0
  161. package/typings/data-types/float4-type.d.ts +3 -0
  162. package/typings/data-types/float8-type.d.ts +3 -0
  163. package/typings/data-types/int2-type.d.ts +3 -0
  164. package/typings/data-types/int2-vector-type.d.ts +3 -0
  165. package/typings/data-types/int4-type.d.ts +3 -0
  166. package/typings/data-types/int8-type.d.ts +3 -0
  167. package/typings/data-types/json-type.d.ts +3 -0
  168. package/typings/data-types/jsonb-type.d.ts +3 -0
  169. package/typings/data-types/lseg-type.d.ts +3 -0
  170. package/typings/data-types/numeric-type.d.ts +12 -0
  171. package/typings/data-types/oid-type.d.ts +4 -0
  172. package/typings/data-types/point-type.d.ts +3 -0
  173. package/typings/data-types/time-type.d.ts +3 -0
  174. package/typings/data-types/timestamp-type.d.ts +3 -0
  175. package/typings/data-types/timestamptz-type.d.ts +3 -0
  176. package/typings/data-types/uuid-type.d.ts +3 -0
  177. package/typings/data-types/varchar-type.d.ts +3 -0
  178. package/typings/index.d.ts +25 -0
  179. package/typings/interfaces/command-result.d.ts +28 -0
  180. package/typings/interfaces/data-mapping-options.d.ts +9 -0
  181. package/typings/interfaces/data-type.d.ts +31 -0
  182. package/typings/interfaces/database-connection-params.d.ts +38 -0
  183. package/typings/interfaces/field-info.d.ts +46 -0
  184. package/typings/interfaces/query-options.d.ts +46 -0
  185. package/typings/interfaces/query-result.d.ts +8 -0
  186. package/typings/interfaces/script-execute-options.d.ts +26 -0
  187. package/typings/interfaces/script-result.d.ts +15 -0
  188. package/typings/interfaces/statement-prepare-options.d.ts +13 -0
  189. package/typings/protocol/backend.d.ts +9 -0
  190. package/typings/protocol/buffer-reader.d.ts +18 -0
  191. package/typings/protocol/database-error.d.ts +20 -0
  192. package/typings/protocol/frontend.d.ts +59 -0
  193. package/typings/protocol/pg-socket.d.ts +51 -0
  194. package/typings/protocol/protocol.d.ts +180 -0
  195. package/typings/protocol/sasl.d.ts +13 -0
  196. package/typings/protocol/smart-buffer.d.ts +39 -0
  197. package/typings/safe-event-emitter.d.ts +5 -0
  198. package/typings/types.d.ts +15 -0
  199. package/typings/util/array-calculatedim.d.ts +1 -0
  200. package/typings/util/bigint-methods.d.ts +3 -0
  201. package/typings/util/config-from-env.d.ts +2 -0
  202. package/typings/util/connection-config.d.ts +3 -0
  203. package/typings/util/convert-row-to-object.d.ts +2 -0
  204. package/typings/util/decode-binaryarray.d.ts +4 -0
  205. package/typings/util/encode-binaryarray.d.ts +5 -0
  206. package/typings/util/escape-literal.d.ts +1 -0
  207. package/typings/util/fast-parseint.d.ts +1 -0
  208. package/typings/util/get-parsers.d.ts +4 -0
  209. package/typings/util/parse-array.d.ts +5 -0
  210. package/typings/util/parse-datetime.d.ts +1 -0
  211. package/typings/util/parse-row.d.ts +3 -0
  212. package/typings/util/parse-time.d.ts +3 -0
  213. package/typings/util/stringify-arrayliteral.d.ts +3 -0
  214. package/typings/util/stringify-for-sql.d.ts +4 -0
  215. package/typings/util/wrap-row-description.d.ts +5 -0
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BufferReader = void 0;
4
+ class BufferReader {
5
+ constructor(buffer) {
6
+ this.offset = 0;
7
+ this.buffer = buffer;
8
+ }
9
+ get length() {
10
+ return this.buffer.length;
11
+ }
12
+ readUInt8() {
13
+ this._checkReadable(1);
14
+ const v = this.buffer.readUInt8(this.offset);
15
+ this.offset++;
16
+ return v;
17
+ }
18
+ readUInt16BE() {
19
+ this._checkReadable(2);
20
+ const v = this.buffer.readUInt16BE(this.offset);
21
+ this.offset += 2;
22
+ return v;
23
+ }
24
+ readInt16BE() {
25
+ this._checkReadable(2);
26
+ const v = this.buffer.readInt16BE(this.offset);
27
+ this.offset += 2;
28
+ return v;
29
+ }
30
+ readUInt32BE() {
31
+ this._checkReadable(4);
32
+ const v = this.buffer.readUInt32BE(this.offset);
33
+ this.offset += 4;
34
+ return v;
35
+ }
36
+ readInt32BE() {
37
+ this._checkReadable(4);
38
+ const v = this.buffer.readInt32BE(this.offset);
39
+ this.offset += 4;
40
+ return v;
41
+ }
42
+ readCString(encoding) {
43
+ const idx = this.buffer.indexOf(0, this.offset);
44
+ const v = this.buffer.toString(encoding, this.offset, idx);
45
+ this.offset = idx + 1;
46
+ return v;
47
+ }
48
+ readLString(len, encoding) {
49
+ if (len < 0)
50
+ return null;
51
+ this._checkReadable(len);
52
+ const v = this.buffer.toString(encoding, this.offset, this.offset + len);
53
+ this.offset += len;
54
+ return v;
55
+ }
56
+ readBuffer(len) {
57
+ if (len)
58
+ this._checkReadable(len);
59
+ const end = len !== undefined ? this.offset + len : this.length;
60
+ const buf = this.buffer.slice(this.offset, end);
61
+ this.offset = end;
62
+ return buf;
63
+ }
64
+ moveBy(n) {
65
+ return this.moveTo(this.offset + n);
66
+ }
67
+ moveTo(pos) {
68
+ if (pos >= this.length)
69
+ throw new Error('Eof in buffer detected');
70
+ this.offset = pos;
71
+ return this;
72
+ }
73
+ _checkReadable(size) {
74
+ if (this.offset + size - 1 >= this.length)
75
+ throw new Error('Eof in buffer detected');
76
+ }
77
+ }
78
+ exports.BufferReader = BufferReader;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DatabaseError = void 0;
4
+ class DatabaseError extends Error {
5
+ constructor(msg) {
6
+ super(msg.message);
7
+ Object.assign(this, {
8
+ ...msg,
9
+ line: undefined,
10
+ file: undefined,
11
+ routine: undefined,
12
+ });
13
+ if (msg.position)
14
+ this.position = parseInt(msg.position, 10) || undefined;
15
+ }
16
+ }
17
+ exports.DatabaseError = DatabaseError;
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Frontend = void 0;
4
+ const constants_js_1 = require("../constants.js");
5
+ const encode_binaryarray_js_1 = require("../util/encode-binaryarray.js");
6
+ const stringify_arrayliteral_js_1 = require("../util/stringify-arrayliteral.js");
7
+ const protocol_js_1 = require("./protocol.js");
8
+ const smart_buffer_js_1 = require("./smart-buffer.js");
9
+ const DataFormat = protocol_js_1.Protocol.DataFormat;
10
+ const StaticFlushBuffer = Buffer.from([protocol_js_1.Protocol.FrontendMessageCode.Flush, 0x00, 0x00, 0x00, 0x04]);
11
+ const StaticTerminateBuffer = Buffer.from([protocol_js_1.Protocol.FrontendMessageCode.Terminate, 0x00, 0x00, 0x00, 0x04]);
12
+ const StaticSyncBuffer = Buffer.from([protocol_js_1.Protocol.FrontendMessageCode.Sync, 0x00, 0x00, 0x00, 0x04]);
13
+ class Frontend {
14
+ constructor(options) {
15
+ this._io = new smart_buffer_js_1.SmartBuffer(options?.buffer);
16
+ }
17
+ getSSLRequestMessage() {
18
+ return this._io
19
+ .start()
20
+ .writeUInt32BE(8) // Length of message contents in bytes, including self.
21
+ .writeUInt16BE(1234)
22
+ .writeUInt16BE(5679)
23
+ .flush();
24
+ }
25
+ getStartupMessage(args) {
26
+ const io = this._io
27
+ .start()
28
+ .writeInt32BE(0) // Preserve length
29
+ .writeInt16BE(protocol_js_1.Protocol.VERSION_MAJOR)
30
+ .writeInt16BE(protocol_js_1.Protocol.VERSION_MINOR);
31
+ for (const [k, v] of Object.entries(args)) {
32
+ if (k !== 'client_encoding')
33
+ io.writeCString(k, 'utf8').writeCString(v, 'utf8');
34
+ }
35
+ io.writeCString('client_encoding', 'utf8').writeCString('UTF8', 'utf8').writeUInt8(0);
36
+ return setLengthAndFlush(io, 0);
37
+ }
38
+ getPasswordMessage(password) {
39
+ const io = this._io
40
+ .start()
41
+ .writeInt8(protocol_js_1.Protocol.FrontendMessageCode.PasswordMessage)
42
+ .writeInt32BE(0) // Preserve header
43
+ .writeCString(password, 'utf8');
44
+ return setLengthAndFlush(io, 1);
45
+ }
46
+ getSASLMessage(sasl) {
47
+ const io = this._io
48
+ .start()
49
+ .writeInt8(protocol_js_1.Protocol.FrontendMessageCode.PasswordMessage)
50
+ .writeInt32BE(0) // Preserve header
51
+ .writeCString(sasl.mechanism, 'utf8')
52
+ .writeLString(sasl.clientFirstMessage);
53
+ return setLengthAndFlush(io, 1);
54
+ }
55
+ getSASLFinalMessage(session) {
56
+ const io = this._io
57
+ .start()
58
+ .writeInt8(protocol_js_1.Protocol.FrontendMessageCode.PasswordMessage)
59
+ .writeInt32BE(0) // Preserve header
60
+ .writeString(session.clientFinalMessage);
61
+ return setLengthAndFlush(io, 1);
62
+ }
63
+ getParseMessage(args) {
64
+ if (args.statement && args.statement.length > 63)
65
+ throw new Error('Query name length must be lower than 63');
66
+ const io = this._io
67
+ .start()
68
+ .writeInt8(protocol_js_1.Protocol.FrontendMessageCode.Parse)
69
+ .writeInt32BE(0) // Preserve header
70
+ .writeCString(args.statement || '', 'utf8')
71
+ .writeCString(args.sql, 'utf8')
72
+ .writeUInt16BE(args.paramTypes ? args.paramTypes.length : 0);
73
+ if (args.paramTypes) {
74
+ for (const t of args.paramTypes) {
75
+ io.writeUInt32BE(t || 0);
76
+ }
77
+ }
78
+ return setLengthAndFlush(io, 1);
79
+ }
80
+ getBindMessage(args) {
81
+ if (args.portal && args.portal.length > 63)
82
+ throw new Error('Portal name length must be lower than 63');
83
+ if (args.statement && args.statement.length > 63)
84
+ throw new Error('Query name length must be lower than 63');
85
+ const io = this._io
86
+ .start()
87
+ .writeInt8(protocol_js_1.Protocol.FrontendMessageCode.Bind)
88
+ .writeInt32BE(0) // Preserve header
89
+ .writeCString(args.portal || '', 'utf8')
90
+ .writeCString(args.statement || '', 'utf8');
91
+ const { params, paramTypes, queryOptions } = args;
92
+ const columnFormat = queryOptions.columnFormat != null ? queryOptions.columnFormat : constants_js_1.DEFAULT_COLUMN_FORMAT;
93
+ if (params && params.length) {
94
+ io.writeInt16BE(params.length);
95
+ const formatOffset = io.offset;
96
+ for (let i = 0; i < params.length; i++) {
97
+ io.writeInt16BE(0); // Preserve
98
+ }
99
+ // Write parameter values
100
+ io.writeUInt16BE(params.length);
101
+ for (let i = 0; i < params?.length; i++) {
102
+ let v = params[i];
103
+ if (v == null) {
104
+ io.writeInt32BE(-1);
105
+ continue;
106
+ }
107
+ const dataTypeOid = paramTypes ? paramTypes[i] : undefined;
108
+ const dt = dataTypeOid ? args.typeMap.get(dataTypeOid) : undefined;
109
+ if (dt) {
110
+ if (typeof dt.encodeBinary === 'function') {
111
+ // Set param format to binary
112
+ io.buffer.writeInt16BE(protocol_js_1.Protocol.DataFormat.binary, formatOffset + i * 2);
113
+ // Preserve data length
114
+ io.writeInt32BE(0);
115
+ const dataOffset = io.offset;
116
+ if (dt.elementsOID) {
117
+ // If data type is array
118
+ v = Array.isArray(v) ? v : [v];
119
+ (0, encode_binaryarray_js_1.encodeBinaryArray)(io, v, dt.elementsOID, queryOptions, dt.encodeBinary, dt.encodeCalculateDim);
120
+ }
121
+ else {
122
+ dt.encodeBinary(io, v, queryOptions);
123
+ }
124
+ io.buffer.writeInt32BE(io.length - dataOffset, dataOffset - 4); // Update length
125
+ }
126
+ else if (typeof dt.encodeText === 'function') {
127
+ v = dt.elementsOID ? (0, stringify_arrayliteral_js_1.stringifyArrayLiteral)(v, queryOptions, dt.encodeText) : dt.encodeText(v, queryOptions);
128
+ io.writeLString(v, 'utf8');
129
+ }
130
+ }
131
+ else if (Buffer.isBuffer(v)) {
132
+ // Set param format to binary
133
+ io.buffer.writeInt16BE(protocol_js_1.Protocol.DataFormat.binary, formatOffset + i * 2);
134
+ // Preserve data length
135
+ io.writeInt32BE(0);
136
+ const dataOffset = io.offset;
137
+ io.writeBuffer(v);
138
+ io.buffer.writeInt32BE(io.length - dataOffset, dataOffset - 4); // Update length
139
+ }
140
+ else {
141
+ io.writeLString('' + v, 'utf8');
142
+ }
143
+ }
144
+ }
145
+ else {
146
+ io.writeUInt16BE(0);
147
+ io.writeUInt16BE(0);
148
+ }
149
+ if (Array.isArray(columnFormat)) {
150
+ io.writeUInt16BE(columnFormat.length);
151
+ for (let i = 0; i < columnFormat.length; i++) {
152
+ io.writeUInt16BE(columnFormat[i]);
153
+ }
154
+ }
155
+ else if (columnFormat === DataFormat.binary) {
156
+ io.writeUInt16BE(1);
157
+ io.writeUInt16BE(DataFormat.binary);
158
+ }
159
+ else
160
+ io.writeUInt16BE(0);
161
+ return setLengthAndFlush(io, 1);
162
+ }
163
+ getDescribeMessage(args) {
164
+ if (args.name && args.name.length > 63)
165
+ throw new Error(args.type === 'P' ? 'Portal' : 'Statement' + 'name length must be lower than 63');
166
+ const io = this._io
167
+ .start()
168
+ .writeInt8(protocol_js_1.Protocol.FrontendMessageCode.Describe)
169
+ .writeInt32BE(0) // Preserve header
170
+ .writeUInt8(args.type.charCodeAt(0))
171
+ .writeCString(args.name || '', 'utf8');
172
+ return setLengthAndFlush(io, 1);
173
+ }
174
+ getExecuteMessage(args) {
175
+ if (args.fetchCount && (args.fetchCount < 0 || args.fetchCount > 4294967295))
176
+ throw new Error('fetchCount can be between 0 and 4294967295');
177
+ const io = this._io
178
+ .start()
179
+ .writeInt8(protocol_js_1.Protocol.FrontendMessageCode.Execute)
180
+ .writeInt32BE(0) // Preserve header
181
+ .writeCString(args.portal || '', 'utf8')
182
+ .writeUInt32BE(args.fetchCount || 0);
183
+ return setLengthAndFlush(io, 1);
184
+ }
185
+ getCloseMessage(args) {
186
+ if (args.name && args.name.length > 63)
187
+ throw new Error(args.type === 'P' ? 'Portal' : 'Statement' + 'name length must be lower than 63');
188
+ const io = this._io
189
+ .start()
190
+ .writeInt8(protocol_js_1.Protocol.FrontendMessageCode.Close)
191
+ .writeInt32BE(0) // Preserve header
192
+ .writeUInt8(args.type.charCodeAt(0))
193
+ .writeCString(args.name || '', 'utf8');
194
+ return setLengthAndFlush(io, 1);
195
+ }
196
+ getQueryMessage(sql) {
197
+ const io = this._io
198
+ .start()
199
+ .writeInt8(protocol_js_1.Protocol.FrontendMessageCode.Query)
200
+ .writeInt32BE(0) // Preserve header
201
+ .writeCString(sql || '', 'utf8');
202
+ return setLengthAndFlush(io, 1);
203
+ }
204
+ getFlushMessage() {
205
+ return StaticFlushBuffer;
206
+ }
207
+ getTerminateMessage() {
208
+ return StaticTerminateBuffer;
209
+ }
210
+ getSyncMessage() {
211
+ return StaticSyncBuffer;
212
+ }
213
+ }
214
+ exports.Frontend = Frontend;
215
+ function setLengthAndFlush(io, lengthOffset) {
216
+ io.buffer.writeUInt32BE(io.length - lengthOffset, lengthOffset);
217
+ return io.flush();
218
+ }
@@ -0,0 +1,345 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PgSocket = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const net_1 = __importDefault(require("net"));
9
+ const putil_promisify_1 = __importDefault(require("putil-promisify"));
10
+ const tls_1 = __importDefault(require("tls"));
11
+ const constants_js_1 = require("../constants.js");
12
+ const safe_event_emitter_js_1 = require("../safe-event-emitter.js");
13
+ const backend_js_1 = require("./backend.js");
14
+ const database_error_js_1 = require("./database-error.js");
15
+ const frontend_js_1 = require("./frontend.js");
16
+ const protocol_js_1 = require("./protocol.js");
17
+ const sasl_js_1 = require("./sasl.js");
18
+ const DEFAULT_PORT_NUMBER = 5432;
19
+ const COMMAND_RESULT_PATTERN = /^([^\d]+)(?: (\d+)(?: (\d+))?)?$/;
20
+ class PgSocket extends safe_event_emitter_js_1.SafeEventEmitter {
21
+ constructor(options) {
22
+ super();
23
+ this.options = options;
24
+ this._state = constants_js_1.ConnectionState.CLOSED;
25
+ this._backend = new backend_js_1.Backend();
26
+ this._sessionParameters = {};
27
+ this._frontend = new frontend_js_1.Frontend({ buffer: options.buffer });
28
+ this.setMaxListeners(99);
29
+ }
30
+ get state() {
31
+ if (!this._socket || this._socket.destroyed)
32
+ this._state = constants_js_1.ConnectionState.CLOSED;
33
+ return this._state;
34
+ }
35
+ get processID() {
36
+ return this._processID;
37
+ }
38
+ get secretKey() {
39
+ return this._secretKey;
40
+ }
41
+ get sessionParameters() {
42
+ return this._sessionParameters;
43
+ }
44
+ connect() {
45
+ if (this._socket)
46
+ return;
47
+ this._state = constants_js_1.ConnectionState.CONNECTING;
48
+ const options = this.options;
49
+ const socket = (this._socket = new net_1.default.Socket());
50
+ const errorHandler = err => {
51
+ this._state = constants_js_1.ConnectionState.CLOSED;
52
+ this._removeListeners();
53
+ this._reset();
54
+ socket.destroy();
55
+ this._socket = undefined;
56
+ this.emit('error', err);
57
+ };
58
+ const connectHandler = () => {
59
+ socket.setTimeout(0);
60
+ if (this.options.keepAlive || this.options.keepAlive == null)
61
+ socket.setKeepAlive(true);
62
+ if (options.ssl) {
63
+ socket.write(this._frontend.getSSLRequestMessage());
64
+ socket.once('data', x => {
65
+ this._removeListeners();
66
+ if (x.toString() === 'S') {
67
+ const tslOptions = { ...options.ssl, socket };
68
+ if (options.host && net_1.default.isIP(options.host) === 0)
69
+ tslOptions.servername = options.host;
70
+ const tlsSocket = (this._socket = tls_1.default.connect(tslOptions));
71
+ tlsSocket.once('error', errorHandler);
72
+ tlsSocket.once('secureConnect', () => {
73
+ this._removeListeners();
74
+ this._handleConnect();
75
+ });
76
+ return;
77
+ }
78
+ if (x.toString() === 'N')
79
+ return errorHandler(new Error('Server does not support SSL connections'));
80
+ return errorHandler(new Error('There was an error establishing an SSL connection'));
81
+ });
82
+ }
83
+ else {
84
+ this._handleConnect();
85
+ }
86
+ };
87
+ socket.setNoDelay(true);
88
+ socket.setTimeout(options.connectTimeoutMs || 30000, () => errorHandler(new Error('Connection timed out')));
89
+ socket.once('error', errorHandler);
90
+ socket.once('connect', connectHandler);
91
+ this.emit('connecting');
92
+ if (options.host && options.host.startsWith('/'))
93
+ socket.connect(options.host);
94
+ else
95
+ socket.connect(options.port || DEFAULT_PORT_NUMBER, options.host || 'localhost');
96
+ }
97
+ close() {
98
+ if (!this._socket || this._socket.destroyed) {
99
+ this._state = constants_js_1.ConnectionState.CLOSED;
100
+ this._socket = undefined;
101
+ this._reset();
102
+ return;
103
+ }
104
+ if (this._state === constants_js_1.ConnectionState.CLOSING)
105
+ return;
106
+ const socket = this._socket;
107
+ this._state = constants_js_1.ConnectionState.CLOSING;
108
+ this._removeListeners();
109
+ socket.once('close', () => this._handleClose());
110
+ socket.destroy();
111
+ }
112
+ sendParseMessage(args, cb) {
113
+ if (this.listenerCount('debug'))
114
+ this.emit('debug', { location: 'PgSocket.sendParseMessage', args });
115
+ this._send(this._frontend.getParseMessage(args), cb);
116
+ }
117
+ sendBindMessage(args, cb) {
118
+ if (this.listenerCount('debug'))
119
+ this.emit('debug', { location: 'PgSocket.sendBindMessage', args });
120
+ this._send(this._frontend.getBindMessage(args), cb);
121
+ }
122
+ sendDescribeMessage(args, cb) {
123
+ if (this.listenerCount('debug'))
124
+ this.emit('debug', { location: 'PgSocket.sendDescribeMessage', args });
125
+ this._send(this._frontend.getDescribeMessage(args), cb);
126
+ }
127
+ sendExecuteMessage(args, cb) {
128
+ if (this.listenerCount('debug'))
129
+ this.emit('debug', { location: 'PgSocket.sendDescribeMessage', args });
130
+ this._send(this._frontend.getExecuteMessage(args), cb);
131
+ }
132
+ sendCloseMessage(args, cb) {
133
+ if (this.listenerCount('debug'))
134
+ this.emit('debug', { location: 'PgSocket.sendCloseMessage', args });
135
+ this._send(this._frontend.getCloseMessage(args), cb);
136
+ }
137
+ sendQueryMessage(sql, cb) {
138
+ if (this.listenerCount('debug'))
139
+ this.emit('debug', { location: 'PgSocket.sendQueryMessage', sql });
140
+ this._send(this._frontend.getQueryMessage(sql), cb);
141
+ }
142
+ sendFlushMessage(cb) {
143
+ if (this.listenerCount('debug'))
144
+ this.emit('debug', { location: 'PgSocket.sendFlushMessage' });
145
+ this._send(this._frontend.getFlushMessage(), cb);
146
+ }
147
+ sendTerminateMessage(cb) {
148
+ if (this.listenerCount('debug'))
149
+ this.emit('debug', { location: 'PgSocket.sendTerminateMessage' });
150
+ this._send(this._frontend.getTerminateMessage(), cb);
151
+ }
152
+ sendSyncMessage() {
153
+ if (this.listenerCount('debug'))
154
+ this.emit('debug', { location: 'PgSocket.sendSyncMessage' });
155
+ this._send(this._frontend.getSyncMessage());
156
+ }
157
+ capture(callback) {
158
+ return new Promise((resolve, reject) => {
159
+ const done = (err, result) => {
160
+ this.removeListener('error', errorHandler);
161
+ this.removeListener('message', msgHandler);
162
+ if (err)
163
+ reject(err);
164
+ else
165
+ resolve(result);
166
+ };
167
+ const errorHandler = (err) => {
168
+ this.removeListener('message', msgHandler);
169
+ reject(err);
170
+ };
171
+ const msgHandler = (code, msg) => {
172
+ const x = callback(code, msg, done);
173
+ if (putil_promisify_1.default.isPromise(x))
174
+ x.catch(err => done(err));
175
+ };
176
+ this.once('error', errorHandler);
177
+ this.on('message', msgHandler);
178
+ });
179
+ }
180
+ _removeListeners() {
181
+ if (!this._socket)
182
+ return;
183
+ this._socket.removeAllListeners('error');
184
+ this._socket.removeAllListeners('connect');
185
+ this._socket.removeAllListeners('data');
186
+ this._socket.removeAllListeners('close');
187
+ }
188
+ _reset() {
189
+ this._backend.reset();
190
+ this._sessionParameters = {};
191
+ this._processID = undefined;
192
+ this._secretKey = undefined;
193
+ this._saslSession = undefined;
194
+ }
195
+ _handleConnect() {
196
+ const socket = this._socket;
197
+ if (!socket)
198
+ return;
199
+ this._state = constants_js_1.ConnectionState.AUTHORIZING;
200
+ this._reset();
201
+ socket.on('data', (data) => this._handleData(data));
202
+ socket.on('error', (err) => this._handleError(err));
203
+ socket.on('close', () => this._handleClose());
204
+ this._send(this._frontend.getStartupMessage({
205
+ user: this.options.user || 'postgres',
206
+ database: this.options.database || '',
207
+ }));
208
+ }
209
+ _handleClose() {
210
+ this._reset();
211
+ this._socket = undefined;
212
+ this._state = constants_js_1.ConnectionState.CLOSED;
213
+ this.emit('close');
214
+ }
215
+ _handleError(err) {
216
+ if (this._state !== constants_js_1.ConnectionState.READY) {
217
+ this._socket?.end();
218
+ }
219
+ this.emit('error', err);
220
+ }
221
+ _handleData(data) {
222
+ this._backend.parse(data, (code, payload) => {
223
+ try {
224
+ switch (code) {
225
+ case protocol_js_1.Protocol.BackendMessageCode.Authentication:
226
+ this._handleAuthenticationMessage(payload);
227
+ break;
228
+ case protocol_js_1.Protocol.BackendMessageCode.ErrorResponse:
229
+ this.emit('error', new database_error_js_1.DatabaseError(payload));
230
+ break;
231
+ case protocol_js_1.Protocol.BackendMessageCode.NoticeResponse:
232
+ this.emit('notice', payload);
233
+ break;
234
+ case protocol_js_1.Protocol.BackendMessageCode.NotificationResponse:
235
+ this.emit('notification', payload);
236
+ break;
237
+ case protocol_js_1.Protocol.BackendMessageCode.ParameterStatus:
238
+ this._handleParameterStatus(payload);
239
+ break;
240
+ case protocol_js_1.Protocol.BackendMessageCode.BackendKeyData:
241
+ this._handleBackendKeyData(payload);
242
+ break;
243
+ case protocol_js_1.Protocol.BackendMessageCode.ReadyForQuery:
244
+ if (this._state !== constants_js_1.ConnectionState.READY) {
245
+ this._state = constants_js_1.ConnectionState.READY;
246
+ this.emit('ready');
247
+ }
248
+ else
249
+ this.emit('message', code, payload);
250
+ break;
251
+ case protocol_js_1.Protocol.BackendMessageCode.CommandComplete: {
252
+ const msg = this._handleCommandComplete(payload);
253
+ this.emit('message', code, msg);
254
+ break;
255
+ }
256
+ default:
257
+ this.emit('message', code, payload);
258
+ }
259
+ }
260
+ catch (e) {
261
+ this._handleError(e);
262
+ }
263
+ });
264
+ }
265
+ _resolvePassword(cb) {
266
+ (async () => {
267
+ const pass = typeof this.options.password === 'function' ? await this.options.password() : this.options.password;
268
+ cb(pass || '');
269
+ })().catch(err => this._handleError(err));
270
+ }
271
+ _handleAuthenticationMessage(msg) {
272
+ if (!msg) {
273
+ this.emit('authenticate');
274
+ return;
275
+ }
276
+ switch (msg.kind) {
277
+ case protocol_js_1.Protocol.AuthenticationMessageKind.CleartextPassword:
278
+ this._resolvePassword(password => {
279
+ this._send(this._frontend.getPasswordMessage(password));
280
+ });
281
+ break;
282
+ case protocol_js_1.Protocol.AuthenticationMessageKind.MD5Password:
283
+ this._resolvePassword(password => {
284
+ const md5 = (x) => crypto_1.default.createHash('md5').update(x, 'utf8').digest('hex');
285
+ const l = md5(password + this.options.user);
286
+ const r = md5(Buffer.concat([Buffer.from(l), msg.salt]));
287
+ const pass = 'md5' + r;
288
+ this._send(this._frontend.getPasswordMessage(pass));
289
+ });
290
+ break;
291
+ case protocol_js_1.Protocol.AuthenticationMessageKind.SASL: {
292
+ if (!msg.mechanisms.includes('SCRAM-SHA-256'))
293
+ throw new Error('SASL: Only mechanism SCRAM-SHA-256 is currently supported');
294
+ const saslSession = (this._saslSession = sasl_js_1.SASL.createSession(this.options.user || '', 'SCRAM-SHA-256'));
295
+ this._send(this._frontend.getSASLMessage(saslSession));
296
+ break;
297
+ }
298
+ case protocol_js_1.Protocol.AuthenticationMessageKind.SASLContinue: {
299
+ const saslSession = this._saslSession;
300
+ if (!saslSession)
301
+ throw new Error('SASL: Session not started yet');
302
+ this._resolvePassword(password => {
303
+ sasl_js_1.SASL.continueSession(saslSession, password, msg.data);
304
+ const buf = this._frontend.getSASLFinalMessage(saslSession);
305
+ this._send(buf);
306
+ });
307
+ break;
308
+ }
309
+ case protocol_js_1.Protocol.AuthenticationMessageKind.SASLFinal: {
310
+ const session = this._saslSession;
311
+ if (!session)
312
+ throw new Error('SASL: Session not started yet');
313
+ sasl_js_1.SASL.finalizeSession(session, msg.data);
314
+ this._saslSession = undefined;
315
+ break;
316
+ }
317
+ }
318
+ }
319
+ _handleParameterStatus(msg) {
320
+ this._sessionParameters[msg.name] = msg.value;
321
+ }
322
+ _handleBackendKeyData(msg) {
323
+ this._processID = msg.processID;
324
+ this._secretKey = msg.secretKey;
325
+ }
326
+ _handleCommandComplete(msg) {
327
+ const m = msg.command && msg.command.match(COMMAND_RESULT_PATTERN);
328
+ const result = {
329
+ command: m[1],
330
+ };
331
+ if (m[3] != null) {
332
+ result.oid = parseInt(m[2], 10);
333
+ result.rowCount = parseInt(m[3], 10);
334
+ }
335
+ else if (m[2])
336
+ result.rowCount = parseInt(m[2], 10);
337
+ return result;
338
+ }
339
+ _send(data, cb) {
340
+ if (this._socket && this._socket.writable) {
341
+ this._socket.write(data, cb);
342
+ }
343
+ }
344
+ }
345
+ exports.PgSocket = PgSocket;