describe-batch-tables
Retrieve detailed schema information for multiple Firebird database tables simultaneously to accelerate database analysis and documentation processes.
Instructions
Gets the detailed schema of multiple tables in parallel for improved performance.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tableNames | Yes | Array of table names to describe | |
| maxConcurrent | No | Maximum number of concurrent operations (default: 5) |
Implementation Reference
- src/tools/database.ts:513-544 (handler)Handler function for the describe-batch-tables tool, which calls describeBatchTables and formats the response.tools.set("describe-batch-tables", { name: "describe-batch-tables", description: "Gets the detailed schema of multiple tables in parallel for improved performance.", inputSchema: DescribeBatchTablesArgsSchema, handler: async (args: z.infer<typeof DescribeBatchTablesArgsSchema>) => { const { tableNames, maxConcurrent = 5 } = args; logger.info(`Describing batch of ${tableNames.length} tables with max concurrency ${maxConcurrent}`); try { const results = await describeBatchTables(tableNames, undefined, maxConcurrent); logger.info(`Batch description completed: ${results.filter(r => r.schema !== null).length} succeeded, ${results.filter(r => r.schema === null).length} failed`); return { content: [{ type: "text", text: formatForClaude(results) }] }; } catch (error) { const errorResponse = wrapError(error); logger.error(`Error describing batch tables: ${errorResponse.error} [${errorResponse.errorType || 'UNKNOWN'}]`); return { content: [{ type: "text", text: formatForClaude(errorResponse) }] }; } } });
- src/tools/database.ts:100-103 (schema)Zod input schema defining parameters for describe-batch-tables: array of table names and optional max concurrent.export const DescribeBatchTablesArgsSchema = z.object({ tableNames: z.array(z.string().min(1)).min(1).max(20).describe("Array of table names to describe"), maxConcurrent: z.number().int().min(1).max(10).optional().default(5).describe("Maximum number of concurrent operations (default: 5)") });
- src/tools/database.ts:513-544 (registration)Registration of the describe-batch-tables tool in the tools map, including name, description, schema, and handler.tools.set("describe-batch-tables", { name: "describe-batch-tables", description: "Gets the detailed schema of multiple tables in parallel for improved performance.", inputSchema: DescribeBatchTablesArgsSchema, handler: async (args: z.infer<typeof DescribeBatchTablesArgsSchema>) => { const { tableNames, maxConcurrent = 5 } = args; logger.info(`Describing batch of ${tableNames.length} tables with max concurrency ${maxConcurrent}`); try { const results = await describeBatchTables(tableNames, undefined, maxConcurrent); logger.info(`Batch description completed: ${results.filter(r => r.schema !== null).length} succeeded, ${results.filter(r => r.schema === null).length} failed`); return { content: [{ type: "text", text: formatForClaude(results) }] }; } catch (error) { const errorResponse = wrapError(error); logger.error(`Error describing batch tables: ${errorResponse.error} [${errorResponse.errorType || 'UNKNOWN'}]`); return { content: [{ type: "text", text: formatForClaude(errorResponse) }] }; } } });
- src/db/queries.ts:984-1069 (helper)Core helper function that implements batch table description by calling describeTable in parallel batches with concurrency control and validation.export const describeBatchTables = async ( tableNames: string[], config = DEFAULT_CONFIG, maxConcurrent: number = 5 ): Promise<Array<{tableName: string, schema: ColumnInfo[] | null, 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 describeBatchTables: ${globalConfig.database}`); config = globalConfig; } // Validate input if (!Array.isArray(tableNames) || tableNames.length === 0) { throw new FirebirdError( 'Invalid tableNames array: must be a non-empty array of table names', 'VALIDATION_ERROR' ); } // Limit the number of tables to prevent abuse const MAX_TABLES = 20; if (tableNames.length > MAX_TABLES) { throw new FirebirdError( `Too many tables: maximum allowed is ${MAX_TABLES}`, 'VALIDATION_ERROR' ); } // Validate each table name tableNames.forEach((tableName, index) => { if (!tableName || typeof tableName !== 'string') { throw new FirebirdError( `Invalid table name at index ${index}`, 'VALIDATION_ERROR' ); } if (!validateSql(tableName)) { throw new FirebirdError( `Potentially unsafe table name at index ${index}: ${tableName}`, 'SECURITY_ERROR' ); } }); logger.info(`Describing batch of ${tableNames.length} tables`); // Execute queries in batches to limit concurrency const results: Array<{tableName: string, schema: ColumnInfo[] | null, error?: string, errorType?: string}> = []; // Process tables in batches of maxConcurrent for (let i = 0; i < tableNames.length; i += maxConcurrent) { const batch = tableNames.slice(i, i + maxConcurrent); // Execute batch in parallel const batchPromises = batch.map(async (tableName, batchIndex) => { const tableIndex = i + batchIndex; try { logger.debug(`Describing table ${tableIndex + 1}/${tableNames.length}: ${tableName}`); const schema = await describeTable(tableName, config); return { tableName, schema }; } catch (error: any) { logger.error(`Error describing table ${tableIndex + 1}: ${error.message || error}`); // Format error response const errorType = error instanceof FirebirdError ? error.type : 'TABLE_DESCRIBE_ERROR'; const errorMessage = error instanceof Error ? error.message : String(error); return { tableName, schema: null, error: errorMessage, errorType }; } }); // Wait for all queries in this batch to complete const batchResults = await Promise.all(batchPromises); results.push(...batchResults); } logger.info(`Batch description completed: ${results.filter(r => r.schema !== null).length} succeeded, ${results.filter(r => r.schema === null).length} failed`); return results; };
- src/db/queries.ts:355-446 (helper)Fundamental helper function that describes a single table's schema using Firebird system tables, used by describeBatchTables.export const describeTable = async (tableName: string, config = DEFAULT_CONFIG): Promise<ColumnInfo[]> => { // Try to load config from global variable first const globalConfig = getGlobalConfig(); if (globalConfig && globalConfig.database) { logger.info(`Using global configuration for describeTable: ${globalConfig.database}`); config = globalConfig; } try { logger.info(`Obteniendo estructura de la tabla: ${tableName}`); if (!validateSql(tableName)) { throw new FirebirdError( `Nombre de tabla inválido: ${tableName}`, 'VALIDATION_ERROR' ); } // Consulta para obtener información de las columnas const sql = ` SELECT TRIM(rf.RDB$FIELD_NAME) as FIELD_NAME, CASE f.RDB$FIELD_TYPE WHEN 7 THEN 'SMALLINT' WHEN 8 THEN 'INTEGER' WHEN 10 THEN 'FLOAT' WHEN 12 THEN 'DATE' WHEN 13 THEN 'TIME' WHEN 14 THEN 'CHAR' WHEN 16 THEN 'BIGINT' WHEN 27 THEN 'DOUBLE PRECISION' WHEN 35 THEN 'TIMESTAMP' WHEN 37 THEN 'VARCHAR' WHEN 261 THEN 'BLOB' ELSE 'UNKNOWN' END as FIELD_TYPE, f.RDB$FIELD_LENGTH as FIELD_LENGTH, f.RDB$FIELD_SCALE as FIELD_SCALE, CASE rf.RDB$NULL_FLAG WHEN 1 THEN 0 ELSE 1 END as NULLABLE, rf.RDB$DEFAULT_SOURCE as DEFAULT_VALUE, CASE WHEN EXISTS ( SELECT 1 FROM RDB$RELATION_CONSTRAINTS rc JOIN RDB$INDEX_SEGMENTS isg ON rc.RDB$INDEX_NAME = isg.RDB$INDEX_NAME WHERE rc.RDB$RELATION_NAME = rf.RDB$RELATION_NAME AND rc.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' AND isg.RDB$FIELD_NAME = rf.RDB$FIELD_NAME ) THEN 1 ELSE 0 END as PRIMARY_KEY, CAST(rf.RDB$DESCRIPTION AS VARCHAR(500)) as DESCRIPTION FROM RDB$RELATION_FIELDS rf JOIN RDB$FIELDS f ON rf.RDB$FIELD_SOURCE = f.RDB$FIELD_NAME WHERE rf.RDB$RELATION_NAME = ? ORDER BY rf.RDB$FIELD_POSITION `; const columns = await executeQuery(sql, [tableName], config); if (columns.length === 0) { logger.warn(`No se encontraron columnas para la tabla: ${tableName}`); throw new FirebirdError( `No se encontraron columnas para la tabla: ${tableName}. Es posible que la tabla no exista.`, 'TABLE_NOT_FOUND' ); } logger.info(`Se encontraron ${columns.length} columnas para la tabla: ${tableName}`); return columns.map((col: any) => ({ field_name: col.FIELD_NAME, field_type: col.FIELD_TYPE, field_length: col.FIELD_LENGTH, field_scale: col.FIELD_SCALE !== null ? -1 * col.FIELD_SCALE : undefined, nullable: Boolean(col.NULLABLE), default_value: col.DEFAULT_VALUE, primary_key: Boolean(col.PRIMARY_KEY), description: col.DESCRIPTION || null })); } catch (error: any) { // Propagar el error si ya es un FirebirdError if (error instanceof FirebirdError) { throw error; } const errorMessage = `Error describiendo la tabla ${tableName}: ${error.message || error}`; logger.error(errorMessage); throw new FirebirdError(errorMessage, 'TABLE_DESCRIBE_ERROR', error); } };