@pilat/mcp-datalink 1.0.1
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/README.md +442 -0
- package/databases.example.json +18 -0
- package/dist/__integration__/global-setup.d.ts +8 -0
- package/dist/__integration__/global-setup.d.ts.map +1 -0
- package/dist/__integration__/global-setup.js +34 -0
- package/dist/__integration__/global-setup.js.map +1 -0
- package/dist/__integration__/global-teardown.d.ts +8 -0
- package/dist/__integration__/global-teardown.d.ts.map +1 -0
- package/dist/__integration__/global-teardown.js +17 -0
- package/dist/__integration__/global-teardown.js.map +1 -0
- package/dist/__integration__/helpers.d.ts +58 -0
- package/dist/__integration__/helpers.d.ts.map +1 -0
- package/dist/__integration__/helpers.js +568 -0
- package/dist/__integration__/helpers.js.map +1 -0
- package/dist/__integration__/setup.d.ts +79 -0
- package/dist/__integration__/setup.d.ts.map +1 -0
- package/dist/__integration__/setup.js +230 -0
- package/dist/__integration__/setup.js.map +1 -0
- package/dist/adapters/factory.d.ts +40 -0
- package/dist/adapters/factory.d.ts.map +1 -0
- package/dist/adapters/factory.js +114 -0
- package/dist/adapters/factory.js.map +1 -0
- package/dist/adapters/index.d.ts +31 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +34 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/mysql/adapter.d.ts +61 -0
- package/dist/adapters/mysql/adapter.d.ts.map +1 -0
- package/dist/adapters/mysql/adapter.js +567 -0
- package/dist/adapters/mysql/adapter.js.map +1 -0
- package/dist/adapters/postgresql/adapter.d.ts +52 -0
- package/dist/adapters/postgresql/adapter.d.ts.map +1 -0
- package/dist/adapters/postgresql/adapter.js +429 -0
- package/dist/adapters/postgresql/adapter.js.map +1 -0
- package/dist/adapters/sqlite/adapter.d.ts +56 -0
- package/dist/adapters/sqlite/adapter.d.ts.map +1 -0
- package/dist/adapters/sqlite/adapter.js +582 -0
- package/dist/adapters/sqlite/adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +155 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +7 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +127 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +191 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/describe-table.d.ts +11 -0
- package/dist/tools/describe-table.d.ts.map +1 -0
- package/dist/tools/describe-table.js +23 -0
- package/dist/tools/describe-table.js.map +1 -0
- package/dist/tools/execute.d.ts +22 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/execute.js +48 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/explain.d.ts +25 -0
- package/dist/tools/explain.d.ts.map +1 -0
- package/dist/tools/explain.js +81 -0
- package/dist/tools/explain.js.map +1 -0
- package/dist/tools/list-databases.d.ts +18 -0
- package/dist/tools/list-databases.d.ts.map +1 -0
- package/dist/tools/list-databases.js +17 -0
- package/dist/tools/list-databases.js.map +1 -0
- package/dist/tools/list-tables.d.ts +22 -0
- package/dist/tools/list-tables.d.ts.map +1 -0
- package/dist/tools/list-tables.js +43 -0
- package/dist/tools/list-tables.js.map +1 -0
- package/dist/tools/query.d.ts +25 -0
- package/dist/tools/query.d.ts.map +1 -0
- package/dist/tools/query.js +109 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/errors.d.ts +22 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +41 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/formatter.d.ts +13 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +56 -0
- package/dist/utils/formatter.js.map +1 -0
- package/dist/utils/truncate.d.ts +37 -0
- package/dist/utils/truncate.d.ts.map +1 -0
- package/dist/utils/truncate.js +91 -0
- package/dist/utils/truncate.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MySQL Database Adapter
|
|
3
|
+
*
|
|
4
|
+
* Implements DatabaseAdapter interface for MySQL databases.
|
|
5
|
+
* Uses mysql2/promise driver with per-request connection recycling.
|
|
6
|
+
*/
|
|
7
|
+
import * as mysql from 'mysql2/promise';
|
|
8
|
+
import { DbMcpError, ErrorCode } from '../../utils/errors.js';
|
|
9
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
// SQL Dialect helpers (formerly in dialect.ts)
|
|
11
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
/**
|
|
13
|
+
* MySQL-specific dangerous patterns
|
|
14
|
+
*/
|
|
15
|
+
const DANGEROUS_MYSQL_PATTERNS = [
|
|
16
|
+
{
|
|
17
|
+
pattern: /\bLOAD\s+DATA\b/i,
|
|
18
|
+
reason: 'LOAD DATA statements are not allowed (file system access)',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
pattern: /\bINTO\s+OUTFILE\b/i,
|
|
22
|
+
reason: 'INTO OUTFILE is not allowed (file system write)',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
pattern: /\bINTO\s+DUMPFILE\b/i,
|
|
26
|
+
reason: 'INTO DUMPFILE is not allowed (file system write)',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
pattern: /\bLOAD_FILE\s*\(/i,
|
|
30
|
+
reason: 'LOAD_FILE() function is not allowed (file system read)',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
/**
|
|
34
|
+
* Standard dangerous SQL operations (DDL/DCL)
|
|
35
|
+
*/
|
|
36
|
+
const DANGEROUS_PREFIXES = [
|
|
37
|
+
'DROP',
|
|
38
|
+
'TRUNCATE',
|
|
39
|
+
'ALTER',
|
|
40
|
+
'CREATE',
|
|
41
|
+
'GRANT',
|
|
42
|
+
'REVOKE',
|
|
43
|
+
'RENAME',
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Strip SQL comments from a query
|
|
47
|
+
*/
|
|
48
|
+
function stripComments(sql) {
|
|
49
|
+
let result = '';
|
|
50
|
+
let i = 0;
|
|
51
|
+
const len = sql.length;
|
|
52
|
+
while (i < len) {
|
|
53
|
+
const char = sql[i];
|
|
54
|
+
const nextChar = sql[i + 1];
|
|
55
|
+
// Handle strings - preserve content inside quotes
|
|
56
|
+
if (char === "'" || char === '"' || char === '`') {
|
|
57
|
+
const quote = char;
|
|
58
|
+
result += char;
|
|
59
|
+
i++;
|
|
60
|
+
while (i < len) {
|
|
61
|
+
const c = sql[i];
|
|
62
|
+
result += c;
|
|
63
|
+
i++;
|
|
64
|
+
if (c === '\\' && i < len) {
|
|
65
|
+
result += sql[i];
|
|
66
|
+
i++;
|
|
67
|
+
}
|
|
68
|
+
else if (c === quote) {
|
|
69
|
+
if (sql[i] === quote) {
|
|
70
|
+
result += sql[i];
|
|
71
|
+
i++;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// Handle single-line comment: --
|
|
81
|
+
if (char === '-' && nextChar === '-') {
|
|
82
|
+
i += 2;
|
|
83
|
+
while (i < len && sql[i] !== '\n') {
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
result += ' ';
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
// Handle single-line comment: # (MySQL-specific)
|
|
90
|
+
if (char === '#') {
|
|
91
|
+
i++;
|
|
92
|
+
while (i < len && sql[i] !== '\n') {
|
|
93
|
+
i++;
|
|
94
|
+
}
|
|
95
|
+
result += ' ';
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// Handle multi-line comment: /* */
|
|
99
|
+
if (char === '/' && nextChar === '*') {
|
|
100
|
+
i += 2;
|
|
101
|
+
while (i < len - 1) {
|
|
102
|
+
if (sql[i] === '*' && sql[i + 1] === '/') {
|
|
103
|
+
i += 2;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
i++;
|
|
107
|
+
}
|
|
108
|
+
result += ' ';
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
result += char;
|
|
112
|
+
i++;
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* String-aware statement splitting
|
|
118
|
+
*/
|
|
119
|
+
function splitStatements(sql) {
|
|
120
|
+
const statements = [];
|
|
121
|
+
let current = '';
|
|
122
|
+
let i = 0;
|
|
123
|
+
const len = sql.length;
|
|
124
|
+
while (i < len) {
|
|
125
|
+
const char = sql[i];
|
|
126
|
+
// Handle strings - don't split inside quotes
|
|
127
|
+
if (char === "'" || char === '"' || char === '`') {
|
|
128
|
+
const quote = char;
|
|
129
|
+
current += char;
|
|
130
|
+
i++;
|
|
131
|
+
while (i < len) {
|
|
132
|
+
const c = sql[i];
|
|
133
|
+
current += c;
|
|
134
|
+
i++;
|
|
135
|
+
if (c === '\\' && i < len) {
|
|
136
|
+
current += sql[i];
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
else if (c === quote) {
|
|
140
|
+
if (sql[i] === quote) {
|
|
141
|
+
current += sql[i];
|
|
142
|
+
i++;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// Handle semicolon - split point
|
|
152
|
+
if (char === ';') {
|
|
153
|
+
const trimmed = current.trim();
|
|
154
|
+
if (trimmed.length > 0) {
|
|
155
|
+
statements.push(trimmed);
|
|
156
|
+
}
|
|
157
|
+
current = '';
|
|
158
|
+
i++;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
current += char;
|
|
162
|
+
i++;
|
|
163
|
+
}
|
|
164
|
+
const trimmed = current.trim();
|
|
165
|
+
if (trimmed.length > 0) {
|
|
166
|
+
statements.push(trimmed);
|
|
167
|
+
}
|
|
168
|
+
return statements;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Detect query type from normalized SQL
|
|
172
|
+
*/
|
|
173
|
+
function detectQueryType(normalizedSql) {
|
|
174
|
+
if (normalizedSql.startsWith('SELECT') || normalizedSql.startsWith('WITH')) {
|
|
175
|
+
return 'select';
|
|
176
|
+
}
|
|
177
|
+
if (normalizedSql.startsWith('INSERT')) {
|
|
178
|
+
return 'insert';
|
|
179
|
+
}
|
|
180
|
+
if (normalizedSql.startsWith('UPDATE')) {
|
|
181
|
+
return 'update';
|
|
182
|
+
}
|
|
183
|
+
if (normalizedSql.startsWith('DELETE')) {
|
|
184
|
+
return 'delete';
|
|
185
|
+
}
|
|
186
|
+
return 'other';
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Check if SQL contains dangerous MySQL-specific patterns
|
|
190
|
+
*/
|
|
191
|
+
function checkMySqlDangerousPatterns(sql) {
|
|
192
|
+
for (const { pattern, reason } of DANGEROUS_MYSQL_PATTERNS) {
|
|
193
|
+
if (pattern.test(sql)) {
|
|
194
|
+
return { isDangerous: true, reason };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return { isDangerous: false };
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Check if SQL starts with a dangerous prefix (DDL/DCL)
|
|
201
|
+
*/
|
|
202
|
+
function checkDangerousPrefix(normalizedSql) {
|
|
203
|
+
for (const prefix of DANGEROUS_PREFIXES) {
|
|
204
|
+
if (normalizedSql.startsWith(prefix + ' ') ||
|
|
205
|
+
normalizedSql.startsWith(prefix + '\t') ||
|
|
206
|
+
normalizedSql.startsWith(prefix + '\n') ||
|
|
207
|
+
normalizedSql === prefix) {
|
|
208
|
+
return {
|
|
209
|
+
isDangerous: true,
|
|
210
|
+
reason: `${prefix} statements are not allowed`,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return { isDangerous: false };
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Check if a SELECT query has a LIMIT clause
|
|
218
|
+
*/
|
|
219
|
+
function hasLimitClause(sql) {
|
|
220
|
+
return /\bLIMIT\s+\d+/i.test(sql);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* MySQL database adapter
|
|
224
|
+
*
|
|
225
|
+
* Creates new connections for each request to prevent session state attacks.
|
|
226
|
+
*/
|
|
227
|
+
export class MySqlAdapter {
|
|
228
|
+
type = 'mysql';
|
|
229
|
+
connectionUrl;
|
|
230
|
+
timeout;
|
|
231
|
+
constructor(config) {
|
|
232
|
+
this.connectionUrl = config.database.url;
|
|
233
|
+
this.timeout = config.defaults.timeout;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get the default schema name for MySQL (database name from URL)
|
|
237
|
+
*/
|
|
238
|
+
getDefaultSchema() {
|
|
239
|
+
try {
|
|
240
|
+
const url = new URL(this.connectionUrl);
|
|
241
|
+
return url.pathname.slice(1);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
return 'mysql';
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
248
|
+
// SQL Dialect methods
|
|
249
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
250
|
+
/**
|
|
251
|
+
* Parse and validate a SQL query
|
|
252
|
+
*/
|
|
253
|
+
parseQuery(sql) {
|
|
254
|
+
const withoutComments = stripComments(sql);
|
|
255
|
+
const statements = splitStatements(withoutComments);
|
|
256
|
+
if (statements.length === 0) {
|
|
257
|
+
throw new DbMcpError(ErrorCode.INVALID_SQL, 'No valid SQL statement found', {
|
|
258
|
+
sql,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
if (statements.length > 1) {
|
|
262
|
+
throw new DbMcpError(ErrorCode.MULTI_STATEMENT, 'Multiple SQL statements are not allowed. Please provide a single statement.', { sql, statementCount: statements.length });
|
|
263
|
+
}
|
|
264
|
+
const statement = statements[0];
|
|
265
|
+
const normalizedSql = statement.trim().toUpperCase();
|
|
266
|
+
const mysqlDanger = checkMySqlDangerousPatterns(statement);
|
|
267
|
+
if (mysqlDanger.isDangerous) {
|
|
268
|
+
return {
|
|
269
|
+
type: 'other',
|
|
270
|
+
hasLimit: false,
|
|
271
|
+
isDangerous: true,
|
|
272
|
+
dangerousReason: mysqlDanger.reason,
|
|
273
|
+
sql,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
const prefixDanger = checkDangerousPrefix(normalizedSql);
|
|
277
|
+
if (prefixDanger.isDangerous) {
|
|
278
|
+
return {
|
|
279
|
+
type: 'other',
|
|
280
|
+
hasLimit: false,
|
|
281
|
+
isDangerous: true,
|
|
282
|
+
dangerousReason: prefixDanger.reason,
|
|
283
|
+
sql,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
const queryType = detectQueryType(normalizedSql);
|
|
287
|
+
const hasLimit = queryType === 'select' ? hasLimitClause(statement) : false;
|
|
288
|
+
return {
|
|
289
|
+
type: queryType,
|
|
290
|
+
hasLimit,
|
|
291
|
+
isDangerous: false,
|
|
292
|
+
sql,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Inject a LIMIT clause into a SELECT query if it doesn't have one
|
|
297
|
+
*/
|
|
298
|
+
injectLimit(sql, limit) {
|
|
299
|
+
if (hasLimitClause(sql)) {
|
|
300
|
+
return sql;
|
|
301
|
+
}
|
|
302
|
+
const trimmed = sql.replace(/;\s*$/, '').trim();
|
|
303
|
+
return `${trimmed} LIMIT ${limit}`;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Validate that a SQL query is appropriate for a specific tool
|
|
307
|
+
*/
|
|
308
|
+
validateQueryForTool(sql, tool) {
|
|
309
|
+
const parsed = this.parseQuery(sql);
|
|
310
|
+
if (tool === 'query') {
|
|
311
|
+
if (parsed.type !== 'select') {
|
|
312
|
+
throw new DbMcpError(ErrorCode.QUERY_BLOCKED, 'The query tool only accepts SELECT statements. Use the execute tool for ' +
|
|
313
|
+
parsed.type.toUpperCase() +
|
|
314
|
+
' statements.', { sql, queryType: parsed.type, tool });
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
else if (tool === 'execute') {
|
|
318
|
+
if (parsed.type === 'select') {
|
|
319
|
+
throw new DbMcpError(ErrorCode.QUERY_BLOCKED, 'The execute tool does not accept SELECT statements. Use the query tool instead.', { sql, queryType: parsed.type, tool });
|
|
320
|
+
}
|
|
321
|
+
if (parsed.isDangerous) {
|
|
322
|
+
throw new DbMcpError(ErrorCode.QUERY_BLOCKED, parsed.dangerousReason ?? 'This operation is not allowed', { sql, queryType: parsed.type, tool });
|
|
323
|
+
}
|
|
324
|
+
const allowedTypes = ['insert', 'update', 'delete'];
|
|
325
|
+
if (!allowedTypes.includes(parsed.type)) {
|
|
326
|
+
throw new DbMcpError(ErrorCode.QUERY_BLOCKED, 'The execute tool only accepts INSERT, UPDATE, or DELETE statements.', { sql, queryType: parsed.type, tool });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get the EXPLAIN prefix for MySQL
|
|
332
|
+
*/
|
|
333
|
+
getExplainPrefix(analyze) {
|
|
334
|
+
return analyze ? 'EXPLAIN ANALYZE ' : 'EXPLAIN ';
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Convert PostgreSQL-style placeholders ($1, $2) to MySQL-style (?)
|
|
338
|
+
*/
|
|
339
|
+
convertPlaceholders(sql) {
|
|
340
|
+
return sql.replace(/\$\d+/g, '?');
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Execute a function with a managed MySQL connection
|
|
344
|
+
*/
|
|
345
|
+
async withConnection(fn) {
|
|
346
|
+
let connection;
|
|
347
|
+
try {
|
|
348
|
+
connection = await mysql.createConnection(this.connectionUrl);
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
throw new DbMcpError(ErrorCode.CONNECTION_FAILED, 'Failed to connect to MySQL database', {
|
|
352
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
// SET command doesn't support parameterized queries, so validate timeout first
|
|
357
|
+
if (!Number.isInteger(this.timeout) || this.timeout < 0) {
|
|
358
|
+
throw new DbMcpError(ErrorCode.CONNECTION_FAILED, `Invalid timeout value: ${this.timeout}`);
|
|
359
|
+
}
|
|
360
|
+
// Try to set max_execution_time (MySQL 5.7.8+)
|
|
361
|
+
// Gracefully handle older versions that don't support it
|
|
362
|
+
try {
|
|
363
|
+
await connection.execute(`SET max_execution_time = ${this.timeout}`);
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
// Silently ignore if max_execution_time is not supported (older MySQL)
|
|
367
|
+
// The query will still run, just without execution timeout
|
|
368
|
+
// Log for debugging purposes would go here in production
|
|
369
|
+
}
|
|
370
|
+
// Create connection wrapper and execute user function
|
|
371
|
+
const adapter = new MySqlConnection(connection);
|
|
372
|
+
return await fn(adapter);
|
|
373
|
+
}
|
|
374
|
+
finally {
|
|
375
|
+
await connection.end();
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Clean up resources (no persistent resources in this adapter)
|
|
380
|
+
*/
|
|
381
|
+
async dispose() {
|
|
382
|
+
// No persistent resources to clean up
|
|
383
|
+
// Each connection is created and destroyed per request
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* MySQL connection wrapper
|
|
388
|
+
*
|
|
389
|
+
* Provides AdapterConnection interface over mysql2 Connection.
|
|
390
|
+
* Handles MySQL-specific query execution and metadata retrieval.
|
|
391
|
+
*/
|
|
392
|
+
class MySqlConnection {
|
|
393
|
+
conn;
|
|
394
|
+
constructor(conn) {
|
|
395
|
+
this.conn = conn;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Execute a parameterized query using prepared statements
|
|
399
|
+
*/
|
|
400
|
+
async query(sql, params) {
|
|
401
|
+
const [result, fields] = await this.conn.execute(sql, params ?? []);
|
|
402
|
+
// For non-SELECT queries (INSERT/UPDATE/DELETE), fields is undefined
|
|
403
|
+
// and result is a ResultSetHeader with affectedRows
|
|
404
|
+
if (!fields || !Array.isArray(fields)) {
|
|
405
|
+
// ResultSetHeader for INSERT/UPDATE/DELETE
|
|
406
|
+
const header = result;
|
|
407
|
+
return {
|
|
408
|
+
fields: [],
|
|
409
|
+
rows: [],
|
|
410
|
+
rowCount: header.affectedRows ?? 0,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
// SELECT query - mysql2 returns rows as objects, convert to arrays
|
|
414
|
+
const rows = result;
|
|
415
|
+
const fieldNames = fields.map((f) => f.name);
|
|
416
|
+
return {
|
|
417
|
+
fields: fieldNames.map((name) => ({ name })),
|
|
418
|
+
rows: rows.map((row) => fieldNames.map((f) => row[f])),
|
|
419
|
+
rowCount: rows.length,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Execute a raw SQL statement (for BEGIN, COMMIT, ROLLBACK)
|
|
424
|
+
*/
|
|
425
|
+
async execute(sql) {
|
|
426
|
+
await this.conn.query(sql);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* List tables in a MySQL database (schema = database in MySQL terminology)
|
|
430
|
+
*
|
|
431
|
+
* Uses information_schema.TABLES for table metadata.
|
|
432
|
+
*/
|
|
433
|
+
async listTables(schema, _maxTables) {
|
|
434
|
+
const sql = `
|
|
435
|
+
SELECT
|
|
436
|
+
TABLE_NAME as name,
|
|
437
|
+
TABLE_SCHEMA as \`schema\`,
|
|
438
|
+
CASE WHEN TABLE_TYPE = 'BASE TABLE' THEN 'table' ELSE 'view' END as type,
|
|
439
|
+
TABLE_ROWS as rows_estimate
|
|
440
|
+
FROM information_schema.TABLES
|
|
441
|
+
WHERE TABLE_SCHEMA = ?
|
|
442
|
+
ORDER BY TABLE_NAME
|
|
443
|
+
`;
|
|
444
|
+
const [rows] = await this.conn.execute(sql, [schema]);
|
|
445
|
+
const tables = rows.map((row) => ({
|
|
446
|
+
name: row.name,
|
|
447
|
+
schema: row.schema,
|
|
448
|
+
type: row.type,
|
|
449
|
+
rows_estimate: row.rows_estimate !== null ? Number(row.rows_estimate) : null,
|
|
450
|
+
}));
|
|
451
|
+
return {
|
|
452
|
+
tables,
|
|
453
|
+
totalAvailable: tables.length,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Describe a MySQL table
|
|
458
|
+
*
|
|
459
|
+
* Retrieves columns, indexes, and foreign keys from information_schema.
|
|
460
|
+
*/
|
|
461
|
+
async describeTable(table, schema, limits) {
|
|
462
|
+
// Query 1: Get columns
|
|
463
|
+
const columnsQuery = `
|
|
464
|
+
SELECT
|
|
465
|
+
COLUMN_NAME as name,
|
|
466
|
+
CONCAT(
|
|
467
|
+
DATA_TYPE,
|
|
468
|
+
CASE
|
|
469
|
+
WHEN CHARACTER_MAXIMUM_LENGTH IS NOT NULL
|
|
470
|
+
THEN CONCAT('(', CHARACTER_MAXIMUM_LENGTH, ')')
|
|
471
|
+
WHEN NUMERIC_PRECISION IS NOT NULL AND DATA_TYPE NOT IN ('int', 'bigint', 'smallint', 'tinyint', 'mediumint')
|
|
472
|
+
THEN CONCAT('(', NUMERIC_PRECISION, ',', IFNULL(NUMERIC_SCALE, 0), ')')
|
|
473
|
+
ELSE ''
|
|
474
|
+
END
|
|
475
|
+
) as type,
|
|
476
|
+
IS_NULLABLE = 'YES' as nullable,
|
|
477
|
+
COLUMN_DEFAULT as \`default\`,
|
|
478
|
+
COLUMN_KEY = 'PRI' as primaryKey
|
|
479
|
+
FROM information_schema.COLUMNS
|
|
480
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
|
481
|
+
ORDER BY ORDINAL_POSITION
|
|
482
|
+
`;
|
|
483
|
+
// Query 2: Get indexes
|
|
484
|
+
const indexesQuery = `
|
|
485
|
+
SELECT
|
|
486
|
+
INDEX_NAME as name,
|
|
487
|
+
GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) as columns,
|
|
488
|
+
NOT NON_UNIQUE as \`unique\`,
|
|
489
|
+
INDEX_NAME = 'PRIMARY' as \`primary\`
|
|
490
|
+
FROM information_schema.STATISTICS
|
|
491
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
|
|
492
|
+
GROUP BY INDEX_NAME, NON_UNIQUE
|
|
493
|
+
ORDER BY INDEX_NAME
|
|
494
|
+
`;
|
|
495
|
+
// Query 3: Get foreign keys
|
|
496
|
+
const foreignKeysQuery = `
|
|
497
|
+
SELECT
|
|
498
|
+
kcu.COLUMN_NAME as \`column\`,
|
|
499
|
+
kcu.REFERENCED_TABLE_NAME as ref_table,
|
|
500
|
+
kcu.REFERENCED_COLUMN_NAME as ref_column
|
|
501
|
+
FROM information_schema.KEY_COLUMN_USAGE kcu
|
|
502
|
+
JOIN information_schema.TABLE_CONSTRAINTS tc
|
|
503
|
+
ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
|
|
504
|
+
AND tc.TABLE_SCHEMA = kcu.TABLE_SCHEMA
|
|
505
|
+
AND tc.TABLE_NAME = kcu.TABLE_NAME
|
|
506
|
+
WHERE tc.CONSTRAINT_TYPE = 'FOREIGN KEY'
|
|
507
|
+
AND kcu.TABLE_SCHEMA = ?
|
|
508
|
+
AND kcu.TABLE_NAME = ?
|
|
509
|
+
`;
|
|
510
|
+
const [columnsResult, indexesResult, foreignKeysResult] = await Promise.all([
|
|
511
|
+
this.conn.execute(columnsQuery, [schema, table]),
|
|
512
|
+
this.conn.execute(indexesQuery, [schema, table]),
|
|
513
|
+
this.conn.execute(foreignKeysQuery, [schema, table]),
|
|
514
|
+
]);
|
|
515
|
+
const [columnsRows] = columnsResult;
|
|
516
|
+
const [indexesRows] = indexesResult;
|
|
517
|
+
const [foreignKeysRows] = foreignKeysResult;
|
|
518
|
+
// Build columns array
|
|
519
|
+
const allColumns = columnsRows.map((row) => ({
|
|
520
|
+
name: row.name,
|
|
521
|
+
type: row.type,
|
|
522
|
+
nullable: Boolean(row.nullable),
|
|
523
|
+
default: row.default,
|
|
524
|
+
primaryKey: Boolean(row.primaryKey),
|
|
525
|
+
}));
|
|
526
|
+
// Build indexes array
|
|
527
|
+
const allIndexes = indexesRows.map((row) => ({
|
|
528
|
+
name: row.name,
|
|
529
|
+
columns: row.columns.split(','),
|
|
530
|
+
unique: Boolean(row.unique),
|
|
531
|
+
primary: Boolean(row.primary),
|
|
532
|
+
}));
|
|
533
|
+
// Build foreign keys array
|
|
534
|
+
const foreignKeys = foreignKeysRows.map((row) => ({
|
|
535
|
+
column: row.column,
|
|
536
|
+
references: {
|
|
537
|
+
table: row.ref_table,
|
|
538
|
+
column: row.ref_column,
|
|
539
|
+
},
|
|
540
|
+
}));
|
|
541
|
+
// Apply limits and track truncation
|
|
542
|
+
let truncated = false;
|
|
543
|
+
const truncationReasons = [];
|
|
544
|
+
const columns = allColumns.length > limits.maxColumns
|
|
545
|
+
? ((truncated = true),
|
|
546
|
+
truncationReasons.push(`columns (${allColumns.length} > ${limits.maxColumns})`),
|
|
547
|
+
allColumns.slice(0, limits.maxColumns))
|
|
548
|
+
: allColumns;
|
|
549
|
+
const indexes = allIndexes.length > limits.maxIndexes
|
|
550
|
+
? ((truncated = true),
|
|
551
|
+
truncationReasons.push(`indexes (${allIndexes.length} > ${limits.maxIndexes})`),
|
|
552
|
+
allIndexes.slice(0, limits.maxIndexes))
|
|
553
|
+
: allIndexes;
|
|
554
|
+
return {
|
|
555
|
+
table,
|
|
556
|
+
schema,
|
|
557
|
+
columns,
|
|
558
|
+
indexes,
|
|
559
|
+
foreignKeys,
|
|
560
|
+
truncated,
|
|
561
|
+
...(truncated && { truncationReason: truncationReasons.join(', ') }),
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
// Export helper functions for testing
|
|
566
|
+
export { stripComments, splitStatements };
|
|
567
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/adapters/mysql/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgreSQL Database Adapter
|
|
3
|
+
*
|
|
4
|
+
* Implements DatabaseAdapter interface for PostgreSQL databases.
|
|
5
|
+
* Uses node-postgres (pg) driver with per-request connection recycling.
|
|
6
|
+
*/
|
|
7
|
+
import type { DatabaseAdapter, AdapterConnection, AdapterConfig } from '../types.js';
|
|
8
|
+
import type { ParsedQuery } from '../../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* PostgreSQL database adapter
|
|
11
|
+
*
|
|
12
|
+
* Creates new connections for each request to prevent session state attacks.
|
|
13
|
+
*/
|
|
14
|
+
export declare class PostgreSqlAdapter implements DatabaseAdapter {
|
|
15
|
+
readonly type: "postgresql";
|
|
16
|
+
private readonly connectionUrl;
|
|
17
|
+
private readonly timeout;
|
|
18
|
+
constructor(config: AdapterConfig);
|
|
19
|
+
/**
|
|
20
|
+
* Get the default schema name for PostgreSQL
|
|
21
|
+
*/
|
|
22
|
+
getDefaultSchema(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Parse and validate a SQL query
|
|
25
|
+
*/
|
|
26
|
+
parseQuery(sql: string): ParsedQuery;
|
|
27
|
+
/**
|
|
28
|
+
* Inject a LIMIT clause into a SELECT query if it doesn't have one
|
|
29
|
+
*/
|
|
30
|
+
injectLimit(sql: string, limit: number): string;
|
|
31
|
+
/**
|
|
32
|
+
* Validate that a SQL query is appropriate for a specific tool
|
|
33
|
+
*/
|
|
34
|
+
validateQueryForTool(sql: string, tool: 'query' | 'execute'): void;
|
|
35
|
+
/**
|
|
36
|
+
* Get the EXPLAIN prefix for PostgreSQL
|
|
37
|
+
*/
|
|
38
|
+
getExplainPrefix(analyze: boolean): string;
|
|
39
|
+
/**
|
|
40
|
+
* Convert placeholders - no-op for PostgreSQL (already uses $1, $2, $3)
|
|
41
|
+
*/
|
|
42
|
+
convertPlaceholders(sql: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Execute a function with a managed PostgreSQL connection
|
|
45
|
+
*/
|
|
46
|
+
withConnection<T>(fn: (conn: AdapterConnection) => Promise<T>): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Clean up resources (no persistent resources in this adapter)
|
|
49
|
+
*/
|
|
50
|
+
dispose(): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/postgresql/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAEjB,aAAa,EAEd,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,WAAW,EAOZ,MAAM,gBAAgB,CAAC;AA2ExB;;;;GAIG;AACH,qBAAa,iBAAkB,YAAW,eAAe;IACvD,QAAQ,CAAC,IAAI,EAAG,YAAY,CAAU;IAEtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,aAAa;IAKjC;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAQ1B;;OAEG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW;IAgDpC;;OAEG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAkC/C;;OAEG;IACH,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI;IAyClE;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAI1C;;OAEG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAIxC;;OAEG;IACG,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAoChF;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAI/B"}
|