@yejiming/dsh-data-agent 0.0.13 → 0.1.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.en.md +43 -8
- package/README.md +43 -8
- package/conformance/dsh-ecosystem/inventory.json +26 -3
- package/conformance/dsh-ecosystem/restrictions.json +2 -2
- package/cordis.patch.yml +6 -3
- package/dsh-plugin.json +9 -4
- package/lib/catalog-DEJqOXRo.js +1944 -0
- package/lib/catalog-identity-CVftmvQL.js +96 -0
- package/lib/client.js +2217 -109
- package/lib/client.js.map +1 -1
- package/lib/command-CzzSPmag.js +1719 -0
- package/lib/command.js +2 -2
- package/lib/{connections-CHY4uB6z.js → connections-CFXOZTHZ.js} +223 -9
- package/lib/index.js +366 -16
- package/lib/routes.js +257 -4
- package/lib/{tool-ZTOS4B33.js → tool-DNkywSph.js} +364 -3
- package/lib/tool.js +1 -1
- package/lib/types/catalog-adapters.d.ts +52 -0
- package/lib/types/catalog-ai.d.ts +49 -0
- package/lib/types/catalog-command.d.ts +28 -0
- package/lib/types/catalog-identity.d.ts +23 -0
- package/lib/types/catalog-storage.d.ts +265 -0
- package/lib/types/catalog-tools.d.ts +5 -0
- package/lib/types/catalog-tui.d.ts +18 -0
- package/lib/types/catalog-types.d.ts +1376 -0
- package/lib/types/catalog.d.ts +59 -0
- package/lib/types/client/CatalogPanel.d.ts +15 -0
- package/lib/types/client/catalog-client.d.ts +57 -0
- package/lib/types/client/locales.d.ts +242 -0
- package/lib/types/command.d.ts +14 -3
- package/lib/types/connections.d.ts +9 -0
- package/lib/types/defaults.d.ts +22 -0
- package/lib/types/index.d.ts +42 -5
- package/lib/types/tui-connection-form.d.ts +11 -5
- package/package.json +4 -2
- package/preset/data-agent/agent.cordis.yml +9 -1
- package/lib/command-utC5MHd9.js +0 -916
- package/lib/defaults-Cngd8Tf8.js +0 -131
package/lib/command.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { DATABASE_COMMAND_USAGE, DATA_AGENT_TOOL_NAMES, apply, executeDatabaseCommand, formatConnectionStatus, inject, name, parseConnectArguments, parseDatabaseAction };
|
|
1
|
+
import { a as executeDatabaseCommand, c as isDshTuiPluginLoaded, d as parseDatabaseAction, i as apply, l as name, n as DATA_AGENT_TOOL_NAMES, o as formatConnectionStatus, r as DSH_TUI_PLUGIN_RUNTIME_NAME, s as inject, t as DATABASE_COMMAND_USAGE, u as parseConnectArguments } from "./command-CzzSPmag.js";
|
|
2
|
+
export { DATABASE_COMMAND_USAGE, DATA_AGENT_TOOL_NAMES, DSH_TUI_PLUGIN_RUNTIME_NAME, apply, executeDatabaseCommand, formatConnectionStatus, inject, isDshTuiPluginLoaded, name, parseConnectArguments, parseDatabaseAction };
|
|
@@ -1,10 +1,115 @@
|
|
|
1
|
-
import { c as WORKBENCH_MAX_RESULT_CHARS, d as defaultDatabasePort, f as defaultDatabaseUser, p as isDatabaseType, s as WORKBENCH_MAX_EXPORT_ROWS } from "./defaults-Cngd8Tf8.js";
|
|
2
1
|
import { readdir } from "node:fs/promises";
|
|
3
2
|
import { homedir } from "node:os";
|
|
4
3
|
import { posix, resolve, win32 } from "node:path";
|
|
5
4
|
import z from "schemastery";
|
|
6
5
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
7
6
|
import { createClient } from "@clickhouse/client";
|
|
7
|
+
//#region src/database-types.ts
|
|
8
|
+
/**
|
|
9
|
+
* Browser-safe database type descriptors shared by every DSH surface.
|
|
10
|
+
* Keep this module dependency-free: server-only client/process details belong
|
|
11
|
+
* in the database adapters, not in Web or persistence bundles.
|
|
12
|
+
*/
|
|
13
|
+
const DATABASE_TYPES = [
|
|
14
|
+
"mysql",
|
|
15
|
+
"postgres",
|
|
16
|
+
"sqlite",
|
|
17
|
+
"oracle",
|
|
18
|
+
"hive",
|
|
19
|
+
"impala",
|
|
20
|
+
"clickhouse",
|
|
21
|
+
"doris",
|
|
22
|
+
"sqlserver"
|
|
23
|
+
];
|
|
24
|
+
const DATABASE_TYPE_DESCRIPTORS = {
|
|
25
|
+
mysql: {
|
|
26
|
+
type: "mysql",
|
|
27
|
+
label: "MySQL",
|
|
28
|
+
localeKey: "type.mysql",
|
|
29
|
+
defaultPort: 3306,
|
|
30
|
+
defaultUser: "root",
|
|
31
|
+
fileBased: false
|
|
32
|
+
},
|
|
33
|
+
postgres: {
|
|
34
|
+
type: "postgres",
|
|
35
|
+
label: "PostgreSQL",
|
|
36
|
+
localeKey: "type.postgres",
|
|
37
|
+
defaultPort: 5432,
|
|
38
|
+
defaultUser: "postgres",
|
|
39
|
+
fileBased: false
|
|
40
|
+
},
|
|
41
|
+
sqlite: {
|
|
42
|
+
type: "sqlite",
|
|
43
|
+
label: "SQLite",
|
|
44
|
+
localeKey: "type.sqlite",
|
|
45
|
+
defaultPort: 0,
|
|
46
|
+
defaultUser: "",
|
|
47
|
+
fileBased: true
|
|
48
|
+
},
|
|
49
|
+
oracle: {
|
|
50
|
+
type: "oracle",
|
|
51
|
+
label: "Oracle",
|
|
52
|
+
localeKey: "type.oracle",
|
|
53
|
+
defaultPort: 1521,
|
|
54
|
+
defaultUser: "",
|
|
55
|
+
fileBased: false
|
|
56
|
+
},
|
|
57
|
+
hive: {
|
|
58
|
+
type: "hive",
|
|
59
|
+
label: "Hive",
|
|
60
|
+
localeKey: "type.hive",
|
|
61
|
+
defaultPort: 1e4,
|
|
62
|
+
defaultUser: "",
|
|
63
|
+
fileBased: false
|
|
64
|
+
},
|
|
65
|
+
impala: {
|
|
66
|
+
type: "impala",
|
|
67
|
+
label: "Impala",
|
|
68
|
+
localeKey: "type.impala",
|
|
69
|
+
defaultPort: 21050,
|
|
70
|
+
defaultUser: "",
|
|
71
|
+
fileBased: false
|
|
72
|
+
},
|
|
73
|
+
clickhouse: {
|
|
74
|
+
type: "clickhouse",
|
|
75
|
+
label: "ClickHouse",
|
|
76
|
+
localeKey: "type.clickhouse",
|
|
77
|
+
defaultPort: 8123,
|
|
78
|
+
securePort: 8443,
|
|
79
|
+
defaultUser: "default",
|
|
80
|
+
fileBased: false
|
|
81
|
+
},
|
|
82
|
+
doris: {
|
|
83
|
+
type: "doris",
|
|
84
|
+
label: "Apache Doris",
|
|
85
|
+
localeKey: "type.doris",
|
|
86
|
+
defaultPort: 9030,
|
|
87
|
+
defaultUser: "root",
|
|
88
|
+
fileBased: false
|
|
89
|
+
},
|
|
90
|
+
sqlserver: {
|
|
91
|
+
type: "sqlserver",
|
|
92
|
+
label: "SQL Server",
|
|
93
|
+
localeKey: "type.sqlserver",
|
|
94
|
+
defaultPort: 1433,
|
|
95
|
+
defaultUser: "sa",
|
|
96
|
+
fileBased: false
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
function isDatabaseType(value) {
|
|
100
|
+
return typeof value === "string" && DATABASE_TYPES.includes(value);
|
|
101
|
+
}
|
|
102
|
+
function defaultDatabasePort(type, secure = false) {
|
|
103
|
+
const descriptor = DATABASE_TYPE_DESCRIPTORS[type];
|
|
104
|
+
return secure && descriptor.securePort !== void 0 ? descriptor.securePort : descriptor.defaultPort;
|
|
105
|
+
}
|
|
106
|
+
function defaultDatabaseUser(type) {
|
|
107
|
+
return DATABASE_TYPE_DESCRIPTORS[type].defaultUser;
|
|
108
|
+
}
|
|
109
|
+
function databaseTypeLabel(type) {
|
|
110
|
+
return DATABASE_TYPE_DESCRIPTORS[type].label;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
8
113
|
//#region src/sql.ts
|
|
9
114
|
/**
|
|
10
115
|
* Lightweight SQL-text scanning helpers shared by the sql-cmd tool half and
|
|
@@ -1145,6 +1250,40 @@ function parseColumns(type, stdout) {
|
|
|
1145
1250
|
return columns;
|
|
1146
1251
|
}
|
|
1147
1252
|
//#endregion
|
|
1253
|
+
//#region src/defaults.ts
|
|
1254
|
+
/**
|
|
1255
|
+
* Package-wide defaults shared by the server half (`src/index.ts`) and the
|
|
1256
|
+
* database tool half (`src/tool.ts`). Loader schemas carry these as their
|
|
1257
|
+
* defaults so a deployment may override every one of them in cordis.yml.
|
|
1258
|
+
* @module @yejiming/dsh-data-agent/defaults
|
|
1259
|
+
*/
|
|
1260
|
+
/** Preset directory name installed into `$DSH_HOME/.agent-presets/`. */
|
|
1261
|
+
const DEFAULT_PRESET_ID = "data-agent";
|
|
1262
|
+
/** End-to-end deadline for one `/connect` connectivity check, milliseconds. */
|
|
1263
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
1264
|
+
/** End-to-end deadline for one database-tool query, milliseconds. */
|
|
1265
|
+
const DEFAULT_QUERY_TIMEOUT_MS = 3e4;
|
|
1266
|
+
/** In-memory cap on database-tool captured output (stdout and stderr each). */
|
|
1267
|
+
const DEFAULT_MAX_RESULT_CHARS = 2e4;
|
|
1268
|
+
/** Hard row cap for one structured Web workbench result/export. */
|
|
1269
|
+
const WORKBENCH_MAX_EXPORT_ROWS = 5e4;
|
|
1270
|
+
/** Bounded capture size for the larger structured Web workbench result. */
|
|
1271
|
+
const WORKBENCH_MAX_RESULT_CHARS = 33554432;
|
|
1272
|
+
/** Cap on one /query SQL text length (abuse guard; the wire body stays small). */
|
|
1273
|
+
const DEFAULT_MAX_QUERY_CHARS = 65536;
|
|
1274
|
+
/** Catalog metadata query deadline. Kept separate from user SQL execution. */
|
|
1275
|
+
const DEFAULT_CATALOG_QUERY_TIMEOUT_MS = 3e4;
|
|
1276
|
+
/**
|
|
1277
|
+
* Per-stream capture budget for one system-catalog query. Catalog metadata is
|
|
1278
|
+
* intentionally independent from the much smaller model/interactive SQL
|
|
1279
|
+
* result budget because a schema snapshot can contain thousands of objects.
|
|
1280
|
+
*/
|
|
1281
|
+
const DEFAULT_CATALOG_MAX_RESULT_CHARS = 33554432;
|
|
1282
|
+
/** Hard bound on technical assets (including columns) staged by one run. */
|
|
1283
|
+
const DEFAULT_CATALOG_MAX_ASSETS = 5e4;
|
|
1284
|
+
/** Maximum normalized length of one database or human-authored text field. */
|
|
1285
|
+
const DEFAULT_CATALOG_MAX_TEXT_CHARS = 4096;
|
|
1286
|
+
//#endregion
|
|
1148
1287
|
//#region src/client-discovery.ts
|
|
1149
1288
|
/**
|
|
1150
1289
|
* Cross-platform database CLI discovery.
|
|
@@ -1950,15 +2089,15 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
1950
2089
|
tables: copyTables(connection.tables)
|
|
1951
2090
|
};
|
|
1952
2091
|
};
|
|
1953
|
-
const queryOptions = (mode, connect = false, maxResultChars = resolvedOptions.maxResultChars) => ({
|
|
2092
|
+
const queryOptions = (mode, connect = false, maxResultChars = resolvedOptions.maxResultChars, catalog = false) => ({
|
|
1954
2093
|
clients: resolvedOptions.clients,
|
|
1955
|
-
timeoutMs: connect ? resolvedOptions.connectTimeoutMs : resolvedOptions.queryTimeoutMs,
|
|
2094
|
+
timeoutMs: connect ? resolvedOptions.connectTimeoutMs : catalog ? resolvedOptions.catalogQueryTimeoutMs ?? resolvedOptions.queryTimeoutMs : resolvedOptions.queryTimeoutMs,
|
|
1956
2095
|
maxResultChars,
|
|
1957
2096
|
...mode !== void 0 ? { mode } : {}
|
|
1958
2097
|
});
|
|
1959
|
-
const run = async (connection, sql, signal, introspection = false, connect = false, mode, maxResultChars) => {
|
|
2098
|
+
const run = async (connection, sql, signal, introspection = false, connect = false, mode, maxResultChars, catalog = false) => {
|
|
1960
2099
|
try {
|
|
1961
|
-
return redactQueryResult(await runClientQuery(requireContext(), connection, sql, queryOptions(mode, connect, maxResultChars), signal, introspection), connection);
|
|
2100
|
+
return redactQueryResult(await runClientQuery(requireContext(), connection, sql, queryOptions(mode, connect, maxResultChars, catalog), signal, introspection), connection);
|
|
1962
2101
|
} catch (error) {
|
|
1963
2102
|
const message = redactSecretText(error instanceof Error ? error.message : String(error), [connection.password]);
|
|
1964
2103
|
throw new Error(message, error instanceof Error ? { cause: error } : void 0);
|
|
@@ -2021,6 +2160,50 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
2021
2160
|
throw error;
|
|
2022
2161
|
}
|
|
2023
2162
|
};
|
|
2163
|
+
const matchingProfiles = (connection) => (persistence?.listProfiles?.() ?? []).filter((entry) => profileMatchesConnection(entry.profile, connection, resolvedOptions.cwd));
|
|
2164
|
+
const preferredMatches = (matches) => {
|
|
2165
|
+
const preferred = new Set(resolvedOptions.preferredProfileIds?.() ?? []);
|
|
2166
|
+
return matches.filter((entry) => preferred.has(entry.profileId));
|
|
2167
|
+
};
|
|
2168
|
+
const reusableProfileId = (sessionId, connection) => {
|
|
2169
|
+
if (connection.profileId !== void 0) return connection.profileId;
|
|
2170
|
+
const fallback = `session:${sessionId}`;
|
|
2171
|
+
const matches = matchingProfiles(connection);
|
|
2172
|
+
const binding = persistence?.getBinding(sessionId);
|
|
2173
|
+
const boundMatch = binding === void 0 ? void 0 : matches.find((entry) => entry.profileId === binding.profileId);
|
|
2174
|
+
const preferred = preferredMatches(matches);
|
|
2175
|
+
const stableMatches = matches.filter((entry) => !entry.profileId.startsWith("session:"));
|
|
2176
|
+
if (boundMatch !== void 0 && preferred.some((entry) => entry.profileId === boundMatch.profileId)) return boundMatch.profileId;
|
|
2177
|
+
if (preferred.length === 1) return preferred[0].profileId;
|
|
2178
|
+
if (preferred.length > 1) return fallback;
|
|
2179
|
+
if (boundMatch !== void 0 && !boundMatch.profileId.startsWith("session:")) return boundMatch.profileId;
|
|
2180
|
+
if (stableMatches.length === 1) return stableMatches[0].profileId;
|
|
2181
|
+
if (stableMatches.length > 1) return fallback;
|
|
2182
|
+
if (boundMatch !== void 0) return boundMatch.profileId;
|
|
2183
|
+
return matches.length === 1 ? matches[0].profileId : fallback;
|
|
2184
|
+
};
|
|
2185
|
+
const reconcileStableProfile = async (sessionId, connection) => {
|
|
2186
|
+
if (persistence === void 0 || connection.profileId === void 0) return connection;
|
|
2187
|
+
const matches = matchingProfiles(connection);
|
|
2188
|
+
const preferred = preferredMatches(matches);
|
|
2189
|
+
if (preferred.some((entry) => entry.profileId === connection.profileId)) return connection;
|
|
2190
|
+
const stableMatches = matches.filter((entry) => !entry.profileId.startsWith("session:"));
|
|
2191
|
+
const target = preferred.length === 1 ? preferred[0] : connection.profileId.startsWith("session:") ? stableMatches.length === 1 ? stableMatches[0] : void 0 : void 0;
|
|
2192
|
+
if (target === void 0) return connection;
|
|
2193
|
+
const profileId = target.profileId;
|
|
2194
|
+
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2195
|
+
await persistence.putBinding(sessionId, {
|
|
2196
|
+
profileId,
|
|
2197
|
+
updatedAt
|
|
2198
|
+
});
|
|
2199
|
+
const reconciled = {
|
|
2200
|
+
...connection,
|
|
2201
|
+
profileId,
|
|
2202
|
+
tables: copyTables(connection.tables)
|
|
2203
|
+
};
|
|
2204
|
+
runtime.set(sessionId, reconciled);
|
|
2205
|
+
return reconciled;
|
|
2206
|
+
};
|
|
2024
2207
|
const credentialSummary = async (connection) => {
|
|
2025
2208
|
const mode = credentialModeOf(connection);
|
|
2026
2209
|
if (connection.type === "sqlite" || mode === "none") return void 0;
|
|
@@ -2095,14 +2278,14 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
2095
2278
|
async status(sessionId) {
|
|
2096
2279
|
const connection = rawConnection(sessionId);
|
|
2097
2280
|
if (connection === void 0) return void 0;
|
|
2098
|
-
return statusSummary(connection);
|
|
2281
|
+
return statusSummary(await reconcileStableProfile(sessionId, connection));
|
|
2099
2282
|
},
|
|
2100
2283
|
async connect(sessionId, input, signal) {
|
|
2101
2284
|
if (sessionId.length === 0) throw new Error("sessionId 必须是非空字符串");
|
|
2102
2285
|
const normalized = normalizeConnectionInput(input, resolvedOptions.cwd);
|
|
2103
2286
|
const execution = await resolveCredential(normalized);
|
|
2104
2287
|
const tables = await verify(execution, signal, true);
|
|
2105
|
-
const profileId = normalized
|
|
2288
|
+
const profileId = reusableProfileId(sessionId, normalized);
|
|
2106
2289
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2107
2290
|
const draft = formDraftFromConnection(normalized);
|
|
2108
2291
|
await persistAtomically(sessionId, profileId, profileFromConnection(normalized, updatedAt), draft);
|
|
@@ -2141,6 +2324,20 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
2141
2324
|
if (connection === void 0) throw new Error("请先在 Web「数据库」标签页连接数据库,或在 TUI 运行 /database connect(未找到当前会话的连接)");
|
|
2142
2325
|
return resolveCredential(connection);
|
|
2143
2326
|
},
|
|
2327
|
+
async queryMetadata(sessionId, sql, signal) {
|
|
2328
|
+
if (sql.trim().length === 0) throw new Error("Catalog metadata SQL must not be empty");
|
|
2329
|
+
const maxQueryChars = resolvedOptions.maxQueryChars ?? 65536;
|
|
2330
|
+
if (sql.length > maxQueryChars) throw new Error(`Catalog metadata SQL exceeds ${maxQueryChars} characters`);
|
|
2331
|
+
assertSingleStatement(sql, "Catalog metadata query");
|
|
2332
|
+
const connection = await service.resolveForExecution(sessionId);
|
|
2333
|
+
if (classifyStatement(sql, connection.type) !== "read") throw new Error("Catalog metadata execution accepts read-only system catalog statements only");
|
|
2334
|
+
const result = await run(connection, sql, signal, true, false, void 0, resolvedOptions.catalogMaxResultChars ?? resolvedOptions.maxResultChars, true);
|
|
2335
|
+
if (result.exitCode !== 0) {
|
|
2336
|
+
const detail = result.stderr.trim() !== "" ? result.stderr.trim() : result.stdout.trim();
|
|
2337
|
+
throw new Error(`Catalog metadata query failed (exit ${result.exitCode}): ${detail}`);
|
|
2338
|
+
}
|
|
2339
|
+
return result;
|
|
2340
|
+
},
|
|
2144
2341
|
async listSchemas(sessionId, signal) {
|
|
2145
2342
|
const connection = await service.resolveForExecution(sessionId);
|
|
2146
2343
|
const stdout = await runMetadata(connection, "schemas", signal);
|
|
@@ -2182,7 +2379,7 @@ function createConnectionService(ctx, options, persistence) {
|
|
|
2182
2379
|
kind: "message",
|
|
2183
2380
|
...await run(connection, sql, signal)
|
|
2184
2381
|
};
|
|
2185
|
-
const limitedSql = enforceReadRowLimit(sql, connection.type,
|
|
2382
|
+
const limitedSql = enforceReadRowLimit(sql, connection.type, 50001);
|
|
2186
2383
|
const startedAt = Date.now();
|
|
2187
2384
|
const result = await run(connection, limitedSql, signal, false, false, "structured", WORKBENCH_MAX_RESULT_CHARS);
|
|
2188
2385
|
if (result.exitCode !== 0) return {
|
|
@@ -2294,6 +2491,23 @@ function profileFromConnection(connection, updatedAt) {
|
|
|
2294
2491
|
...connection.credentialMode !== void 0 ? { credentialMode: connection.credentialMode } : {}
|
|
2295
2492
|
};
|
|
2296
2493
|
}
|
|
2494
|
+
/** Match only normalized, non-secret endpoint/principal identity fields. */
|
|
2495
|
+
function profileMatchesConnection(profile, connection, cwd = process.cwd()) {
|
|
2496
|
+
let candidate;
|
|
2497
|
+
try {
|
|
2498
|
+
candidate = normalizeConnectionInput({
|
|
2499
|
+
type: profile.type,
|
|
2500
|
+
database: profile.database,
|
|
2501
|
+
...profile.host !== void 0 ? { host: profile.host } : {},
|
|
2502
|
+
...profile.port !== void 0 ? { port: profile.port } : {},
|
|
2503
|
+
...profile.user !== void 0 ? { user: profile.user } : {},
|
|
2504
|
+
...profile.secure !== void 0 ? { secure: profile.secure } : {}
|
|
2505
|
+
}, cwd);
|
|
2506
|
+
} catch {
|
|
2507
|
+
return false;
|
|
2508
|
+
}
|
|
2509
|
+
return candidate.type === connection.type && candidate.database === connection.database && candidate.host === connection.host && candidate.port === connection.port && candidate.user === connection.user && (candidate.secure ?? false) === (connection.secure ?? false);
|
|
2510
|
+
}
|
|
2297
2511
|
/** Infer legacy records while leaving ambiguous secret-less SQL profiles conservative. */
|
|
2298
2512
|
function credentialModeOf(connection) {
|
|
2299
2513
|
if (connection.credentialMode !== void 0) return connection.credentialMode;
|
|
@@ -2308,4 +2522,4 @@ function requireIdentifier(type, value, label) {
|
|
|
2308
2522
|
return value;
|
|
2309
2523
|
}
|
|
2310
2524
|
//#endregion
|
|
2311
|
-
export { parseStructuredQueryOutput as a,
|
|
2525
|
+
export { isDatabaseType as C, defaultDatabasePort as S, clientsSchema as _, parseStructuredQueryOutput as a, DATABASE_TYPES as b, DEFAULT_CATALOG_MAX_RESULT_CHARS as c, DEFAULT_CONNECT_TIMEOUT_MS as d, DEFAULT_MAX_QUERY_CHARS as f, classifyStatement as g, DEFAULT_QUERY_TIMEOUT_MS as h, validatePasswordRef as i, DEFAULT_CATALOG_MAX_TEXT_CHARS as l, DEFAULT_PRESET_ID as m, redactQueryResult as n, runClientQuery as o, DEFAULT_MAX_RESULT_CHARS as p, redactSecretText as r, DEFAULT_CATALOG_MAX_ASSETS as s, createConnectionService as t, DEFAULT_CATALOG_QUERY_TIMEOUT_MS as u, enforceReadRowLimit as v, databaseTypeLabel as x, assertSingleStatement as y };
|