@zz1996/dbhub-dameng 0.1.3 → 0.1.5
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/{dameng-JYMTC4HE.js → dameng-DTI47UV6.js} +224 -18
- package/dist/index.js +31 -1
- package/package.json +1 -1
|
@@ -8,6 +8,14 @@ import {
|
|
|
8
8
|
|
|
9
9
|
// src/connectors/dameng/index.ts
|
|
10
10
|
import dmdb from "dmdb";
|
|
11
|
+
var DEFAULT_OPERATION_TIMEOUT_MS = 11e4;
|
|
12
|
+
var RESOURCE_CLEANUP_TIMEOUT_MS = 2e3;
|
|
13
|
+
var DamengOperationTimeoutError = class extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "DamengOperationTimeoutError";
|
|
17
|
+
}
|
|
18
|
+
};
|
|
11
19
|
var DamengDSNParser = class {
|
|
12
20
|
async parse(dsn, config) {
|
|
13
21
|
if (!this.isValidDSN(dsn)) {
|
|
@@ -74,6 +82,10 @@ var DamengConnector = class _DamengConnector {
|
|
|
74
82
|
this.sourceId = "default";
|
|
75
83
|
this.defaultSchema = null;
|
|
76
84
|
this.poolAlias = null;
|
|
85
|
+
this.connectionConfig = null;
|
|
86
|
+
this.connectionTimeoutMs = 5e3;
|
|
87
|
+
this.operationTimeoutMs = DEFAULT_OPERATION_TIMEOUT_MS;
|
|
88
|
+
this.reconnectingPool = null;
|
|
77
89
|
}
|
|
78
90
|
getId() {
|
|
79
91
|
return this.sourceId;
|
|
@@ -88,14 +100,22 @@ var DamengConnector = class _DamengConnector {
|
|
|
88
100
|
connectionConfig.poolAlias = this.buildPoolAlias();
|
|
89
101
|
this.defaultSchema = connectionConfig.schema ?? null;
|
|
90
102
|
this.poolAlias = connectionConfig.poolAlias;
|
|
103
|
+
this.connectionTimeoutMs = config?.connectionTimeoutSeconds !== void 0 ? config.connectionTimeoutSeconds * 1e3 : 5e3;
|
|
104
|
+
this.operationTimeoutMs = config?.queryTimeoutSeconds !== void 0 ? config.queryTimeoutSeconds * 1e3 : DEFAULT_OPERATION_TIMEOUT_MS;
|
|
91
105
|
await this.closeRegisteredPool(connectionConfig.poolAlias);
|
|
92
106
|
await this.validateDirectConnection(connectionConfig);
|
|
93
107
|
createdPool = await dmdb.createPool(connectionConfig);
|
|
94
108
|
this.pool = createdPool;
|
|
95
109
|
await this.withConnection(async (conn) => {
|
|
96
|
-
await
|
|
110
|
+
await this.executeWithTimeout(
|
|
111
|
+
conn,
|
|
112
|
+
"SELECT 1 AS OK",
|
|
113
|
+
[],
|
|
114
|
+
this.executeOptions()
|
|
115
|
+
);
|
|
97
116
|
if (!this.defaultSchema) {
|
|
98
|
-
const result = await
|
|
117
|
+
const result = await this.executeWithTimeout(
|
|
118
|
+
conn,
|
|
99
119
|
"SELECT USER AS SCHEMA_NAME FROM DUAL",
|
|
100
120
|
[],
|
|
101
121
|
this.executeOptions()
|
|
@@ -104,10 +124,17 @@ var DamengConnector = class _DamengConnector {
|
|
|
104
124
|
}
|
|
105
125
|
if (initScript) {
|
|
106
126
|
for (const statement of splitSQLStatements(initScript, "dameng")) {
|
|
107
|
-
await
|
|
127
|
+
await this.executeWithTimeout(
|
|
128
|
+
conn,
|
|
129
|
+
statement,
|
|
130
|
+
[],
|
|
131
|
+
this.executeOptions({ autoCommit: true })
|
|
132
|
+
);
|
|
108
133
|
}
|
|
109
134
|
}
|
|
110
135
|
});
|
|
136
|
+
this.connectionConfig = connectionConfig;
|
|
137
|
+
this.initScript = initScript;
|
|
111
138
|
} catch (error) {
|
|
112
139
|
if (createdPool) {
|
|
113
140
|
await this.closePoolQuietly(createdPool);
|
|
@@ -116,6 +143,8 @@ var DamengConnector = class _DamengConnector {
|
|
|
116
143
|
}
|
|
117
144
|
this.pool = null;
|
|
118
145
|
this.poolAlias = null;
|
|
146
|
+
this.connectionConfig = null;
|
|
147
|
+
this.initScript = void 0;
|
|
119
148
|
console.error("Failed to connect to Dameng database:", error);
|
|
120
149
|
throw error;
|
|
121
150
|
}
|
|
@@ -129,6 +158,9 @@ var DamengConnector = class _DamengConnector {
|
|
|
129
158
|
await this.closeRegisteredPool(this.poolAlias);
|
|
130
159
|
this.poolAlias = null;
|
|
131
160
|
}
|
|
161
|
+
this.connectionConfig = null;
|
|
162
|
+
this.initScript = void 0;
|
|
163
|
+
this.reconnectingPool = null;
|
|
132
164
|
}
|
|
133
165
|
async getSchemas() {
|
|
134
166
|
const rows = await this.queryRows(`
|
|
@@ -185,6 +217,64 @@ var DamengConnector = class _DamengConnector {
|
|
|
185
217
|
);
|
|
186
218
|
return rows.map((row) => this.rowValue(row, "TABLE_NAME")).filter(this.isPresent).map((name) => ({ name, schema: owner }));
|
|
187
219
|
}
|
|
220
|
+
async searchColumns(pattern, schema, table, limit = 100) {
|
|
221
|
+
const owner = await this.resolveSchema(schema);
|
|
222
|
+
const rowLimit = this.normalizeLimit(limit);
|
|
223
|
+
const bindValues = [
|
|
224
|
+
owner,
|
|
225
|
+
this.normalizeLikePattern(pattern),
|
|
226
|
+
...table ? [this.normalizeIdentifier(table)] : []
|
|
227
|
+
];
|
|
228
|
+
const tablePredicate = table ? "AND c.TABLE_NAME = :3" : "";
|
|
229
|
+
const rows = await this.queryRows(
|
|
230
|
+
`
|
|
231
|
+
SELECT COLUMN_NAME,
|
|
232
|
+
TABLE_NAME,
|
|
233
|
+
DATA_TYPE,
|
|
234
|
+
DATA_LENGTH,
|
|
235
|
+
DATA_PRECISION,
|
|
236
|
+
DATA_SCALE,
|
|
237
|
+
NULLABLE,
|
|
238
|
+
DATA_DEFAULT,
|
|
239
|
+
COMMENTS
|
|
240
|
+
FROM (
|
|
241
|
+
SELECT c.COLUMN_NAME,
|
|
242
|
+
c.TABLE_NAME,
|
|
243
|
+
c.DATA_TYPE,
|
|
244
|
+
c.DATA_LENGTH,
|
|
245
|
+
c.DATA_PRECISION,
|
|
246
|
+
c.DATA_SCALE,
|
|
247
|
+
c.NULLABLE,
|
|
248
|
+
c.DATA_DEFAULT,
|
|
249
|
+
cc.COMMENTS,
|
|
250
|
+
c.COLUMN_ID
|
|
251
|
+
FROM ALL_TAB_COLUMNS c
|
|
252
|
+
LEFT JOIN ALL_COL_COMMENTS cc
|
|
253
|
+
ON cc.OWNER = c.OWNER
|
|
254
|
+
AND cc.TABLE_NAME = c.TABLE_NAME
|
|
255
|
+
AND cc.COLUMN_NAME = c.COLUMN_NAME
|
|
256
|
+
WHERE c.OWNER = :1
|
|
257
|
+
AND c.COLUMN_NAME LIKE :2
|
|
258
|
+
${tablePredicate}
|
|
259
|
+
ORDER BY c.TABLE_NAME, c.COLUMN_ID
|
|
260
|
+
)
|
|
261
|
+
WHERE ROWNUM <= ${rowLimit}
|
|
262
|
+
`,
|
|
263
|
+
bindValues
|
|
264
|
+
);
|
|
265
|
+
return rows.map((row) => {
|
|
266
|
+
const description = this.rowValue(row, "COMMENTS");
|
|
267
|
+
return {
|
|
268
|
+
name: this.rowValue(row, "COLUMN_NAME") ?? "",
|
|
269
|
+
table: this.rowValue(row, "TABLE_NAME") ?? "",
|
|
270
|
+
schema: owner,
|
|
271
|
+
type: this.formatDataType(row),
|
|
272
|
+
nullable: this.rowValue(row, "NULLABLE") === "Y",
|
|
273
|
+
default: this.rowValue(row, "DATA_DEFAULT") ?? null,
|
|
274
|
+
...description ? { description } : {}
|
|
275
|
+
};
|
|
276
|
+
});
|
|
277
|
+
}
|
|
188
278
|
async getViews(schema) {
|
|
189
279
|
const owner = await this.resolveSchema(schema);
|
|
190
280
|
const rows = await this.queryRows(
|
|
@@ -379,7 +469,8 @@ var DamengConnector = class _DamengConnector {
|
|
|
379
469
|
processedSQL,
|
|
380
470
|
index === 0 ? parameters ?? [] : []
|
|
381
471
|
);
|
|
382
|
-
const result = await
|
|
472
|
+
const result = await this.executeWithTimeout(
|
|
473
|
+
conn,
|
|
383
474
|
boundSQL,
|
|
384
475
|
this.toBindParams(bindValues),
|
|
385
476
|
this.executeOptions({ autoCommit: true, maxRows: options.maxRows })
|
|
@@ -393,25 +484,136 @@ var DamengConnector = class _DamengConnector {
|
|
|
393
484
|
}
|
|
394
485
|
async queryRows(sql, bindValues = []) {
|
|
395
486
|
return this.withConnection(async (conn) => {
|
|
396
|
-
const result = await
|
|
487
|
+
const result = await this.executeWithTimeout(
|
|
488
|
+
conn,
|
|
489
|
+
sql,
|
|
490
|
+
this.toBindParams(bindValues),
|
|
491
|
+
this.executeOptions()
|
|
492
|
+
);
|
|
397
493
|
return this.normalizeRows(result.rows ?? []);
|
|
398
494
|
});
|
|
399
495
|
}
|
|
400
496
|
async withConnection(fn) {
|
|
401
|
-
|
|
497
|
+
await this.ensurePool();
|
|
498
|
+
const pool = this.pool;
|
|
499
|
+
if (!pool) {
|
|
402
500
|
throw new Error("Not connected to Dameng database");
|
|
403
501
|
}
|
|
404
|
-
|
|
502
|
+
let conn = null;
|
|
503
|
+
let shouldRelease = true;
|
|
405
504
|
try {
|
|
505
|
+
conn = await this.withTimeout(
|
|
506
|
+
pool.getConnection(),
|
|
507
|
+
this.connectionTimeoutMs,
|
|
508
|
+
"Dameng connection acquisition"
|
|
509
|
+
);
|
|
406
510
|
return await fn(conn);
|
|
511
|
+
} catch (error) {
|
|
512
|
+
if (error instanceof DamengOperationTimeoutError) {
|
|
513
|
+
shouldRelease = false;
|
|
514
|
+
this.markPoolUnhealthy(error.message);
|
|
515
|
+
}
|
|
516
|
+
throw error;
|
|
517
|
+
} finally {
|
|
518
|
+
if (conn && shouldRelease) {
|
|
519
|
+
await this.releaseConnectionQuietly(conn);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
async ensurePool() {
|
|
524
|
+
if (this.pool) {
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
if (!this.connectionConfig) {
|
|
528
|
+
throw new Error("Not connected to Dameng database");
|
|
529
|
+
}
|
|
530
|
+
if (!this.reconnectingPool) {
|
|
531
|
+
this.reconnectingPool = this.reconnectPool();
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
await this.reconnectingPool;
|
|
407
535
|
} finally {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
536
|
+
this.reconnectingPool = null;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
async reconnectPool() {
|
|
540
|
+
const config = this.connectionConfig;
|
|
541
|
+
if (!config) {
|
|
542
|
+
throw new Error("Not connected to Dameng database");
|
|
543
|
+
}
|
|
544
|
+
console.error(`Reconnecting Dameng source '${this.sourceId}' after pool reset...`);
|
|
545
|
+
await this.closeRegisteredPool(config.poolAlias ?? this.buildPoolAlias());
|
|
546
|
+
await this.validateDirectConnection(config);
|
|
547
|
+
const createdPool = await dmdb.createPool(config);
|
|
548
|
+
this.pool = createdPool;
|
|
549
|
+
this.poolAlias = config.poolAlias ?? null;
|
|
550
|
+
try {
|
|
551
|
+
await this.withConnection(async (conn) => {
|
|
552
|
+
await this.executeWithTimeout(conn, "SELECT 1 AS OK", [], this.executeOptions());
|
|
553
|
+
if (this.initScript) {
|
|
554
|
+
for (const statement of splitSQLStatements(this.initScript, "dameng")) {
|
|
555
|
+
await this.executeWithTimeout(
|
|
556
|
+
conn,
|
|
557
|
+
statement,
|
|
558
|
+
[],
|
|
559
|
+
this.executeOptions({ autoCommit: true })
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
} catch (error) {
|
|
565
|
+
await this.closePoolQuietly(createdPool);
|
|
566
|
+
this.pool = null;
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
executeWithTimeout(conn, sql, bindParams, options) {
|
|
571
|
+
return this.withTimeout(
|
|
572
|
+
conn.execute(sql, bindParams, options),
|
|
573
|
+
this.operationTimeoutMs,
|
|
574
|
+
"Dameng SQL execution"
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
async withTimeout(promise, timeoutMs, label) {
|
|
578
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
579
|
+
return promise;
|
|
580
|
+
}
|
|
581
|
+
let timer;
|
|
582
|
+
const timeout = new Promise((_, reject) => {
|
|
583
|
+
timer = setTimeout(() => {
|
|
584
|
+
reject(new DamengOperationTimeoutError(`${label} timed out after ${timeoutMs}ms`));
|
|
585
|
+
}, timeoutMs);
|
|
586
|
+
});
|
|
587
|
+
try {
|
|
588
|
+
return await Promise.race([promise, timeout]);
|
|
589
|
+
} finally {
|
|
590
|
+
if (timer) {
|
|
591
|
+
clearTimeout(timer);
|
|
412
592
|
}
|
|
413
593
|
}
|
|
414
594
|
}
|
|
595
|
+
markPoolUnhealthy(reason) {
|
|
596
|
+
const pool = this.pool;
|
|
597
|
+
this.pool = null;
|
|
598
|
+
console.error(`Resetting Dameng source '${this.sourceId}' pool: ${reason}`);
|
|
599
|
+
if (pool) {
|
|
600
|
+
void this.closePoolQuietly(pool);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
async releaseConnectionQuietly(conn) {
|
|
604
|
+
try {
|
|
605
|
+
const release = conn.release ? conn.release() : conn.close();
|
|
606
|
+
await this.withTimeout(
|
|
607
|
+
release,
|
|
608
|
+
RESOURCE_CLEANUP_TIMEOUT_MS,
|
|
609
|
+
"Dameng connection release"
|
|
610
|
+
);
|
|
611
|
+
} catch (error) {
|
|
612
|
+
this.markPoolUnhealthy(
|
|
613
|
+
`failed to release connection: ${error instanceof Error ? error.message : String(error)}`
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
415
617
|
executeOptions(extra = {}) {
|
|
416
618
|
return {
|
|
417
619
|
outFormat: dmdb.OUT_FORMAT_OBJECT,
|
|
@@ -430,15 +632,19 @@ var DamengConnector = class _DamengConnector {
|
|
|
430
632
|
queueTimeout,
|
|
431
633
|
...directConfig
|
|
432
634
|
} = config;
|
|
433
|
-
const directConn = await
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
635
|
+
const directConn = await this.withTimeout(
|
|
636
|
+
dmdb.getConnection({
|
|
637
|
+
...directConfig,
|
|
638
|
+
connectString: directConnectString ?? config.connectString
|
|
639
|
+
}),
|
|
640
|
+
this.connectionTimeoutMs,
|
|
641
|
+
"Dameng direct connection"
|
|
642
|
+
);
|
|
437
643
|
conn = directConn;
|
|
438
|
-
await
|
|
644
|
+
await this.executeWithTimeout(conn, "SELECT 1 AS OK", [], this.executeOptions());
|
|
439
645
|
} finally {
|
|
440
646
|
if (conn) {
|
|
441
|
-
await
|
|
647
|
+
await this.releaseConnectionQuietly(conn);
|
|
442
648
|
}
|
|
443
649
|
}
|
|
444
650
|
}
|
|
@@ -456,7 +662,7 @@ var DamengConnector = class _DamengConnector {
|
|
|
456
662
|
}
|
|
457
663
|
async closePoolQuietly(pool) {
|
|
458
664
|
try {
|
|
459
|
-
await pool.close(0);
|
|
665
|
+
await this.withTimeout(pool.close(0), RESOURCE_CLEANUP_TIMEOUT_MS, "Dameng pool close");
|
|
460
666
|
} catch {
|
|
461
667
|
if (pool.poolAlias) {
|
|
462
668
|
dmdb.pools?.delete?.(pool.poolAlias);
|
package/dist/index.js
CHANGED
|
@@ -586,6 +586,36 @@ async function searchColumns(connector, pattern, schemaFilter, tableFilter, deta
|
|
|
586
586
|
for (const schemaName of schemasToSearch) {
|
|
587
587
|
if (results.length >= limit) break;
|
|
588
588
|
try {
|
|
589
|
+
const searchableConnector = connector;
|
|
590
|
+
if (searchableConnector.searchColumns) {
|
|
591
|
+
const matchedColumns = await searchableConnector.searchColumns(
|
|
592
|
+
pattern,
|
|
593
|
+
schemaName,
|
|
594
|
+
tableFilter,
|
|
595
|
+
limit - results.length
|
|
596
|
+
);
|
|
597
|
+
for (const column of matchedColumns) {
|
|
598
|
+
if (results.length >= limit) break;
|
|
599
|
+
if (detailLevel === "names") {
|
|
600
|
+
results.push({
|
|
601
|
+
name: column.name,
|
|
602
|
+
table: column.table,
|
|
603
|
+
schema: column.schema
|
|
604
|
+
});
|
|
605
|
+
} else {
|
|
606
|
+
results.push({
|
|
607
|
+
name: column.name,
|
|
608
|
+
table: column.table,
|
|
609
|
+
schema: column.schema,
|
|
610
|
+
type: column.type,
|
|
611
|
+
nullable: column.nullable,
|
|
612
|
+
default: column.default,
|
|
613
|
+
...column.description ? { description: column.description } : {}
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
589
619
|
let tablesToSearch;
|
|
590
620
|
if (tableFilter) {
|
|
591
621
|
tablesToSearch = [tableFilter];
|
|
@@ -1835,7 +1865,7 @@ var connectorModules = [
|
|
|
1835
1865
|
{ load: () => import("./sqlite-IOUAYHGE.js"), name: "SQLite", driver: "node:sqlite" },
|
|
1836
1866
|
{ load: () => import("./mysql-A43SL7UM.js"), name: "MySQL", driver: "mysql2" },
|
|
1837
1867
|
{ load: () => import("./mariadb-7F72IRB4.js"), name: "MariaDB", driver: "mariadb" },
|
|
1838
|
-
{ load: () => import("./dameng-
|
|
1868
|
+
{ load: () => import("./dameng-DTI47UV6.js"), name: "Dameng", driver: "dmdb" }
|
|
1839
1869
|
];
|
|
1840
1870
|
loadConnectors(connectorModules).then(() => main()).catch((error) => {
|
|
1841
1871
|
console.error("Fatal error:", error);
|