@bytebase/dbhub 0.20.0 → 0.21.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/dist/{chunk-25VMLRAQ.js → chunk-GRGEI5QT.js} +1 -1
- package/dist/chunk-RTB262PR.js +60 -0
- package/dist/{demo-loader-FM5OJVDA.js → demo-loader-PSMTLZ2T.js} +0 -2
- package/dist/index.js +7 -8
- package/dist/mariadb-VGTS4WXE.js +462 -0
- package/dist/mysql-I35IQ2GH.js +469 -0
- package/dist/postgres-B7YSSZMH.js +480 -0
- package/dist/{registry-FOASCI6Y.js → registry-XSMMLRC4.js} +1 -2
- package/dist/sqlite-FSCLCRIH.js +320 -0
- package/dist/sqlserver-FDBRUELV.js +479 -0
- package/package.json +1 -1
- package/dist/chunk-B6JS6INF.js +0 -3644
- package/dist/chunk-OKXJNFBS.js +0 -380
- package/dist/chunk-WWAWV7DQ.js +0 -72
- package/dist/mariadb-L3YMONWJ.js +0 -17727
- package/dist/mysql-FOCVUTPX.js +0 -15872
- package/dist/postgres-JB3LPXGR.js +0 -5559
- package/dist/sqlite-5LT56F5B.js +0 -1099
- package/dist/sqlserver-LGFLHJHL.js +0 -38500
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SQLRowLimiter
|
|
3
|
+
} from "./chunk-BRXZ5ZQB.js";
|
|
4
|
+
import {
|
|
5
|
+
ConnectorRegistry,
|
|
6
|
+
SafeURL,
|
|
7
|
+
obfuscateDSNPassword
|
|
8
|
+
} from "./chunk-C7WEAPX4.js";
|
|
9
|
+
|
|
10
|
+
// src/connectors/sqlserver/index.ts
|
|
11
|
+
import sql from "mssql";
|
|
12
|
+
import { DefaultAzureCredential } from "@azure/identity";
|
|
13
|
+
var SQLServerDSNParser = class {
|
|
14
|
+
async parse(dsn, config) {
|
|
15
|
+
const connectionTimeoutSeconds = config?.connectionTimeoutSeconds;
|
|
16
|
+
const queryTimeoutSeconds = config?.queryTimeoutSeconds;
|
|
17
|
+
if (!this.isValidDSN(dsn)) {
|
|
18
|
+
const obfuscatedDSN = obfuscateDSNPassword(dsn);
|
|
19
|
+
const expectedFormat = this.getSampleDSN();
|
|
20
|
+
throw new Error(
|
|
21
|
+
`Invalid SQL Server DSN format.
|
|
22
|
+
Provided: ${obfuscatedDSN}
|
|
23
|
+
Expected: ${expectedFormat}`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const url = new SafeURL(dsn);
|
|
28
|
+
const options = {};
|
|
29
|
+
url.forEachSearchParam((value, key) => {
|
|
30
|
+
if (key === "authentication") {
|
|
31
|
+
options.authentication = value;
|
|
32
|
+
} else if (key === "sslmode") {
|
|
33
|
+
options.sslmode = value;
|
|
34
|
+
} else if (key === "instanceName") {
|
|
35
|
+
options.instanceName = value;
|
|
36
|
+
} else if (key === "domain") {
|
|
37
|
+
options.domain = value;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
if (options.authentication === "ntlm" && !options.domain) {
|
|
41
|
+
throw new Error("NTLM authentication requires 'domain' parameter");
|
|
42
|
+
}
|
|
43
|
+
if (options.domain && options.authentication !== "ntlm") {
|
|
44
|
+
throw new Error("Parameter 'domain' requires 'authentication=ntlm'");
|
|
45
|
+
}
|
|
46
|
+
if (options.sslmode) {
|
|
47
|
+
if (options.sslmode === "disable") {
|
|
48
|
+
options.encrypt = false;
|
|
49
|
+
options.trustServerCertificate = false;
|
|
50
|
+
} else if (options.sslmode === "require") {
|
|
51
|
+
options.encrypt = true;
|
|
52
|
+
options.trustServerCertificate = true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const config2 = {
|
|
56
|
+
server: url.hostname,
|
|
57
|
+
port: url.port ? parseInt(url.port) : 1433,
|
|
58
|
+
// Default SQL Server port
|
|
59
|
+
database: url.pathname ? url.pathname.substring(1) : "",
|
|
60
|
+
// Remove leading slash
|
|
61
|
+
options: {
|
|
62
|
+
encrypt: options.encrypt ?? false,
|
|
63
|
+
// Default to unencrypted for development
|
|
64
|
+
trustServerCertificate: options.trustServerCertificate ?? false,
|
|
65
|
+
...connectionTimeoutSeconds !== void 0 && {
|
|
66
|
+
connectTimeout: connectionTimeoutSeconds * 1e3
|
|
67
|
+
},
|
|
68
|
+
...queryTimeoutSeconds !== void 0 && {
|
|
69
|
+
requestTimeout: queryTimeoutSeconds * 1e3
|
|
70
|
+
},
|
|
71
|
+
instanceName: options.instanceName
|
|
72
|
+
// Add named instance support
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
switch (options.authentication) {
|
|
76
|
+
case "azure-active-directory-access-token": {
|
|
77
|
+
try {
|
|
78
|
+
const credential = new DefaultAzureCredential();
|
|
79
|
+
const token = await credential.getToken("https://database.windows.net/");
|
|
80
|
+
config2.authentication = {
|
|
81
|
+
type: "azure-active-directory-access-token",
|
|
82
|
+
options: {
|
|
83
|
+
token: token.token
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
} catch (error) {
|
|
87
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
88
|
+
throw new Error(`Failed to get Azure AD token: ${errorMessage}`);
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case "ntlm":
|
|
93
|
+
config2.authentication = {
|
|
94
|
+
type: "ntlm",
|
|
95
|
+
options: {
|
|
96
|
+
domain: options.domain,
|
|
97
|
+
userName: url.username,
|
|
98
|
+
password: url.password
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
break;
|
|
102
|
+
default:
|
|
103
|
+
config2.user = url.username;
|
|
104
|
+
config2.password = url.password;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
return config2;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Failed to parse SQL Server DSN: ${error instanceof Error ? error.message : String(error)}`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
getSampleDSN() {
|
|
115
|
+
return "sqlserver://username:password@localhost:1433/database?sslmode=disable&instanceName=INSTANCE1";
|
|
116
|
+
}
|
|
117
|
+
isValidDSN(dsn) {
|
|
118
|
+
try {
|
|
119
|
+
return dsn.startsWith("sqlserver://");
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
var SQLServerConnector = class _SQLServerConnector {
|
|
126
|
+
constructor() {
|
|
127
|
+
this.id = "sqlserver";
|
|
128
|
+
this.name = "SQL Server";
|
|
129
|
+
this.dsnParser = new SQLServerDSNParser();
|
|
130
|
+
// Source ID is set by ConnectorManager after cloning
|
|
131
|
+
this.sourceId = "default";
|
|
132
|
+
}
|
|
133
|
+
getId() {
|
|
134
|
+
return this.sourceId;
|
|
135
|
+
}
|
|
136
|
+
clone() {
|
|
137
|
+
return new _SQLServerConnector();
|
|
138
|
+
}
|
|
139
|
+
async connect(dsn, initScript, config) {
|
|
140
|
+
try {
|
|
141
|
+
this.config = await this.dsnParser.parse(dsn, config);
|
|
142
|
+
if (!this.config.options) {
|
|
143
|
+
this.config.options = {};
|
|
144
|
+
}
|
|
145
|
+
this.connection = await new sql.ConnectionPool(this.config).connect();
|
|
146
|
+
} catch (error) {
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async disconnect() {
|
|
151
|
+
if (this.connection) {
|
|
152
|
+
await this.connection.close();
|
|
153
|
+
this.connection = void 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async getSchemas() {
|
|
157
|
+
if (!this.connection) {
|
|
158
|
+
throw new Error("Not connected to SQL Server database");
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const result = await this.connection.request().query(`
|
|
162
|
+
SELECT SCHEMA_NAME
|
|
163
|
+
FROM INFORMATION_SCHEMA.SCHEMATA
|
|
164
|
+
ORDER BY SCHEMA_NAME
|
|
165
|
+
`);
|
|
166
|
+
return result.recordset.map((row) => row.SCHEMA_NAME);
|
|
167
|
+
} catch (error) {
|
|
168
|
+
throw new Error(`Failed to get schemas: ${error.message}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async getTables(schema) {
|
|
172
|
+
if (!this.connection) {
|
|
173
|
+
throw new Error("Not connected to SQL Server database");
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const schemaToUse = schema || "dbo";
|
|
177
|
+
const request = this.connection.request().input("schema", sql.VarChar, schemaToUse);
|
|
178
|
+
const query = `
|
|
179
|
+
SELECT TABLE_NAME
|
|
180
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
181
|
+
WHERE TABLE_SCHEMA = @schema
|
|
182
|
+
ORDER BY TABLE_NAME
|
|
183
|
+
`;
|
|
184
|
+
const result = await request.query(query);
|
|
185
|
+
return result.recordset.map((row) => row.TABLE_NAME);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
throw new Error(`Failed to get tables: ${error.message}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async tableExists(tableName, schema) {
|
|
191
|
+
if (!this.connection) {
|
|
192
|
+
throw new Error("Not connected to SQL Server database");
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const schemaToUse = schema || "dbo";
|
|
196
|
+
const request = this.connection.request().input("tableName", sql.VarChar, tableName).input("schema", sql.VarChar, schemaToUse);
|
|
197
|
+
const query = `
|
|
198
|
+
SELECT COUNT(*) as count
|
|
199
|
+
FROM INFORMATION_SCHEMA.TABLES
|
|
200
|
+
WHERE TABLE_NAME = @tableName
|
|
201
|
+
AND TABLE_SCHEMA = @schema
|
|
202
|
+
`;
|
|
203
|
+
const result = await request.query(query);
|
|
204
|
+
return result.recordset[0].count > 0;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
throw new Error(`Failed to check if table exists: ${error.message}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async getTableIndexes(tableName, schema) {
|
|
210
|
+
if (!this.connection) {
|
|
211
|
+
throw new Error("Not connected to SQL Server database");
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const schemaToUse = schema || "dbo";
|
|
215
|
+
const request = this.connection.request().input("tableName", sql.VarChar, tableName).input("schema", sql.VarChar, schemaToUse);
|
|
216
|
+
const query = `
|
|
217
|
+
SELECT i.name AS index_name,
|
|
218
|
+
i.is_unique,
|
|
219
|
+
i.is_primary_key,
|
|
220
|
+
c.name AS column_name,
|
|
221
|
+
ic.key_ordinal
|
|
222
|
+
FROM sys.indexes i
|
|
223
|
+
INNER JOIN
|
|
224
|
+
sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
|
225
|
+
INNER JOIN
|
|
226
|
+
sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
|
|
227
|
+
INNER JOIN
|
|
228
|
+
sys.tables t ON i.object_id = t.object_id
|
|
229
|
+
INNER JOIN
|
|
230
|
+
sys.schemas s ON t.schema_id = s.schema_id
|
|
231
|
+
WHERE t.name = @tableName
|
|
232
|
+
AND s.name = @schema
|
|
233
|
+
ORDER BY i.name,
|
|
234
|
+
ic.key_ordinal
|
|
235
|
+
`;
|
|
236
|
+
const result = await request.query(query);
|
|
237
|
+
const indexMap = /* @__PURE__ */ new Map();
|
|
238
|
+
for (const row of result.recordset) {
|
|
239
|
+
const indexName = row.index_name;
|
|
240
|
+
const columnName = row.column_name;
|
|
241
|
+
const isUnique = !!row.is_unique;
|
|
242
|
+
const isPrimary = !!row.is_primary_key;
|
|
243
|
+
if (!indexMap.has(indexName)) {
|
|
244
|
+
indexMap.set(indexName, {
|
|
245
|
+
columns: [],
|
|
246
|
+
is_unique: isUnique,
|
|
247
|
+
is_primary: isPrimary
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
const indexInfo = indexMap.get(indexName);
|
|
251
|
+
indexInfo.columns.push(columnName);
|
|
252
|
+
}
|
|
253
|
+
const indexes = [];
|
|
254
|
+
indexMap.forEach((info, name) => {
|
|
255
|
+
indexes.push({
|
|
256
|
+
index_name: name,
|
|
257
|
+
column_names: info.columns,
|
|
258
|
+
is_unique: info.is_unique,
|
|
259
|
+
is_primary: info.is_primary
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
return indexes;
|
|
263
|
+
} catch (error) {
|
|
264
|
+
throw new Error(`Failed to get indexes for table ${tableName}: ${error.message}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async getTableSchema(tableName, schema) {
|
|
268
|
+
if (!this.connection) {
|
|
269
|
+
throw new Error("Not connected to SQL Server database");
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const schemaToUse = schema || "dbo";
|
|
273
|
+
const request = this.connection.request().input("tableName", sql.VarChar, tableName).input("schema", sql.VarChar, schemaToUse);
|
|
274
|
+
const query = `
|
|
275
|
+
SELECT c.COLUMN_NAME as column_name,
|
|
276
|
+
c.DATA_TYPE as data_type,
|
|
277
|
+
c.IS_NULLABLE as is_nullable,
|
|
278
|
+
c.COLUMN_DEFAULT as column_default,
|
|
279
|
+
ep.value as description
|
|
280
|
+
FROM INFORMATION_SCHEMA.COLUMNS c
|
|
281
|
+
LEFT JOIN sys.columns sc
|
|
282
|
+
ON sc.name = c.COLUMN_NAME
|
|
283
|
+
AND sc.object_id = OBJECT_ID(QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME))
|
|
284
|
+
LEFT JOIN sys.extended_properties ep
|
|
285
|
+
ON ep.major_id = sc.object_id
|
|
286
|
+
AND ep.minor_id = sc.column_id
|
|
287
|
+
AND ep.name = 'MS_Description'
|
|
288
|
+
WHERE c.TABLE_NAME = @tableName
|
|
289
|
+
AND c.TABLE_SCHEMA = @schema
|
|
290
|
+
ORDER BY c.ORDINAL_POSITION
|
|
291
|
+
`;
|
|
292
|
+
const result = await request.query(query);
|
|
293
|
+
return result.recordset.map((row) => ({
|
|
294
|
+
...row,
|
|
295
|
+
description: row.description || null
|
|
296
|
+
}));
|
|
297
|
+
} catch (error) {
|
|
298
|
+
throw new Error(`Failed to get schema for table ${tableName}: ${error.message}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
async getTableComment(tableName, schema) {
|
|
302
|
+
if (!this.connection) {
|
|
303
|
+
throw new Error("Not connected to SQL Server database");
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const schemaToUse = schema || "dbo";
|
|
307
|
+
const request = this.connection.request().input("tableName", sql.VarChar, tableName).input("schema", sql.VarChar, schemaToUse);
|
|
308
|
+
const query = `
|
|
309
|
+
SELECT ep.value as table_comment
|
|
310
|
+
FROM sys.extended_properties ep
|
|
311
|
+
JOIN sys.tables t ON ep.major_id = t.object_id
|
|
312
|
+
JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
313
|
+
WHERE ep.minor_id = 0
|
|
314
|
+
AND ep.name = 'MS_Description'
|
|
315
|
+
AND t.name = @tableName
|
|
316
|
+
AND s.name = @schema
|
|
317
|
+
`;
|
|
318
|
+
const result = await request.query(query);
|
|
319
|
+
if (result.recordset.length > 0) {
|
|
320
|
+
return result.recordset[0].table_comment || null;
|
|
321
|
+
}
|
|
322
|
+
return null;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
async getStoredProcedures(schema, routineType) {
|
|
328
|
+
if (!this.connection) {
|
|
329
|
+
throw new Error("Not connected to SQL Server database");
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
const schemaToUse = schema || "dbo";
|
|
333
|
+
const request = this.connection.request().input("schema", sql.VarChar, schemaToUse);
|
|
334
|
+
let typeFilter;
|
|
335
|
+
if (routineType === "function") {
|
|
336
|
+
typeFilter = "AND ROUTINE_TYPE = 'FUNCTION'";
|
|
337
|
+
} else if (routineType === "procedure") {
|
|
338
|
+
typeFilter = "AND ROUTINE_TYPE = 'PROCEDURE'";
|
|
339
|
+
} else {
|
|
340
|
+
typeFilter = "AND (ROUTINE_TYPE = 'PROCEDURE' OR ROUTINE_TYPE = 'FUNCTION')";
|
|
341
|
+
}
|
|
342
|
+
const query = `
|
|
343
|
+
SELECT ROUTINE_NAME
|
|
344
|
+
FROM INFORMATION_SCHEMA.ROUTINES
|
|
345
|
+
WHERE ROUTINE_SCHEMA = @schema
|
|
346
|
+
${typeFilter}
|
|
347
|
+
ORDER BY ROUTINE_NAME
|
|
348
|
+
`;
|
|
349
|
+
const result = await request.query(query);
|
|
350
|
+
return result.recordset.map((row) => row.ROUTINE_NAME);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
throw new Error(`Failed to get stored procedures: ${error.message}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
async getStoredProcedureDetail(procedureName, schema) {
|
|
356
|
+
if (!this.connection) {
|
|
357
|
+
throw new Error("Not connected to SQL Server database");
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
const schemaToUse = schema || "dbo";
|
|
361
|
+
const request = this.connection.request().input("procedureName", sql.VarChar, procedureName).input("schema", sql.VarChar, schemaToUse);
|
|
362
|
+
const routineQuery = `
|
|
363
|
+
SELECT ROUTINE_NAME as procedure_name,
|
|
364
|
+
ROUTINE_TYPE,
|
|
365
|
+
DATA_TYPE as return_data_type
|
|
366
|
+
FROM INFORMATION_SCHEMA.ROUTINES
|
|
367
|
+
WHERE ROUTINE_NAME = @procedureName
|
|
368
|
+
AND ROUTINE_SCHEMA = @schema
|
|
369
|
+
`;
|
|
370
|
+
const routineResult = await request.query(routineQuery);
|
|
371
|
+
if (routineResult.recordset.length === 0) {
|
|
372
|
+
throw new Error(`Stored procedure '${procedureName}' not found in schema '${schemaToUse}'`);
|
|
373
|
+
}
|
|
374
|
+
const routine = routineResult.recordset[0];
|
|
375
|
+
const parameterQuery = `
|
|
376
|
+
SELECT PARAMETER_NAME,
|
|
377
|
+
PARAMETER_MODE,
|
|
378
|
+
DATA_TYPE,
|
|
379
|
+
CHARACTER_MAXIMUM_LENGTH,
|
|
380
|
+
ORDINAL_POSITION
|
|
381
|
+
FROM INFORMATION_SCHEMA.PARAMETERS
|
|
382
|
+
WHERE SPECIFIC_NAME = @procedureName
|
|
383
|
+
AND SPECIFIC_SCHEMA = @schema
|
|
384
|
+
ORDER BY ORDINAL_POSITION
|
|
385
|
+
`;
|
|
386
|
+
const parameterResult = await request.query(parameterQuery);
|
|
387
|
+
let parameterList = "";
|
|
388
|
+
if (parameterResult.recordset.length > 0) {
|
|
389
|
+
parameterList = parameterResult.recordset.map(
|
|
390
|
+
(param) => {
|
|
391
|
+
const lengthStr = param.CHARACTER_MAXIMUM_LENGTH > 0 ? `(${param.CHARACTER_MAXIMUM_LENGTH})` : "";
|
|
392
|
+
return `${param.PARAMETER_NAME} ${param.PARAMETER_MODE} ${param.DATA_TYPE}${lengthStr}`;
|
|
393
|
+
}
|
|
394
|
+
).join(", ");
|
|
395
|
+
}
|
|
396
|
+
const definitionQuery = `
|
|
397
|
+
SELECT definition
|
|
398
|
+
FROM sys.sql_modules sm
|
|
399
|
+
JOIN sys.objects o ON sm.object_id = o.object_id
|
|
400
|
+
JOIN sys.schemas s ON o.schema_id = s.schema_id
|
|
401
|
+
WHERE o.name = @procedureName
|
|
402
|
+
AND s.name = @schema
|
|
403
|
+
`;
|
|
404
|
+
const definitionResult = await request.query(definitionQuery);
|
|
405
|
+
let definition = void 0;
|
|
406
|
+
if (definitionResult.recordset.length > 0) {
|
|
407
|
+
definition = definitionResult.recordset[0].definition;
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
procedure_name: routine.procedure_name,
|
|
411
|
+
procedure_type: routine.ROUTINE_TYPE === "PROCEDURE" ? "procedure" : "function",
|
|
412
|
+
language: "sql",
|
|
413
|
+
// SQL Server procedures are typically in T-SQL
|
|
414
|
+
parameter_list: parameterList,
|
|
415
|
+
return_type: routine.ROUTINE_TYPE === "FUNCTION" ? routine.return_data_type : void 0,
|
|
416
|
+
definition
|
|
417
|
+
};
|
|
418
|
+
} catch (error) {
|
|
419
|
+
throw new Error(`Failed to get stored procedure details: ${error.message}`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
async executeSQL(sqlQuery, options, parameters) {
|
|
423
|
+
if (!this.connection) {
|
|
424
|
+
throw new Error("Not connected to SQL Server database");
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
let processedSQL = sqlQuery;
|
|
428
|
+
if (options.maxRows) {
|
|
429
|
+
processedSQL = SQLRowLimiter.applyMaxRowsForSQLServer(sqlQuery, options.maxRows);
|
|
430
|
+
}
|
|
431
|
+
const request = this.connection.request();
|
|
432
|
+
if (parameters && parameters.length > 0) {
|
|
433
|
+
parameters.forEach((param, index) => {
|
|
434
|
+
const paramName = `p${index + 1}`;
|
|
435
|
+
if (typeof param === "string") {
|
|
436
|
+
request.input(paramName, sql.VarChar, param);
|
|
437
|
+
} else if (typeof param === "number") {
|
|
438
|
+
if (Number.isInteger(param)) {
|
|
439
|
+
request.input(paramName, sql.Int, param);
|
|
440
|
+
} else {
|
|
441
|
+
request.input(paramName, sql.Float, param);
|
|
442
|
+
}
|
|
443
|
+
} else if (typeof param === "boolean") {
|
|
444
|
+
request.input(paramName, sql.Bit, param);
|
|
445
|
+
} else if (param === null || param === void 0) {
|
|
446
|
+
request.input(paramName, sql.VarChar, param);
|
|
447
|
+
} else if (Array.isArray(param)) {
|
|
448
|
+
request.input(paramName, sql.VarChar, JSON.stringify(param));
|
|
449
|
+
} else {
|
|
450
|
+
request.input(paramName, sql.VarChar, JSON.stringify(param));
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
let result;
|
|
455
|
+
try {
|
|
456
|
+
result = await request.query(processedSQL);
|
|
457
|
+
} catch (error) {
|
|
458
|
+
if (parameters && parameters.length > 0) {
|
|
459
|
+
console.error(`[SQL Server executeSQL] ERROR: ${error.message}`);
|
|
460
|
+
console.error(`[SQL Server executeSQL] SQL: ${processedSQL}`);
|
|
461
|
+
console.error(`[SQL Server executeSQL] Parameters: ${JSON.stringify(parameters)}`);
|
|
462
|
+
}
|
|
463
|
+
throw error;
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
rows: result.recordset || [],
|
|
467
|
+
rowCount: result.rowsAffected[0] || 0
|
|
468
|
+
};
|
|
469
|
+
} catch (error) {
|
|
470
|
+
throw new Error(`Failed to execute query: ${error.message}`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
var sqlServerConnector = new SQLServerConnector();
|
|
475
|
+
ConnectorRegistry.register(sqlServerConnector);
|
|
476
|
+
export {
|
|
477
|
+
SQLServerConnector,
|
|
478
|
+
SQLServerDSNParser
|
|
479
|
+
};
|
package/package.json
CHANGED