@squadbase/vite-server 0.1.9-dev.08f5c5f → 0.1.9-dev.3841401
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/cli/index.js +586 -343
- package/dist/connectors/azure-sql.js +13 -2
- package/dist/connectors/clickup.js +1 -1
- package/dist/connectors/freshdesk.js +2 -2
- package/dist/connectors/freshsales.js +28 -28
- package/dist/connectors/freshservice.js +1 -1
- package/dist/connectors/github.js +1 -1
- package/dist/connectors/google-search-console-oauth.js +39 -8
- package/dist/connectors/jdbc.js +510 -98
- package/dist/connectors/monday.js +44 -4
- package/dist/connectors/oracle.js +13 -2
- package/dist/connectors/sqlserver.js +13 -2
- package/dist/connectors/supabase.js +1 -1
- package/dist/index.js +586 -343
- package/dist/main.js +586 -343
- package/dist/vite-plugin.js +586 -343
- package/package.json +1 -1
package/dist/connectors/jdbc.js
CHANGED
|
@@ -20254,6 +20254,230 @@ var ParameterDefinition = class {
|
|
|
20254
20254
|
}
|
|
20255
20255
|
};
|
|
20256
20256
|
|
|
20257
|
+
// ../connectors/src/connectors/sqlserver/utils.ts
|
|
20258
|
+
var SQLSERVER_PREFIX_RE = /^(?:jdbc:)?sqlserver:\/\//i;
|
|
20259
|
+
var TRUE_VALUES = /* @__PURE__ */ new Set(["true", "1", "yes"]);
|
|
20260
|
+
var FALSE_VALUES = /* @__PURE__ */ new Set(["false", "0", "no"]);
|
|
20261
|
+
function parseBoolean(value) {
|
|
20262
|
+
if (value == null) return void 0;
|
|
20263
|
+
const lower = value.toLowerCase();
|
|
20264
|
+
if (TRUE_VALUES.has(lower)) return true;
|
|
20265
|
+
if (FALSE_VALUES.has(lower)) return false;
|
|
20266
|
+
return void 0;
|
|
20267
|
+
}
|
|
20268
|
+
function parseSqlServerJdbcUrl(jdbcUrl, options = {}) {
|
|
20269
|
+
const trimmed = jdbcUrl.trim();
|
|
20270
|
+
if (!SQLSERVER_PREFIX_RE.test(trimmed)) {
|
|
20271
|
+
throw new Error(
|
|
20272
|
+
`Unsupported SQL Server URL "${redactSqlServerUrl(trimmed)}". Expected prefix: jdbc:sqlserver:// or sqlserver://.`
|
|
20273
|
+
);
|
|
20274
|
+
}
|
|
20275
|
+
const withoutPrefix = trimmed.replace(SQLSERVER_PREFIX_RE, "");
|
|
20276
|
+
const [hostAndPath, ...propertySegments] = withoutPrefix.split(";");
|
|
20277
|
+
const props = {};
|
|
20278
|
+
for (const segment of propertySegments) {
|
|
20279
|
+
if (!segment) continue;
|
|
20280
|
+
const eqIdx = segment.indexOf("=");
|
|
20281
|
+
if (eqIdx === -1) continue;
|
|
20282
|
+
const key = segment.slice(0, eqIdx).trim().toLowerCase();
|
|
20283
|
+
const value = segment.slice(eqIdx + 1).trim();
|
|
20284
|
+
if (key) props[key] = value;
|
|
20285
|
+
}
|
|
20286
|
+
const url = new URL(`mssql://${hostAndPath}`);
|
|
20287
|
+
for (const [key, value] of url.searchParams.entries()) {
|
|
20288
|
+
if (!(key.toLowerCase() in props)) {
|
|
20289
|
+
props[key.toLowerCase()] = value;
|
|
20290
|
+
}
|
|
20291
|
+
}
|
|
20292
|
+
const server = url.hostname;
|
|
20293
|
+
const port = url.port ? Number(url.port) : 1433;
|
|
20294
|
+
const pathname = url.pathname.replace(/^\//, "");
|
|
20295
|
+
const database = pathname || props["database"] || props["databasename"];
|
|
20296
|
+
const user = props["user"] || props["username"] || props["userid"] || options.username;
|
|
20297
|
+
const password = props["password"] || options.password;
|
|
20298
|
+
return {
|
|
20299
|
+
server,
|
|
20300
|
+
port,
|
|
20301
|
+
database,
|
|
20302
|
+
user,
|
|
20303
|
+
password,
|
|
20304
|
+
options: props
|
|
20305
|
+
};
|
|
20306
|
+
}
|
|
20307
|
+
function toMssqlConfig(parsed, defaults = {}) {
|
|
20308
|
+
const encrypt = parseBoolean(parsed.options["encrypt"]) ?? defaults.encrypt ?? false;
|
|
20309
|
+
const trustServerCertificate = parseBoolean(parsed.options["trustservercertificate"]) ?? !encrypt;
|
|
20310
|
+
return {
|
|
20311
|
+
server: parsed.server,
|
|
20312
|
+
port: parsed.port,
|
|
20313
|
+
database: parsed.database,
|
|
20314
|
+
user: parsed.user,
|
|
20315
|
+
password: parsed.password,
|
|
20316
|
+
connectionTimeout: 1e4,
|
|
20317
|
+
requestTimeout: 6e4,
|
|
20318
|
+
options: {
|
|
20319
|
+
encrypt,
|
|
20320
|
+
trustServerCertificate
|
|
20321
|
+
}
|
|
20322
|
+
};
|
|
20323
|
+
}
|
|
20324
|
+
function redactSqlServerUrl(jdbcUrl) {
|
|
20325
|
+
return jdbcUrl.replace(/(:\/\/)([^@/;]+)@/, "$1***@").replace(/(password\s*=\s*)([^;]+)/gi, "$1***");
|
|
20326
|
+
}
|
|
20327
|
+
|
|
20328
|
+
// ../connectors/src/lib/mssql-runner.ts
|
|
20329
|
+
async function importMssql() {
|
|
20330
|
+
const mod = await import("mssql");
|
|
20331
|
+
return mod.default ?? mod;
|
|
20332
|
+
}
|
|
20333
|
+
async function runMssqlQuery(parsed, sql, options = {}) {
|
|
20334
|
+
const sqlMod = await importMssql();
|
|
20335
|
+
const config = toMssqlConfig(parsed, {
|
|
20336
|
+
encrypt: options.forceEncrypt
|
|
20337
|
+
});
|
|
20338
|
+
const pool = new sqlMod.ConnectionPool(config);
|
|
20339
|
+
await pool.connect();
|
|
20340
|
+
try {
|
|
20341
|
+
const result = await pool.request().query(sql);
|
|
20342
|
+
const recordset = result.recordset ?? [];
|
|
20343
|
+
return { rows: recordset };
|
|
20344
|
+
} finally {
|
|
20345
|
+
await pool.close();
|
|
20346
|
+
}
|
|
20347
|
+
}
|
|
20348
|
+
async function checkMssqlConnection(url, credentials, options = {}) {
|
|
20349
|
+
let parsed;
|
|
20350
|
+
try {
|
|
20351
|
+
parsed = parseSqlServerJdbcUrl(url, credentials);
|
|
20352
|
+
} catch (err) {
|
|
20353
|
+
return {
|
|
20354
|
+
success: false,
|
|
20355
|
+
error: err instanceof Error ? err.message : String(err)
|
|
20356
|
+
};
|
|
20357
|
+
}
|
|
20358
|
+
try {
|
|
20359
|
+
await runMssqlQuery(parsed, "SELECT 1 AS one", options);
|
|
20360
|
+
return { success: true };
|
|
20361
|
+
} catch (err) {
|
|
20362
|
+
let msg = err instanceof Error ? err.message : String(err);
|
|
20363
|
+
msg = msg.replaceAll(url, redactSqlServerUrl(url));
|
|
20364
|
+
return { success: false, error: msg };
|
|
20365
|
+
}
|
|
20366
|
+
}
|
|
20367
|
+
|
|
20368
|
+
// ../connectors/src/connectors/oracle/utils.ts
|
|
20369
|
+
var JDBC_THIN_PREFIX_RE = /^jdbc:oracle:thin:/i;
|
|
20370
|
+
var JDBC_OCI_PREFIX_RE = /^jdbc:oracle:oci/i;
|
|
20371
|
+
var URL_PREFIX_RE = /^oracle:\/\//i;
|
|
20372
|
+
function parseOracleJdbcUrl(jdbcUrl, options = {}) {
|
|
20373
|
+
const trimmed = jdbcUrl.trim();
|
|
20374
|
+
if (JDBC_OCI_PREFIX_RE.test(trimmed)) {
|
|
20375
|
+
throw new Error(
|
|
20376
|
+
"Oracle OCI driver URLs are not supported. Use the thin driver form: jdbc:oracle:thin:@host:port/service"
|
|
20377
|
+
);
|
|
20378
|
+
}
|
|
20379
|
+
if (URL_PREFIX_RE.test(trimmed)) {
|
|
20380
|
+
const url = new URL(trimmed);
|
|
20381
|
+
const path2 = url.pathname.replace(/^\//, "");
|
|
20382
|
+
if (!url.hostname || !path2) {
|
|
20383
|
+
throw new Error(
|
|
20384
|
+
`Invalid Oracle URL "${redactOracleUrl(trimmed)}". Expected oracle://[user:password@]host:port/service`
|
|
20385
|
+
);
|
|
20386
|
+
}
|
|
20387
|
+
const port = url.port || "1521";
|
|
20388
|
+
return {
|
|
20389
|
+
connectString: `${url.hostname}:${port}/${path2}`,
|
|
20390
|
+
user: url.username ? decodeURIComponent(url.username) : options.username,
|
|
20391
|
+
password: url.password ? decodeURIComponent(url.password) : options.password
|
|
20392
|
+
};
|
|
20393
|
+
}
|
|
20394
|
+
if (!JDBC_THIN_PREFIX_RE.test(trimmed)) {
|
|
20395
|
+
throw new Error(
|
|
20396
|
+
`Unsupported Oracle URL "${redactOracleUrl(trimmed)}". Expected prefix: jdbc:oracle:thin:@ or oracle://`
|
|
20397
|
+
);
|
|
20398
|
+
}
|
|
20399
|
+
const afterPrefix = trimmed.replace(JDBC_THIN_PREFIX_RE, "");
|
|
20400
|
+
const atIdx = afterPrefix.indexOf("@");
|
|
20401
|
+
if (atIdx === -1) {
|
|
20402
|
+
throw new Error(
|
|
20403
|
+
`Invalid Oracle JDBC URL "${redactOracleUrl(trimmed)}". Expected '@' separator before host.`
|
|
20404
|
+
);
|
|
20405
|
+
}
|
|
20406
|
+
const credentialsPart = afterPrefix.slice(0, atIdx);
|
|
20407
|
+
const target = afterPrefix.slice(atIdx + 1).replace(/^\/\//, "");
|
|
20408
|
+
let user = options.username;
|
|
20409
|
+
let password = options.password;
|
|
20410
|
+
if (credentialsPart) {
|
|
20411
|
+
const slashIdx = credentialsPart.indexOf("/");
|
|
20412
|
+
if (slashIdx === -1) {
|
|
20413
|
+
user = credentialsPart || user;
|
|
20414
|
+
} else {
|
|
20415
|
+
user = credentialsPart.slice(0, slashIdx) || user;
|
|
20416
|
+
password = credentialsPart.slice(slashIdx + 1) || password;
|
|
20417
|
+
}
|
|
20418
|
+
}
|
|
20419
|
+
if (!target) {
|
|
20420
|
+
throw new Error(
|
|
20421
|
+
`Invalid Oracle JDBC URL "${redactOracleUrl(trimmed)}". Missing host portion after '@'.`
|
|
20422
|
+
);
|
|
20423
|
+
}
|
|
20424
|
+
return {
|
|
20425
|
+
connectString: target,
|
|
20426
|
+
user,
|
|
20427
|
+
password
|
|
20428
|
+
};
|
|
20429
|
+
}
|
|
20430
|
+
function redactOracleUrl(jdbcUrl) {
|
|
20431
|
+
return jdbcUrl.replace(/(:\/\/)([^@/]+)@/, "$1***@").replace(/(thin:)([^@]+)@/i, "$1***@");
|
|
20432
|
+
}
|
|
20433
|
+
|
|
20434
|
+
// ../connectors/src/lib/oracle-runner.ts
|
|
20435
|
+
async function importOracleDb() {
|
|
20436
|
+
const mod = await import("oracledb");
|
|
20437
|
+
return mod.default ?? mod;
|
|
20438
|
+
}
|
|
20439
|
+
async function runOracleQuery(parsed, sql) {
|
|
20440
|
+
const oracledb = await importOracleDb();
|
|
20441
|
+
const connection2 = await oracledb.getConnection({
|
|
20442
|
+
user: parsed.user,
|
|
20443
|
+
password: parsed.password,
|
|
20444
|
+
connectString: parsed.connectString
|
|
20445
|
+
});
|
|
20446
|
+
try {
|
|
20447
|
+
const result = await connection2.execute(sql, [], {
|
|
20448
|
+
outFormat: oracledb.OUT_FORMAT_OBJECT,
|
|
20449
|
+
// Bound by the connector's own row cap, but keep the driver from
|
|
20450
|
+
// streaming arbitrarily large result sets.
|
|
20451
|
+
maxRows: 5e3
|
|
20452
|
+
});
|
|
20453
|
+
return { rows: result.rows ?? [] };
|
|
20454
|
+
} finally {
|
|
20455
|
+
try {
|
|
20456
|
+
await connection2.close();
|
|
20457
|
+
} catch {
|
|
20458
|
+
}
|
|
20459
|
+
}
|
|
20460
|
+
}
|
|
20461
|
+
async function checkOracleConnection(url, credentials) {
|
|
20462
|
+
let parsed;
|
|
20463
|
+
try {
|
|
20464
|
+
parsed = parseOracleJdbcUrl(url, credentials);
|
|
20465
|
+
} catch (err) {
|
|
20466
|
+
return {
|
|
20467
|
+
success: false,
|
|
20468
|
+
error: err instanceof Error ? err.message : String(err)
|
|
20469
|
+
};
|
|
20470
|
+
}
|
|
20471
|
+
try {
|
|
20472
|
+
await runOracleQuery(parsed, "SELECT 1 FROM DUAL");
|
|
20473
|
+
return { success: true };
|
|
20474
|
+
} catch (err) {
|
|
20475
|
+
let msg = err instanceof Error ? err.message : String(err);
|
|
20476
|
+
msg = msg.replaceAll(url, redactOracleUrl(url));
|
|
20477
|
+
return { success: false, error: msg };
|
|
20478
|
+
}
|
|
20479
|
+
}
|
|
20480
|
+
|
|
20257
20481
|
// ../connectors/src/lib/ssh-tunnel.ts
|
|
20258
20482
|
var sshTunnelParameters = {
|
|
20259
20483
|
sshHost: new ParameterDefinition({
|
|
@@ -20415,20 +20639,82 @@ var parameters = {
|
|
|
20415
20639
|
};
|
|
20416
20640
|
|
|
20417
20641
|
// ../connectors/src/connectors/jdbc/utils.ts
|
|
20418
|
-
var
|
|
20642
|
+
var POSTGRES_PREFIX_RE = /^jdbc:(postgresql|postgres):\/\//i;
|
|
20643
|
+
var MYSQL_PREFIX_RE = /^jdbc:(mysql|mariadb):\/\//i;
|
|
20644
|
+
var REDSHIFT_PREFIX_RE = /^jdbc:redshift:\/\//i;
|
|
20645
|
+
var SQLSERVER_PREFIX_RE2 = /^jdbc:sqlserver:\/\//i;
|
|
20646
|
+
var ORACLE_PREFIX_RE = /^jdbc:oracle:thin:/i;
|
|
20647
|
+
var KNOWN_UNSUPPORTED = [
|
|
20648
|
+
{
|
|
20649
|
+
prefix: /^jdbc:snowflake:\/\//i,
|
|
20650
|
+
message: "Snowflake JDBC URLs are not routable through the generic `jdbc` connector. Use the dedicated `snowflake` connector."
|
|
20651
|
+
},
|
|
20652
|
+
{
|
|
20653
|
+
prefix: /^jdbc:bigquery:\/\//i,
|
|
20654
|
+
message: "BigQuery JDBC URLs are not routable through the generic `jdbc` connector. Use the dedicated `bigquery` connector."
|
|
20655
|
+
},
|
|
20656
|
+
{
|
|
20657
|
+
prefix: /^jdbc:databricks:\/\//i,
|
|
20658
|
+
message: "Databricks JDBC URLs are not routable through the generic `jdbc` connector. Use the dedicated `databricks` connector."
|
|
20659
|
+
},
|
|
20660
|
+
{
|
|
20661
|
+
prefix: /^jdbc:(trino|presto):\/\//i,
|
|
20662
|
+
message: "Trino/Presto JDBC URLs are not yet supported by the `jdbc` connector (no Node.js client bundled)."
|
|
20663
|
+
},
|
|
20664
|
+
{
|
|
20665
|
+
prefix: /^jdbc:td:\/\//i,
|
|
20666
|
+
message: "Treasure Data JDBC URLs are not yet supported by the `jdbc` connector (no Node.js client bundled). The TD JDBC driver speaks Presto under the hood; Trino/Presto support is the same prerequisite."
|
|
20667
|
+
},
|
|
20668
|
+
{
|
|
20669
|
+
prefix: /^jdbc:oracle:oci/i,
|
|
20670
|
+
message: "Oracle OCI driver URLs are not supported. Use the thin driver form: jdbc:oracle:thin:@host:port/service"
|
|
20671
|
+
},
|
|
20672
|
+
{
|
|
20673
|
+
prefix: /^jdbc:db2:\/\//i,
|
|
20674
|
+
message: "DB2 JDBC URLs are not yet supported by the `jdbc` connector."
|
|
20675
|
+
},
|
|
20676
|
+
{
|
|
20677
|
+
prefix: /^jdbc:(sybase|h2|hsqldb|derby|firebird|sqlite):/i,
|
|
20678
|
+
message: "This JDBC dialect is not supported by the `jdbc` connector."
|
|
20679
|
+
}
|
|
20680
|
+
];
|
|
20419
20681
|
function parseJdbcUrl(jdbcUrl, options = {}) {
|
|
20420
20682
|
const trimmed = jdbcUrl.trim();
|
|
20421
|
-
|
|
20422
|
-
|
|
20683
|
+
if (SQLSERVER_PREFIX_RE2.test(trimmed)) {
|
|
20684
|
+
return { driver: "sqlserver", originalUrl: trimmed };
|
|
20685
|
+
}
|
|
20686
|
+
if (ORACLE_PREFIX_RE.test(trimmed)) {
|
|
20687
|
+
return { driver: "oracle", originalUrl: trimmed };
|
|
20688
|
+
}
|
|
20689
|
+
let driver;
|
|
20690
|
+
let defaultPort;
|
|
20691
|
+
let forceSsl = false;
|
|
20692
|
+
let nativeProtocol;
|
|
20693
|
+
let withoutPrefix;
|
|
20694
|
+
if (POSTGRES_PREFIX_RE.test(trimmed)) {
|
|
20695
|
+
driver = "postgresql";
|
|
20696
|
+
defaultPort = 5432;
|
|
20697
|
+
nativeProtocol = "postgresql://";
|
|
20698
|
+
withoutPrefix = trimmed.replace(POSTGRES_PREFIX_RE, nativeProtocol);
|
|
20699
|
+
} else if (REDSHIFT_PREFIX_RE.test(trimmed)) {
|
|
20700
|
+
driver = "postgresql";
|
|
20701
|
+
defaultPort = 5439;
|
|
20702
|
+
forceSsl = true;
|
|
20703
|
+
nativeProtocol = "postgresql://";
|
|
20704
|
+
withoutPrefix = trimmed.replace(REDSHIFT_PREFIX_RE, nativeProtocol);
|
|
20705
|
+
} else if (MYSQL_PREFIX_RE.test(trimmed)) {
|
|
20706
|
+
driver = "mysql";
|
|
20707
|
+
defaultPort = 3306;
|
|
20708
|
+
nativeProtocol = "mysql://";
|
|
20709
|
+
withoutPrefix = trimmed.replace(MYSQL_PREFIX_RE, nativeProtocol);
|
|
20710
|
+
} else {
|
|
20711
|
+
for (const { prefix, message } of KNOWN_UNSUPPORTED) {
|
|
20712
|
+
if (prefix.test(trimmed)) throw new Error(message);
|
|
20713
|
+
}
|
|
20423
20714
|
throw new Error(
|
|
20424
|
-
`Unsupported JDBC URL "${redactJdbcUrl(trimmed)}". Supported prefixes: jdbc:postgresql://, jdbc:mysql://, jdbc:mariadb://.`
|
|
20715
|
+
`Unsupported JDBC URL "${redactJdbcUrl(trimmed)}". Supported prefixes: jdbc:postgresql://, jdbc:postgres://, jdbc:mysql://, jdbc:mariadb://, jdbc:sqlserver://, jdbc:oracle:thin:@, jdbc:redshift://.`
|
|
20425
20716
|
);
|
|
20426
20717
|
}
|
|
20427
|
-
const subProtocol = match[1].toLowerCase();
|
|
20428
|
-
const driver = subProtocol === "mysql" || subProtocol === "mariadb" ? "mysql" : "postgresql";
|
|
20429
|
-
const defaultPort = driver === "postgresql" ? 5432 : 3306;
|
|
20430
|
-
const nativeProtocol = driver === "postgresql" ? "postgresql://" : "mysql://";
|
|
20431
|
-
const withoutPrefix = trimmed.replace(JDBC_PREFIX_RE, nativeProtocol);
|
|
20432
20718
|
const url = new URL(withoutPrefix);
|
|
20433
20719
|
if (options.username && !url.username) {
|
|
20434
20720
|
url.username = encodeURIComponent(options.username);
|
|
@@ -20436,10 +20722,10 @@ function parseJdbcUrl(jdbcUrl, options = {}) {
|
|
|
20436
20722
|
if (options.password && !url.password) {
|
|
20437
20723
|
url.password = encodeURIComponent(options.password);
|
|
20438
20724
|
}
|
|
20439
|
-
return { driver, nativeUrl: url.toString(), defaultPort };
|
|
20725
|
+
return { driver, nativeUrl: url.toString(), defaultPort, forceSsl };
|
|
20440
20726
|
}
|
|
20441
20727
|
function redactJdbcUrl(jdbcUrl) {
|
|
20442
|
-
return jdbcUrl.replace(/(:\/\/)([^@/]+)@/, "$1***@");
|
|
20728
|
+
return jdbcUrl.replace(/(:\/\/)([^@/]+)@/, "$1***@").replace(/(password\s*=\s*)([^;&]+)/gi, "$1***");
|
|
20443
20729
|
}
|
|
20444
20730
|
|
|
20445
20731
|
// ../connectors/src/connectors/jdbc/sdk/index.ts
|
|
@@ -20452,46 +20738,76 @@ function createClient(params) {
|
|
|
20452
20738
|
const password = params[parameters.password.slug];
|
|
20453
20739
|
const parsed = parseJdbcUrl(jdbcUrl, { username, password });
|
|
20454
20740
|
async function runQuery(sql, queryParams) {
|
|
20455
|
-
let tunnel;
|
|
20456
20741
|
try {
|
|
20457
|
-
|
|
20742
|
+
if (parsed.driver === "sqlserver") {
|
|
20743
|
+
if (queryParams && queryParams.length > 0) {
|
|
20744
|
+
throw new Error(
|
|
20745
|
+
"jdbc sdk: positional parameters are not yet supported for the sqlserver route. Inline literals into the SQL."
|
|
20746
|
+
);
|
|
20747
|
+
}
|
|
20748
|
+
const mssqlParsed = parseSqlServerJdbcUrl(parsed.originalUrl, {
|
|
20749
|
+
username,
|
|
20750
|
+
password
|
|
20751
|
+
});
|
|
20752
|
+
const result = await runMssqlQuery(mssqlParsed, sql);
|
|
20753
|
+
return result.rows;
|
|
20754
|
+
}
|
|
20755
|
+
if (parsed.driver === "oracle") {
|
|
20756
|
+
if (queryParams && queryParams.length > 0) {
|
|
20757
|
+
throw new Error(
|
|
20758
|
+
"jdbc sdk: positional parameters are not yet supported for the oracle route. Inline literals into the SQL."
|
|
20759
|
+
);
|
|
20760
|
+
}
|
|
20761
|
+
const oracleParsed = parseOracleJdbcUrl(parsed.originalUrl, {
|
|
20762
|
+
username,
|
|
20763
|
+
password
|
|
20764
|
+
});
|
|
20765
|
+
const cleanSql = sql.replace(/;\s*$/, "");
|
|
20766
|
+
const result = await runOracleQuery(oracleParsed, cleanSql);
|
|
20767
|
+
return result.rows;
|
|
20768
|
+
}
|
|
20769
|
+
const tunnel = await maybeOpenSshTunnel(
|
|
20458
20770
|
params,
|
|
20459
20771
|
parsed.nativeUrl,
|
|
20460
20772
|
parsed.defaultPort
|
|
20461
20773
|
);
|
|
20462
|
-
|
|
20463
|
-
|
|
20464
|
-
|
|
20465
|
-
|
|
20466
|
-
|
|
20467
|
-
|
|
20468
|
-
|
|
20774
|
+
try {
|
|
20775
|
+
if (parsed.driver === "postgresql") {
|
|
20776
|
+
const { Pool } = await import("pg");
|
|
20777
|
+
const pool2 = new Pool({
|
|
20778
|
+
connectionString: tunnel.connectionUrl,
|
|
20779
|
+
ssl: { rejectUnauthorized: false },
|
|
20780
|
+
connectionTimeoutMillis: 1e4,
|
|
20781
|
+
statement_timeout: 6e4
|
|
20782
|
+
});
|
|
20783
|
+
try {
|
|
20784
|
+
const result = await pool2.query(sql, queryParams);
|
|
20785
|
+
return result.rows;
|
|
20786
|
+
} finally {
|
|
20787
|
+
await pool2.end();
|
|
20788
|
+
}
|
|
20789
|
+
}
|
|
20790
|
+
const mysql = await import("mysql2/promise");
|
|
20791
|
+
const pool = mysql.createPool({
|
|
20792
|
+
uri: tunnel.connectionUrl,
|
|
20793
|
+
connectTimeout: 1e4
|
|
20469
20794
|
});
|
|
20470
20795
|
try {
|
|
20471
|
-
const
|
|
20472
|
-
return
|
|
20796
|
+
const [rows] = await pool.query(sql, queryParams);
|
|
20797
|
+
return Array.isArray(rows) ? rows : [];
|
|
20473
20798
|
} finally {
|
|
20474
|
-
await
|
|
20799
|
+
await pool.end();
|
|
20475
20800
|
}
|
|
20476
|
-
}
|
|
20477
|
-
const mysql = await import("mysql2/promise");
|
|
20478
|
-
const pool = mysql.createPool({
|
|
20479
|
-
uri: tunnel.connectionUrl,
|
|
20480
|
-
connectTimeout: 1e4
|
|
20481
|
-
});
|
|
20482
|
-
try {
|
|
20483
|
-
const [rows] = await pool.query(sql, queryParams);
|
|
20484
|
-
return Array.isArray(rows) ? rows : [];
|
|
20485
20801
|
} finally {
|
|
20486
|
-
await
|
|
20802
|
+
await tunnel.close();
|
|
20487
20803
|
}
|
|
20488
20804
|
} catch (err) {
|
|
20489
20805
|
let msg = err instanceof Error ? err.message : String(err);
|
|
20490
|
-
|
|
20806
|
+
if (parsed.driver === "postgresql" || parsed.driver === "mysql") {
|
|
20807
|
+
msg = msg.replaceAll(parsed.nativeUrl, redactJdbcUrl(jdbcUrl));
|
|
20808
|
+
}
|
|
20491
20809
|
msg = msg.replaceAll(jdbcUrl, redactJdbcUrl(jdbcUrl));
|
|
20492
20810
|
throw new Error(msg);
|
|
20493
|
-
} finally {
|
|
20494
|
-
await tunnel?.close();
|
|
20495
20811
|
}
|
|
20496
20812
|
}
|
|
20497
20813
|
return {
|
|
@@ -20678,7 +20994,7 @@ var inputSchema = z.object({
|
|
|
20678
20994
|
),
|
|
20679
20995
|
connectionId: z.string().describe("ID of the JDBC connection to use"),
|
|
20680
20996
|
sql: z.string().describe(
|
|
20681
|
-
"SQL query to execute. Use the dialect that matches the JDBC URL (PostgreSQL
|
|
20997
|
+
"SQL query to execute. Use the dialect that matches the JDBC URL prefix (PostgreSQL / Redshift: LIMIT N; MySQL/MariaDB: LIMIT N; SQL Server: TOP N; Oracle: FETCH FIRST N ROWS ONLY). Always bound the row count."
|
|
20682
20998
|
)
|
|
20683
20999
|
});
|
|
20684
21000
|
var outputSchema = z.discriminatedUnion("success", [
|
|
@@ -20696,9 +21012,10 @@ var outputSchema = z.discriminatedUnion("success", [
|
|
|
20696
21012
|
var executeQueryTool = new ConnectorTool({
|
|
20697
21013
|
name: "executeQuery",
|
|
20698
21014
|
description: `Execute a SQL query through the JDBC connector. Returns up to ${MAX_ROWS} rows.
|
|
20699
|
-
Use for: schema exploration via \`information_schema
|
|
20700
|
-
The connector dispatches by JDBC URL prefix to the matching driver
|
|
20701
|
-
so use the dialect that matches the connection.
|
|
21015
|
+
Use for: schema exploration via \`information_schema\` (or USER_TABLES on Oracle), data sampling, analytical queries.
|
|
21016
|
+
The connector dispatches by JDBC URL prefix to the matching driver
|
|
21017
|
+
(PostgreSQL / Redshift / MySQL / MariaDB / SQL Server / Oracle), so use the dialect that matches the connection.
|
|
21018
|
+
Always bound results: LIMIT for PG/MySQL/Redshift, TOP for SQL Server, FETCH FIRST for Oracle.`,
|
|
20702
21019
|
inputSchema,
|
|
20703
21020
|
outputSchema,
|
|
20704
21021
|
async execute({ connectionId, sql }, connections) {
|
|
@@ -20724,87 +21041,121 @@ so use the dialect that matches the connection. Always include LIMIT.`,
|
|
|
20724
21041
|
error: err instanceof Error ? err.message : String(err)
|
|
20725
21042
|
};
|
|
20726
21043
|
}
|
|
20727
|
-
let tunnel;
|
|
20728
21044
|
try {
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
const
|
|
20736
|
-
|
|
20737
|
-
|
|
20738
|
-
|
|
20739
|
-
|
|
20740
|
-
|
|
21045
|
+
if (parsed.driver === "sqlserver") {
|
|
21046
|
+
const mssqlParsed = parseSqlServerJdbcUrl(parsed.originalUrl, {
|
|
21047
|
+
username,
|
|
21048
|
+
password
|
|
21049
|
+
});
|
|
21050
|
+
const result = await runMssqlQuery(mssqlParsed, sql);
|
|
21051
|
+
const rows = result.rows;
|
|
21052
|
+
return {
|
|
21053
|
+
success: true,
|
|
21054
|
+
rowCount: Math.min(rows.length, MAX_ROWS),
|
|
21055
|
+
truncated: rows.length > MAX_ROWS,
|
|
21056
|
+
rows: rows.slice(0, MAX_ROWS)
|
|
21057
|
+
};
|
|
21058
|
+
}
|
|
21059
|
+
if (parsed.driver === "oracle") {
|
|
21060
|
+
const oracleParsed = parseOracleJdbcUrl(parsed.originalUrl, {
|
|
21061
|
+
username,
|
|
21062
|
+
password
|
|
21063
|
+
});
|
|
21064
|
+
const cleanSql = sql.replace(/;\s*$/, "");
|
|
21065
|
+
const result = await runOracleQuery(oracleParsed, cleanSql);
|
|
21066
|
+
const rows = result.rows;
|
|
21067
|
+
return {
|
|
21068
|
+
success: true,
|
|
21069
|
+
rowCount: Math.min(rows.length, MAX_ROWS),
|
|
21070
|
+
truncated: rows.length > MAX_ROWS,
|
|
21071
|
+
rows: rows.slice(0, MAX_ROWS)
|
|
21072
|
+
};
|
|
21073
|
+
}
|
|
21074
|
+
let tunnel;
|
|
21075
|
+
try {
|
|
21076
|
+
tunnel = await maybeOpenSshTunnel(
|
|
21077
|
+
connectionParamsToRecord(connection2),
|
|
21078
|
+
parsed.nativeUrl,
|
|
21079
|
+
parsed.defaultPort
|
|
21080
|
+
);
|
|
21081
|
+
if (parsed.driver === "postgresql") {
|
|
21082
|
+
const { Pool } = await import("pg");
|
|
21083
|
+
const pool2 = new Pool({
|
|
21084
|
+
connectionString: tunnel.connectionUrl,
|
|
21085
|
+
ssl: { rejectUnauthorized: false },
|
|
21086
|
+
connectionTimeoutMillis: CONNECT_TIMEOUT_MS,
|
|
21087
|
+
statement_timeout: STATEMENT_TIMEOUT_MS
|
|
21088
|
+
});
|
|
21089
|
+
try {
|
|
21090
|
+
const result = await pool2.query(sql);
|
|
21091
|
+
const rows = result.rows;
|
|
21092
|
+
const truncated = rows.length > MAX_ROWS;
|
|
21093
|
+
return {
|
|
21094
|
+
success: true,
|
|
21095
|
+
rowCount: Math.min(rows.length, MAX_ROWS),
|
|
21096
|
+
truncated,
|
|
21097
|
+
rows: rows.slice(0, MAX_ROWS)
|
|
21098
|
+
};
|
|
21099
|
+
} finally {
|
|
21100
|
+
await pool2.end();
|
|
21101
|
+
}
|
|
21102
|
+
}
|
|
21103
|
+
const mysql = await import("mysql2/promise");
|
|
21104
|
+
const pool = mysql.createPool({
|
|
21105
|
+
uri: tunnel.connectionUrl,
|
|
21106
|
+
connectTimeout: CONNECT_TIMEOUT_MS
|
|
20741
21107
|
});
|
|
20742
21108
|
try {
|
|
20743
|
-
const
|
|
20744
|
-
const
|
|
20745
|
-
|
|
21109
|
+
const queryPromise = pool.query(sql);
|
|
21110
|
+
const timeoutPromise = new Promise(
|
|
21111
|
+
(_, reject) => setTimeout(
|
|
21112
|
+
() => reject(new Error("Query timed out after 60 seconds")),
|
|
21113
|
+
STATEMENT_TIMEOUT_MS
|
|
21114
|
+
)
|
|
21115
|
+
);
|
|
21116
|
+
const [rows] = await Promise.race([queryPromise, timeoutPromise]);
|
|
21117
|
+
const resultRows = Array.isArray(rows) ? rows : [];
|
|
21118
|
+
const truncated = resultRows.length > MAX_ROWS;
|
|
20746
21119
|
return {
|
|
20747
21120
|
success: true,
|
|
20748
|
-
rowCount: Math.min(
|
|
21121
|
+
rowCount: Math.min(resultRows.length, MAX_ROWS),
|
|
20749
21122
|
truncated,
|
|
20750
|
-
rows:
|
|
21123
|
+
rows: resultRows.slice(0, MAX_ROWS)
|
|
20751
21124
|
};
|
|
20752
21125
|
} finally {
|
|
20753
|
-
await
|
|
21126
|
+
await pool.end();
|
|
20754
21127
|
}
|
|
20755
|
-
}
|
|
20756
|
-
const mysql = await import("mysql2/promise");
|
|
20757
|
-
const pool = mysql.createPool({
|
|
20758
|
-
uri: tunnel.connectionUrl,
|
|
20759
|
-
connectTimeout: CONNECT_TIMEOUT_MS
|
|
20760
|
-
});
|
|
20761
|
-
try {
|
|
20762
|
-
const queryPromise = pool.query(sql);
|
|
20763
|
-
const timeoutPromise = new Promise(
|
|
20764
|
-
(_, reject) => setTimeout(
|
|
20765
|
-
() => reject(new Error("Query timed out after 60 seconds")),
|
|
20766
|
-
STATEMENT_TIMEOUT_MS
|
|
20767
|
-
)
|
|
20768
|
-
);
|
|
20769
|
-
const [rows] = await Promise.race([queryPromise, timeoutPromise]);
|
|
20770
|
-
const resultRows = Array.isArray(rows) ? rows : [];
|
|
20771
|
-
const truncated = resultRows.length > MAX_ROWS;
|
|
20772
|
-
return {
|
|
20773
|
-
success: true,
|
|
20774
|
-
rowCount: Math.min(resultRows.length, MAX_ROWS),
|
|
20775
|
-
truncated,
|
|
20776
|
-
rows: resultRows.slice(0, MAX_ROWS)
|
|
20777
|
-
};
|
|
20778
21128
|
} finally {
|
|
20779
|
-
await
|
|
21129
|
+
await tunnel?.close();
|
|
20780
21130
|
}
|
|
20781
21131
|
} catch (err) {
|
|
20782
21132
|
let msg = err instanceof Error ? err.message : String(err);
|
|
20783
|
-
|
|
21133
|
+
if (parsed.driver === "postgresql" || parsed.driver === "mysql") {
|
|
21134
|
+
msg = msg.replaceAll(parsed.nativeUrl, redactJdbcUrl(jdbcUrl));
|
|
21135
|
+
}
|
|
20784
21136
|
msg = msg.replaceAll(jdbcUrl, redactJdbcUrl(jdbcUrl));
|
|
20785
21137
|
return { success: false, error: msg };
|
|
20786
|
-
} finally {
|
|
20787
|
-
await tunnel?.close();
|
|
20788
21138
|
}
|
|
20789
21139
|
}
|
|
20790
21140
|
});
|
|
20791
21141
|
|
|
20792
21142
|
// ../connectors/src/connectors/jdbc/index.ts
|
|
20793
21143
|
var tools = { executeQuery: executeQueryTool };
|
|
21144
|
+
var SAMPLE_WRAPPER_RE = /^\s*SELECT\s+\*\s+FROM\s+\(([\s\S]+)\)\s+AS\s+_sq\s+LIMIT\s+(\d+)\s*;?\s*$/i;
|
|
20794
21145
|
var jdbcConnector = new ConnectorPlugin({
|
|
20795
21146
|
slug: "jdbc",
|
|
20796
21147
|
authType: AUTH_TYPES.USER_PASSWORD,
|
|
20797
21148
|
name: "JDBC",
|
|
20798
|
-
description: "Generic JDBC-style connection. Accepts a JDBC URL and dispatches to the matching driver (PostgreSQL, MySQL,
|
|
21149
|
+
description: "Generic JDBC-style connection. Accepts a JDBC URL and dispatches to the matching driver (PostgreSQL, MySQL/MariaDB, SQL Server, Oracle, Redshift).",
|
|
20799
21150
|
iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/4Hgb5qQffrdu5nOkc49WtM/76d82ef6b108c7780e42998137c61b83/jdbc-icon.png",
|
|
20800
21151
|
parameters,
|
|
20801
|
-
releaseFlag: { dev1: true, dev2:
|
|
21152
|
+
releaseFlag: { dev1: true, dev2: true, prod: true },
|
|
20802
21153
|
categories: ["database"],
|
|
20803
21154
|
onboarding: jdbcOnboarding,
|
|
20804
21155
|
systemPrompt: {
|
|
20805
21156
|
en: `### Tools
|
|
20806
21157
|
|
|
20807
|
-
- \`jdbc_executeQuery\`: Executes a SQL query through a JDBC URL and returns rows. The connector dispatches by URL prefix to the matching driver
|
|
21158
|
+
- \`jdbc_executeQuery\`: Executes a SQL query through a JDBC URL and returns rows. The connector dispatches by URL prefix to the matching native driver, so use the dialect that matches the connection. Use this for schema exploration via \`information_schema\` (or vendor equivalent) and for sampling data. See the SQL Reference below.
|
|
20808
21159
|
|
|
20809
21160
|
### Business Logic
|
|
20810
21161
|
|
|
@@ -20814,16 +21165,29 @@ The business logic type for this connector is "sql".
|
|
|
20814
21165
|
|
|
20815
21166
|
The dialect depends on the JDBC URL prefix:
|
|
20816
21167
|
|
|
20817
|
-
- \`jdbc:postgresql://...\` \u2192 PostgreSQL
|
|
21168
|
+
- \`jdbc:postgresql://...\` / \`jdbc:postgres://...\` \u2192 PostgreSQL (driver: \`pg\`). \`LIMIT N\` is native.
|
|
20818
21169
|
- List tables: \`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\`
|
|
20819
21170
|
- List columns: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
|
|
20820
|
-
- \`jdbc:
|
|
21171
|
+
- \`jdbc:redshift://...\` \u2192 Amazon Redshift (driver: \`pg\` with SSL forced; default port 5439). PostgreSQL-compatible wire protocol; \`LIMIT N\` is native.
|
|
21172
|
+
- \`jdbc:mysql://...\` / \`jdbc:mariadb://...\` \u2192 MySQL / MariaDB (driver: \`mysql2\`). \`LIMIT N\` is native.
|
|
20821
21173
|
- List tables: \`SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()\`
|
|
20822
21174
|
- List columns: \`SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'xxx'\`
|
|
20823
|
-
-
|
|
21175
|
+
- \`jdbc:sqlserver://...\` \u2192 Microsoft SQL Server / Azure SQL (driver: \`mssql\` / \`tedious\`). T-SQL dialect. **Use \`TOP N\` instead of \`LIMIT N\`** in queries you write.
|
|
21176
|
+
- List tables: \`SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'\`
|
|
21177
|
+
- List columns: \`SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'xxx'\`
|
|
21178
|
+
- \`jdbc:oracle:thin:@host:port/service\` (or \`@//host:port/service\` / \`@host:port:sid\`) \u2192 Oracle Database (driver: \`oracledb\` thin). Oracle SQL. **No \`LIMIT\` keyword** \u2014 use \`FETCH FIRST N ROWS ONLY\`, \`OFFSET m ROWS FETCH NEXT N ROWS ONLY\`, or \`ROWNUM\` filters.
|
|
21179
|
+
- List tables: \`SELECT TABLE_NAME FROM USER_TABLES\`
|
|
21180
|
+
- List columns: \`SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS WHERE TABLE_NAME = UPPER('xxx')\`
|
|
21181
|
+
|
|
21182
|
+
Explicitly **not** supported via this connector \u2014 use the dedicated connector or open a request:
|
|
21183
|
+
\`jdbc:snowflake://\` (use \`snowflake\`), \`jdbc:bigquery://\` (use \`bigquery\`), \`jdbc:databricks://\` (use \`databricks\`), \`jdbc:trino://\` / \`jdbc:presto://\` / \`jdbc:td://\` (Treasure Data) \u2014 no Node.js client bundled.
|
|
21184
|
+
|
|
21185
|
+
### Row-limit compatibility (server-logic schema inference)
|
|
21186
|
+
|
|
21187
|
+
The platform's server-logic schema inference may wrap your query as \`SELECT * FROM (<inner>) AS _sq LIMIT N\` (PostgreSQL/MySQL syntax). For PostgreSQL / Redshift / MySQL routes this executes natively. For \`jdbc:sqlserver://\` and \`jdbc:oracle:thin:\` routes, the connector detects this exact wrapper at \`query()\` time, executes \`<inner>\` directly via the dialect-specific driver, and slices the first N rows in JS. You do not need to handle this \u2014 but in queries **you author**, do not use \`LIMIT\` for the SQL Server / Oracle routes; use \`TOP\` / \`FETCH FIRST\` as listed above.`,
|
|
20824
21188
|
ja: `### \u30C4\u30FC\u30EB
|
|
20825
21189
|
|
|
20826
|
-
- \`jdbc_executeQuery\`: JDBC URL \u7D4C\u7531\u3067 SQL \u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u3057\u3001\u884C\u30C7\u30FC\u30BF\u3092\u8FD4\u3057\u307E\u3059\u3002\u30B3\u30CD\u30AF\u30BF\u306F URL \u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u304B\u3089\u5BFE\u5FDC\u3059\u308B\
|
|
21190
|
+
- \`jdbc_executeQuery\`: JDBC URL \u7D4C\u7531\u3067 SQL \u30AF\u30A8\u30EA\u3092\u5B9F\u884C\u3057\u3001\u884C\u30C7\u30FC\u30BF\u3092\u8FD4\u3057\u307E\u3059\u3002\u30B3\u30CD\u30AF\u30BF\u306F URL \u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u304B\u3089\u5BFE\u5FDC\u3059\u308B\u30CD\u30A4\u30C6\u30A3\u30D6\u30C9\u30E9\u30A4\u30D0\u3078\u632F\u308A\u5206\u3051\u308B\u305F\u3081\u3001\u63A5\u7D9A\u5148\u306B\u5408\u3063\u305F\u65B9\u8A00\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\`information_schema\`\uFF08\u307E\u305F\u306F\u5404 DB \u306E\u540C\u7B49\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u30D3\u30E5\u30FC\uFF09\u3092\u4F7F\u3063\u305F\u30B9\u30AD\u30FC\u30DE\u63A2\u7D22\u3084\u30C7\u30FC\u30BF\u306E\u30B5\u30F3\u30D7\u30EA\u30F3\u30B0\u306B\u4F7F\u3044\u307E\u3059\u3002\u4E0B\u90E8\u306E\u300CSQL \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9\u300D\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
20827
21191
|
|
|
20828
21192
|
### Business Logic
|
|
20829
21193
|
|
|
@@ -20833,13 +21197,26 @@ The dialect depends on the JDBC URL prefix:
|
|
|
20833
21197
|
|
|
20834
21198
|
JDBC URL \u306E\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u306B\u3088\u308A\u65B9\u8A00\u304C\u6C7A\u307E\u308A\u307E\u3059:
|
|
20835
21199
|
|
|
20836
|
-
- \`jdbc:postgresql://...\` \u2192 PostgreSQL \
|
|
21200
|
+
- \`jdbc:postgresql://...\` / \`jdbc:postgres://...\` \u2192 PostgreSQL\uFF08\u30C9\u30E9\u30A4\u30D0: \`pg\`\uFF09\u3002\`LIMIT N\` \u304C\u30CD\u30A4\u30C6\u30A3\u30D6\u3067\u4F7F\u3048\u307E\u3059\u3002
|
|
20837
21201
|
- \u30C6\u30FC\u30D6\u30EB\u4E00\u89A7: \`SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'\`
|
|
20838
21202
|
- \u30AB\u30E9\u30E0\u4E00\u89A7: \`SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'xxx'\`
|
|
20839
|
-
- \`jdbc:
|
|
21203
|
+
- \`jdbc:redshift://...\` \u2192 Amazon Redshift\uFF08\u30C9\u30E9\u30A4\u30D0: \`pg\`\u3001SSL \u5F37\u5236\u3001\u30C7\u30D5\u30A9\u30EB\u30C8\u30DD\u30FC\u30C8 5439\uFF09\u3002PostgreSQL \u30EF\u30A4\u30E4\u4E92\u63DB\u306E\u305F\u3081 \`LIMIT N\` \u304C\u305D\u306E\u307E\u307E\u4F7F\u3048\u307E\u3059\u3002
|
|
21204
|
+
- \`jdbc:mysql://...\` / \`jdbc:mariadb://...\` \u2192 MySQL / MariaDB\uFF08\u30C9\u30E9\u30A4\u30D0: \`mysql2\`\uFF09\u3002\`LIMIT N\` \u304C\u30CD\u30A4\u30C6\u30A3\u30D6\u3067\u4F7F\u3048\u307E\u3059\u3002
|
|
20840
21205
|
- \u30C6\u30FC\u30D6\u30EB\u4E00\u89A7: \`SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE()\`
|
|
20841
21206
|
- \u30AB\u30E9\u30E0\u4E00\u89A7: \`SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'xxx'\`
|
|
20842
|
-
- \
|
|
21207
|
+
- \`jdbc:sqlserver://...\` \u2192 Microsoft SQL Server / Azure SQL\uFF08\u30C9\u30E9\u30A4\u30D0: \`mssql\` / \`tedious\`\uFF09\u3002T-SQL \u65B9\u8A00\u3002**\u81EA\u5206\u3067\u66F8\u304F SQL \u3067\u306F \`LIMIT N\` \u3067\u306F\u306A\u304F \`TOP N\` \u3092\u4F7F\u3046\u3053\u3068**\u3002
|
|
21208
|
+
- \u30C6\u30FC\u30D6\u30EB\u4E00\u89A7: \`SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'\`
|
|
21209
|
+
- \u30AB\u30E9\u30E0\u4E00\u89A7: \`SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'xxx'\`
|
|
21210
|
+
- \`jdbc:oracle:thin:@host:port/service\`\uFF08\`@//host:port/service\` / \`@host:port:sid\` \u3082\u53EF\uFF09\u2192 Oracle Database\uFF08\u30C9\u30E9\u30A4\u30D0: \`oracledb\` thin\uFF09\u3002Oracle SQL\u3002**\`LIMIT\` \u30AD\u30FC\u30EF\u30FC\u30C9\u306F\u5B58\u5728\u3057\u307E\u305B\u3093** \u2014 \`FETCH FIRST N ROWS ONLY\` / \`OFFSET m ROWS FETCH NEXT N ROWS ONLY\` / \`ROWNUM\` \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
21211
|
+
- \u30C6\u30FC\u30D6\u30EB\u4E00\u89A7: \`SELECT TABLE_NAME FROM USER_TABLES\`
|
|
21212
|
+
- \u30AB\u30E9\u30E0\u4E00\u89A7: \`SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS WHERE TABLE_NAME = UPPER('xxx')\`
|
|
21213
|
+
|
|
21214
|
+
\u3053\u306E\u30B3\u30CD\u30AF\u30BF\u3067\u306F **\u30B5\u30DD\u30FC\u30C8\u5916**\uFF08\u5C02\u7528\u30B3\u30CD\u30AF\u30BF\u3092\u4F7F\u3046\u304B\u3001\u30EA\u30AF\u30A8\u30B9\u30C8\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\uFF09:
|
|
21215
|
+
\`jdbc:snowflake://\`\uFF08\`snowflake\` \u3092\u4F7F\u7528\uFF09\u3001\`jdbc:bigquery://\`\uFF08\`bigquery\` \u3092\u4F7F\u7528\uFF09\u3001\`jdbc:databricks://\`\uFF08\`databricks\` \u3092\u4F7F\u7528\uFF09\u3001\`jdbc:trino://\` / \`jdbc:presto://\` / \`jdbc:td://\`\uFF08Treasure Data\uFF09\u2014 Node.js \u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u3092\u540C\u68B1\u3057\u3066\u3044\u307E\u305B\u3093\u3002
|
|
21216
|
+
|
|
21217
|
+
### \u884C\u6570\u5236\u9650\u306E\u4E92\u63DB\u6027\uFF08server-logic \u30B9\u30AD\u30FC\u30DE\u63A8\u8AD6\uFF09
|
|
21218
|
+
|
|
21219
|
+
\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0\u306E server-logic \u30B9\u30AD\u30FC\u30DE\u63A8\u8AD6\u306F\u3001\u30AF\u30A8\u30EA\u3092 \`SELECT * FROM (<inner>) AS _sq LIMIT N\`\uFF08PostgreSQL/MySQL \u69CB\u6587\uFF09\u306E\u5F62\u3067\u30E9\u30C3\u30D7\u3057\u3066\u304F\u308B\u3053\u3068\u304C\u3042\u308A\u307E\u3059\u3002PostgreSQL / Redshift / MySQL \u30EB\u30FC\u30C8\u3067\u306F\u305D\u306E\u307E\u307E\u5B9F\u884C\u3055\u308C\u307E\u3059\u3002\`jdbc:sqlserver://\` \u304A\u3088\u3073 \`jdbc:oracle:thin:\` \u30EB\u30FC\u30C8\u3067\u306F\u3001\u30B3\u30CD\u30AF\u30BF\u304C \`query()\` \u5185\u3067\u3053\u306E\u30E9\u30C3\u30D1\u3092\u691C\u51FA\u3057\u3001\`<inner>\` \u3092\u65B9\u8A00\u56FA\u6709\u306E\u30C9\u30E9\u30A4\u30D0\u3067\u76F4\u63A5\u5B9F\u884C\u3057\u3066 JS \u5074\u3067\u5148\u982D N \u884C\u306B\u5207\u308A\u8A70\u3081\u307E\u3059\u3002\u5229\u7528\u8005\u5074\u3067\u5BFE\u51E6\u3059\u308B\u5FC5\u8981\u306F\u3042\u308A\u307E\u305B\u3093\u304C\u3001**\u81EA\u5206\u3067\u66F8\u304F SQL** \u3067\u306F SQL Server / Oracle \u30EB\u30FC\u30C8\u3067 \`LIMIT\` \u3092\u4F7F\u308F\u305A\u3001\u4E0A\u8A18\u306E \`TOP\` / \`FETCH FIRST\` \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044\u3002`
|
|
20843
21220
|
},
|
|
20844
21221
|
tools,
|
|
20845
21222
|
async checkConnection(params, _config) {
|
|
@@ -20855,6 +21232,12 @@ JDBC URL \u306E\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u306B\u3088\u308A\u65B
|
|
|
20855
21232
|
error: e instanceof Error ? e.message : String(e)
|
|
20856
21233
|
};
|
|
20857
21234
|
}
|
|
21235
|
+
if (parsed.driver === "sqlserver") {
|
|
21236
|
+
return checkMssqlConnection(parsed.originalUrl, { username, password });
|
|
21237
|
+
}
|
|
21238
|
+
if (parsed.driver === "oracle") {
|
|
21239
|
+
return checkOracleConnection(parsed.originalUrl, { username, password });
|
|
21240
|
+
}
|
|
20858
21241
|
const tunnel = await maybeOpenSshTunnel(
|
|
20859
21242
|
params,
|
|
20860
21243
|
parsed.nativeUrl,
|
|
@@ -20864,7 +21247,7 @@ JDBC URL \u306E\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u306B\u3088\u308A\u65B
|
|
|
20864
21247
|
const { Pool } = await import("pg");
|
|
20865
21248
|
const pool2 = new Pool({
|
|
20866
21249
|
connectionString: tunnel.connectionUrl,
|
|
20867
|
-
ssl: { rejectUnauthorized: false },
|
|
21250
|
+
ssl: parsed.forceSsl ? { rejectUnauthorized: false } : { rejectUnauthorized: false },
|
|
20868
21251
|
connectionTimeoutMillis: 1e4
|
|
20869
21252
|
});
|
|
20870
21253
|
try {
|
|
@@ -20903,6 +21286,35 @@ JDBC URL \u306E\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u306B\u3088\u308A\u65B
|
|
|
20903
21286
|
const username = params[parameters.username.slug];
|
|
20904
21287
|
const password = params[parameters.password.slug];
|
|
20905
21288
|
const parsed = parseJdbcUrl(jdbcUrl, { username, password });
|
|
21289
|
+
if (parsed.driver === "sqlserver") {
|
|
21290
|
+
const mssqlParsed = parseSqlServerJdbcUrl(parsed.originalUrl, {
|
|
21291
|
+
username,
|
|
21292
|
+
password
|
|
21293
|
+
});
|
|
21294
|
+
const wrapper = sql.match(SAMPLE_WRAPPER_RE);
|
|
21295
|
+
if (wrapper) {
|
|
21296
|
+
const inner = wrapper[1].trim();
|
|
21297
|
+
const limit = Number.parseInt(wrapper[2], 10);
|
|
21298
|
+
const result = await runMssqlQuery(mssqlParsed, inner);
|
|
21299
|
+
return { rows: result.rows.slice(0, limit) };
|
|
21300
|
+
}
|
|
21301
|
+
return runMssqlQuery(mssqlParsed, sql);
|
|
21302
|
+
}
|
|
21303
|
+
if (parsed.driver === "oracle") {
|
|
21304
|
+
const oracleParsed = parseOracleJdbcUrl(parsed.originalUrl, {
|
|
21305
|
+
username,
|
|
21306
|
+
password
|
|
21307
|
+
});
|
|
21308
|
+
const wrapper = sql.match(SAMPLE_WRAPPER_RE);
|
|
21309
|
+
if (wrapper) {
|
|
21310
|
+
const inner = wrapper[1].trim().replace(/;\s*$/, "");
|
|
21311
|
+
const limit = Number.parseInt(wrapper[2], 10);
|
|
21312
|
+
const result = await runOracleQuery(oracleParsed, inner);
|
|
21313
|
+
return { rows: result.rows.slice(0, limit) };
|
|
21314
|
+
}
|
|
21315
|
+
const cleanSql = sql.replace(/;\s*$/, "");
|
|
21316
|
+
return runOracleQuery(oracleParsed, cleanSql);
|
|
21317
|
+
}
|
|
20906
21318
|
const tunnel = await maybeOpenSshTunnel(
|
|
20907
21319
|
params,
|
|
20908
21320
|
parsed.nativeUrl,
|
|
@@ -20913,7 +21325,7 @@ JDBC URL \u306E\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u306B\u3088\u308A\u65B
|
|
|
20913
21325
|
const cleanSql = sql.replace(/;\s*$/, "");
|
|
20914
21326
|
const pool2 = new Pool({
|
|
20915
21327
|
connectionString: tunnel.connectionUrl,
|
|
20916
|
-
ssl: { rejectUnauthorized: false },
|
|
21328
|
+
ssl: parsed.forceSsl ? { rejectUnauthorized: false } : { rejectUnauthorized: false },
|
|
20917
21329
|
connectionTimeoutMillis: 1e4,
|
|
20918
21330
|
statement_timeout: 6e4
|
|
20919
21331
|
});
|