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.
- package/CHANGELOG.md +814 -0
- package/LICENSE +21 -0
- package/README.md +200 -0
- package/cjs/connection/bind-param.js +10 -0
- package/cjs/connection/connection.js +279 -0
- package/cjs/connection/cursor.js +93 -0
- package/cjs/connection/intl-connection.js +243 -0
- package/cjs/connection/pool.js +226 -0
- package/cjs/connection/portal.js +148 -0
- package/cjs/connection/prepared-statement.js +217 -0
- package/cjs/constants.js +250 -0
- package/cjs/data-type-map.js +119 -0
- package/cjs/data-types/bool-type.js +27 -0
- package/cjs/data-types/box-type.js +52 -0
- package/cjs/data-types/bytea-type.js +29 -0
- package/cjs/data-types/char-type.js +27 -0
- package/cjs/data-types/circle-type.js +48 -0
- package/cjs/data-types/date-type.js +67 -0
- package/cjs/data-types/float4-type.js +25 -0
- package/cjs/data-types/float8-type.js +25 -0
- package/cjs/data-types/int2-type.js +26 -0
- package/cjs/data-types/int2-vector-type.js +38 -0
- package/cjs/data-types/int4-type.js +26 -0
- package/cjs/data-types/int8-type.js +31 -0
- package/cjs/data-types/json-type.js +38 -0
- package/cjs/data-types/jsonb-type.js +42 -0
- package/cjs/data-types/lseg-type.js +52 -0
- package/cjs/data-types/numeric-type.js +125 -0
- package/cjs/data-types/oid-type.js +32 -0
- package/cjs/data-types/point-type.js +39 -0
- package/cjs/data-types/time-type.js +54 -0
- package/cjs/data-types/timestamp-type.js +81 -0
- package/cjs/data-types/timestamptz-type.js +73 -0
- package/cjs/data-types/uuid-type.js +39 -0
- package/cjs/data-types/varchar-type.js +27 -0
- package/cjs/index.js +41 -0
- package/cjs/interfaces/command-result.js +2 -0
- package/cjs/interfaces/data-mapping-options.js +2 -0
- package/cjs/interfaces/data-type.js +2 -0
- package/cjs/interfaces/database-connection-params.js +2 -0
- package/cjs/interfaces/field-info.js +2 -0
- package/cjs/interfaces/query-options.js +2 -0
- package/cjs/interfaces/query-result.js +2 -0
- package/cjs/interfaces/script-execute-options.js +2 -0
- package/cjs/interfaces/script-result.js +2 -0
- package/cjs/interfaces/statement-prepare-options.js +2 -0
- package/cjs/package.json +3 -0
- package/cjs/protocol/backend.js +256 -0
- package/cjs/protocol/buffer-reader.js +78 -0
- package/cjs/protocol/database-error.js +17 -0
- package/cjs/protocol/frontend.js +218 -0
- package/cjs/protocol/pg-socket.js +345 -0
- package/cjs/protocol/protocol.js +71 -0
- package/cjs/protocol/sasl.js +108 -0
- package/cjs/protocol/smart-buffer.js +195 -0
- package/cjs/safe-event-emitter.js +17 -0
- package/cjs/types.js +2 -0
- package/cjs/util/array-calculatedim.js +19 -0
- package/cjs/util/bigint-methods.js +42 -0
- package/cjs/util/config-from-env.js +30 -0
- package/cjs/util/connection-config.js +65 -0
- package/cjs/util/convert-row-to-object.js +13 -0
- package/cjs/util/decode-binaryarray.js +39 -0
- package/cjs/util/encode-binaryarray.js +45 -0
- package/cjs/util/escape-literal.js +27 -0
- package/cjs/util/fast-parseint.js +32 -0
- package/cjs/util/get-parsers.js +42 -0
- package/cjs/util/parse-array.js +61 -0
- package/cjs/util/parse-datetime.js +38 -0
- package/cjs/util/parse-row.js +11 -0
- package/cjs/util/parse-time.js +29 -0
- package/cjs/util/stringify-arrayliteral.js +38 -0
- package/cjs/util/stringify-for-sql.js +30 -0
- package/cjs/util/wrap-row-description.js +35 -0
- package/esm/connection/bind-param.js +6 -0
- package/esm/connection/connection.js +275 -0
- package/esm/connection/cursor.js +86 -0
- package/esm/connection/intl-connection.js +238 -0
- package/esm/connection/pool.js +222 -0
- package/esm/connection/portal.js +144 -0
- package/esm/connection/prepared-statement.js +213 -0
- package/esm/constants.js +247 -0
- package/esm/data-type-map.js +115 -0
- package/esm/data-types/bool-type.js +24 -0
- package/esm/data-types/box-type.js +49 -0
- package/esm/data-types/bytea-type.js +23 -0
- package/esm/data-types/char-type.js +24 -0
- package/esm/data-types/circle-type.js +45 -0
- package/esm/data-types/date-type.js +64 -0
- package/esm/data-types/float4-type.js +22 -0
- package/esm/data-types/float8-type.js +22 -0
- package/esm/data-types/int2-type.js +23 -0
- package/esm/data-types/int2-vector-type.js +35 -0
- package/esm/data-types/int4-type.js +23 -0
- package/esm/data-types/int8-type.js +28 -0
- package/esm/data-types/json-type.js +35 -0
- package/esm/data-types/jsonb-type.js +39 -0
- package/esm/data-types/lseg-type.js +49 -0
- package/esm/data-types/numeric-type.js +121 -0
- package/esm/data-types/oid-type.js +29 -0
- package/esm/data-types/point-type.js +36 -0
- package/esm/data-types/time-type.js +51 -0
- package/esm/data-types/timestamp-type.js +78 -0
- package/esm/data-types/timestamptz-type.js +70 -0
- package/esm/data-types/uuid-type.js +36 -0
- package/esm/data-types/varchar-type.js +24 -0
- package/esm/index.js +25 -0
- package/esm/interfaces/command-result.js +1 -0
- package/esm/interfaces/data-mapping-options.js +1 -0
- package/esm/interfaces/data-type.js +1 -0
- package/esm/interfaces/database-connection-params.js +1 -0
- package/esm/interfaces/field-info.js +1 -0
- package/esm/interfaces/query-options.js +1 -0
- package/esm/interfaces/query-result.js +1 -0
- package/esm/interfaces/script-execute-options.js +1 -0
- package/esm/interfaces/script-result.js +1 -0
- package/esm/interfaces/statement-prepare-options.js +1 -0
- package/esm/protocol/backend.js +252 -0
- package/esm/protocol/buffer-reader.js +74 -0
- package/esm/protocol/database-error.js +13 -0
- package/esm/protocol/frontend.js +214 -0
- package/esm/protocol/pg-socket.js +338 -0
- package/esm/protocol/protocol.js +68 -0
- package/esm/protocol/sasl.js +102 -0
- package/esm/protocol/smart-buffer.js +168 -0
- package/esm/safe-event-emitter.js +13 -0
- package/esm/types.js +1 -0
- package/esm/util/array-calculatedim.js +15 -0
- package/esm/util/bigint-methods.js +37 -0
- package/esm/util/config-from-env.js +26 -0
- package/esm/util/connection-config.js +57 -0
- package/esm/util/convert-row-to-object.js +9 -0
- package/esm/util/decode-binaryarray.js +35 -0
- package/esm/util/encode-binaryarray.js +41 -0
- package/esm/util/escape-literal.js +23 -0
- package/esm/util/fast-parseint.js +28 -0
- package/esm/util/get-parsers.js +38 -0
- package/esm/util/parse-array.js +57 -0
- package/esm/util/parse-datetime.js +34 -0
- package/esm/util/parse-row.js +7 -0
- package/esm/util/parse-time.js +25 -0
- package/esm/util/stringify-arrayliteral.js +34 -0
- package/esm/util/stringify-for-sql.js +25 -0
- package/esm/util/wrap-row-description.js +31 -0
- package/package.json +54 -0
- package/typings/connection/bind-param.d.ts +6 -0
- package/typings/connection/connection.d.ts +110 -0
- package/typings/connection/cursor.d.ts +25 -0
- package/typings/connection/intl-connection.d.ts +40 -0
- package/typings/connection/pool.d.ts +52 -0
- package/typings/connection/portal.d.ts +23 -0
- package/typings/connection/prepared-statement.d.ts +27 -0
- package/typings/constants.d.ts +130 -0
- package/typings/data-type-map.d.ts +11 -0
- package/typings/data-types/bool-type.d.ts +3 -0
- package/typings/data-types/box-type.d.ts +3 -0
- package/typings/data-types/bytea-type.d.ts +3 -0
- package/typings/data-types/char-type.d.ts +3 -0
- package/typings/data-types/circle-type.d.ts +3 -0
- package/typings/data-types/date-type.d.ts +3 -0
- package/typings/data-types/float4-type.d.ts +3 -0
- package/typings/data-types/float8-type.d.ts +3 -0
- package/typings/data-types/int2-type.d.ts +3 -0
- package/typings/data-types/int2-vector-type.d.ts +3 -0
- package/typings/data-types/int4-type.d.ts +3 -0
- package/typings/data-types/int8-type.d.ts +3 -0
- package/typings/data-types/json-type.d.ts +3 -0
- package/typings/data-types/jsonb-type.d.ts +3 -0
- package/typings/data-types/lseg-type.d.ts +3 -0
- package/typings/data-types/numeric-type.d.ts +12 -0
- package/typings/data-types/oid-type.d.ts +4 -0
- package/typings/data-types/point-type.d.ts +3 -0
- package/typings/data-types/time-type.d.ts +3 -0
- package/typings/data-types/timestamp-type.d.ts +3 -0
- package/typings/data-types/timestamptz-type.d.ts +3 -0
- package/typings/data-types/uuid-type.d.ts +3 -0
- package/typings/data-types/varchar-type.d.ts +3 -0
- package/typings/index.d.ts +25 -0
- package/typings/interfaces/command-result.d.ts +28 -0
- package/typings/interfaces/data-mapping-options.d.ts +9 -0
- package/typings/interfaces/data-type.d.ts +31 -0
- package/typings/interfaces/database-connection-params.d.ts +38 -0
- package/typings/interfaces/field-info.d.ts +46 -0
- package/typings/interfaces/query-options.d.ts +46 -0
- package/typings/interfaces/query-result.d.ts +8 -0
- package/typings/interfaces/script-execute-options.d.ts +26 -0
- package/typings/interfaces/script-result.d.ts +15 -0
- package/typings/interfaces/statement-prepare-options.d.ts +13 -0
- package/typings/protocol/backend.d.ts +9 -0
- package/typings/protocol/buffer-reader.d.ts +18 -0
- package/typings/protocol/database-error.d.ts +20 -0
- package/typings/protocol/frontend.d.ts +59 -0
- package/typings/protocol/pg-socket.d.ts +51 -0
- package/typings/protocol/protocol.d.ts +180 -0
- package/typings/protocol/sasl.d.ts +13 -0
- package/typings/protocol/smart-buffer.d.ts +39 -0
- package/typings/safe-event-emitter.d.ts +5 -0
- package/typings/types.d.ts +15 -0
- package/typings/util/array-calculatedim.d.ts +1 -0
- package/typings/util/bigint-methods.d.ts +3 -0
- package/typings/util/config-from-env.d.ts +2 -0
- package/typings/util/connection-config.d.ts +3 -0
- package/typings/util/convert-row-to-object.d.ts +2 -0
- package/typings/util/decode-binaryarray.d.ts +4 -0
- package/typings/util/encode-binaryarray.d.ts +5 -0
- package/typings/util/escape-literal.d.ts +1 -0
- package/typings/util/fast-parseint.d.ts +1 -0
- package/typings/util/get-parsers.d.ts +4 -0
- package/typings/util/parse-array.d.ts +5 -0
- package/typings/util/parse-datetime.d.ts +1 -0
- package/typings/util/parse-row.d.ts +3 -0
- package/typings/util/parse-time.d.ts +3 -0
- package/typings/util/stringify-arrayliteral.d.ts +3 -0
- package/typings/util/stringify-for-sql.d.ts +4 -0
- package/typings/util/wrap-row-description.d.ts +5 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* eslint-disable no-bitwise */
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
export var SASL;
|
|
4
|
+
(function (SASL) {
|
|
5
|
+
const CLIENT_KEY = 'Client Key';
|
|
6
|
+
const SERVER_KEY = 'Server Key';
|
|
7
|
+
const GS2_HEADER = 'n,,';
|
|
8
|
+
function createSession(username, mechanism) {
|
|
9
|
+
const nonce = crypto.randomBytes(18).toString('base64');
|
|
10
|
+
const clientFirstMessage = `${GS2_HEADER}${firstMessageBare(username, nonce)}`;
|
|
11
|
+
return {
|
|
12
|
+
username,
|
|
13
|
+
mechanism,
|
|
14
|
+
nonce,
|
|
15
|
+
clientFirstMessage,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
SASL.createSession = createSession;
|
|
19
|
+
function continueSession(session, password, data) {
|
|
20
|
+
const s = data.toString();
|
|
21
|
+
const items = s.split(',');
|
|
22
|
+
let nonce = '';
|
|
23
|
+
let salt = '';
|
|
24
|
+
let iteration = 0;
|
|
25
|
+
for (const i of items) {
|
|
26
|
+
switch (i[0]) {
|
|
27
|
+
case 'r':
|
|
28
|
+
nonce = i.substring(2);
|
|
29
|
+
break;
|
|
30
|
+
case 's':
|
|
31
|
+
salt = i.substring(2);
|
|
32
|
+
break;
|
|
33
|
+
case 'i':
|
|
34
|
+
iteration = parseInt(i.substring(2), 10);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!nonce)
|
|
39
|
+
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: nonce missing');
|
|
40
|
+
if (!salt)
|
|
41
|
+
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: salt missing');
|
|
42
|
+
if (!iteration)
|
|
43
|
+
throw new Error('SASL: SCRAM-SERVER-FIRST-MESSAGE: iteration missing');
|
|
44
|
+
if (!nonce.startsWith(session.nonce))
|
|
45
|
+
throw new Error('SASL: Server nonce does not start with client nonce');
|
|
46
|
+
const serverFirstMessage = `r=${nonce},s=${salt},i=${iteration}`;
|
|
47
|
+
const clientFinalMessageWithoutProof = `c=${encode64(GS2_HEADER)},r=${nonce}`;
|
|
48
|
+
const authMessage = `${firstMessageBare(session.username, session.nonce)},${serverFirstMessage},${clientFinalMessageWithoutProof}`;
|
|
49
|
+
const saltPass = hi(password, salt, iteration);
|
|
50
|
+
const clientKey = hmac(saltPass, CLIENT_KEY);
|
|
51
|
+
const storedKey = hash(clientKey);
|
|
52
|
+
const clientSignature = hmac(storedKey, authMessage);
|
|
53
|
+
const clientProofBytes = xor(clientKey, clientSignature);
|
|
54
|
+
const clientProof = clientProofBytes.toString('base64');
|
|
55
|
+
const serverKey = hmac(saltPass, SERVER_KEY);
|
|
56
|
+
const serverSignatureBytes = hmac(serverKey, authMessage);
|
|
57
|
+
session.serverSignature = serverSignatureBytes.toString('base64');
|
|
58
|
+
session.clientFinalMessage = clientFinalMessageWithoutProof + ',p=' + clientProof;
|
|
59
|
+
}
|
|
60
|
+
SASL.continueSession = continueSession;
|
|
61
|
+
function finalizeSession(session, data) {
|
|
62
|
+
let serverSignature = '';
|
|
63
|
+
const arr = data.split(',');
|
|
64
|
+
for (const s of arr) {
|
|
65
|
+
if (s[0] === 'v')
|
|
66
|
+
serverSignature = s.substr(2);
|
|
67
|
+
}
|
|
68
|
+
if (serverSignature !== session.serverSignature)
|
|
69
|
+
throw new Error('SASL: Server signature does not match');
|
|
70
|
+
}
|
|
71
|
+
SASL.finalizeSession = finalizeSession;
|
|
72
|
+
function firstMessageBare(username, nonce) {
|
|
73
|
+
return `n=${username},r=${nonce}`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Hi() is, essentially, PBKDF2 [RFC2898] with HMAC() as the
|
|
77
|
+
* pseudorandom function (PRF) and with dkLen == output length of
|
|
78
|
+
* HMAC() == output length of H()
|
|
79
|
+
*/
|
|
80
|
+
function hi(text, salt, iterations) {
|
|
81
|
+
return crypto.pbkdf2Sync(text, Buffer.from(salt, 'base64'), iterations, 32, 'sha256');
|
|
82
|
+
}
|
|
83
|
+
const encode64 = str => Buffer.from(str).toString('base64');
|
|
84
|
+
function hmac(key, msg) {
|
|
85
|
+
return crypto.createHmac('sha256', key).update(msg).digest();
|
|
86
|
+
}
|
|
87
|
+
function hash(data) {
|
|
88
|
+
return crypto.createHash('sha256').update(data).digest();
|
|
89
|
+
}
|
|
90
|
+
function xor(a, b) {
|
|
91
|
+
a = Buffer.isBuffer(a) ? a : Buffer.from(a);
|
|
92
|
+
b = Buffer.isBuffer(b) ? b : Buffer.from(b);
|
|
93
|
+
if (a.length !== b.length)
|
|
94
|
+
throw new Error('Buffers must be of the same length');
|
|
95
|
+
const l = a.length;
|
|
96
|
+
const out = Buffer.allocUnsafe(l);
|
|
97
|
+
for (let i = 0; i < l; i++) {
|
|
98
|
+
out[i] = a[i] ^ b[i];
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
})(SASL || (SASL = {}));
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import * as os from 'os';
|
|
2
|
+
import { writeBigUInt64BE } from '../util/bigint-methods.js';
|
|
3
|
+
import { BufferReader } from './buffer-reader.js';
|
|
4
|
+
export class SmartBuffer extends BufferReader {
|
|
5
|
+
constructor(cfg) {
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
super(Buffer.allocUnsafe((cfg?.pageSize ? parseInt(cfg.pageSize, 10) : 0) || SmartBuffer.DEFAULT_PAGE_SIZE));
|
|
8
|
+
this._lastHouseKeep = 0;
|
|
9
|
+
this._stMaxPages = 1;
|
|
10
|
+
this._length = 0;
|
|
11
|
+
this._houseKeepInterval = cfg?.houseKeepInterval || 5000;
|
|
12
|
+
this.pageSize = this.buffer.length;
|
|
13
|
+
this.maxSize = cfg?.maxLength || SmartBuffer.DEFAULT_MAX_SIZE;
|
|
14
|
+
this._length = 0;
|
|
15
|
+
}
|
|
16
|
+
get capacity() {
|
|
17
|
+
return this.buffer.length;
|
|
18
|
+
}
|
|
19
|
+
get length() {
|
|
20
|
+
return this._length;
|
|
21
|
+
}
|
|
22
|
+
start() {
|
|
23
|
+
this.offset = 0;
|
|
24
|
+
this._length = 0;
|
|
25
|
+
if (this._houseKeepTimer) {
|
|
26
|
+
clearTimeout(this._houseKeepTimer);
|
|
27
|
+
this._houseKeepTimer = undefined;
|
|
28
|
+
}
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
flush() {
|
|
32
|
+
if (this._houseKeepTimer)
|
|
33
|
+
clearTimeout(this._houseKeepTimer);
|
|
34
|
+
const length = this.length;
|
|
35
|
+
this._length = 0;
|
|
36
|
+
const out = this.buffer.slice(0, length);
|
|
37
|
+
const pages = length ? Math.ceil(length / this.pageSize) : 1;
|
|
38
|
+
this._stMaxPages = Math.max(this._stMaxPages, pages);
|
|
39
|
+
if (this._lastHouseKeep < Date.now() + this._houseKeepInterval)
|
|
40
|
+
this._houseKeep();
|
|
41
|
+
this._houseKeepTimer = setTimeout(() => {
|
|
42
|
+
this._houseKeepTimer = undefined;
|
|
43
|
+
this._houseKeep();
|
|
44
|
+
}, this._houseKeepInterval).unref();
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
growSize(len) {
|
|
48
|
+
const endOffset = this.offset + len;
|
|
49
|
+
if (this.capacity < endOffset) {
|
|
50
|
+
if (endOffset > this.maxSize)
|
|
51
|
+
throw new Error('Buffer limit exceeded.');
|
|
52
|
+
const newSize = Math.ceil(endOffset / this.pageSize) * this.pageSize;
|
|
53
|
+
const newBuffer = Buffer.allocUnsafe(newSize);
|
|
54
|
+
this.buffer.copy(newBuffer);
|
|
55
|
+
this.buffer = newBuffer;
|
|
56
|
+
}
|
|
57
|
+
this._length = Math.max(this.length, endOffset);
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
fill(value = 0, len = 1) {
|
|
61
|
+
this.growSize(len);
|
|
62
|
+
this.buffer.fill(value, this.offset, this.offset + len);
|
|
63
|
+
this.offset += len;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
writeCString(str, encoding) {
|
|
67
|
+
const len = str ? Buffer.byteLength(str, encoding) : 0;
|
|
68
|
+
this.growSize(len + 1);
|
|
69
|
+
if (str) {
|
|
70
|
+
this.buffer.write(str, this.offset, encoding);
|
|
71
|
+
this.offset += len;
|
|
72
|
+
}
|
|
73
|
+
this.writeUInt8(0);
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
writeLString(str, encoding) {
|
|
77
|
+
const len = str ? Buffer.byteLength(str, encoding) : 0;
|
|
78
|
+
this.growSize(len + 4);
|
|
79
|
+
this.writeInt32BE(str == null ? -1 : len);
|
|
80
|
+
if (str) {
|
|
81
|
+
if (encoding)
|
|
82
|
+
this.offset += this.buffer.write(str, this.offset, encoding);
|
|
83
|
+
else
|
|
84
|
+
this.offset += this.buffer.write(str, this.offset);
|
|
85
|
+
}
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
writeString(str, encoding) {
|
|
89
|
+
if (str) {
|
|
90
|
+
const len = Buffer.byteLength(str, encoding);
|
|
91
|
+
this.growSize(len);
|
|
92
|
+
this.offset += this.buffer.write(str, this.offset, encoding);
|
|
93
|
+
}
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
writeInt8(n) {
|
|
97
|
+
this.growSize(1);
|
|
98
|
+
this.buffer.writeInt8(n, this.offset);
|
|
99
|
+
this.offset++;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
writeUInt8(n) {
|
|
103
|
+
this.growSize(1);
|
|
104
|
+
this.buffer.writeUInt8(n, this.offset);
|
|
105
|
+
this.offset++;
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
writeUInt16BE(n) {
|
|
109
|
+
this.growSize(2);
|
|
110
|
+
this.buffer.writeUInt16BE(n, this.offset);
|
|
111
|
+
this.offset += 2;
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
writeUInt32BE(n) {
|
|
115
|
+
this.growSize(4);
|
|
116
|
+
this.buffer.writeUInt32BE(n, this.offset);
|
|
117
|
+
this.offset += 4;
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
writeInt16BE(n) {
|
|
121
|
+
this.growSize(2);
|
|
122
|
+
this.buffer.writeInt16BE(n, this.offset);
|
|
123
|
+
this.offset += 2;
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
writeInt32BE(n) {
|
|
127
|
+
this.growSize(4);
|
|
128
|
+
this.buffer.writeInt32BE(n, this.offset);
|
|
129
|
+
this.offset += 4;
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
writeBigInt64BE(n) {
|
|
133
|
+
n = typeof n === 'bigint' ? n : BigInt(n);
|
|
134
|
+
this.growSize(8);
|
|
135
|
+
if (typeof this.buffer.writeBigInt64BE === 'function')
|
|
136
|
+
this.buffer.writeBigInt64BE(n, this.offset);
|
|
137
|
+
else
|
|
138
|
+
writeBigUInt64BE(this.buffer, n, this.offset);
|
|
139
|
+
this.offset += 8;
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
writeFloatBE(n) {
|
|
143
|
+
this.growSize(4);
|
|
144
|
+
this.buffer.writeFloatBE(n, this.offset);
|
|
145
|
+
this.offset += 4;
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
writeDoubleBE(n) {
|
|
149
|
+
this.growSize(8);
|
|
150
|
+
this.buffer.writeDoubleBE(n, this.offset);
|
|
151
|
+
this.offset += 8;
|
|
152
|
+
return this;
|
|
153
|
+
}
|
|
154
|
+
writeBuffer(buffer) {
|
|
155
|
+
this.growSize(buffer.length);
|
|
156
|
+
buffer.copy(this.buffer, this.offset, 0, buffer.length);
|
|
157
|
+
this.offset += buffer.length;
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
_houseKeep() {
|
|
161
|
+
const needSize = this._stMaxPages * this.pageSize;
|
|
162
|
+
if (this.buffer.length > needSize)
|
|
163
|
+
this.buffer = Buffer.allocUnsafe(needSize);
|
|
164
|
+
this._stMaxPages = this.length ? Math.ceil(this.length / this.pageSize) : 1;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
SmartBuffer.DEFAULT_PAGE_SIZE = 4096;
|
|
168
|
+
SmartBuffer.DEFAULT_MAX_SIZE = Math.min(Math.floor(os.totalmem() / 2), 1024 * 1024 * 1024 * 2);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
export class SafeEventEmitter extends EventEmitter {
|
|
3
|
+
emit(event, ...args) {
|
|
4
|
+
try {
|
|
5
|
+
if (event === 'error' && !this.listenerCount('error'))
|
|
6
|
+
return false;
|
|
7
|
+
return super.emit(event, ...args);
|
|
8
|
+
}
|
|
9
|
+
catch (ignored) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
package/esm/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function arrayCalculateDim(arr) {
|
|
2
|
+
if (!arr || arr.length === 0)
|
|
3
|
+
return [0];
|
|
4
|
+
const dim = [arr.length];
|
|
5
|
+
const iterate = (a, level) => {
|
|
6
|
+
for (let i = 0; i < a.length; i++) {
|
|
7
|
+
if (Array.isArray(a[i])) {
|
|
8
|
+
dim[level] = Math.max(dim[level] || 0, a[i].length);
|
|
9
|
+
iterate(a[i], level + 1);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
iterate(arr, 1);
|
|
14
|
+
return dim;
|
|
15
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* eslint-disable no-bitwise */
|
|
2
|
+
const big0 = BigInt(0);
|
|
3
|
+
const beAnd = BigInt('0xffffffff');
|
|
4
|
+
const big32 = BigInt(32);
|
|
5
|
+
// https://github.com/nodejs/node/blob/v13.9.0/lib/internal/buffer.js
|
|
6
|
+
export function readBigInt64BE(buf, offset = 0) {
|
|
7
|
+
const first = buf[offset];
|
|
8
|
+
const last = buf[offset + 7];
|
|
9
|
+
if (first === undefined || last === undefined)
|
|
10
|
+
return big0;
|
|
11
|
+
const val = (first << 24) + // Overflow
|
|
12
|
+
buf[++offset] * 2 ** 16 +
|
|
13
|
+
buf[++offset] * 2 ** 8 +
|
|
14
|
+
buf[++offset];
|
|
15
|
+
return ((BigInt(val) << big32) + BigInt(buf[++offset] * 2 ** 24 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 8 + last));
|
|
16
|
+
}
|
|
17
|
+
export function writeBigUInt64BE(buf, value, offset = 0) {
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
let lo = Number(value & beAnd);
|
|
20
|
+
buf[offset + 7] = lo;
|
|
21
|
+
lo = lo >> 8;
|
|
22
|
+
buf[offset + 6] = lo;
|
|
23
|
+
lo = lo >> 8;
|
|
24
|
+
buf[offset + 5] = lo;
|
|
25
|
+
lo = lo >> 8;
|
|
26
|
+
buf[offset + 4] = lo;
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
let hi = Number((value >> big32) & beAnd);
|
|
29
|
+
buf[offset + 3] = hi;
|
|
30
|
+
hi = hi >> 8;
|
|
31
|
+
buf[offset + 2] = hi;
|
|
32
|
+
hi = hi >> 8;
|
|
33
|
+
buf[offset + 1] = hi;
|
|
34
|
+
hi = hi >> 8;
|
|
35
|
+
buf[offset] = hi;
|
|
36
|
+
return offset + 8;
|
|
37
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { toInt, toIntDef } from 'putil-varhelpers';
|
|
2
|
+
export function configFromEnv() {
|
|
3
|
+
const env = process.env;
|
|
4
|
+
const result = {};
|
|
5
|
+
result.host = env.PGHOST || env.PGHOSTADDR;
|
|
6
|
+
if (env.PGPORT)
|
|
7
|
+
result.port = toIntDef(env.PGPORT, 5432);
|
|
8
|
+
if (env.PGDATABASE)
|
|
9
|
+
result.database = env.PGDATABASE;
|
|
10
|
+
if (env.PGUSER)
|
|
11
|
+
result.user = env.PGUSER;
|
|
12
|
+
if (env.PGPASSWORD)
|
|
13
|
+
result.password = env.PGPASSWORD;
|
|
14
|
+
if (env.PGAPPNAME)
|
|
15
|
+
result.applicationName = env.PGAPPNAME;
|
|
16
|
+
if (env.PGTZ)
|
|
17
|
+
result.timezone = env.PGTZ;
|
|
18
|
+
if (env.PGSCHEMA)
|
|
19
|
+
result.schema = env.PGSCHEMA;
|
|
20
|
+
if (env.PGCONNECT_TIMEOUT)
|
|
21
|
+
result.connectTimeoutMs = toIntDef(env.PGCONNECT_TIMEOUT, 30000);
|
|
22
|
+
if (env.PGMAX_BUFFER_SIZE) {
|
|
23
|
+
result.buffer = { maxLength: toInt(env.PGMAX_BUFFER_SIZE) };
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import merge from 'putil-merge';
|
|
2
|
+
import { configFromEnv } from './config-from-env.js';
|
|
3
|
+
export function getConnectionConfig(config) {
|
|
4
|
+
const cfg = configFromEnv();
|
|
5
|
+
if (typeof config === 'string') {
|
|
6
|
+
merge(cfg, parseConnectionString(config));
|
|
7
|
+
}
|
|
8
|
+
else if (typeof config === 'object') {
|
|
9
|
+
merge(cfg, config);
|
|
10
|
+
}
|
|
11
|
+
if (cfg.host) {
|
|
12
|
+
const x = parseConnectionString('' + cfg.host);
|
|
13
|
+
merge(cfg, x);
|
|
14
|
+
}
|
|
15
|
+
cfg.user = cfg.user || 'postgres';
|
|
16
|
+
cfg.database = cfg.database || 'postgres';
|
|
17
|
+
cfg.host = cfg.host || '127.0.0.1';
|
|
18
|
+
return cfg;
|
|
19
|
+
}
|
|
20
|
+
export function parseConnectionString(str) {
|
|
21
|
+
if (str.startsWith('/'))
|
|
22
|
+
str = 'socket:/' + str;
|
|
23
|
+
if (!str.includes('://'))
|
|
24
|
+
str = 'postgres://' + str;
|
|
25
|
+
const parsed = new URL(str);
|
|
26
|
+
const getFirst = (v) => {
|
|
27
|
+
return typeof v === 'string' ? v : Array.isArray(v) ? v[0] : '';
|
|
28
|
+
};
|
|
29
|
+
const cfg = {};
|
|
30
|
+
cfg.host = decodeURI(parsed.hostname || '');
|
|
31
|
+
if (parsed.port)
|
|
32
|
+
cfg.port = parseInt(parsed.port, 10);
|
|
33
|
+
if (parsed.protocol === 'socket:' || parsed.protocol === 'unix:') {
|
|
34
|
+
if (!cfg.host.startsWith('/'))
|
|
35
|
+
cfg.host = '/' + cfg.host;
|
|
36
|
+
cfg.host += decodeURI(parsed.pathname || '');
|
|
37
|
+
if (parsed.searchParams.get('db'))
|
|
38
|
+
cfg.database = decodeURI(getFirst(parsed.searchParams.get('db')));
|
|
39
|
+
}
|
|
40
|
+
else if (parsed.protocol === 'pg:' || parsed.protocol === 'postgres:') {
|
|
41
|
+
if (parsed.pathname)
|
|
42
|
+
cfg.database = decodeURI(parsed.pathname.substring(1));
|
|
43
|
+
}
|
|
44
|
+
if (parsed.searchParams.get('host'))
|
|
45
|
+
cfg.host = decodeURI(getFirst(parsed.searchParams.get('host')));
|
|
46
|
+
if (parsed.searchParams.get('db'))
|
|
47
|
+
cfg.database = decodeURI(getFirst(parsed.searchParams.get('db')));
|
|
48
|
+
if (parsed.searchParams.get('schema'))
|
|
49
|
+
cfg.schema = decodeURI(getFirst(parsed.searchParams.get('schema')));
|
|
50
|
+
if (parsed.searchParams.get('application_name'))
|
|
51
|
+
cfg.applicationName = decodeURI(getFirst(parsed.searchParams.get('application_name')));
|
|
52
|
+
if (parsed.username)
|
|
53
|
+
cfg.user = parsed.username;
|
|
54
|
+
if (parsed.password)
|
|
55
|
+
cfg.password = parsed.password;
|
|
56
|
+
return cfg;
|
|
57
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BufferReader } from '../protocol/buffer-reader.js';
|
|
2
|
+
export function decodeBinaryArray(buf, decoder, options = {}) {
|
|
3
|
+
if (!buf.length)
|
|
4
|
+
return null;
|
|
5
|
+
const io = new BufferReader(buf);
|
|
6
|
+
const ndims = io.readInt32BE();
|
|
7
|
+
io.readInt32BE(); // hasNulls
|
|
8
|
+
const elementOID = io.readInt32BE(); // element oid
|
|
9
|
+
if (ndims === 0)
|
|
10
|
+
return [];
|
|
11
|
+
const dims = [];
|
|
12
|
+
const readDim = (level) => {
|
|
13
|
+
const elemCount = dims[level];
|
|
14
|
+
const target = new Array(elemCount);
|
|
15
|
+
for (let i = 0; i < elemCount; i++) {
|
|
16
|
+
if (level < dims.length - 1) {
|
|
17
|
+
target[i] = readDim(level + 1);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const len = io.readInt32BE();
|
|
21
|
+
if (len === -1)
|
|
22
|
+
target[i] = null;
|
|
23
|
+
else {
|
|
24
|
+
const b = io.readBuffer(len);
|
|
25
|
+
target[i] = decoder(b, { ...options, elementOID });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return target;
|
|
29
|
+
};
|
|
30
|
+
for (let d = 0; d < ndims; d++) {
|
|
31
|
+
dims[d] = io.readInt32BE();
|
|
32
|
+
io.readInt32BE(); // LBound
|
|
33
|
+
}
|
|
34
|
+
return readDim(0);
|
|
35
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { DataTypeOIDs } from '../constants.js';
|
|
2
|
+
import { arrayCalculateDim } from './array-calculatedim.js';
|
|
3
|
+
export function encodeBinaryArray(io, value, itemOid, options, encode, encodeCalculateDimFn) {
|
|
4
|
+
encodeCalculateDimFn = encodeCalculateDimFn || arrayCalculateDim;
|
|
5
|
+
itemOid = itemOid || DataTypeOIDs.varchar;
|
|
6
|
+
const dim = encodeCalculateDimFn(value);
|
|
7
|
+
const ndims = dim.length;
|
|
8
|
+
const zeroOffset = io.offset;
|
|
9
|
+
io.writeInt32BE(ndims) // Number of dimensions
|
|
10
|
+
.writeInt32BE(0) // reserved for has-null flag
|
|
11
|
+
.writeInt32BE(itemOid);
|
|
12
|
+
for (let d = 0; d < ndims; d++) {
|
|
13
|
+
io.writeInt32BE(dim[d]); // Number of items in dimension
|
|
14
|
+
io.writeInt32BE(0); // LBound always 0.
|
|
15
|
+
}
|
|
16
|
+
let hasNull = false;
|
|
17
|
+
let pos;
|
|
18
|
+
const writeDim = (arr, level) => {
|
|
19
|
+
const elemCount = dim[level];
|
|
20
|
+
for (let i = 0; i < elemCount; i++) {
|
|
21
|
+
if (level < dim.length - 1) {
|
|
22
|
+
writeDim(arr && arr[i], level + 1);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
// if value is null
|
|
26
|
+
if (!arr || arr[i] == null) {
|
|
27
|
+
hasNull = true;
|
|
28
|
+
io.writeInt32BE(-1);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
io.writeInt32BE(0); // reserved for data len
|
|
32
|
+
pos = io.offset;
|
|
33
|
+
encode(io, arr[i], options);
|
|
34
|
+
// Update item data size
|
|
35
|
+
io.buffer.writeInt32BE(io.length - pos, pos - 4);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
writeDim(value, 0);
|
|
39
|
+
if (hasNull)
|
|
40
|
+
io.buffer.writeInt32BE(1, zeroOffset + 4);
|
|
41
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Ported from PostgreSQL 9.2.4 source code in src/interfaces/libpq/fe-exec.c
|
|
2
|
+
export function escapeLiteral(str) {
|
|
3
|
+
let backSlash = false;
|
|
4
|
+
let out = "'";
|
|
5
|
+
let i;
|
|
6
|
+
let c;
|
|
7
|
+
const l = str.length;
|
|
8
|
+
for (i = 0; i < l; i++) {
|
|
9
|
+
c = str[i];
|
|
10
|
+
if (c === "'")
|
|
11
|
+
out += c + c;
|
|
12
|
+
else if (c === '\\') {
|
|
13
|
+
out += c + c;
|
|
14
|
+
backSlash = true;
|
|
15
|
+
}
|
|
16
|
+
else
|
|
17
|
+
out += c;
|
|
18
|
+
}
|
|
19
|
+
out += "'";
|
|
20
|
+
if (backSlash)
|
|
21
|
+
out = ' E' + out;
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function fastParseInt(str) {
|
|
2
|
+
/* istanbul ignore next */
|
|
3
|
+
if (typeof str === 'number')
|
|
4
|
+
return Math.floor(str);
|
|
5
|
+
// noinspection SuspiciousTypeOfGuard
|
|
6
|
+
if (typeof str !== 'string')
|
|
7
|
+
return NaN;
|
|
8
|
+
const strLength = str.length;
|
|
9
|
+
let res = 0;
|
|
10
|
+
let i = 0;
|
|
11
|
+
let neg = false;
|
|
12
|
+
if (str.startsWith('-')) {
|
|
13
|
+
neg = true;
|
|
14
|
+
i++;
|
|
15
|
+
}
|
|
16
|
+
do {
|
|
17
|
+
const charCode = str.charCodeAt(i);
|
|
18
|
+
/* istanbul ignore next */
|
|
19
|
+
if (charCode === 46)
|
|
20
|
+
return res;
|
|
21
|
+
/* istanbul ignore next */
|
|
22
|
+
if (charCode < 48 || charCode > 57)
|
|
23
|
+
return NaN;
|
|
24
|
+
res *= 10;
|
|
25
|
+
res += charCode - 48;
|
|
26
|
+
} while (++i < strLength);
|
|
27
|
+
return neg ? -res : res;
|
|
28
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DataFormat } from '../constants.js';
|
|
2
|
+
import { decodeBinaryArray } from './decode-binaryarray.js';
|
|
3
|
+
import { parsePostgresArray } from './parse-array.js';
|
|
4
|
+
const DefaultColumnParser = (v) => v;
|
|
5
|
+
export function getParsers(typeMap, fields) {
|
|
6
|
+
const parsers = new Array(fields.length);
|
|
7
|
+
const l = fields.length;
|
|
8
|
+
let f;
|
|
9
|
+
let i;
|
|
10
|
+
for (i = 0; i < l; i++) {
|
|
11
|
+
f = fields[i];
|
|
12
|
+
const dataTypeReg = typeMap.get(f.dataTypeId);
|
|
13
|
+
if (dataTypeReg) {
|
|
14
|
+
const isArray = !!dataTypeReg.elementsOID;
|
|
15
|
+
if (f.format === DataFormat.binary) {
|
|
16
|
+
const decode = dataTypeReg.parseBinary;
|
|
17
|
+
if (decode) {
|
|
18
|
+
parsers[i] = !isArray
|
|
19
|
+
? decode
|
|
20
|
+
: (v, options) => decodeBinaryArray(v, decode, options);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else if (f.format === DataFormat.text) {
|
|
24
|
+
const parse = dataTypeReg.parseText;
|
|
25
|
+
if (parse) {
|
|
26
|
+
parsers[i] = !isArray
|
|
27
|
+
? parse
|
|
28
|
+
: (v, options) => parsePostgresArray(v, {
|
|
29
|
+
transform: x => parse(x, options),
|
|
30
|
+
separator: dataTypeReg.arraySeparator,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
parsers[i] = parsers[i] || DefaultColumnParser;
|
|
36
|
+
}
|
|
37
|
+
return parsers;
|
|
38
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export function parsePostgresArray(s, opts) {
|
|
2
|
+
if (!s)
|
|
3
|
+
return;
|
|
4
|
+
const sep = (opts?.separator || ',').substring(0, 1);
|
|
5
|
+
const transform = opts?.transform;
|
|
6
|
+
const len = s.length;
|
|
7
|
+
let idx = 0;
|
|
8
|
+
const out = [];
|
|
9
|
+
const iterate = (arr) => {
|
|
10
|
+
let c;
|
|
11
|
+
let exactlyValue = false;
|
|
12
|
+
let token = '';
|
|
13
|
+
let quote = '';
|
|
14
|
+
while (idx < len) {
|
|
15
|
+
c = s.charAt(idx++);
|
|
16
|
+
if (!quote) {
|
|
17
|
+
if (!token && c === '{') {
|
|
18
|
+
const a = [];
|
|
19
|
+
arr.push(a);
|
|
20
|
+
iterate(a);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (c === '}' || c === sep) {
|
|
24
|
+
if (token) {
|
|
25
|
+
if (token === 'NULL' && !exactlyValue)
|
|
26
|
+
arr.push(null);
|
|
27
|
+
else
|
|
28
|
+
arr.push(transform ? transform(token) : token);
|
|
29
|
+
exactlyValue = false;
|
|
30
|
+
}
|
|
31
|
+
token = '';
|
|
32
|
+
if (c === '}')
|
|
33
|
+
return;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (c === '\\') {
|
|
38
|
+
c = s.charAt(idx++);
|
|
39
|
+
token += c;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (c === '"' || c === "'") {
|
|
43
|
+
if (quote && quote === c) {
|
|
44
|
+
quote = '';
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
exactlyValue = true;
|
|
48
|
+
quote = c;
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
token += c;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
iterate(out);
|
|
56
|
+
return out.length ? out[0] : undefined;
|
|
57
|
+
}
|