@zz1996/dbhub-dameng 0.1.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.
@@ -0,0 +1,127 @@
1
+ import {
2
+ stripCommentsAndStrings
3
+ } from "./chunk-SQA2ISDE.js";
4
+
5
+ // src/utils/sql-row-limiter.ts
6
+ var SQLRowLimiter = class {
7
+ /**
8
+ * Check if a SQL statement is a SELECT query that can benefit from row limiting
9
+ * Only handles SELECT queries
10
+ */
11
+ static isSelectQuery(sql) {
12
+ const trimmed = sql.trim().toLowerCase();
13
+ return trimmed.startsWith("select");
14
+ }
15
+ /**
16
+ * Check if a SQL statement already has a LIMIT clause.
17
+ * Strips comments and string literals first to avoid false positives.
18
+ */
19
+ static hasLimitClause(sql) {
20
+ const cleanedSQL = stripCommentsAndStrings(sql);
21
+ const limitRegex = /\blimit\s+(?:\d+|\$\d+|\?|@p\d+)/i;
22
+ return limitRegex.test(cleanedSQL);
23
+ }
24
+ /**
25
+ * Check if a SQL statement already has a TOP clause (SQL Server).
26
+ * Strips comments and string literals first to avoid false positives.
27
+ */
28
+ static hasTopClause(sql) {
29
+ const cleanedSQL = stripCommentsAndStrings(sql);
30
+ const topRegex = /\bselect\s+top\s+\d+/i;
31
+ return topRegex.test(cleanedSQL);
32
+ }
33
+ /**
34
+ * Extract existing LIMIT value from SQL if present.
35
+ * Strips comments and string literals first to avoid false positives.
36
+ */
37
+ static extractLimitValue(sql) {
38
+ const cleanedSQL = stripCommentsAndStrings(sql);
39
+ const limitMatch = cleanedSQL.match(/\blimit\s+(\d+)/i);
40
+ if (limitMatch) {
41
+ return parseInt(limitMatch[1], 10);
42
+ }
43
+ return null;
44
+ }
45
+ /**
46
+ * Extract existing TOP value from SQL if present (SQL Server).
47
+ * Strips comments and string literals first to avoid false positives.
48
+ */
49
+ static extractTopValue(sql) {
50
+ const cleanedSQL = stripCommentsAndStrings(sql);
51
+ const topMatch = cleanedSQL.match(/\bselect\s+top\s+(\d+)/i);
52
+ if (topMatch) {
53
+ return parseInt(topMatch[1], 10);
54
+ }
55
+ return null;
56
+ }
57
+ /**
58
+ * Add or modify LIMIT clause in a SQL statement
59
+ */
60
+ static applyLimitToQuery(sql, maxRows) {
61
+ const existingLimit = this.extractLimitValue(sql);
62
+ if (existingLimit !== null) {
63
+ const effectiveLimit = Math.min(existingLimit, maxRows);
64
+ return sql.replace(/\blimit\s+\d+/i, `LIMIT ${effectiveLimit}`);
65
+ } else {
66
+ const trimmed = sql.trim();
67
+ const hasSemicolon = trimmed.endsWith(";");
68
+ const sqlWithoutSemicolon = hasSemicolon ? trimmed.slice(0, -1) : trimmed;
69
+ return `${sqlWithoutSemicolon} LIMIT ${maxRows}${hasSemicolon ? ";" : ""}`;
70
+ }
71
+ }
72
+ /**
73
+ * Add or modify TOP clause in a SQL statement (SQL Server)
74
+ */
75
+ static applyTopToQuery(sql, maxRows) {
76
+ const existingTop = this.extractTopValue(sql);
77
+ if (existingTop !== null) {
78
+ const effectiveTop = Math.min(existingTop, maxRows);
79
+ return sql.replace(/\bselect\s+top\s+\d+/i, `SELECT TOP ${effectiveTop}`);
80
+ } else {
81
+ return sql.replace(/\bselect\s+/i, `SELECT TOP ${maxRows} `);
82
+ }
83
+ }
84
+ /**
85
+ * Check if a LIMIT clause uses a parameter placeholder (not a literal number).
86
+ * Strips comments and string literals first to avoid false positives.
87
+ */
88
+ static hasParameterizedLimit(sql) {
89
+ const cleanedSQL = stripCommentsAndStrings(sql);
90
+ const parameterizedLimitRegex = /\blimit\s+(?:\$\d+|\?|@p\d+)/i;
91
+ return parameterizedLimitRegex.test(cleanedSQL);
92
+ }
93
+ /**
94
+ * Apply maxRows limit to a SELECT query only
95
+ *
96
+ * This method is used by PostgreSQL, MySQL, MariaDB, and SQLite connectors which all support
97
+ * the LIMIT clause syntax. SQL Server uses applyMaxRowsForSQLServer() instead with TOP syntax.
98
+ *
99
+ * For parameterized LIMIT clauses (e.g., LIMIT $1 or LIMIT ?), we wrap the query in a subquery
100
+ * to enforce max_rows as a hard cap, since the parameter value is not known until runtime.
101
+ */
102
+ static applyMaxRows(sql, maxRows) {
103
+ if (!maxRows || !this.isSelectQuery(sql)) {
104
+ return sql;
105
+ }
106
+ if (this.hasParameterizedLimit(sql)) {
107
+ const trimmed = sql.trim();
108
+ const hasSemicolon = trimmed.endsWith(";");
109
+ const sqlWithoutSemicolon = hasSemicolon ? trimmed.slice(0, -1) : trimmed;
110
+ return `SELECT * FROM (${sqlWithoutSemicolon}) AS subq LIMIT ${maxRows}${hasSemicolon ? ";" : ""}`;
111
+ }
112
+ return this.applyLimitToQuery(sql, maxRows);
113
+ }
114
+ /**
115
+ * Apply maxRows limit to a SELECT query using SQL Server TOP syntax
116
+ */
117
+ static applyMaxRowsForSQLServer(sql, maxRows) {
118
+ if (!maxRows || !this.isSelectQuery(sql)) {
119
+ return sql;
120
+ }
121
+ return this.applyTopToQuery(sql, maxRows);
122
+ }
123
+ };
124
+
125
+ export {
126
+ SQLRowLimiter
127
+ };
@@ -0,0 +1,504 @@
1
+ import {
2
+ ConnectorRegistry,
3
+ SafeURL,
4
+ obfuscateDSNPassword,
5
+ splitSQLStatements,
6
+ stripCommentsAndStrings
7
+ } from "./chunk-SQA2ISDE.js";
8
+
9
+ // src/connectors/dameng/index.ts
10
+ import dmdb from "dmdb";
11
+ var DamengDSNParser = class {
12
+ async parse(dsn, config) {
13
+ if (!this.isValidDSN(dsn)) {
14
+ const obfuscatedDSN = obfuscateDSNPassword(dsn);
15
+ const expectedFormat = this.getSampleDSN();
16
+ throw new Error(
17
+ `Invalid Dameng DSN format.
18
+ Provided: ${obfuscatedDSN}
19
+ Expected: ${expectedFormat}`
20
+ );
21
+ }
22
+ try {
23
+ const url = new SafeURL(dsn);
24
+ const schema = url.pathname ? decodeURIComponent(url.pathname.substring(1)) : void 0;
25
+ const port = url.port ? parseInt(url.port, 10) : 5236;
26
+ const queryParams = [];
27
+ url.forEachSearchParam((value, key) => {
28
+ queryParams.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
29
+ });
30
+ const connectString = `dm://${encodeURIComponent(url.username)}:${encodeURIComponent(url.password)}@${url.hostname}:${port}${queryParams.length > 0 ? `?${queryParams.join("&")}` : ""}`;
31
+ const connectionConfig = {
32
+ connectString,
33
+ user: url.username,
34
+ password: url.password,
35
+ schema: schema || void 0,
36
+ poolMin: 0,
37
+ poolMax: 4
38
+ };
39
+ if (config?.connectionTimeoutSeconds !== void 0) {
40
+ connectionConfig.queueTimeout = config.connectionTimeoutSeconds * 1e3;
41
+ }
42
+ return connectionConfig;
43
+ } catch (error) {
44
+ throw new Error(
45
+ `Failed to parse Dameng DSN: ${error instanceof Error ? error.message : String(error)}`
46
+ );
47
+ }
48
+ }
49
+ getSampleDSN() {
50
+ return "dameng://SYSDBA:password@localhost:5236/SYSDBA";
51
+ }
52
+ isValidDSN(dsn) {
53
+ try {
54
+ return dsn.startsWith("dameng://") || dsn.startsWith("dm://");
55
+ } catch {
56
+ return false;
57
+ }
58
+ }
59
+ };
60
+ var DamengConnector = class _DamengConnector {
61
+ constructor() {
62
+ this.id = "dameng";
63
+ this.name = "Dameng";
64
+ this.dsnParser = new DamengDSNParser();
65
+ this.pool = null;
66
+ this.sourceId = "default";
67
+ this.defaultSchema = null;
68
+ }
69
+ getId() {
70
+ return this.sourceId;
71
+ }
72
+ clone() {
73
+ return new _DamengConnector();
74
+ }
75
+ async connect(dsn, initScript, config) {
76
+ try {
77
+ const connectionConfig = await this.dsnParser.parse(dsn, config);
78
+ this.defaultSchema = connectionConfig.schema ?? null;
79
+ if (config?.queryTimeoutSeconds !== void 0) {
80
+ this.queryTimeoutMs = config.queryTimeoutSeconds * 1e3;
81
+ }
82
+ this.pool = await dmdb.createPool(connectionConfig);
83
+ await this.withConnection(async (conn) => {
84
+ await conn.execute("SELECT 1 AS OK", [], this.executeOptions());
85
+ if (!this.defaultSchema) {
86
+ const result = await conn.execute(
87
+ "SELECT USER AS SCHEMA_NAME FROM DUAL",
88
+ [],
89
+ this.executeOptions()
90
+ );
91
+ this.defaultSchema = this.rowValue(result.rows?.[0], "SCHEMA_NAME") ?? null;
92
+ }
93
+ if (initScript) {
94
+ for (const statement of splitSQLStatements(initScript, "dameng")) {
95
+ await conn.execute(statement, [], this.executeOptions({ autoCommit: true }));
96
+ }
97
+ }
98
+ });
99
+ } catch (error) {
100
+ console.error("Failed to connect to Dameng database:", error);
101
+ throw error;
102
+ }
103
+ }
104
+ async disconnect() {
105
+ if (this.pool) {
106
+ await this.pool.close(0);
107
+ this.pool = null;
108
+ }
109
+ }
110
+ async getSchemas() {
111
+ const rows = await this.queryRows(`
112
+ SELECT USERNAME AS SCHEMA_NAME
113
+ FROM ALL_USERS
114
+ WHERE USERNAME NOT IN ('SYS', 'SYSTEM', 'SYSAUDITOR', 'SYSSSO', 'CTISYS')
115
+ ORDER BY USERNAME
116
+ `);
117
+ return rows.map((row) => this.rowValue(row, "SCHEMA_NAME")).filter(this.isPresent);
118
+ }
119
+ async getDefaultSchema() {
120
+ return this.defaultSchema;
121
+ }
122
+ async getTables(schema) {
123
+ const owner = await this.resolveSchema(schema);
124
+ const rows = await this.queryRows(
125
+ `
126
+ SELECT TABLE_NAME
127
+ FROM ALL_TABLES
128
+ WHERE OWNER = :1
129
+ ORDER BY TABLE_NAME
130
+ `,
131
+ [owner]
132
+ );
133
+ return rows.map((row) => this.rowValue(row, "TABLE_NAME")).filter(this.isPresent);
134
+ }
135
+ async getViews(schema) {
136
+ const owner = await this.resolveSchema(schema);
137
+ const rows = await this.queryRows(
138
+ `
139
+ SELECT VIEW_NAME
140
+ FROM ALL_VIEWS
141
+ WHERE OWNER = :1
142
+ ORDER BY VIEW_NAME
143
+ `,
144
+ [owner]
145
+ );
146
+ return rows.map((row) => this.rowValue(row, "VIEW_NAME")).filter(this.isPresent);
147
+ }
148
+ async tableExists(tableName, schema) {
149
+ const owner = await this.resolveSchema(schema);
150
+ const rows = await this.queryRows(
151
+ `
152
+ SELECT COUNT(*) AS CNT
153
+ FROM ALL_OBJECTS
154
+ WHERE OWNER = :1
155
+ AND OBJECT_NAME = :2
156
+ AND OBJECT_TYPE IN ('TABLE', 'VIEW')
157
+ `,
158
+ [owner, this.normalizeIdentifier(tableName)]
159
+ );
160
+ return Number(this.rowValue(rows[0], "CNT") ?? 0) > 0;
161
+ }
162
+ async getTableSchema(tableName, schema) {
163
+ const owner = await this.resolveSchema(schema);
164
+ const rows = await this.queryRows(
165
+ `
166
+ SELECT c.COLUMN_NAME,
167
+ c.DATA_TYPE,
168
+ c.DATA_LENGTH,
169
+ c.DATA_PRECISION,
170
+ c.DATA_SCALE,
171
+ c.NULLABLE,
172
+ c.DATA_DEFAULT,
173
+ cc.COMMENTS
174
+ FROM ALL_TAB_COLUMNS c
175
+ LEFT JOIN ALL_COL_COMMENTS cc
176
+ ON cc.OWNER = c.OWNER
177
+ AND cc.TABLE_NAME = c.TABLE_NAME
178
+ AND cc.COLUMN_NAME = c.COLUMN_NAME
179
+ WHERE c.OWNER = :1
180
+ AND c.TABLE_NAME = :2
181
+ ORDER BY c.COLUMN_ID
182
+ `,
183
+ [owner, this.normalizeIdentifier(tableName)]
184
+ );
185
+ return rows.map((row) => {
186
+ const dataType = this.formatDataType(row);
187
+ return {
188
+ column_name: this.rowValue(row, "COLUMN_NAME") ?? "",
189
+ data_type: dataType,
190
+ is_nullable: this.rowValue(row, "NULLABLE") === "Y" ? "YES" : "NO",
191
+ column_default: this.rowValue(row, "DATA_DEFAULT") ?? null,
192
+ description: this.rowValue(row, "COMMENTS") ?? null
193
+ };
194
+ });
195
+ }
196
+ async getTableIndexes(tableName, schema) {
197
+ const owner = await this.resolveSchema(schema);
198
+ const rows = await this.queryRows(
199
+ `
200
+ SELECT i.INDEX_NAME,
201
+ i.UNIQUENESS,
202
+ ic.COLUMN_NAME,
203
+ ic.COLUMN_POSITION,
204
+ CASE WHEN c.CONSTRAINT_TYPE = 'P' THEN 1 ELSE 0 END AS IS_PRIMARY
205
+ FROM ALL_INDEXES i
206
+ JOIN ALL_IND_COLUMNS ic
207
+ ON i.OWNER = ic.INDEX_OWNER
208
+ AND i.INDEX_NAME = ic.INDEX_NAME
209
+ LEFT JOIN ALL_CONSTRAINTS c
210
+ ON c.OWNER = i.TABLE_OWNER
211
+ AND c.TABLE_NAME = i.TABLE_NAME
212
+ AND c.INDEX_NAME = i.INDEX_NAME
213
+ AND c.CONSTRAINT_TYPE = 'P'
214
+ WHERE i.TABLE_OWNER = :1
215
+ AND i.TABLE_NAME = :2
216
+ ORDER BY i.INDEX_NAME, ic.COLUMN_POSITION
217
+ `,
218
+ [owner, this.normalizeIdentifier(tableName)]
219
+ );
220
+ const indexMap = /* @__PURE__ */ new Map();
221
+ for (const row of rows) {
222
+ const indexName = this.rowValue(row, "INDEX_NAME") ?? "";
223
+ if (!indexMap.has(indexName)) {
224
+ indexMap.set(indexName, {
225
+ index_name: indexName,
226
+ column_names: [],
227
+ is_unique: this.rowValue(row, "UNIQUENESS") === "UNIQUE",
228
+ is_primary: Number(this.rowValue(row, "IS_PRIMARY") ?? 0) === 1
229
+ });
230
+ }
231
+ const columnName = this.rowValue(row, "COLUMN_NAME");
232
+ if (columnName) {
233
+ indexMap.get(indexName).column_names.push(columnName);
234
+ }
235
+ }
236
+ return Array.from(indexMap.values());
237
+ }
238
+ async getStoredProcedures(schema, routineType) {
239
+ const owner = await this.resolveSchema(schema);
240
+ const types = routineType ? [routineType === "procedure" ? "PROCEDURE" : "FUNCTION"] : ["PROCEDURE", "FUNCTION"];
241
+ const rows = await this.queryRows(
242
+ `
243
+ SELECT OBJECT_NAME
244
+ FROM ALL_OBJECTS
245
+ WHERE OWNER = :1
246
+ AND OBJECT_TYPE IN (${types.map((_, i) => `:${i + 2}`).join(", ")})
247
+ ORDER BY OBJECT_NAME
248
+ `,
249
+ [owner, ...types]
250
+ );
251
+ return rows.map((row) => this.rowValue(row, "OBJECT_NAME")).filter(this.isPresent);
252
+ }
253
+ async getStoredProcedureDetail(procedureName, schema) {
254
+ const owner = await this.resolveSchema(schema);
255
+ const name = this.normalizeIdentifier(procedureName);
256
+ const rows = await this.queryRows(
257
+ `
258
+ SELECT OBJECT_NAME, OBJECT_TYPE
259
+ FROM ALL_OBJECTS
260
+ WHERE OWNER = :1
261
+ AND OBJECT_NAME = :2
262
+ AND OBJECT_TYPE IN ('PROCEDURE', 'FUNCTION')
263
+ `,
264
+ [owner, name]
265
+ );
266
+ if (rows.length === 0) {
267
+ throw new Error(`Stored procedure '${procedureName}' not found in ${owner}`);
268
+ }
269
+ const sourceRows = await this.queryRows(
270
+ `
271
+ SELECT TEXT
272
+ FROM ALL_SOURCE
273
+ WHERE OWNER = :1
274
+ AND NAME = :2
275
+ ORDER BY LINE
276
+ `,
277
+ [owner, name]
278
+ );
279
+ const objectType = this.rowValue(rows[0], "OBJECT_TYPE") ?? "PROCEDURE";
280
+ return {
281
+ procedure_name: this.rowValue(rows[0], "OBJECT_NAME") ?? procedureName,
282
+ procedure_type: objectType === "FUNCTION" ? "function" : "procedure",
283
+ language: "sql",
284
+ parameter_list: "",
285
+ definition: sourceRows.map((row) => this.rowValue(row, "TEXT") ?? "").join("")
286
+ };
287
+ }
288
+ async getTableRowCount(tableName, schema) {
289
+ const owner = await this.resolveSchema(schema);
290
+ const rows = await this.queryRows(
291
+ `
292
+ SELECT NUM_ROWS
293
+ FROM ALL_TABLES
294
+ WHERE OWNER = :1
295
+ AND TABLE_NAME = :2
296
+ `,
297
+ [owner, this.normalizeIdentifier(tableName)]
298
+ );
299
+ const value = this.rowValue(rows[0], "NUM_ROWS");
300
+ return value === null || value === void 0 ? null : Number(value);
301
+ }
302
+ async getTableComment(tableName, schema) {
303
+ const owner = await this.resolveSchema(schema);
304
+ const rows = await this.queryRows(
305
+ `
306
+ SELECT COMMENTS
307
+ FROM ALL_TAB_COMMENTS
308
+ WHERE OWNER = :1
309
+ AND TABLE_NAME = :2
310
+ `,
311
+ [owner, this.normalizeIdentifier(tableName)]
312
+ );
313
+ return this.rowValue(rows[0], "COMMENTS") ?? null;
314
+ }
315
+ async executeSQL(sql, options, parameters) {
316
+ if (!this.pool) {
317
+ throw new Error("Not connected to Dameng database");
318
+ }
319
+ return this.withConnection(async (conn) => {
320
+ const statements = splitSQLStatements(sql, "dameng");
321
+ const allRows = [];
322
+ let rowCount = 0;
323
+ for (const [index, statement] of statements.entries()) {
324
+ const processedSQL = this.applyMaxRows(statement, options.maxRows);
325
+ const { sql: boundSQL, bindValues } = this.replacePositionalParameters(
326
+ processedSQL,
327
+ index === 0 ? parameters ?? [] : []
328
+ );
329
+ const result = await conn.execute(
330
+ boundSQL,
331
+ this.toBindParams(bindValues),
332
+ this.executeOptions({ autoCommit: true, maxRows: options.maxRows })
333
+ );
334
+ const rows = this.normalizeRows(result.rows ?? []);
335
+ allRows.push(...rows);
336
+ rowCount += Number(result.rowsAffected ?? rows.length ?? 0);
337
+ }
338
+ return { rows: allRows, rowCount };
339
+ });
340
+ }
341
+ async queryRows(sql, bindValues = []) {
342
+ return this.withConnection(async (conn) => {
343
+ const result = await conn.execute(sql, this.toBindParams(bindValues), this.executeOptions());
344
+ return this.normalizeRows(result.rows ?? []);
345
+ });
346
+ }
347
+ async withConnection(fn) {
348
+ if (!this.pool) {
349
+ throw new Error("Not connected to Dameng database");
350
+ }
351
+ const conn = await this.pool.getConnection();
352
+ try {
353
+ return await fn(conn);
354
+ } finally {
355
+ if (conn.release) {
356
+ await conn.release();
357
+ } else {
358
+ await conn.close();
359
+ }
360
+ }
361
+ }
362
+ executeOptions(extra = {}) {
363
+ return {
364
+ outFormat: dmdb.OUT_FORMAT_OBJECT,
365
+ ...this.queryTimeoutMs !== void 0 && { queryTimeout: this.queryTimeoutMs },
366
+ ...extra
367
+ };
368
+ }
369
+ async resolveSchema(schema) {
370
+ const resolved = schema || this.defaultSchema || await this.getDefaultSchema();
371
+ if (!resolved) {
372
+ throw new Error("No Dameng schema specified and current schema could not be resolved");
373
+ }
374
+ return this.normalizeIdentifier(resolved);
375
+ }
376
+ normalizeIdentifier(identifier) {
377
+ return /[a-z]/.test(identifier) ? identifier.toUpperCase() : identifier;
378
+ }
379
+ normalizeRows(rows) {
380
+ return rows.map((row) => {
381
+ if (!Array.isArray(row)) {
382
+ return row;
383
+ }
384
+ return row;
385
+ });
386
+ }
387
+ rowValue(row, key) {
388
+ if (!row) {
389
+ return null;
390
+ }
391
+ return row[key] ?? row[key.toLowerCase()] ?? row[key.toUpperCase()] ?? null;
392
+ }
393
+ isPresent(value) {
394
+ return value !== null && value !== "";
395
+ }
396
+ formatDataType(row) {
397
+ const dataType = this.rowValue(row, "DATA_TYPE") ?? "";
398
+ const precision = this.rowValue(row, "DATA_PRECISION");
399
+ const scale = this.rowValue(row, "DATA_SCALE");
400
+ const length = this.rowValue(row, "DATA_LENGTH");
401
+ if (precision !== null && precision !== void 0) {
402
+ return scale !== null && scale !== void 0 ? `${dataType}(${precision},${scale})` : `${dataType}(${precision})`;
403
+ }
404
+ if (length !== null && length !== void 0 && /CHAR|VARCHAR|BINARY/i.test(dataType)) {
405
+ return `${dataType}(${length})`;
406
+ }
407
+ return dataType;
408
+ }
409
+ toBindParams(values) {
410
+ return values.map((value) => ({ val: value }));
411
+ }
412
+ applyMaxRows(sql, maxRows) {
413
+ if (!maxRows) {
414
+ return sql;
415
+ }
416
+ const cleaned = stripCommentsAndStrings(sql, "dameng").trim().toLowerCase();
417
+ if (!cleaned.startsWith("select")) {
418
+ return sql;
419
+ }
420
+ const trimmed = sql.trim();
421
+ const withoutSemicolon = trimmed.endsWith(";") ? trimmed.slice(0, -1) : trimmed;
422
+ return `SELECT * FROM (${withoutSemicolon}) WHERE ROWNUM <= ${maxRows}`;
423
+ }
424
+ replacePositionalParameters(sql, parameters) {
425
+ if (!parameters.length) {
426
+ return { sql, bindValues: [] };
427
+ }
428
+ let index = 0;
429
+ let result = "";
430
+ let i = 0;
431
+ while (i < sql.length) {
432
+ const char = sql[i];
433
+ const next = sql[i + 1];
434
+ if (char === "'") {
435
+ const start = i++;
436
+ while (i < sql.length) {
437
+ if (sql[i] === "'" && sql[i + 1] === "'") {
438
+ i += 2;
439
+ } else if (sql[i] === "'") {
440
+ i++;
441
+ break;
442
+ } else {
443
+ i++;
444
+ }
445
+ }
446
+ result += sql.slice(start, i);
447
+ continue;
448
+ }
449
+ if (char === '"') {
450
+ const start = i++;
451
+ while (i < sql.length) {
452
+ if (sql[i] === '"' && sql[i + 1] === '"') {
453
+ i += 2;
454
+ } else if (sql[i] === '"') {
455
+ i++;
456
+ break;
457
+ } else {
458
+ i++;
459
+ }
460
+ }
461
+ result += sql.slice(start, i);
462
+ continue;
463
+ }
464
+ if (char === "-" && next === "-") {
465
+ const start = i;
466
+ i += 2;
467
+ while (i < sql.length && sql[i] !== "\n") {
468
+ i++;
469
+ }
470
+ result += sql.slice(start, i);
471
+ continue;
472
+ }
473
+ if (char === "/" && next === "*") {
474
+ const start = i;
475
+ i += 2;
476
+ while (i < sql.length && !(sql[i] === "*" && sql[i + 1] === "/")) {
477
+ i++;
478
+ }
479
+ i = i < sql.length ? i + 2 : i;
480
+ result += sql.slice(start, i);
481
+ continue;
482
+ }
483
+ if (char === "?") {
484
+ index += 1;
485
+ result += `:${index}`;
486
+ i++;
487
+ continue;
488
+ }
489
+ result += char;
490
+ i++;
491
+ }
492
+ if (index !== parameters.length) {
493
+ throw new Error(
494
+ `Parameter count mismatch: SQL statement has ${index} parameter(s), but ${parameters.length} value(s) were provided.`
495
+ );
496
+ }
497
+ return { sql: result, bindValues: parameters };
498
+ }
499
+ };
500
+ var damengConnector = new DamengConnector();
501
+ ConnectorRegistry.register(damengConnector);
502
+ export {
503
+ DamengConnector
504
+ };