@zz1996/dbhub-dameng 0.1.3 → 0.1.4

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.
@@ -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 conn.execute("SELECT 1 AS OK", [], this.executeOptions());
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 conn.execute(
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 conn.execute(statement, [], this.executeOptions({ autoCommit: true }));
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(`
@@ -379,7 +411,8 @@ var DamengConnector = class _DamengConnector {
379
411
  processedSQL,
380
412
  index === 0 ? parameters ?? [] : []
381
413
  );
382
- const result = await conn.execute(
414
+ const result = await this.executeWithTimeout(
415
+ conn,
383
416
  boundSQL,
384
417
  this.toBindParams(bindValues),
385
418
  this.executeOptions({ autoCommit: true, maxRows: options.maxRows })
@@ -393,25 +426,136 @@ var DamengConnector = class _DamengConnector {
393
426
  }
394
427
  async queryRows(sql, bindValues = []) {
395
428
  return this.withConnection(async (conn) => {
396
- const result = await conn.execute(sql, this.toBindParams(bindValues), this.executeOptions());
429
+ const result = await this.executeWithTimeout(
430
+ conn,
431
+ sql,
432
+ this.toBindParams(bindValues),
433
+ this.executeOptions()
434
+ );
397
435
  return this.normalizeRows(result.rows ?? []);
398
436
  });
399
437
  }
400
438
  async withConnection(fn) {
401
- if (!this.pool) {
439
+ await this.ensurePool();
440
+ const pool = this.pool;
441
+ if (!pool) {
402
442
  throw new Error("Not connected to Dameng database");
403
443
  }
404
- const conn = await this.pool.getConnection();
444
+ let conn = null;
445
+ let shouldRelease = true;
405
446
  try {
447
+ conn = await this.withTimeout(
448
+ pool.getConnection(),
449
+ this.connectionTimeoutMs,
450
+ "Dameng connection acquisition"
451
+ );
406
452
  return await fn(conn);
453
+ } catch (error) {
454
+ if (error instanceof DamengOperationTimeoutError) {
455
+ shouldRelease = false;
456
+ this.markPoolUnhealthy(error.message);
457
+ }
458
+ throw error;
459
+ } finally {
460
+ if (conn && shouldRelease) {
461
+ await this.releaseConnectionQuietly(conn);
462
+ }
463
+ }
464
+ }
465
+ async ensurePool() {
466
+ if (this.pool) {
467
+ return;
468
+ }
469
+ if (!this.connectionConfig) {
470
+ throw new Error("Not connected to Dameng database");
471
+ }
472
+ if (!this.reconnectingPool) {
473
+ this.reconnectingPool = this.reconnectPool();
474
+ }
475
+ try {
476
+ await this.reconnectingPool;
477
+ } finally {
478
+ this.reconnectingPool = null;
479
+ }
480
+ }
481
+ async reconnectPool() {
482
+ const config = this.connectionConfig;
483
+ if (!config) {
484
+ throw new Error("Not connected to Dameng database");
485
+ }
486
+ console.error(`Reconnecting Dameng source '${this.sourceId}' after pool reset...`);
487
+ await this.closeRegisteredPool(config.poolAlias ?? this.buildPoolAlias());
488
+ await this.validateDirectConnection(config);
489
+ const createdPool = await dmdb.createPool(config);
490
+ this.pool = createdPool;
491
+ this.poolAlias = config.poolAlias ?? null;
492
+ try {
493
+ await this.withConnection(async (conn) => {
494
+ await this.executeWithTimeout(conn, "SELECT 1 AS OK", [], this.executeOptions());
495
+ if (this.initScript) {
496
+ for (const statement of splitSQLStatements(this.initScript, "dameng")) {
497
+ await this.executeWithTimeout(
498
+ conn,
499
+ statement,
500
+ [],
501
+ this.executeOptions({ autoCommit: true })
502
+ );
503
+ }
504
+ }
505
+ });
506
+ } catch (error) {
507
+ await this.closePoolQuietly(createdPool);
508
+ this.pool = null;
509
+ throw error;
510
+ }
511
+ }
512
+ executeWithTimeout(conn, sql, bindParams, options) {
513
+ return this.withTimeout(
514
+ conn.execute(sql, bindParams, options),
515
+ this.operationTimeoutMs,
516
+ "Dameng SQL execution"
517
+ );
518
+ }
519
+ async withTimeout(promise, timeoutMs, label) {
520
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
521
+ return promise;
522
+ }
523
+ let timer;
524
+ const timeout = new Promise((_, reject) => {
525
+ timer = setTimeout(() => {
526
+ reject(new DamengOperationTimeoutError(`${label} timed out after ${timeoutMs}ms`));
527
+ }, timeoutMs);
528
+ });
529
+ try {
530
+ return await Promise.race([promise, timeout]);
407
531
  } finally {
408
- if (conn.release) {
409
- await conn.release();
410
- } else {
411
- await conn.close();
532
+ if (timer) {
533
+ clearTimeout(timer);
412
534
  }
413
535
  }
414
536
  }
537
+ markPoolUnhealthy(reason) {
538
+ const pool = this.pool;
539
+ this.pool = null;
540
+ console.error(`Resetting Dameng source '${this.sourceId}' pool: ${reason}`);
541
+ if (pool) {
542
+ void this.closePoolQuietly(pool);
543
+ }
544
+ }
545
+ async releaseConnectionQuietly(conn) {
546
+ try {
547
+ const release = conn.release ? conn.release() : conn.close();
548
+ await this.withTimeout(
549
+ release,
550
+ RESOURCE_CLEANUP_TIMEOUT_MS,
551
+ "Dameng connection release"
552
+ );
553
+ } catch (error) {
554
+ this.markPoolUnhealthy(
555
+ `failed to release connection: ${error instanceof Error ? error.message : String(error)}`
556
+ );
557
+ }
558
+ }
415
559
  executeOptions(extra = {}) {
416
560
  return {
417
561
  outFormat: dmdb.OUT_FORMAT_OBJECT,
@@ -430,15 +574,19 @@ var DamengConnector = class _DamengConnector {
430
574
  queueTimeout,
431
575
  ...directConfig
432
576
  } = config;
433
- const directConn = await dmdb.getConnection({
434
- ...directConfig,
435
- connectString: directConnectString ?? config.connectString
436
- });
577
+ const directConn = await this.withTimeout(
578
+ dmdb.getConnection({
579
+ ...directConfig,
580
+ connectString: directConnectString ?? config.connectString
581
+ }),
582
+ this.connectionTimeoutMs,
583
+ "Dameng direct connection"
584
+ );
437
585
  conn = directConn;
438
- await conn.execute("SELECT 1 AS OK", [], this.executeOptions());
586
+ await this.executeWithTimeout(conn, "SELECT 1 AS OK", [], this.executeOptions());
439
587
  } finally {
440
588
  if (conn) {
441
- await conn.close();
589
+ await this.releaseConnectionQuietly(conn);
442
590
  }
443
591
  }
444
592
  }
@@ -456,7 +604,7 @@ var DamengConnector = class _DamengConnector {
456
604
  }
457
605
  async closePoolQuietly(pool) {
458
606
  try {
459
- await pool.close(0);
607
+ await this.withTimeout(pool.close(0), RESOURCE_CLEANUP_TIMEOUT_MS, "Dameng pool close");
460
608
  } catch {
461
609
  if (pool.poolAlias) {
462
610
  dmdb.pools?.delete?.(pool.poolAlias);
package/dist/index.js CHANGED
@@ -1835,7 +1835,7 @@ var connectorModules = [
1835
1835
  { load: () => import("./sqlite-IOUAYHGE.js"), name: "SQLite", driver: "node:sqlite" },
1836
1836
  { load: () => import("./mysql-A43SL7UM.js"), name: "MySQL", driver: "mysql2" },
1837
1837
  { load: () => import("./mariadb-7F72IRB4.js"), name: "MariaDB", driver: "mariadb" },
1838
- { load: () => import("./dameng-JYMTC4HE.js"), name: "Dameng", driver: "dmdb" }
1838
+ { load: () => import("./dameng-SOGGZUEW.js"), name: "Dameng", driver: "dmdb" }
1839
1839
  ];
1840
1840
  loadConnectors(connectorModules).then(() => main()).catch((error) => {
1841
1841
  console.error("Fatal error:", error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zz1996/dbhub-dameng",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "mcpName": "io.github.zuozh11/dbhub-dameng",
5
5
  "description": "Local fork of DBHub with Dameng/DM8 database connector support",
6
6
  "repository": {