@bytebase/dbhub 1.2.5 → 1.3.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.
- package/README.md +7 -7
- package/dist/{chunk-A4TSDCPY.js → chunk-6SZKW6GD.js} +1 -1
- package/dist/{chunk-VDA5BVNE.js → chunk-77BJNE6E.js} +87 -57
- package/dist/{chunk-IQRBLAB4.js → chunk-ABTVMHD6.js} +40 -10
- package/dist/{chunk-MF6LSVWK.js → chunk-IXC4NQGC.js} +29 -3
- package/dist/{chunk-JFWX35TB.js → chunk-X2EC47W4.js} +1 -0
- package/dist/chunk-YIGJHEU6.js +343 -0
- package/dist/index.js +16 -15
- package/dist/{mariadb-EVJ5HLYH.js → mariadb-L7Z55ROY.js} +6 -5
- package/dist/{mysql-GXDUNLJ6.js → mysql-XXIHWQGR.js} +6 -5
- package/dist/oracle-OUKBU52X.js +754 -0
- package/dist/{postgres-M3W3Y6F5.js → postgres-6XJ7V4J4.js} +13 -6
- package/dist/public/assets/{index-BdBaFSHd.js → index-BRlIJaqn.js} +27 -27
- package/dist/public/index.html +1 -1
- package/dist/{registry-UF3N2H4G.js → registry-P4IGJ56H.js} +2 -2
- package/dist/{sqlite-ASYMU5BI.js → sqlite-AO2BKIC6.js} +22 -10
- package/dist/{sqlserver-WNVSBFJ3.js → sqlserver-AJUK6L55.js} +10 -18
- package/package.json +5 -2
- package/dist/chunk-6QETXS44.js +0 -254
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasMutatingKeyword
|
|
3
|
+
} from "./chunk-ABTVMHD6.js";
|
|
4
|
+
import {
|
|
5
|
+
blankCommentsAndStrings
|
|
6
|
+
} from "./chunk-IXC4NQGC.js";
|
|
7
|
+
|
|
8
|
+
// src/utils/sql-row-limiter.ts
|
|
9
|
+
var SQLRowLimiter = class {
|
|
10
|
+
/**
|
|
11
|
+
* Check if a SQL statement is a row-returning query that can benefit from row limiting.
|
|
12
|
+
*
|
|
13
|
+
* Classification runs on the comment-blanked text, so a query introduced by a
|
|
14
|
+
* `--` or `/* ... *\/` comment (a query tag, say) is classified by its real
|
|
15
|
+
* leading keyword. The SQL sent to the server is never rewritten by this
|
|
16
|
+
* check, so an attribution comment survives verbatim.
|
|
17
|
+
*
|
|
18
|
+
* `WITH` leads a CTE whose final statement is normally a SELECT, so it is
|
|
19
|
+
* limitable too, except for a data-modifying CTE
|
|
20
|
+
* (`WITH x AS (DELETE ... RETURNING *) SELECT ...`), where a LIMIT would cap
|
|
21
|
+
* the rows handed back while the write still runs in full. Detection there is
|
|
22
|
+
* the same keyword heuristic the read-only classifier uses, so a false
|
|
23
|
+
* positive only means the statement keeps the old behaviour of not being limited.
|
|
24
|
+
*
|
|
25
|
+
* `dialect` selects the connector's scanner so dialect-specific quoting
|
|
26
|
+
* (PostgreSQL dollar quotes, MySQL backticks, SQL Server brackets) is
|
|
27
|
+
* blanked the same way the read-only classifier blanks it; without it only
|
|
28
|
+
* ANSI syntax is recognized.
|
|
29
|
+
*/
|
|
30
|
+
static isSelectQuery(sql, dialect) {
|
|
31
|
+
const blankedSQL = blankCommentsAndStrings(sql, dialect).trim().toLowerCase();
|
|
32
|
+
const firstKeyword = /^[(;\s]*([a-z_]+)/.exec(blankedSQL)?.[1] ?? "";
|
|
33
|
+
if (firstKeyword === "select") {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return firstKeyword === "with" && !hasMutatingKeyword(blankedSQL, dialect);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if a SQL statement has a LIMIT clause of its own (not one nested in
|
|
40
|
+
* a CTE body or subquery).
|
|
41
|
+
*/
|
|
42
|
+
static hasLimitClause(sql, dialect) {
|
|
43
|
+
return this.findTopLevelLimit(sql, dialect) !== null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if a SQL statement has a TOP clause of its own (SQL Server).
|
|
47
|
+
*/
|
|
48
|
+
static hasTopClause(sql) {
|
|
49
|
+
return this.findTopLevelTop(sql) !== null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Extract the statement's own LIMIT value. Null when it has no LIMIT of its
|
|
53
|
+
* own, or when that LIMIT is a parameter placeholder rather than a literal
|
|
54
|
+
* (see hasParameterizedLimit).
|
|
55
|
+
*/
|
|
56
|
+
static extractLimitValue(sql, dialect) {
|
|
57
|
+
return this.findTopLevelLimit(sql, dialect)?.value ?? null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Extract the statement's own TOP value (SQL Server), or null when it has none.
|
|
61
|
+
*/
|
|
62
|
+
static extractTopValue(sql) {
|
|
63
|
+
return this.findTopLevelTop(sql)?.value ?? null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Check if the statement's own LIMIT clause uses a parameter placeholder
|
|
67
|
+
* ($1, ?, @p1) instead of a literal number.
|
|
68
|
+
*/
|
|
69
|
+
static hasParameterizedLimit(sql, dialect) {
|
|
70
|
+
const limit = this.findTopLevelLimit(sql, dialect);
|
|
71
|
+
return limit !== null && limit.value === null;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Add or tighten the LIMIT clause of a SQL statement
|
|
75
|
+
*/
|
|
76
|
+
static applyLimitToQuery(sql, maxRows, dialect) {
|
|
77
|
+
const limit = this.findTopLevelLimit(sql, dialect);
|
|
78
|
+
if (limit !== null && limit.value !== null) {
|
|
79
|
+
const effectiveLimit = Math.min(limit.value, maxRows);
|
|
80
|
+
return `${sql.slice(0, limit.index)}LIMIT ${effectiveLimit}${sql.slice(limit.index + limit.length)}`;
|
|
81
|
+
}
|
|
82
|
+
const { sql: sqlWithoutSemicolon, semicolon } = trimSemicolon(sql);
|
|
83
|
+
return `${sqlWithoutSemicolon}
|
|
84
|
+
LIMIT ${maxRows}${semicolon}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Scan blanked (comment/string-free, length-preserving) SQL for parenthesis
|
|
88
|
+
* depth, invoking onMatch for every regex hit at depth 0 (i.e. not nested
|
|
89
|
+
* inside a subquery, function call, or window OVER clause).
|
|
90
|
+
*/
|
|
91
|
+
static scanTopLevel(blankedSQL, regex, onMatch) {
|
|
92
|
+
let depth = 0;
|
|
93
|
+
let m;
|
|
94
|
+
while ((m = regex.exec(blankedSQL)) !== null) {
|
|
95
|
+
const token = m[0];
|
|
96
|
+
if (token === "(") {
|
|
97
|
+
depth++;
|
|
98
|
+
} else if (token === ")") {
|
|
99
|
+
depth--;
|
|
100
|
+
} else if (depth === 0) {
|
|
101
|
+
onMatch(m);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The first or last regex match at parenthesis depth 0, i.e. one belonging
|
|
107
|
+
* to the statement itself rather than to a nested query. Match indices refer
|
|
108
|
+
* to positions in the original `sql`, since blankCommentsAndStrings
|
|
109
|
+
* preserves length. The regex must offer `\(` and `\)` alternatives so depth
|
|
110
|
+
* can be tracked, and must carry the `g` flag.
|
|
111
|
+
*/
|
|
112
|
+
static findTopLevelMatch(sql, regex, pick, dialect) {
|
|
113
|
+
let found = null;
|
|
114
|
+
this.scanTopLevel(blankCommentsAndStrings(sql, dialect), regex, (m) => {
|
|
115
|
+
if (pick === "last" || found === null) {
|
|
116
|
+
found = m;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return found;
|
|
120
|
+
}
|
|
121
|
+
/** The statement's own LIMIT clause, literal or parameterized ($1, ?, @p1). */
|
|
122
|
+
static findTopLevelLimit(sql, dialect) {
|
|
123
|
+
const match = this.findTopLevelMatch(
|
|
124
|
+
sql,
|
|
125
|
+
/\(|\)|\blimit\s+(?:(\d+)|\$\d+|\?|@p\d+)/gi,
|
|
126
|
+
"last",
|
|
127
|
+
dialect
|
|
128
|
+
);
|
|
129
|
+
if (match === null) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
index: match.index,
|
|
134
|
+
length: match[0].length,
|
|
135
|
+
value: match[1] !== void 0 ? parseInt(match[1], 10) : null
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/** The statement's own `SELECT TOP n` clause (SQL Server). */
|
|
139
|
+
static findTopLevelTop(sql) {
|
|
140
|
+
const match = this.findTopLevelMatch(sql, /\(|\)|\bselect\s+top\s+(\d+)/gi, "first", "sqlserver");
|
|
141
|
+
if (match === null) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
return { index: match.index, length: match[0].length, value: parseInt(match[1], 10) };
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The statement's own SELECT keyword (SQL Server). For a CTE this is the
|
|
148
|
+
* final SELECT, not the one inside a CTE body.
|
|
149
|
+
*/
|
|
150
|
+
static findTopLevelSelect(sql) {
|
|
151
|
+
return this.findTopLevelMatch(sql, /\(|\)|\bselect\b/gi, "first", "sqlserver");
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Check if a SQL statement combines multiple SELECTs with a set operator
|
|
155
|
+
* (UNION [ALL], INTERSECT, EXCEPT) at the top level — i.e. not nested
|
|
156
|
+
* inside a subquery already wrapped in parentheses.
|
|
157
|
+
*/
|
|
158
|
+
static hasSetOperator(sql) {
|
|
159
|
+
return this.findTopLevelMatch(sql, /\(|\)|\bunion\b|\bintersect\b|\bexcept\b/gi, "first", "sqlserver") !== null;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Find the start index of a top-level trailing ORDER BY clause (not one
|
|
163
|
+
* nested inside a subquery or a window function's OVER (...) clause).
|
|
164
|
+
* Returns -1 if none exists.
|
|
165
|
+
*/
|
|
166
|
+
static findTopLevelOrderByIndex(sql) {
|
|
167
|
+
return this.findTopLevelMatch(sql, /\(|\)|\border\s+by\b/gi, "last", "sqlserver")?.index ?? -1;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Add or modify TOP clause in a SQL statement (SQL Server)
|
|
171
|
+
*/
|
|
172
|
+
static applyTopToQuery(sql, maxRows) {
|
|
173
|
+
if (this.hasSetOperator(sql)) {
|
|
174
|
+
const { sql: sqlWithoutSemicolon, semicolon } = trimSemicolon(sql);
|
|
175
|
+
const cteIndex = this.findTopLevelSelect(sqlWithoutSemicolon)?.index ?? 0;
|
|
176
|
+
const ctePrefix = sqlWithoutSemicolon.slice(0, cteIndex);
|
|
177
|
+
const body = sqlWithoutSemicolon.slice(cteIndex);
|
|
178
|
+
const orderByIndex = this.findTopLevelOrderByIndex(body);
|
|
179
|
+
if (orderByIndex !== -1) {
|
|
180
|
+
const innerSql = body.slice(0, orderByIndex).trimEnd();
|
|
181
|
+
const orderByClause = body.slice(orderByIndex).trim();
|
|
182
|
+
return `${ctePrefix}SELECT TOP ${maxRows} * FROM (${innerSql}
|
|
183
|
+
) AS subq ${orderByClause}${semicolon}`;
|
|
184
|
+
}
|
|
185
|
+
return `${ctePrefix}SELECT TOP ${maxRows} * FROM (${body}
|
|
186
|
+
) AS subq${semicolon}`;
|
|
187
|
+
}
|
|
188
|
+
const existingTop = this.findTopLevelTop(sql);
|
|
189
|
+
if (existingTop !== null) {
|
|
190
|
+
const effectiveTop = Math.min(existingTop.value, maxRows);
|
|
191
|
+
return `${sql.slice(0, existingTop.index)}SELECT TOP ${effectiveTop}${sql.slice(existingTop.index + existingTop.length)}`;
|
|
192
|
+
}
|
|
193
|
+
const selectMatch = this.findTopLevelSelect(sql);
|
|
194
|
+
if (selectMatch === null) {
|
|
195
|
+
return sql;
|
|
196
|
+
}
|
|
197
|
+
return `${sql.slice(0, selectMatch.index)}SELECT TOP ${maxRows}${sql.slice(selectMatch.index + selectMatch[0].length)}`;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Apply maxRows limit to a row-returning query only
|
|
201
|
+
*
|
|
202
|
+
* This method is used by PostgreSQL, MySQL, MariaDB, and SQLite connectors which all support
|
|
203
|
+
* the LIMIT clause syntax. SQL Server uses applyMaxRowsForSQLServer() instead with TOP syntax.
|
|
204
|
+
*
|
|
205
|
+
* For parameterized LIMIT clauses (e.g., LIMIT $1 or LIMIT ?), we wrap the query in a subquery
|
|
206
|
+
* to enforce max_rows as a hard cap, since the parameter value is not known until runtime.
|
|
207
|
+
*
|
|
208
|
+
* `dialect` selects the connector's comment/string scanner (see isSelectQuery).
|
|
209
|
+
*/
|
|
210
|
+
static applyMaxRows(sql, maxRows, dialect) {
|
|
211
|
+
if (!maxRows || !this.isSelectQuery(sql, dialect)) {
|
|
212
|
+
return sql;
|
|
213
|
+
}
|
|
214
|
+
if (this.hasParameterizedLimit(sql, dialect)) {
|
|
215
|
+
const { sql: sqlWithoutSemicolon, semicolon } = trimSemicolon(sql);
|
|
216
|
+
return `SELECT * FROM (${sqlWithoutSemicolon}
|
|
217
|
+
) AS subq LIMIT ${maxRows}${semicolon}`;
|
|
218
|
+
}
|
|
219
|
+
return this.applyLimitToQuery(sql, maxRows, dialect);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Apply maxRows limit to a row-returning query using SQL Server TOP syntax
|
|
223
|
+
*/
|
|
224
|
+
static applyMaxRowsForSQLServer(sql, maxRows) {
|
|
225
|
+
if (!maxRows || !this.isSelectQuery(sql, "sqlserver")) {
|
|
226
|
+
return sql;
|
|
227
|
+
}
|
|
228
|
+
return this.applyTopToQuery(sql, maxRows);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Apply maxRows to a row-returning query using Oracle's row-limiting clause.
|
|
232
|
+
*
|
|
233
|
+
* The statement is always wrapped in an inline view and capped from the
|
|
234
|
+
* outside: `SELECT * FROM (<sql>) FETCH FIRST n ROWS ONLY`. Wrapping rather
|
|
235
|
+
* than splicing keeps every shape correct with one rule - a set operation
|
|
236
|
+
* (UNION & co.) is capped as a whole, a trailing ORDER BY stays inside the
|
|
237
|
+
* view where Oracle honours it, and a query that already has its own
|
|
238
|
+
* `FETCH FIRST` / `ROWNUM` cap simply returns the smaller of the two. Oracle
|
|
239
|
+
* also accepts a leading CTE (subquery factoring) inside an inline view, so
|
|
240
|
+
* `WITH ... SELECT` needs no special casing.
|
|
241
|
+
*/
|
|
242
|
+
static applyMaxRowsForOracle(sql, maxRows) {
|
|
243
|
+
if (!maxRows || !this.isSelectQuery(sql, "oracle") || this.hasOracleForUpdate(sql)) {
|
|
244
|
+
return sql;
|
|
245
|
+
}
|
|
246
|
+
const { sql: sqlWithoutSemicolon } = trimSemicolon(sql);
|
|
247
|
+
return `SELECT * FROM (${sqlWithoutSemicolon}
|
|
248
|
+
) FETCH FIRST ${maxRows} ROWS ONLY`;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* A statement-level `FOR UPDATE` (locking read). Oracle allows neither
|
|
252
|
+
* `FOR UPDATE` inside an inline view nor a row-limiting clause alongside
|
|
253
|
+
* it, so such a statement cannot be capped and is left as written.
|
|
254
|
+
*/
|
|
255
|
+
static hasOracleForUpdate(sql) {
|
|
256
|
+
return this.findTopLevelMatch(sql, /\(|\)|\bfor\s+update\b/gi, "first", "oracle") !== null;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Oracle variant of applyMaxRowsWithTruncationProbe. Because the cap always
|
|
260
|
+
* wraps (see applyMaxRowsForOracle), the probe is applied to every
|
|
261
|
+
* row-returning statement; a query whose own cap is tighter than maxRows
|
|
262
|
+
* returns fewer than maxRows + 1 rows and is therefore never flagged.
|
|
263
|
+
* A `FOR UPDATE` statement is never capped (see hasOracleForUpdate).
|
|
264
|
+
*/
|
|
265
|
+
static applyMaxRowsForOracleWithTruncationProbe(sql, maxRows) {
|
|
266
|
+
if (!maxRows || !this.isSelectQuery(sql, "oracle") || this.hasOracleForUpdate(sql)) {
|
|
267
|
+
return { sql, probeApplied: false };
|
|
268
|
+
}
|
|
269
|
+
return { sql: this.applyMaxRowsForOracle(sql, maxRows + 1), probeApplied: true };
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Like applyMaxRows, but requests one probe row (maxRows + 1) whenever the
|
|
273
|
+
* cap is the binding constraint, so callers can detect truncation exactly
|
|
274
|
+
* instead of guessing from `rowCount === maxRows` (which a table with
|
|
275
|
+
* exactly maxRows rows also produces).
|
|
276
|
+
*
|
|
277
|
+
* `probeApplied` is false when the cap cannot fire: no maxRows, not a
|
|
278
|
+
* SELECT, or the query's own literal LIMIT is already within the cap (the
|
|
279
|
+
* user asked for fewer rows than the cap — that is their limit, not
|
|
280
|
+
* truncation).
|
|
281
|
+
*/
|
|
282
|
+
static applyMaxRowsWithTruncationProbe(sql, maxRows, dialect) {
|
|
283
|
+
if (!maxRows || !this.isSelectQuery(sql, dialect)) {
|
|
284
|
+
return { sql, probeApplied: false };
|
|
285
|
+
}
|
|
286
|
+
if (!this.hasParameterizedLimit(sql, dialect)) {
|
|
287
|
+
const existingLimit = this.extractLimitValue(sql, dialect);
|
|
288
|
+
if (existingLimit !== null && existingLimit <= maxRows) {
|
|
289
|
+
return { sql, probeApplied: false };
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return { sql: this.applyMaxRows(sql, maxRows + 1, dialect), probeApplied: true };
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* SQL Server variant of applyMaxRowsWithTruncationProbe, using TOP syntax.
|
|
296
|
+
* A set-operator statement is always wrapped (any TOP on an individual
|
|
297
|
+
* branch caps only that branch, not the combined output), so the probe
|
|
298
|
+
* applies there regardless of branch-level TOPs.
|
|
299
|
+
*/
|
|
300
|
+
static applyMaxRowsForSQLServerWithTruncationProbe(sql, maxRows) {
|
|
301
|
+
if (!maxRows || !this.isSelectQuery(sql, "sqlserver")) {
|
|
302
|
+
return { sql, probeApplied: false };
|
|
303
|
+
}
|
|
304
|
+
if (!this.hasSetOperator(sql)) {
|
|
305
|
+
const existingTop = this.extractTopValue(sql);
|
|
306
|
+
if (existingTop !== null && existingTop <= maxRows) {
|
|
307
|
+
return { sql, probeApplied: false };
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return { sql: this.applyMaxRowsForSQLServer(sql, maxRows + 1), probeApplied: true };
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Post-process a result set produced by a truncation-probe rewrite: when
|
|
314
|
+
* the probe row came back (more than maxRows rows), drop it, clamp the
|
|
315
|
+
* count to maxRows, and mark the set truncated so consumers can tell a
|
|
316
|
+
* capped result from a complete one.
|
|
317
|
+
*/
|
|
318
|
+
static flagTruncation(resultSet, maxRows, probeApplied) {
|
|
319
|
+
if (!probeApplied || !maxRows || resultSet.rows.length <= maxRows) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
resultSet.rows = resultSet.rows.slice(0, maxRows);
|
|
323
|
+
resultSet.rowCount = maxRows;
|
|
324
|
+
resultSet.truncated = true;
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
function trimSemicolon(sql) {
|
|
328
|
+
const trimmed = sql.trim();
|
|
329
|
+
return trimmed.endsWith(";") ? { sql: trimmed.slice(0, -1), semicolon: ";" } : { sql: trimmed, semicolon: "" };
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/utils/resource-cleanup.ts
|
|
333
|
+
async function closeQuietly(close) {
|
|
334
|
+
try {
|
|
335
|
+
await close();
|
|
336
|
+
} catch {
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export {
|
|
341
|
+
SQLRowLimiter,
|
|
342
|
+
closeQuietly
|
|
343
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -18,20 +18,20 @@ import {
|
|
|
18
18
|
resolveSourceConfigs,
|
|
19
19
|
resolveTomlConfigPath,
|
|
20
20
|
resolveTransport
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-77BJNE6E.js";
|
|
22
|
+
import {
|
|
23
|
+
loadConnectors
|
|
24
|
+
} from "./chunk-WVVMH6FJ.js";
|
|
25
|
+
import {
|
|
26
|
+
quoteQualifiedIdentifier
|
|
27
|
+
} from "./chunk-X2EC47W4.js";
|
|
22
28
|
import {
|
|
23
29
|
allowedKeywords,
|
|
24
30
|
getFirstKeyword,
|
|
25
31
|
hasEscapeHatchFunction,
|
|
26
32
|
isReadOnlySQL,
|
|
27
33
|
sqlServerDynamicSqlPattern
|
|
28
|
-
} from "./chunk-
|
|
29
|
-
import {
|
|
30
|
-
loadConnectors
|
|
31
|
-
} from "./chunk-WVVMH6FJ.js";
|
|
32
|
-
import {
|
|
33
|
-
quoteQualifiedIdentifier
|
|
34
|
-
} from "./chunk-JFWX35TB.js";
|
|
34
|
+
} from "./chunk-ABTVMHD6.js";
|
|
35
35
|
import {
|
|
36
36
|
ConnectorRegistry,
|
|
37
37
|
getDatabaseTypeFromDSN,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
parseConnectionInfoFromDSN,
|
|
40
40
|
splitSQLStatements,
|
|
41
41
|
stripCommentsAndStrings
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-IXC4NQGC.js";
|
|
43
43
|
|
|
44
44
|
// src/server.ts
|
|
45
45
|
import { McpServer, createMcpHandler } from "@modelcontextprotocol/server";
|
|
@@ -1913,7 +1913,7 @@ See documentation for more details on configuring database connections.
|
|
|
1913
1913
|
const sources = sourceConfigsData.sources;
|
|
1914
1914
|
console.error(`Configuration source: ${sourceConfigsData.source}`);
|
|
1915
1915
|
await connectorManager.connectWithSources(sources);
|
|
1916
|
-
const { initializeToolRegistry: initializeToolRegistry2 } = await import("./registry-
|
|
1916
|
+
const { initializeToolRegistry: initializeToolRegistry2 } = await import("./registry-P4IGJ56H.js");
|
|
1917
1917
|
initializeToolRegistry2({
|
|
1918
1918
|
sources: sourceConfigsData.sources,
|
|
1919
1919
|
tools: sourceConfigsData.tools
|
|
@@ -2068,11 +2068,12 @@ See documentation for more details on configuring database connections.
|
|
|
2068
2068
|
|
|
2069
2069
|
// src/index.ts
|
|
2070
2070
|
var connectorModules = [
|
|
2071
|
-
{ load: () => import("./postgres-
|
|
2072
|
-
{ load: () => import("./sqlserver-
|
|
2073
|
-
{ load: () => import("./sqlite-
|
|
2074
|
-
{ load: () => import("./mysql-
|
|
2075
|
-
{ load: () => import("./mariadb-
|
|
2071
|
+
{ load: () => import("./postgres-6XJ7V4J4.js"), name: "PostgreSQL", driver: "pg" },
|
|
2072
|
+
{ load: () => import("./sqlserver-AJUK6L55.js"), name: "SQL Server", driver: "mssql" },
|
|
2073
|
+
{ load: () => import("./sqlite-AO2BKIC6.js"), name: "SQLite", driver: "node:sqlite" },
|
|
2074
|
+
{ load: () => import("./mysql-XXIHWQGR.js"), name: "MySQL", driver: "mysql2" },
|
|
2075
|
+
{ load: () => import("./mariadb-L7Z55ROY.js"), name: "MariaDB", driver: "mariadb" },
|
|
2076
|
+
{ load: () => import("./oracle-OUKBU52X.js"), name: "Oracle", driver: "oracledb" }
|
|
2076
2077
|
];
|
|
2077
2078
|
loadConnectors(connectorModules).then(() => main()).catch((error) => {
|
|
2078
2079
|
console.error("Fatal error:", error);
|
|
@@ -5,21 +5,22 @@ import {
|
|
|
5
5
|
parseQueryResultSets,
|
|
6
6
|
requireDatabaseInDSN,
|
|
7
7
|
withReadOnlyTransaction
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6SZKW6GD.js";
|
|
9
9
|
import "./chunk-FU2ZJE4E.js";
|
|
10
10
|
import {
|
|
11
11
|
quoteIdentifier
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-X2EC47W4.js";
|
|
13
13
|
import {
|
|
14
14
|
SQLRowLimiter,
|
|
15
15
|
closeQuietly
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YIGJHEU6.js";
|
|
17
|
+
import "./chunk-ABTVMHD6.js";
|
|
17
18
|
import {
|
|
18
19
|
ConnectorRegistry,
|
|
19
20
|
SafeURL,
|
|
20
21
|
obfuscateDSNPassword,
|
|
21
22
|
splitSQLStatements
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-IXC4NQGC.js";
|
|
23
24
|
|
|
24
25
|
// src/connectors/mariadb/index.ts
|
|
25
26
|
import * as mariadb from "mariadb";
|
|
@@ -515,7 +516,7 @@ var MariaDBConnector = class _MariaDBConnector {
|
|
|
515
516
|
let probes = [];
|
|
516
517
|
if (options.maxRows) {
|
|
517
518
|
const rewrites = statements.map(
|
|
518
|
-
(statement) => SQLRowLimiter.applyMaxRowsWithTruncationProbe(statement, options.maxRows)
|
|
519
|
+
(statement) => SQLRowLimiter.applyMaxRowsWithTruncationProbe(statement, options.maxRows, "mariadb")
|
|
519
520
|
);
|
|
520
521
|
probes = rewrites.map((rewrite) => rewrite.probeApplied);
|
|
521
522
|
processedSQL = rewrites.map((rewrite) => rewrite.sql).join("; ");
|
|
@@ -6,21 +6,22 @@ import {
|
|
|
6
6
|
parseQueryResultSets,
|
|
7
7
|
requireDatabaseInDSN,
|
|
8
8
|
withReadOnlyTransaction
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6SZKW6GD.js";
|
|
10
10
|
import "./chunk-FU2ZJE4E.js";
|
|
11
11
|
import {
|
|
12
12
|
quoteIdentifier
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-X2EC47W4.js";
|
|
14
14
|
import {
|
|
15
15
|
SQLRowLimiter,
|
|
16
16
|
closeQuietly
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-YIGJHEU6.js";
|
|
18
|
+
import "./chunk-ABTVMHD6.js";
|
|
18
19
|
import {
|
|
19
20
|
ConnectorRegistry,
|
|
20
21
|
SafeURL,
|
|
21
22
|
obfuscateDSNPassword,
|
|
22
23
|
splitSQLStatements
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-IXC4NQGC.js";
|
|
24
25
|
|
|
25
26
|
// src/connectors/mysql/index.ts
|
|
26
27
|
import mysql from "mysql2/promise";
|
|
@@ -520,7 +521,7 @@ var _MySQLConnector = class _MySQLConnector {
|
|
|
520
521
|
let probes = [];
|
|
521
522
|
if (options.maxRows) {
|
|
522
523
|
const rewrites = statements.map(
|
|
523
|
-
(statement) => SQLRowLimiter.applyMaxRowsWithTruncationProbe(statement, options.maxRows)
|
|
524
|
+
(statement) => SQLRowLimiter.applyMaxRowsWithTruncationProbe(statement, options.maxRows, "mysql")
|
|
524
525
|
);
|
|
525
526
|
probes = rewrites.map((rewrite) => rewrite.probeApplied);
|
|
526
527
|
processedSQL = rewrites.map((rewrite) => rewrite.sql).join("; ");
|