@xcr1234/dbhub-fork 1.0.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.
Files changed (34) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/dist/chunk-6O5I6UAW.js +2150 -0
  4. package/dist/chunk-BRXZ5ZQB.js +127 -0
  5. package/dist/chunk-C7WEAPX4.js +485 -0
  6. package/dist/chunk-FAIJPBT5.js +40 -0
  7. package/dist/chunk-JFWX35TB.js +34 -0
  8. package/dist/chunk-RTB262PR.js +60 -0
  9. package/dist/chunk-WVVMH6FJ.js +49 -0
  10. package/dist/demo/employee-sqlite/employee.sql +117 -0
  11. package/dist/demo/employee-sqlite/load_department.sql +10 -0
  12. package/dist/demo/employee-sqlite/load_dept_emp.sql +1103 -0
  13. package/dist/demo/employee-sqlite/load_dept_manager.sql +17 -0
  14. package/dist/demo/employee-sqlite/load_employee.sql +1000 -0
  15. package/dist/demo/employee-sqlite/load_salary1.sql +9488 -0
  16. package/dist/demo/employee-sqlite/load_title.sql +1470 -0
  17. package/dist/demo-loader-WKQAEFSX.js +48 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +1584 -0
  20. package/dist/mariadb-QHRMVK47.js +468 -0
  21. package/dist/mysql-GOLPG2Q6.js +475 -0
  22. package/dist/oracle-3V2T7ZWF.js +27739 -0
  23. package/dist/postgres-CK6N5BXI.js +520 -0
  24. package/dist/public/assets/index-BiTHVJQj.js +144 -0
  25. package/dist/public/assets/index-CfPYb3wl.css +1 -0
  26. package/dist/public/assets/postgres-BpcazhJg.svg +22 -0
  27. package/dist/public/assets/sqlserver-ByfFYYpV.svg +11 -0
  28. package/dist/public/favicon.svg +57 -0
  29. package/dist/public/index.html +14 -0
  30. package/dist/public/logo-full-light.svg +58 -0
  31. package/dist/registry-KI3KJMRY.js +13 -0
  32. package/dist/sqlite-P6NXTMYE.js +2473 -0
  33. package/dist/sqlserver-5RM44GWI.js +493 -0
  34. package/package.json +99 -0
@@ -0,0 +1,475 @@
1
+ import {
2
+ extractAffectedRows,
3
+ parseQueryResults
4
+ } from "./chunk-RTB262PR.js";
5
+ import {
6
+ quoteIdentifier
7
+ } from "./chunk-JFWX35TB.js";
8
+ import {
9
+ SQLRowLimiter
10
+ } from "./chunk-BRXZ5ZQB.js";
11
+ import {
12
+ ConnectorRegistry,
13
+ SafeURL,
14
+ obfuscateDSNPassword,
15
+ splitSQLStatements
16
+ } from "./chunk-C7WEAPX4.js";
17
+ import "./chunk-FAIJPBT5.js";
18
+
19
+ // src/connectors/mysql/index.ts
20
+ import mysql from "mysql2/promise";
21
+ var MySQLDSNParser = class {
22
+ async parse(dsn, config) {
23
+ const connectionTimeoutSeconds = config?.connectionTimeoutSeconds;
24
+ if (!this.isValidDSN(dsn)) {
25
+ const obfuscatedDSN = obfuscateDSNPassword(dsn);
26
+ const expectedFormat = this.getSampleDSN();
27
+ throw new Error(
28
+ `Invalid MySQL DSN format.
29
+ Provided: ${obfuscatedDSN}
30
+ Expected: ${expectedFormat}`
31
+ );
32
+ }
33
+ try {
34
+ const url = new SafeURL(dsn);
35
+ const config2 = {
36
+ host: url.hostname,
37
+ port: url.port ? parseInt(url.port) : 3306,
38
+ database: url.pathname ? url.pathname.substring(1) : "",
39
+ // Remove leading '/' if exists
40
+ user: url.username,
41
+ password: url.password,
42
+ multipleStatements: true,
43
+ // Enable native multi-statement support
44
+ supportBigNumbers: true
45
+ // Return BIGINT as string when value exceeds Number.MAX_SAFE_INTEGER
46
+ };
47
+ url.forEachSearchParam((value, key) => {
48
+ if (key === "sslmode") {
49
+ if (value === "disable") {
50
+ config2.ssl = void 0;
51
+ } else if (value === "require") {
52
+ config2.ssl = { rejectUnauthorized: false };
53
+ } else {
54
+ config2.ssl = {};
55
+ }
56
+ }
57
+ });
58
+ if (connectionTimeoutSeconds !== void 0) {
59
+ config2.connectTimeout = connectionTimeoutSeconds * 1e3;
60
+ }
61
+ if (url.password && url.password.includes("X-Amz-Credential")) {
62
+ config2.authPlugins = {
63
+ mysql_clear_password: () => () => {
64
+ return Buffer.from(url.password + "\0");
65
+ }
66
+ };
67
+ if (config2.ssl === void 0) {
68
+ config2.ssl = { rejectUnauthorized: false };
69
+ }
70
+ }
71
+ return config2;
72
+ } catch (error) {
73
+ throw new Error(
74
+ `Failed to parse MySQL DSN: ${error instanceof Error ? error.message : String(error)}`
75
+ );
76
+ }
77
+ }
78
+ getSampleDSN() {
79
+ return "mysql://root:password@localhost:3306/mysql?sslmode=require";
80
+ }
81
+ isValidDSN(dsn) {
82
+ try {
83
+ return dsn.startsWith("mysql://");
84
+ } catch (error) {
85
+ return false;
86
+ }
87
+ }
88
+ };
89
+ var MySQLConnector = class _MySQLConnector {
90
+ constructor() {
91
+ this.id = "mysql";
92
+ this.name = "MySQL";
93
+ this.dsnParser = new MySQLDSNParser();
94
+ this.pool = null;
95
+ // Source ID is set by ConnectorManager after cloning
96
+ this.sourceId = "default";
97
+ }
98
+ getId() {
99
+ return this.sourceId;
100
+ }
101
+ clone() {
102
+ return new _MySQLConnector();
103
+ }
104
+ async connect(dsn, initScript, config) {
105
+ try {
106
+ const connectionOptions = await this.dsnParser.parse(dsn, config);
107
+ this.pool = mysql.createPool(connectionOptions);
108
+ if (config?.queryTimeoutSeconds !== void 0) {
109
+ this.queryTimeoutMs = config.queryTimeoutSeconds * 1e3;
110
+ }
111
+ const [rows] = await this.pool.query("SELECT 1");
112
+ } catch (err) {
113
+ console.error("Failed to connect to MySQL database:", err);
114
+ throw err;
115
+ }
116
+ }
117
+ async disconnect() {
118
+ if (this.pool) {
119
+ await this.pool.end();
120
+ this.pool = null;
121
+ }
122
+ }
123
+ async getSchemas() {
124
+ if (!this.pool) {
125
+ throw new Error("Not connected to database");
126
+ }
127
+ try {
128
+ const [rows] = await this.pool.query(`
129
+ SELECT SCHEMA_NAME
130
+ FROM INFORMATION_SCHEMA.SCHEMATA
131
+ ORDER BY SCHEMA_NAME
132
+ `);
133
+ return rows.map((row) => row.SCHEMA_NAME);
134
+ } catch (error) {
135
+ console.error("Error getting schemas:", error);
136
+ throw error;
137
+ }
138
+ }
139
+ async getTables(schema) {
140
+ if (!this.pool) {
141
+ throw new Error("Not connected to database");
142
+ }
143
+ try {
144
+ const schemaClause = schema ? "WHERE TABLE_SCHEMA = ?" : "WHERE TABLE_SCHEMA = DATABASE()";
145
+ const queryParams = schema ? [schema] : [];
146
+ const [rows] = await this.pool.query(
147
+ `
148
+ SELECT TABLE_NAME
149
+ FROM INFORMATION_SCHEMA.TABLES
150
+ ${schemaClause}
151
+ ORDER BY TABLE_NAME
152
+ `,
153
+ queryParams
154
+ );
155
+ return rows.map((row) => row.TABLE_NAME);
156
+ } catch (error) {
157
+ console.error("Error getting tables:", error);
158
+ throw error;
159
+ }
160
+ }
161
+ async tableExists(tableName, schema) {
162
+ if (!this.pool) {
163
+ throw new Error("Not connected to database");
164
+ }
165
+ try {
166
+ const schemaClause = schema ? "WHERE TABLE_SCHEMA = ?" : "WHERE TABLE_SCHEMA = DATABASE()";
167
+ const queryParams = schema ? [schema, tableName] : [tableName];
168
+ const [rows] = await this.pool.query(
169
+ `
170
+ SELECT COUNT(*) AS COUNT
171
+ FROM INFORMATION_SCHEMA.TABLES
172
+ ${schemaClause}
173
+ AND TABLE_NAME = ?
174
+ `,
175
+ queryParams
176
+ );
177
+ return rows[0].COUNT > 0;
178
+ } catch (error) {
179
+ console.error("Error checking if table exists:", error);
180
+ throw error;
181
+ }
182
+ }
183
+ async getTableIndexes(tableName, schema) {
184
+ if (!this.pool) {
185
+ throw new Error("Not connected to database");
186
+ }
187
+ try {
188
+ const schemaClause = schema ? "TABLE_SCHEMA = ?" : "TABLE_SCHEMA = DATABASE()";
189
+ const queryParams = schema ? [schema, tableName] : [tableName];
190
+ const [indexRows] = await this.pool.query(
191
+ `
192
+ SELECT
193
+ INDEX_NAME,
194
+ COLUMN_NAME,
195
+ NON_UNIQUE,
196
+ SEQ_IN_INDEX
197
+ FROM
198
+ INFORMATION_SCHEMA.STATISTICS
199
+ WHERE
200
+ ${schemaClause}
201
+ AND TABLE_NAME = ?
202
+ ORDER BY
203
+ INDEX_NAME,
204
+ SEQ_IN_INDEX
205
+ `,
206
+ queryParams
207
+ );
208
+ const indexMap = /* @__PURE__ */ new Map();
209
+ for (const row of indexRows) {
210
+ const indexName = row.INDEX_NAME;
211
+ const columnName = row.COLUMN_NAME;
212
+ const isUnique = row.NON_UNIQUE === 0;
213
+ const isPrimary = indexName === "PRIMARY";
214
+ if (!indexMap.has(indexName)) {
215
+ indexMap.set(indexName, {
216
+ columns: [],
217
+ is_unique: isUnique,
218
+ is_primary: isPrimary
219
+ });
220
+ }
221
+ const indexInfo = indexMap.get(indexName);
222
+ indexInfo.columns.push(columnName);
223
+ }
224
+ const results = [];
225
+ indexMap.forEach((indexInfo, indexName) => {
226
+ results.push({
227
+ index_name: indexName,
228
+ column_names: indexInfo.columns,
229
+ is_unique: indexInfo.is_unique,
230
+ is_primary: indexInfo.is_primary
231
+ });
232
+ });
233
+ return results;
234
+ } catch (error) {
235
+ console.error("Error getting table indexes:", error);
236
+ throw error;
237
+ }
238
+ }
239
+ async getTableSchema(tableName, schema) {
240
+ if (!this.pool) {
241
+ throw new Error("Not connected to database");
242
+ }
243
+ try {
244
+ const schemaClause = schema ? "WHERE TABLE_SCHEMA = ?" : "WHERE TABLE_SCHEMA = DATABASE()";
245
+ const queryParams = schema ? [schema, tableName] : [tableName];
246
+ const [rows] = await this.pool.query(
247
+ `
248
+ SELECT
249
+ COLUMN_NAME as column_name,
250
+ DATA_TYPE as data_type,
251
+ IS_NULLABLE as is_nullable,
252
+ COLUMN_DEFAULT as column_default,
253
+ COLUMN_COMMENT as description
254
+ FROM INFORMATION_SCHEMA.COLUMNS
255
+ ${schemaClause}
256
+ AND TABLE_NAME = ?
257
+ ORDER BY ORDINAL_POSITION
258
+ `,
259
+ queryParams
260
+ );
261
+ return rows.map((row) => ({
262
+ ...row,
263
+ description: row.description || null
264
+ }));
265
+ } catch (error) {
266
+ console.error("Error getting table schema:", error);
267
+ throw error;
268
+ }
269
+ }
270
+ async getTableComment(tableName, schema) {
271
+ if (!this.pool) {
272
+ throw new Error("Not connected to database");
273
+ }
274
+ try {
275
+ const schemaClause = schema ? "WHERE TABLE_SCHEMA = ?" : "WHERE TABLE_SCHEMA = DATABASE()";
276
+ const queryParams = schema ? [schema, tableName] : [tableName];
277
+ const [rows] = await this.pool.query(
278
+ `
279
+ SELECT TABLE_COMMENT
280
+ FROM INFORMATION_SCHEMA.TABLES
281
+ ${schemaClause}
282
+ AND TABLE_NAME = ?
283
+ `,
284
+ queryParams
285
+ );
286
+ if (rows.length > 0) {
287
+ return rows[0].TABLE_COMMENT || null;
288
+ }
289
+ return null;
290
+ } catch (error) {
291
+ return null;
292
+ }
293
+ }
294
+ async getStoredProcedures(schema, routineType) {
295
+ if (!this.pool) {
296
+ throw new Error("Not connected to database");
297
+ }
298
+ try {
299
+ const schemaClause = schema ? "WHERE ROUTINE_SCHEMA = ?" : "WHERE ROUTINE_SCHEMA = DATABASE()";
300
+ const queryParams = schema ? [schema] : [];
301
+ let typeFilter = "";
302
+ if (routineType === "function") {
303
+ typeFilter = " AND ROUTINE_TYPE = 'FUNCTION'";
304
+ } else if (routineType === "procedure") {
305
+ typeFilter = " AND ROUTINE_TYPE = 'PROCEDURE'";
306
+ }
307
+ const [rows] = await this.pool.query(
308
+ `
309
+ SELECT ROUTINE_NAME
310
+ FROM INFORMATION_SCHEMA.ROUTINES
311
+ ${schemaClause}${typeFilter}
312
+ ORDER BY ROUTINE_NAME
313
+ `,
314
+ queryParams
315
+ );
316
+ return rows.map((row) => row.ROUTINE_NAME);
317
+ } catch (error) {
318
+ console.error("Error getting stored procedures:", error);
319
+ throw error;
320
+ }
321
+ }
322
+ async getStoredProcedureDetail(procedureName, schema) {
323
+ if (!this.pool) {
324
+ throw new Error("Not connected to database");
325
+ }
326
+ try {
327
+ const schemaClause = schema ? "WHERE r.ROUTINE_SCHEMA = ?" : "WHERE r.ROUTINE_SCHEMA = DATABASE()";
328
+ const queryParams = schema ? [schema, procedureName] : [procedureName];
329
+ const [rows] = await this.pool.query(
330
+ `
331
+ SELECT
332
+ r.ROUTINE_NAME AS procedure_name,
333
+ CASE
334
+ WHEN r.ROUTINE_TYPE = 'PROCEDURE' THEN 'procedure'
335
+ ELSE 'function'
336
+ END AS procedure_type,
337
+ LOWER(r.ROUTINE_TYPE) AS routine_type,
338
+ r.ROUTINE_DEFINITION,
339
+ r.DTD_IDENTIFIER AS return_type,
340
+ (
341
+ SELECT GROUP_CONCAT(
342
+ CONCAT(p.PARAMETER_NAME, ' ', p.PARAMETER_MODE, ' ', p.DATA_TYPE)
343
+ ORDER BY p.ORDINAL_POSITION
344
+ SEPARATOR ', '
345
+ )
346
+ FROM INFORMATION_SCHEMA.PARAMETERS p
347
+ WHERE p.SPECIFIC_SCHEMA = r.ROUTINE_SCHEMA
348
+ AND p.SPECIFIC_NAME = r.ROUTINE_NAME
349
+ AND p.PARAMETER_NAME IS NOT NULL
350
+ ) AS parameter_list
351
+ FROM INFORMATION_SCHEMA.ROUTINES r
352
+ ${schemaClause}
353
+ AND r.ROUTINE_NAME = ?
354
+ `,
355
+ queryParams
356
+ );
357
+ if (rows.length === 0) {
358
+ const schemaName = schema || "current schema";
359
+ throw new Error(`Stored procedure '${procedureName}' not found in ${schemaName}`);
360
+ }
361
+ const procedure = rows[0];
362
+ let definition = procedure.ROUTINE_DEFINITION;
363
+ try {
364
+ const schemaValue = schema || await this.getCurrentSchema();
365
+ const quotedSchema = quoteIdentifier(schemaValue, "mysql");
366
+ const quotedProcName = quoteIdentifier(procedureName, "mysql");
367
+ if (procedure.procedure_type === "procedure") {
368
+ try {
369
+ const [defRows] = await this.pool.query(`
370
+ SHOW CREATE PROCEDURE ${quotedSchema}.${quotedProcName}
371
+ `);
372
+ if (defRows && defRows.length > 0) {
373
+ definition = defRows[0]["Create Procedure"];
374
+ }
375
+ } catch (err) {
376
+ console.error(`Error getting procedure definition with SHOW CREATE: ${err}`);
377
+ }
378
+ } else {
379
+ try {
380
+ const [defRows] = await this.pool.query(`
381
+ SHOW CREATE FUNCTION ${quotedSchema}.${quotedProcName}
382
+ `);
383
+ if (defRows && defRows.length > 0) {
384
+ definition = defRows[0]["Create Function"];
385
+ }
386
+ } catch (innerErr) {
387
+ console.error(`Error getting function definition with SHOW CREATE: ${innerErr}`);
388
+ }
389
+ }
390
+ if (!definition) {
391
+ const [bodyRows] = await this.pool.query(
392
+ `
393
+ SELECT ROUTINE_DEFINITION, ROUTINE_BODY
394
+ FROM INFORMATION_SCHEMA.ROUTINES
395
+ WHERE ROUTINE_SCHEMA = ? AND ROUTINE_NAME = ?
396
+ `,
397
+ [schemaValue, procedureName]
398
+ );
399
+ if (bodyRows && bodyRows.length > 0) {
400
+ if (bodyRows[0].ROUTINE_DEFINITION) {
401
+ definition = bodyRows[0].ROUTINE_DEFINITION;
402
+ } else if (bodyRows[0].ROUTINE_BODY) {
403
+ definition = bodyRows[0].ROUTINE_BODY;
404
+ }
405
+ }
406
+ }
407
+ } catch (error) {
408
+ console.error(`Error getting procedure/function details: ${error}`);
409
+ }
410
+ return {
411
+ procedure_name: procedure.procedure_name,
412
+ procedure_type: procedure.procedure_type,
413
+ language: "sql",
414
+ // MySQL procedures are generally in SQL
415
+ parameter_list: procedure.parameter_list || "",
416
+ return_type: procedure.routine_type === "function" ? procedure.return_type : void 0,
417
+ definition: definition || void 0
418
+ };
419
+ } catch (error) {
420
+ console.error("Error getting stored procedure detail:", error);
421
+ throw error;
422
+ }
423
+ }
424
+ // Helper method to get current schema (database) name
425
+ async getCurrentSchema() {
426
+ const [rows] = await this.pool.query("SELECT DATABASE() AS DB");
427
+ return rows[0].DB;
428
+ }
429
+ async executeSQL(sql, options, parameters) {
430
+ if (!this.pool) {
431
+ throw new Error("Not connected to database");
432
+ }
433
+ const conn = await this.pool.getConnection();
434
+ try {
435
+ let processedSQL = sql;
436
+ if (options.maxRows) {
437
+ const statements = splitSQLStatements(sql, "mysql");
438
+ const processedStatements = statements.map(
439
+ (statement) => SQLRowLimiter.applyMaxRows(statement, options.maxRows)
440
+ );
441
+ processedSQL = processedStatements.join("; ");
442
+ if (sql.trim().endsWith(";")) {
443
+ processedSQL += ";";
444
+ }
445
+ }
446
+ let results;
447
+ if (parameters && parameters.length > 0) {
448
+ try {
449
+ results = await conn.query({ sql: processedSQL, timeout: this.queryTimeoutMs }, parameters);
450
+ } catch (error) {
451
+ console.error(`[MySQL executeSQL] ERROR: ${error.message}`);
452
+ console.error(`[MySQL executeSQL] SQL: ${processedSQL}`);
453
+ console.error(`[MySQL executeSQL] Parameters: ${JSON.stringify(parameters)}`);
454
+ throw error;
455
+ }
456
+ } else {
457
+ results = await conn.query({ sql: processedSQL, timeout: this.queryTimeoutMs });
458
+ }
459
+ const [firstResult] = results;
460
+ const rows = parseQueryResults(firstResult);
461
+ const rowCount = extractAffectedRows(firstResult);
462
+ return { rows, rowCount };
463
+ } catch (error) {
464
+ console.error("Error executing query:", error);
465
+ throw error;
466
+ } finally {
467
+ conn.release();
468
+ }
469
+ }
470
+ };
471
+ var mysqlConnector = new MySQLConnector();
472
+ ConnectorRegistry.register(mysqlConnector);
473
+ export {
474
+ MySQLConnector
475
+ };