MCPcopy Index your code
hub / github.com/bytebase/dbhub / createExecuteSqlToolHandler

Function createExecuteSqlToolHandler

src/tools/execute-sql.ts:36–103  ·  view source on GitHub ↗
(sourceId?: string)

Source from the content-addressed store, hash-verified

34 * @returns A handler function bound to the specified source
35 */
36export function createExecuteSqlToolHandler(sourceId?: string) {
37 return async (args: any, extra: any) => {
38 const { sql } = args as { sql: string };
39 const startTime = Date.now();
40 const effectiveSourceId = getEffectiveSourceId(sourceId);
41 let success = true;
42 let errorMessage: string | undefined;
43 let result: any;
44
45 try {
46 // Ensure source is connected (handles lazy connections)
47 await ConnectorManager.ensureConnected(sourceId);
48
49 // Get connector for the specified source (or default)
50 const connector = ConnectorManager.getCurrentConnector(sourceId);
51 const actualSourceId = connector.getId();
52
53 // Get tool-specific configuration (tool is already registered, so it's enabled)
54 const registry = getToolRegistry();
55 const toolConfig = registry.getBuiltinToolConfig(BUILTIN_TOOL_EXECUTE_SQL, actualSourceId);
56
57 // Check if SQL is allowed based on readonly mode (per-tool)
58 const isReadonly = toolConfig?.readonly === true;
59 if (isReadonly && !areAllStatementsReadOnly(sql, connector.id)) {
60 errorMessage = `Read-only mode is enabled. Only the following SQL operations are allowed: ${allowedKeywords[connector.id]?.join(", ") || "none"}`;
61 success = false;
62 return createToolErrorResponse(errorMessage, "READONLY_VIOLATION");
63 }
64
65 // Execute the SQL (single or multiple statements) if validation passed
66 // Pass readonly and maxRows from tool config (if set)
67 const executeOptions = {
68 readonly: toolConfig?.readonly,
69 maxRows: toolConfig?.max_rows,
70 };
71 result = await connector.executeSQL(sql, executeOptions);
72
73 // Build response data
74 const responseData = {
75 rows: result.rows,
76 count: result.rowCount,
77 source_id: effectiveSourceId,
78 ...(result.messages && result.messages.length > 0 ? { messages: result.messages } : {}),
79 };
80
81 return createToolSuccessResponse(responseData);
82 } catch (error) {
83 success = false;
84 errorMessage = (error as Error).message;
85 const classified = tryClassifyConnectionError(error, sourceId, effectiveSourceId);
86 if (classified) return classified;
87 return createToolErrorResponse(errorMessage, "EXECUTION_ERROR");
88 } finally {
89 // Track the request
90 trackToolRequest(
91 {
92 sourceId: effectiveSourceId,
93 toolName: effectiveSourceId === "default" ? "execute_sql" : `execute_sql_${effectiveSourceId}`,

Callers 2

registerExecuteSqlToolFunction · 0.85

Calls 12

getEffectiveSourceIdFunction · 0.85
getToolRegistryFunction · 0.85
createToolErrorResponseFunction · 0.85
trackToolRequestFunction · 0.85
ensureConnectedMethod · 0.80
getCurrentConnectorMethod · 0.80
getBuiltinToolConfigMethod · 0.80
areAllStatementsReadOnlyFunction · 0.70
getIdMethod · 0.65
executeSQLMethod · 0.65

Tested by

no test coverage detected