@bytebase/dbhub 0.19.1 → 0.21.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/dist/chunk-BRXZ5ZQB.js +127 -0
- package/dist/chunk-C7WEAPX4.js +485 -0
- package/dist/{chunk-LUNM7TUY.js → chunk-GRGEI5QT.js} +24 -476
- package/dist/chunk-JFWX35TB.js +34 -0
- package/dist/chunk-RTB262PR.js +60 -0
- package/dist/index.js +79 -2377
- package/dist/mariadb-VGTS4WXE.js +462 -0
- package/dist/mysql-I35IQ2GH.js +469 -0
- package/dist/postgres-B7YSSZMH.js +480 -0
- package/dist/{registry-6VNMKD6G.js → registry-XSMMLRC4.js} +2 -1
- package/dist/sqlite-FSCLCRIH.js +320 -0
- package/dist/sqlserver-FDBRUELV.js +479 -0
- package/package.json +8 -6
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
import {
|
|
2
|
+
quoteIdentifier
|
|
3
|
+
} from "./chunk-JFWX35TB.js";
|
|
4
|
+
import {
|
|
5
|
+
SQLRowLimiter
|
|
6
|
+
} from "./chunk-BRXZ5ZQB.js";
|
|
7
|
+
import {
|
|
8
|
+
ConnectorRegistry,
|
|
9
|
+
SafeURL,
|
|
10
|
+
obfuscateDSNPassword,
|
|
11
|
+
splitSQLStatements
|
|
12
|
+
} from "./chunk-C7WEAPX4.js";
|
|
13
|
+
|
|
14
|
+
// src/connectors/postgres/index.ts
|
|
15
|
+
import pg from "pg";
|
|
16
|
+
var { Pool } = pg;
|
|
17
|
+
var PostgresDSNParser = class {
|
|
18
|
+
async parse(dsn, config) {
|
|
19
|
+
const connectionTimeoutSeconds = config?.connectionTimeoutSeconds;
|
|
20
|
+
const queryTimeoutSeconds = config?.queryTimeoutSeconds;
|
|
21
|
+
if (!this.isValidDSN(dsn)) {
|
|
22
|
+
const obfuscatedDSN = obfuscateDSNPassword(dsn);
|
|
23
|
+
const expectedFormat = this.getSampleDSN();
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Invalid PostgreSQL DSN format.
|
|
26
|
+
Provided: ${obfuscatedDSN}
|
|
27
|
+
Expected: ${expectedFormat}`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const url = new SafeURL(dsn);
|
|
32
|
+
const poolConfig = {
|
|
33
|
+
host: url.hostname,
|
|
34
|
+
port: url.port ? parseInt(url.port) : 5432,
|
|
35
|
+
database: url.pathname ? url.pathname.substring(1) : "",
|
|
36
|
+
// Remove leading '/' if exists
|
|
37
|
+
user: url.username,
|
|
38
|
+
password: url.password
|
|
39
|
+
};
|
|
40
|
+
url.forEachSearchParam((value, key) => {
|
|
41
|
+
if (key === "sslmode") {
|
|
42
|
+
if (value === "disable") {
|
|
43
|
+
poolConfig.ssl = false;
|
|
44
|
+
} else if (value === "require") {
|
|
45
|
+
poolConfig.ssl = { rejectUnauthorized: false };
|
|
46
|
+
} else {
|
|
47
|
+
poolConfig.ssl = true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
if (connectionTimeoutSeconds !== void 0) {
|
|
52
|
+
poolConfig.connectionTimeoutMillis = connectionTimeoutSeconds * 1e3;
|
|
53
|
+
}
|
|
54
|
+
if (queryTimeoutSeconds !== void 0) {
|
|
55
|
+
poolConfig.query_timeout = queryTimeoutSeconds * 1e3;
|
|
56
|
+
}
|
|
57
|
+
return poolConfig;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Failed to parse PostgreSQL DSN: ${error instanceof Error ? error.message : String(error)}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
getSampleDSN() {
|
|
65
|
+
return "postgres://postgres:password@localhost:5432/postgres?sslmode=require";
|
|
66
|
+
}
|
|
67
|
+
isValidDSN(dsn) {
|
|
68
|
+
try {
|
|
69
|
+
return dsn.startsWith("postgres://") || dsn.startsWith("postgresql://");
|
|
70
|
+
} catch (error) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var PostgresConnector = class _PostgresConnector {
|
|
76
|
+
constructor() {
|
|
77
|
+
this.id = "postgres";
|
|
78
|
+
this.name = "PostgreSQL";
|
|
79
|
+
this.dsnParser = new PostgresDSNParser();
|
|
80
|
+
this.pool = null;
|
|
81
|
+
// Source ID is set by ConnectorManager after cloning
|
|
82
|
+
this.sourceId = "default";
|
|
83
|
+
// Default schema for discovery methods (first entry from search_path, or "public")
|
|
84
|
+
this.defaultSchema = "public";
|
|
85
|
+
}
|
|
86
|
+
getId() {
|
|
87
|
+
return this.sourceId;
|
|
88
|
+
}
|
|
89
|
+
clone() {
|
|
90
|
+
return new _PostgresConnector();
|
|
91
|
+
}
|
|
92
|
+
async connect(dsn, initScript, config) {
|
|
93
|
+
this.defaultSchema = "public";
|
|
94
|
+
try {
|
|
95
|
+
const poolConfig = await this.dsnParser.parse(dsn, config);
|
|
96
|
+
if (config?.readonly) {
|
|
97
|
+
poolConfig.options = (poolConfig.options || "") + " -c default_transaction_read_only=on";
|
|
98
|
+
}
|
|
99
|
+
if (config?.searchPath) {
|
|
100
|
+
const schemas = config.searchPath.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
101
|
+
if (schemas.length > 0) {
|
|
102
|
+
this.defaultSchema = schemas[0];
|
|
103
|
+
const quotedSchemas = schemas.map((s) => quoteIdentifier(s, "postgres"));
|
|
104
|
+
const optionsValue = quotedSchemas.join(",").replace(/\\/g, "\\\\").replace(/ /g, "\\ ");
|
|
105
|
+
poolConfig.options = (poolConfig.options || "") + ` -c search_path=${optionsValue}`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
this.pool = new Pool(poolConfig);
|
|
109
|
+
const client = await this.pool.connect();
|
|
110
|
+
client.release();
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.error("Failed to connect to PostgreSQL database:", err);
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async disconnect() {
|
|
117
|
+
if (this.pool) {
|
|
118
|
+
await this.pool.end();
|
|
119
|
+
this.pool = null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async getSchemas() {
|
|
123
|
+
if (!this.pool) {
|
|
124
|
+
throw new Error("Not connected to database");
|
|
125
|
+
}
|
|
126
|
+
const client = await this.pool.connect();
|
|
127
|
+
try {
|
|
128
|
+
const result = await client.query(`
|
|
129
|
+
SELECT schema_name
|
|
130
|
+
FROM information_schema.schemata
|
|
131
|
+
WHERE schema_name NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
|
|
132
|
+
ORDER BY schema_name
|
|
133
|
+
`);
|
|
134
|
+
return result.rows.map((row) => row.schema_name);
|
|
135
|
+
} finally {
|
|
136
|
+
client.release();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async getTables(schema) {
|
|
140
|
+
if (!this.pool) {
|
|
141
|
+
throw new Error("Not connected to database");
|
|
142
|
+
}
|
|
143
|
+
const client = await this.pool.connect();
|
|
144
|
+
try {
|
|
145
|
+
const schemaToUse = schema || this.defaultSchema;
|
|
146
|
+
const result = await client.query(
|
|
147
|
+
`
|
|
148
|
+
SELECT table_name
|
|
149
|
+
FROM information_schema.tables
|
|
150
|
+
WHERE table_schema = $1
|
|
151
|
+
ORDER BY table_name
|
|
152
|
+
`,
|
|
153
|
+
[schemaToUse]
|
|
154
|
+
);
|
|
155
|
+
return result.rows.map((row) => row.table_name);
|
|
156
|
+
} finally {
|
|
157
|
+
client.release();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async tableExists(tableName, schema) {
|
|
161
|
+
if (!this.pool) {
|
|
162
|
+
throw new Error("Not connected to database");
|
|
163
|
+
}
|
|
164
|
+
const client = await this.pool.connect();
|
|
165
|
+
try {
|
|
166
|
+
const schemaToUse = schema || this.defaultSchema;
|
|
167
|
+
const result = await client.query(
|
|
168
|
+
`
|
|
169
|
+
SELECT EXISTS (
|
|
170
|
+
SELECT FROM information_schema.tables
|
|
171
|
+
WHERE table_schema = $1
|
|
172
|
+
AND table_name = $2
|
|
173
|
+
)
|
|
174
|
+
`,
|
|
175
|
+
[schemaToUse, tableName]
|
|
176
|
+
);
|
|
177
|
+
return result.rows[0].exists;
|
|
178
|
+
} finally {
|
|
179
|
+
client.release();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async getTableIndexes(tableName, schema) {
|
|
183
|
+
if (!this.pool) {
|
|
184
|
+
throw new Error("Not connected to database");
|
|
185
|
+
}
|
|
186
|
+
const client = await this.pool.connect();
|
|
187
|
+
try {
|
|
188
|
+
const schemaToUse = schema || this.defaultSchema;
|
|
189
|
+
const result = await client.query(
|
|
190
|
+
`
|
|
191
|
+
SELECT
|
|
192
|
+
i.relname as index_name,
|
|
193
|
+
array_agg(a.attname) as column_names,
|
|
194
|
+
ix.indisunique as is_unique,
|
|
195
|
+
ix.indisprimary as is_primary
|
|
196
|
+
FROM
|
|
197
|
+
pg_class t,
|
|
198
|
+
pg_class i,
|
|
199
|
+
pg_index ix,
|
|
200
|
+
pg_attribute a,
|
|
201
|
+
pg_namespace ns
|
|
202
|
+
WHERE
|
|
203
|
+
t.oid = ix.indrelid
|
|
204
|
+
AND i.oid = ix.indexrelid
|
|
205
|
+
AND a.attrelid = t.oid
|
|
206
|
+
AND a.attnum = ANY(ix.indkey)
|
|
207
|
+
AND t.relkind = 'r'
|
|
208
|
+
AND t.relname = $1
|
|
209
|
+
AND ns.oid = t.relnamespace
|
|
210
|
+
AND ns.nspname = $2
|
|
211
|
+
GROUP BY
|
|
212
|
+
i.relname,
|
|
213
|
+
ix.indisunique,
|
|
214
|
+
ix.indisprimary
|
|
215
|
+
ORDER BY
|
|
216
|
+
i.relname
|
|
217
|
+
`,
|
|
218
|
+
[tableName, schemaToUse]
|
|
219
|
+
);
|
|
220
|
+
return result.rows.map((row) => ({
|
|
221
|
+
index_name: row.index_name,
|
|
222
|
+
column_names: row.column_names,
|
|
223
|
+
is_unique: row.is_unique,
|
|
224
|
+
is_primary: row.is_primary
|
|
225
|
+
}));
|
|
226
|
+
} finally {
|
|
227
|
+
client.release();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
async getTableSchema(tableName, schema) {
|
|
231
|
+
if (!this.pool) {
|
|
232
|
+
throw new Error("Not connected to database");
|
|
233
|
+
}
|
|
234
|
+
const client = await this.pool.connect();
|
|
235
|
+
try {
|
|
236
|
+
const schemaToUse = schema || this.defaultSchema;
|
|
237
|
+
const result = await client.query(
|
|
238
|
+
`
|
|
239
|
+
SELECT
|
|
240
|
+
c.column_name,
|
|
241
|
+
c.data_type,
|
|
242
|
+
c.is_nullable,
|
|
243
|
+
c.column_default,
|
|
244
|
+
pgd.description
|
|
245
|
+
FROM information_schema.columns c
|
|
246
|
+
LEFT JOIN pg_catalog.pg_namespace nsp
|
|
247
|
+
ON nsp.nspname = c.table_schema
|
|
248
|
+
LEFT JOIN pg_catalog.pg_class cls
|
|
249
|
+
ON cls.relnamespace = nsp.oid
|
|
250
|
+
AND cls.relname = c.table_name
|
|
251
|
+
LEFT JOIN pg_catalog.pg_description pgd
|
|
252
|
+
ON pgd.objoid = cls.oid
|
|
253
|
+
AND pgd.objsubid = c.ordinal_position
|
|
254
|
+
WHERE c.table_schema = $1
|
|
255
|
+
AND c.table_name = $2
|
|
256
|
+
ORDER BY c.ordinal_position
|
|
257
|
+
`,
|
|
258
|
+
[schemaToUse, tableName]
|
|
259
|
+
);
|
|
260
|
+
return result.rows;
|
|
261
|
+
} finally {
|
|
262
|
+
client.release();
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
async getTableRowCount(tableName, schema) {
|
|
266
|
+
if (!this.pool) {
|
|
267
|
+
throw new Error("Not connected to database");
|
|
268
|
+
}
|
|
269
|
+
const client = await this.pool.connect();
|
|
270
|
+
try {
|
|
271
|
+
const schemaToUse = schema || this.defaultSchema;
|
|
272
|
+
const result = await client.query(
|
|
273
|
+
`
|
|
274
|
+
SELECT c.reltuples::bigint as count
|
|
275
|
+
FROM pg_class c
|
|
276
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
277
|
+
WHERE c.relname = $1
|
|
278
|
+
AND n.nspname = $2
|
|
279
|
+
AND c.relkind IN ('r','p','m','f')
|
|
280
|
+
`,
|
|
281
|
+
[tableName, schemaToUse]
|
|
282
|
+
);
|
|
283
|
+
if (result.rows.length > 0) {
|
|
284
|
+
const count = Number(result.rows[0].count);
|
|
285
|
+
return count >= 0 ? count : null;
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
} finally {
|
|
289
|
+
client.release();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async getTableComment(tableName, schema) {
|
|
293
|
+
if (!this.pool) {
|
|
294
|
+
throw new Error("Not connected to database");
|
|
295
|
+
}
|
|
296
|
+
const client = await this.pool.connect();
|
|
297
|
+
try {
|
|
298
|
+
const schemaToUse = schema || this.defaultSchema;
|
|
299
|
+
const result = await client.query(
|
|
300
|
+
`
|
|
301
|
+
SELECT obj_description(c.oid) as table_comment
|
|
302
|
+
FROM pg_catalog.pg_class c
|
|
303
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
304
|
+
WHERE c.relname = $1
|
|
305
|
+
AND n.nspname = $2
|
|
306
|
+
AND c.relkind IN ('r','p','m','f')
|
|
307
|
+
`,
|
|
308
|
+
[tableName, schemaToUse]
|
|
309
|
+
);
|
|
310
|
+
if (result.rows.length > 0) {
|
|
311
|
+
return result.rows[0].table_comment || null;
|
|
312
|
+
}
|
|
313
|
+
return null;
|
|
314
|
+
} finally {
|
|
315
|
+
client.release();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
async getStoredProcedures(schema, routineType) {
|
|
319
|
+
if (!this.pool) {
|
|
320
|
+
throw new Error("Not connected to database");
|
|
321
|
+
}
|
|
322
|
+
const client = await this.pool.connect();
|
|
323
|
+
try {
|
|
324
|
+
const schemaToUse = schema || this.defaultSchema;
|
|
325
|
+
const params = [schemaToUse];
|
|
326
|
+
let typeFilter = "";
|
|
327
|
+
if (routineType === "function") {
|
|
328
|
+
typeFilter = " AND routine_type = 'FUNCTION'";
|
|
329
|
+
} else if (routineType === "procedure") {
|
|
330
|
+
typeFilter = " AND routine_type = 'PROCEDURE'";
|
|
331
|
+
}
|
|
332
|
+
const result = await client.query(
|
|
333
|
+
`
|
|
334
|
+
SELECT
|
|
335
|
+
routine_name
|
|
336
|
+
FROM information_schema.routines
|
|
337
|
+
WHERE routine_schema = $1${typeFilter}
|
|
338
|
+
ORDER BY routine_name
|
|
339
|
+
`,
|
|
340
|
+
params
|
|
341
|
+
);
|
|
342
|
+
return result.rows.map((row) => row.routine_name);
|
|
343
|
+
} finally {
|
|
344
|
+
client.release();
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
async getStoredProcedureDetail(procedureName, schema) {
|
|
348
|
+
if (!this.pool) {
|
|
349
|
+
throw new Error("Not connected to database");
|
|
350
|
+
}
|
|
351
|
+
const client = await this.pool.connect();
|
|
352
|
+
try {
|
|
353
|
+
const schemaToUse = schema || this.defaultSchema;
|
|
354
|
+
const result = await client.query(
|
|
355
|
+
`
|
|
356
|
+
SELECT
|
|
357
|
+
routine_name as procedure_name,
|
|
358
|
+
routine_type,
|
|
359
|
+
CASE WHEN routine_type = 'PROCEDURE' THEN 'procedure' ELSE 'function' END as procedure_type,
|
|
360
|
+
external_language as language,
|
|
361
|
+
data_type as return_type,
|
|
362
|
+
routine_definition as definition,
|
|
363
|
+
(
|
|
364
|
+
SELECT string_agg(
|
|
365
|
+
parameter_name || ' ' ||
|
|
366
|
+
parameter_mode || ' ' ||
|
|
367
|
+
data_type,
|
|
368
|
+
', '
|
|
369
|
+
)
|
|
370
|
+
FROM information_schema.parameters
|
|
371
|
+
WHERE specific_schema = $1
|
|
372
|
+
AND specific_name = $2
|
|
373
|
+
AND parameter_name IS NOT NULL
|
|
374
|
+
) as parameter_list
|
|
375
|
+
FROM information_schema.routines
|
|
376
|
+
WHERE routine_schema = $1
|
|
377
|
+
AND routine_name = $2
|
|
378
|
+
`,
|
|
379
|
+
[schemaToUse, procedureName]
|
|
380
|
+
);
|
|
381
|
+
if (result.rows.length === 0) {
|
|
382
|
+
throw new Error(`Stored procedure '${procedureName}' not found in schema '${schemaToUse}'`);
|
|
383
|
+
}
|
|
384
|
+
const procedure = result.rows[0];
|
|
385
|
+
let definition = procedure.definition;
|
|
386
|
+
try {
|
|
387
|
+
const oidResult = await client.query(
|
|
388
|
+
`
|
|
389
|
+
SELECT p.oid, p.prosrc
|
|
390
|
+
FROM pg_proc p
|
|
391
|
+
JOIN pg_namespace n ON p.pronamespace = n.oid
|
|
392
|
+
WHERE p.proname = $1
|
|
393
|
+
AND n.nspname = $2
|
|
394
|
+
`,
|
|
395
|
+
[procedureName, schemaToUse]
|
|
396
|
+
);
|
|
397
|
+
if (oidResult.rows.length > 0) {
|
|
398
|
+
if (!definition) {
|
|
399
|
+
const oid = oidResult.rows[0].oid;
|
|
400
|
+
const defResult = await client.query(`SELECT pg_get_functiondef($1)`, [oid]);
|
|
401
|
+
if (defResult.rows.length > 0) {
|
|
402
|
+
definition = defResult.rows[0].pg_get_functiondef;
|
|
403
|
+
} else {
|
|
404
|
+
definition = oidResult.rows[0].prosrc;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
} catch (err) {
|
|
409
|
+
console.error(`Error getting procedure definition: ${err}`);
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
procedure_name: procedure.procedure_name,
|
|
413
|
+
procedure_type: procedure.procedure_type,
|
|
414
|
+
language: procedure.language || "sql",
|
|
415
|
+
parameter_list: procedure.parameter_list || "",
|
|
416
|
+
return_type: procedure.return_type !== "void" ? procedure.return_type : void 0,
|
|
417
|
+
definition: definition || void 0
|
|
418
|
+
};
|
|
419
|
+
} finally {
|
|
420
|
+
client.release();
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
async executeSQL(sql, options, parameters) {
|
|
424
|
+
if (!this.pool) {
|
|
425
|
+
throw new Error("Not connected to database");
|
|
426
|
+
}
|
|
427
|
+
const client = await this.pool.connect();
|
|
428
|
+
try {
|
|
429
|
+
const statements = splitSQLStatements(sql, "postgres");
|
|
430
|
+
if (statements.length === 1) {
|
|
431
|
+
const processedStatement = SQLRowLimiter.applyMaxRows(statements[0], options.maxRows);
|
|
432
|
+
let result;
|
|
433
|
+
if (parameters && parameters.length > 0) {
|
|
434
|
+
try {
|
|
435
|
+
result = await client.query(processedStatement, parameters);
|
|
436
|
+
} catch (error) {
|
|
437
|
+
console.error(`[PostgreSQL executeSQL] ERROR: ${error.message}`);
|
|
438
|
+
console.error(`[PostgreSQL executeSQL] SQL: ${processedStatement}`);
|
|
439
|
+
console.error(`[PostgreSQL executeSQL] Parameters: ${JSON.stringify(parameters)}`);
|
|
440
|
+
throw error;
|
|
441
|
+
}
|
|
442
|
+
} else {
|
|
443
|
+
result = await client.query(processedStatement);
|
|
444
|
+
}
|
|
445
|
+
return { rows: result.rows, rowCount: result.rowCount ?? result.rows.length };
|
|
446
|
+
} else {
|
|
447
|
+
if (parameters && parameters.length > 0) {
|
|
448
|
+
throw new Error("Parameters are not supported for multi-statement queries in PostgreSQL");
|
|
449
|
+
}
|
|
450
|
+
let allRows = [];
|
|
451
|
+
let totalRowCount = 0;
|
|
452
|
+
await client.query("BEGIN");
|
|
453
|
+
try {
|
|
454
|
+
for (let statement of statements) {
|
|
455
|
+
const processedStatement = SQLRowLimiter.applyMaxRows(statement, options.maxRows);
|
|
456
|
+
const result = await client.query(processedStatement);
|
|
457
|
+
if (result.rows && result.rows.length > 0) {
|
|
458
|
+
allRows.push(...result.rows);
|
|
459
|
+
}
|
|
460
|
+
if (result.rowCount) {
|
|
461
|
+
totalRowCount += result.rowCount;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
await client.query("COMMIT");
|
|
465
|
+
} catch (error) {
|
|
466
|
+
await client.query("ROLLBACK");
|
|
467
|
+
throw error;
|
|
468
|
+
}
|
|
469
|
+
return { rows: allRows, rowCount: totalRowCount };
|
|
470
|
+
}
|
|
471
|
+
} finally {
|
|
472
|
+
client.release();
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
var postgresConnector = new PostgresConnector();
|
|
477
|
+
ConnectorRegistry.register(postgresConnector);
|
|
478
|
+
export {
|
|
479
|
+
PostgresConnector
|
|
480
|
+
};
|