execute-batch-queries
Execute multiple SQL queries in parallel to improve database performance when working with Firebird databases.
Instructions
Executes multiple SQL queries in parallel for improved performance.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| queries | Yes | Array of query objects, each containing SQL and optional parameters | |
| maxConcurrent | No | Maximum number of concurrent queries (default: 5) |
Implementation Reference
- src/tools/database.ts:90-98 (schema)Zod input schema defining the parameters for the execute-batch-queries tool: array of queries with SQL and optional params, and maxConcurrent.export const ExecuteBatchQueriesArgsSchema = z.object({ queries: z.array( z.object({ sql: z.string().min(1).describe("SQL query to execute"), params: z.array(z.string().or(z.number()).or(z.boolean()).or(z.null())).optional().describe("Parameters for parameterized queries") }) ).min(1).max(20).describe("Array of query objects, each containing SQL and optional parameters"), maxConcurrent: z.number().int().min(1).max(10).optional().default(5).describe("Maximum number of concurrent queries (default: 5)") });
- src/tools/database.ts:468-510 (registration)Tool registration in setupDatabaseTools function, including name, description, schema, and handler.// Add execute-batch-queries tool tools.set("execute-batch-queries", { name: "execute-batch-queries", description: "Executes multiple SQL queries in parallel for improved performance.", inputSchema: ExecuteBatchQueriesArgsSchema, handler: async (args: z.infer<typeof ExecuteBatchQueriesArgsSchema>) => { const { queries, maxConcurrent = 5 } = args; logger.info(`Executing batch of ${queries.length} queries with max concurrency ${maxConcurrent}`); try { // Validate each query for security queries.forEach((query, index) => { if (!validateSql(query.sql)) { throw new FirebirdError( `Potentially unsafe SQL query at index ${index}: ${query.sql.substring(0, 100)}${query.sql.length > 100 ? '...' : ''}`, 'SECURITY_ERROR' ); } }); const results = await executeBatchQueries(queries, undefined, maxConcurrent); logger.info(`Batch execution completed: ${results.filter(r => r.success).length} succeeded, ${results.filter(r => !r.success).length} failed`); return { content: [{ type: "text", text: formatForClaude(results) }] }; } catch (error) { const errorResponse = wrapError(error); logger.error(`Error executing batch queries: ${errorResponse.error} [${errorResponse.errorType || 'UNKNOWN'}]`); return { content: [{ type: "text", text: formatForClaude(errorResponse) }] }; } } });
- src/tools/database.ts:473-509 (handler)The MCP tool handler function: extracts args, validates SQL, calls core executeBatchQueries, formats and returns results or error.handler: async (args: z.infer<typeof ExecuteBatchQueriesArgsSchema>) => { const { queries, maxConcurrent = 5 } = args; logger.info(`Executing batch of ${queries.length} queries with max concurrency ${maxConcurrent}`); try { // Validate each query for security queries.forEach((query, index) => { if (!validateSql(query.sql)) { throw new FirebirdError( `Potentially unsafe SQL query at index ${index}: ${query.sql.substring(0, 100)}${query.sql.length > 100 ? '...' : ''}`, 'SECURITY_ERROR' ); } }); const results = await executeBatchQueries(queries, undefined, maxConcurrent); logger.info(`Batch execution completed: ${results.filter(r => r.success).length} succeeded, ${results.filter(r => !r.success).length} failed`); return { content: [{ type: "text", text: formatForClaude(results) }] }; } catch (error) { const errorResponse = wrapError(error); logger.error(`Error executing batch queries: ${errorResponse.error} [${errorResponse.errorType || 'UNKNOWN'}]`); return { content: [{ type: "text", text: formatForClaude(errorResponse) }] }; } }
- src/db/queries.ts:881-974 (helper)Core helper function implementing batch query execution: validates inputs, processes queries in concurrent batches using executeQuery, collects success/error results.export const executeBatchQueries = async ( queries: Array<{sql: string, params?: any[]}>, config = DEFAULT_CONFIG, maxConcurrent: number = 5 ): Promise<Array<{success: boolean, data?: any[], error?: string, errorType?: string}>> => { // Try to load config from global variable first const globalConfig = getGlobalConfig(); if (globalConfig && globalConfig.database) { logger.info(`Using global configuration for executeBatchQueries: ${globalConfig.database}`); config = globalConfig; } // Validate input if (!Array.isArray(queries) || queries.length === 0) { throw new FirebirdError( 'Invalid queries array: must be a non-empty array of query objects', 'VALIDATION_ERROR' ); } // Limit the number of queries to prevent abuse const MAX_QUERIES = 20; if (queries.length > MAX_QUERIES) { throw new FirebirdError( `Too many queries: maximum allowed is ${MAX_QUERIES}`, 'VALIDATION_ERROR' ); } // Validate each query queries.forEach((query, index) => { if (!query.sql || typeof query.sql !== 'string') { throw new FirebirdError( `Invalid SQL in query at index ${index}`, 'VALIDATION_ERROR' ); } // Validate SQL for security if (!validateSql(query.sql)) { throw new FirebirdError( `Potentially unsafe SQL query at index ${index}: ${query.sql.substring(0, 100)}${query.sql.length > 100 ? '...' : ''}`, 'SECURITY_ERROR' ); } // Ensure params is an array if provided if (query.params !== undefined && !Array.isArray(query.params)) { throw new FirebirdError( `Invalid params in query at index ${index}: must be an array`, 'VALIDATION_ERROR' ); } }); logger.info(`Executing batch of ${queries.length} queries`); // Execute queries in batches to limit concurrency const results: Array<{success: boolean, data?: any[], error?: string, errorType?: string}> = []; // Process queries in batches of maxConcurrent for (let i = 0; i < queries.length; i += maxConcurrent) { const batch = queries.slice(i, i + maxConcurrent); // Execute batch in parallel const batchPromises = batch.map(async (query, batchIndex) => { const queryIndex = i + batchIndex; try { logger.debug(`Executing query ${queryIndex + 1}/${queries.length}: ${query.sql.substring(0, 100)}${query.sql.length > 100 ? '...' : ''}`); const data = await executeQuery(query.sql, query.params || [], config); return { success: true, data }; } catch (error: any) { logger.error(`Error executing query ${queryIndex + 1}: ${error.message || error}`); // Format error response const errorType = error instanceof FirebirdError ? error.type : 'QUERY_EXECUTION_ERROR'; const errorMessage = error instanceof Error ? error.message : String(error); return { success: false, error: errorMessage, errorType }; } }); // Wait for all queries in this batch to complete const batchResults = await Promise.all(batchPromises); results.push(...batchResults); } logger.info(`Batch execution completed: ${results.filter(r => r.success).length} succeeded, ${results.filter(r => !r.success).length} failed`); return results; };