@saptools/cf-hana 0.3.2 → 0.3.4

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.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/backup.ts","../src/errors.ts","../src/lob.ts","../src/result-preview.ts","../src/format.ts","../src/statements.ts","../src/builder.ts","../src/catalog.ts","../src/config.ts","../src/cf.ts","../src/credentials.ts","../src/driver/fake.ts","../src/driver/hdb.ts","../src/driver/index.ts","../src/history.ts","../src/safety.ts","../src/connection.ts","../src/pool.ts","../src/transaction.ts","../src/client.ts","../src/api.ts","../src/cli-results.ts","../src/result-inspect.ts","../src/result-store.ts","../src/metadata-cache.ts","../src/suggestions.ts"],"sourcesContent":["import { Command } from \"commander\";\n\nimport { connect } from \"./api.js\";\nimport { formatCurrentCfAppSelector, readCurrentCfTarget } from \"./cf.js\";\nimport { registerResultCommands } from \"./cli-results.js\";\nimport type { HanaClient } from \"./client.js\";\nimport {\n CLI_NAME,\n CLI_VERSION,\n DEFAULT_AUTO_LIMIT,\n DEFAULT_CELL_LIMIT,\n MAX_CELL_LIMIT,\n} from \"./config.js\";\nimport { CfHanaError, QueryError, databaseCode, errorMessage } from \"./errors.js\";\nimport { formatCompactCsv, formatResult, formatTable } from \"./format.js\";\nimport { loadCatalogObjectsWithCache, toMetadataCacheScope } from \"./metadata-cache.js\";\nimport { createResultSession } from \"./result-store.js\";\nimport { classifyStatement } from \"./statements.js\";\nimport {\n extractInvalidColumnNameFromError,\n extractMissingObjectName,\n extractMissingObjectNameFromError,\n formatColumnSuggestions,\n formatSuggestions,\n isInvalidCatalogObjectError,\n rankCatalogSuggestions,\n rankNameSuggestions,\n} from \"./suggestions.js\";\nimport type {\n ConnectOptions,\n DbUserRole,\n HanaClientInfo,\n OutputFormat,\n QueryResult,\n QueryRow,\n} from \"./types.js\";\n\ninterface ConnectionCliOptions {\n readonly refresh: boolean;\n readonly role: string;\n readonly binding?: string;\n readonly bindingIndex?: number;\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n readonly timeout?: number;\n readonly limit?: number;\n readonly autoLimit: boolean;\n readonly refreshMetadata: boolean;\n}\n\ninterface FormattedCliOptions extends ConnectionCliOptions {\n readonly format: string;\n}\n\ninterface QueryCliOptions extends ConnectionCliOptions {\n readonly param?: readonly string[];\n readonly save: boolean;\n readonly cellLimit?: number;\n readonly resultTtlMinutes?: number;\n}\n\nfunction print(text: string): void {\n process.stdout.write(`${text}\\n`);\n}\n\nfunction fail(message: string): never {\n process.stderr.write(`${CLI_NAME}: ${message}\\n`);\n process.exit(1);\n}\n\nfunction parseIntOption(value: string): number {\n const trimmed = value.trim();\n if (!/^-?\\d+$/.test(trimmed)) {\n throw new CfHanaError(\"CONFIG\", `Expected an integer but received \"${value}\"`);\n }\n const parsed = Number(trimmed);\n if (!Number.isSafeInteger(parsed)) {\n throw new CfHanaError(\"CONFIG\", `Expected a safe integer but received \"${value}\"`);\n }\n return parsed;\n}\n\nfunction assertPositiveOption(name: string, value: number | undefined): void {\n if (value !== undefined && value <= 0) {\n throw new CfHanaError(\"CONFIG\", `${name} must be a positive integer`);\n }\n}\n\nfunction assertNonNegativeOption(name: string, value: number | undefined): void {\n if (value !== undefined && value < 0) {\n throw new CfHanaError(\"CONFIG\", `${name} must be a non-negative integer`);\n }\n}\n\nfunction collectParam(value: string, previous: readonly string[]): readonly string[] {\n return [...previous, value];\n}\n\nfunction parseRole(role: string): DbUserRole {\n if (role === \"runtime\" || role === \"hdi\") {\n return role;\n }\n throw new CfHanaError(\"CONFIG\", `Invalid --role \"${role}\" (expected runtime or hdi)`);\n}\n\nfunction parseFormat(format: string): OutputFormat {\n if (format === \"table\" || format === \"json\" || format === \"csv\") {\n return format;\n }\n throw new CfHanaError(\"CONFIG\", `Invalid --format \"${format}\" (expected table, json, or csv)`);\n}\n\nfunction parseQualifiedName(value: string): { readonly schema: string; readonly table: string } {\n const dot = value.indexOf(\".\");\n if (dot <= 0 || dot >= value.length - 1) {\n throw new CfHanaError(\"CONFIG\", `Expected schema.table but received \"${value}\"`);\n }\n return { schema: value.slice(0, dot), table: value.slice(dot + 1) };\n}\n\nasync function resolveSelectorArgument(selector: string): Promise<string> {\n if (selector.includes(\"/\")) {\n return selector;\n }\n const current = await readCurrentCfTarget().catch((error: unknown) => {\n throw new CfHanaError(\n \"CONFIG\",\n \"No current CF target found. Run `cf target -o <org> -s <space>` or pass a full region/org/space/app selector.\",\n { cause: error },\n );\n });\n if (current === undefined) {\n throw new CfHanaError(\n \"CONFIG\",\n \"No current CF target found. Run `cf target -o <org> -s <space>` or pass a full region/org/space/app selector.\",\n );\n }\n return formatCurrentCfAppSelector(current, selector);\n}\n\nfunction toConnectOptions(opts: ConnectionCliOptions): ConnectOptions {\n assertPositiveOption(\"--limit\", opts.limit);\n assertPositiveOption(\"--timeout\", opts.timeout);\n assertNonNegativeOption(\"--binding-index\", opts.bindingIndex);\n\n return {\n refresh: opts.refresh,\n role: parseRole(opts.role),\n readOnly: opts.readOnly,\n allowDestructive: opts.allowDestructive,\n autoLimit: opts.autoLimit ? (opts.limit ?? DEFAULT_AUTO_LIMIT) : false,\n ...(opts.binding === undefined ? {} : { bindingName: opts.binding }),\n ...(opts.bindingIndex === undefined ? {} : { bindingIndex: opts.bindingIndex }),\n ...(opts.timeout === undefined\n ? {}\n : { queryTimeoutMs: opts.timeout, connectTimeoutMs: opts.timeout }),\n };\n}\n\nfunction resolveCellLimit(value: number | undefined): number {\n const limit = value ?? DEFAULT_CELL_LIMIT;\n assertPositiveOption(\"--cell-limit\", limit);\n if (limit > MAX_CELL_LIMIT) {\n throw new CfHanaError(\"CONFIG\", `--cell-limit must be at most ${String(MAX_CELL_LIMIT)}`);\n }\n return limit;\n}\n\nfunction assertQueryOptions(sql: string, opts: QueryCliOptions): void {\n resolveCellLimit(opts.cellLimit);\n assertPositiveOption(\"--result-ttl-minutes\", opts.resultTtlMinutes);\n if (opts.save && classifyStatement(sql) !== \"select\") {\n throw new CfHanaError(\"CONFIG\", \"--save is only available for SELECT/WITH statements\");\n }\n}\n\nfunction rowsToResult(rows: readonly QueryRow[]): QueryResult {\n const first = rows[0];\n const columns =\n first === undefined\n ? []\n : Object.keys(first).map((name) => ({ name, typeName: \"\" }));\n return {\n rows,\n columns,\n rowCount: rows.length,\n statement: \"select\",\n truncated: false,\n elapsedMs: 0,\n };\n}\n\nfunction formatInfo(info: HanaClientInfo): string {\n return [\n `selector ${info.selector}`,\n `app ${info.appName}`,\n `host ${info.host}`,\n `schema ${info.schema}`,\n `role ${info.role}`,\n `driver ${info.driver}`,\n `credential source ${info.credentialSource}`,\n ].join(\"\\n\");\n}\n\nfunction withConnectionOptions(command: Command): Command {\n return command\n .option(\"--refresh\", \"bypass cached credentials and fetch them live\", false)\n .option(\"--role <role>\", \"HANA user role: runtime or hdi\", \"runtime\")\n .option(\"--binding <name>\", \"select a HANA binding by service name\")\n .option(\"--binding-index <n>\", \"select a HANA binding by index\", parseIntOption)\n .option(\"--read-only\", \"block every DML and DDL statement\", false)\n .option(\"--allow-destructive\", \"permit destructive statements\", false)\n .option(\"--timeout <ms>\", \"connection and query timeout in milliseconds\", parseIntOption)\n .option(\"--limit <n>\", \"row cap auto-applied to bare SELECT statements\", parseIntOption)\n .option(\"--no-auto-limit\", \"disable the automatic SELECT row cap\")\n .option(\"--refresh-metadata\", \"bypass the 30-minute table/view metadata suggestion cache\", false);\n}\n\nfunction withFormattedConnectionOptions(command: Command): Command {\n return withConnectionOptions(command).option(\n \"--format <format>\",\n \"output format: table, json, or csv\",\n \"table\",\n );\n}\n\nasync function loadSuggestionCatalogObjects(\n client: HanaClient,\n refresh: boolean,\n): Promise<Awaited<ReturnType<HanaClient[\"listCatalogObjects\"]>>> {\n try {\n return await loadCatalogObjectsWithCache(\n toMetadataCacheScope(client.info),\n refresh,\n async () => await client.listCatalogObjects(client.info.schema),\n );\n } catch {\n // Retry one direct catalog read for transient metadata lookup failures. The\n // retry intentionally bypasses cache writes so another cache failure cannot\n // hide useful suggestions or the original query error.\n return await client.listCatalogObjects(client.info.schema);\n }\n}\n\nfunction isLobSortOrGroupError(error: unknown): boolean {\n const code = databaseCode(error);\n if (code !== 266 && code !== 274) {\n return false;\n }\n return (\n error instanceof QueryError &&\n /LOB type is not allowed in (?:ORDER BY|GROUP BY) clause/i.test(error.message)\n );\n}\n\nfunction printLobSortOrGroupHint(): void {\n const lines = [\n `${CLI_NAME}: HANA cannot ORDER BY or GROUP BY NCLOB/CLOB/BLOB columns directly.`,\n `${CLI_NAME}: Remove the LOB column from ORDER BY/GROUP BY or wrap it as TO_VARCHAR(<column>).`,\n ];\n process.stderr.write(`${lines.join(\"\\n\")}\\n`);\n}\n\nasync function printColumnSuggestions(\n error: unknown,\n client: HanaClient,\n sql: string,\n): Promise<void> {\n if (databaseCode(error) !== 260) {\n return;\n }\n const columnName = extractInvalidColumnNameFromError(error);\n const tableName = extractMissingObjectName(sql);\n if (columnName === undefined || tableName === undefined) {\n return;\n }\n\n try {\n const columns = await client.listColumns(\n tableName.schema ?? client.info.schema,\n tableName.name,\n );\n const text = formatColumnSuggestions(rankNameSuggestions(columnName, columns));\n if (text !== undefined) {\n process.stderr.write(`${text}\\n`);\n }\n } catch {\n // Column metadata failures are intentionally silent: stderr should stay\n // focused on the original query failure unless reliable suggestions exist.\n }\n}\n\nasync function printCatalogObjectSuggestions(\n error: unknown,\n client: HanaClient,\n sql: string,\n refresh: boolean,\n): Promise<void> {\n if (!isInvalidCatalogObjectError(error)) {\n return;\n }\n const requested = extractMissingObjectNameFromError(error) ?? extractMissingObjectName(sql);\n if (requested === undefined) {\n return;\n }\n try {\n const objects = await loadSuggestionCatalogObjects(client, refresh);\n const text = formatSuggestions(rankCatalogSuggestions(requested, objects));\n if (text !== undefined) {\n process.stderr.write(`${text}\\n`);\n }\n } catch {\n // Metadata lookup failures are intentionally silent: stderr should stay\n // focused on the original query failure unless reliable suggestions exist.\n }\n}\n\nasync function enrichAndRethrowQueryError(\n error: unknown,\n client: HanaClient,\n sql: string,\n refresh: boolean,\n): Promise<never> {\n if (isLobSortOrGroupError(error)) {\n printLobSortOrGroupHint();\n throw error;\n }\n\n await printColumnSuggestions(error, client, sql);\n await printCatalogObjectSuggestions(error, client, sql, refresh);\n throw error;\n}\n\nasync function runQuery(selector: string, sql: string, command: Command): Promise<void> {\n const opts = command.opts<QueryCliOptions>();\n assertQueryOptions(sql, opts);\n const cellLimit = resolveCellLimit(opts.cellLimit);\n const client = await connect(await resolveSelectorArgument(selector), toConnectOptions(opts));\n try {\n const params = opts.param ?? [];\n let backup: Awaited<ReturnType<HanaClient[\"backupWriteStatement\"]>>;\n try {\n backup = await client.backupWriteStatement(sql, params);\n } catch (error) {\n await enrichAndRethrowQueryError(error, client, sql, opts.refreshMetadata || opts.refresh);\n }\n if (backup !== undefined) {\n process.stderr.write(`${CLI_NAME}: backup saved to ${backup.directory}\\n`);\n }\n const result = await client\n .query(sql, params)\n .catch(async (error: unknown): Promise<QueryResult> => {\n return await enrichAndRethrowQueryError(\n error,\n client,\n sql,\n opts.refreshMetadata || opts.refresh,\n );\n });\n if (result.statement === \"select\") {\n const compact = formatCompactCsv(result, cellLimit);\n if (opts.save) {\n const session = await createResultSession({\n result,\n info: client.info,\n ...(opts.resultTtlMinutes === undefined ? {} : { ttlMinutes: opts.resultTtlMinutes }),\n });\n print(`ref=${session.ref}`);\n }\n print(compact.text);\n if (result.truncated) {\n process.stderr.write(`${CLI_NAME}: row limit reached; rerun with --limit for more rows\\n`);\n }\n if (compact.truncatedCells > 0) {\n process.stderr.write(\n `${CLI_NAME}: compacted ${String(compact.truncatedCells)} cell(s); ` +\n \"use --save to inspect exact values by ref\\n\",\n );\n }\n return;\n }\n print(formatTable(result));\n } finally {\n await client.close();\n }\n}\n\nasync function runTables(\n selector: string,\n schema: string | undefined,\n command: Command,\n): Promise<void> {\n const opts = command.opts<FormattedCliOptions>();\n const client = await connect(await resolveSelectorArgument(selector), toConnectOptions(opts));\n try {\n const tables = await client.listTables(schema ?? client.info.schema);\n const rows: readonly QueryRow[] = tables.map((table) => ({\n SCHEMA: table.schema,\n TABLE: table.name,\n TYPE: table.type,\n }));\n print(formatResult(rowsToResult(rows), parseFormat(opts.format)));\n } finally {\n await client.close();\n }\n}\n\nasync function runColumns(selector: string, target: string, command: Command): Promise<void> {\n const opts = command.opts<FormattedCliOptions>();\n const { schema, table } = parseQualifiedName(target);\n const client = await connect(await resolveSelectorArgument(selector), toConnectOptions(opts));\n try {\n const columns = await client.listColumns(schema, table);\n const rows: readonly QueryRow[] = columns.map((column) => ({\n COLUMN: column.name,\n TYPE: column.dataType,\n LENGTH: column.length ?? null,\n NULLABLE: column.nullable,\n POSITION: column.position,\n }));\n print(formatResult(rowsToResult(rows), parseFormat(opts.format)));\n } finally {\n await client.close();\n }\n}\n\nasync function runCount(selector: string, target: string, command: Command): Promise<void> {\n const opts = command.opts<ConnectionCliOptions>();\n const { schema, table } = parseQualifiedName(target);\n const client = await connect(await resolveSelectorArgument(selector), toConnectOptions(opts));\n try {\n const total = await client.count({ schema, table });\n print(String(total));\n } finally {\n await client.close();\n }\n}\n\nasync function runPing(selector: string, command: Command): Promise<void> {\n const opts = command.opts<ConnectionCliOptions>();\n const client = await connect(await resolveSelectorArgument(selector), toConnectOptions(opts));\n try {\n const started = Date.now();\n await client.query(\"SELECT 1 FROM DUMMY\");\n print(\n `OK ${client.info.host} schema=${client.info.schema} ` +\n `${String(Date.now() - started)}ms`,\n );\n } finally {\n await client.close();\n }\n}\n\nasync function runInfo(selector: string, command: Command): Promise<void> {\n const opts = command.opts<ConnectionCliOptions>();\n const client = await connect(await resolveSelectorArgument(selector), toConnectOptions(opts));\n try {\n print(formatInfo(client.info));\n } finally {\n await client.close();\n }\n}\n\nfunction buildProgram(): Command {\n const program = new Command();\n program\n .name(CLI_NAME)\n .description(\"Run SQL against SAP HANA Cloud databases bound to a Cloud Foundry app\")\n .version(CLI_VERSION);\n\n withConnectionOptions(\n program\n .command(\"query <selector> <sql>\")\n .description(\"run a single SQL statement\")\n .option(\"--param <value>\", \"bind a SQL parameter (repeatable)\", collectParam, [])\n .option(\"--save\", \"save exact returned rows for follow-up inspection\", false)\n .option(\"--cell-limit <n>\", \"maximum visible characters per data cell\", parseIntOption)\n .option(\n \"--result-ttl-minutes <n>\",\n \"minutes before a saved result expires\",\n parseIntOption,\n ),\n ).action(async (selector: string, sql: string, _options: unknown, command: Command) => {\n await runQuery(selector, sql, command);\n });\n\n withFormattedConnectionOptions(\n program.command(\"tables <selector> [schema]\").description(\"list tables in a schema\"),\n ).action(\n async (selector: string, schema: string | undefined, _options: unknown, command: Command) => {\n await runTables(selector, schema, command);\n },\n );\n\n withFormattedConnectionOptions(\n program\n .command(\"columns <selector> <schema.table>\")\n .description(\"list the columns of a table\"),\n ).action(async (selector: string, target: string, _options: unknown, command: Command) => {\n await runColumns(selector, target, command);\n });\n\n withConnectionOptions(\n program.command(\"count <selector> <schema.table>\").description(\"count rows in a table\"),\n ).action(async (selector: string, target: string, _options: unknown, command: Command) => {\n await runCount(selector, target, command);\n });\n\n withConnectionOptions(\n program.command(\"ping <selector>\").description(\"connect and measure round-trip latency\"),\n ).action(async (selector: string, _options: unknown, command: Command) => {\n await runPing(selector, command);\n });\n\n withConnectionOptions(\n program.command(\"info <selector>\").description(\"print the resolved connection metadata\"),\n ).action(async (selector: string, _options: unknown, command: Command) => {\n await runInfo(selector, command);\n });\n\n registerResultCommands(program);\n\n return program;\n}\n\ntry {\n await buildProgram().parseAsync(process.argv);\n} catch (error) {\n fail(errorMessage(error));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { QueryError } from \"./errors.js\";\nimport { formatCsv } from \"./format.js\";\nimport { assertParamArity, countPlaceholders, firstKeyword } from \"./statements.js\";\nimport type { QueryResult, SqlParam } from \"./types.js\";\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst BACKUPS_DIR_NAME = \"backups\";\n\nexport type WriteBackupOperation = \"update\" | \"upsert\" | \"delete\";\n\nexport interface WriteBackupPlan {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly selectSql: string;\n readonly selectParams: readonly SqlParam[];\n}\n\nexport interface SqlBackupWriteInput {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly result: QueryResult;\n readonly selector?: string;\n}\n\nexport interface SqlBackupWriteOptions {\n readonly now?: Date;\n readonly saptoolsRoot?: string;\n}\n\nexport interface SqlBackupRecord {\n readonly directory: string;\n readonly statementPath: string;\n readonly backupPath: string;\n readonly metadataPath: string;\n readonly rowCount: number;\n}\n\ntype TopLevelKeyword = \"UPDATE\" | \"UPSERT\" | \"DELETE\" | \"SET\" | \"FROM\" | \"VALUES\" | \"WHERE\";\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction trimStatementSql(sql: string): string {\n return sql.trim().replace(/;+\\s*$/, \"\").trim();\n}\n\nfunction isIdentifierChar(char: string | undefined): boolean {\n return char !== undefined && /[A-Za-z0-9_$#]/.test(char);\n}\n\nfunction skipQuotedText(sql: string, index: number): number {\n const quote = sql[index];\n let cursor = index + 1;\n while (cursor < sql.length) {\n if (sql[cursor] === quote) {\n if (sql[cursor + 1] === quote) {\n cursor += 2;\n continue;\n }\n return cursor + 1;\n }\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipLineComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && sql[cursor] !== \"\\n\") {\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipBlockComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && !(sql[cursor] === \"*\" && sql[cursor + 1] === \"/\")) {\n cursor += 1;\n }\n return Math.min(cursor + 2, sql.length);\n}\n\nfunction skipNonCode(sql: string, index: number): number | undefined {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n return skipQuotedText(sql, index);\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n return skipLineComment(sql, index);\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n return skipBlockComment(sql, index);\n }\n return undefined;\n}\n\nfunction keywordMatches(sql: string, index: number, keyword: TopLevelKeyword): boolean {\n const end = index + keyword.length;\n return (\n sql.slice(index, end).toUpperCase() === keyword &&\n !isIdentifierChar(sql[index - 1]) &&\n !isIdentifierChar(sql[end])\n );\n}\n\nfunction findTopLevelKeyword(\n sql: string,\n keyword: TopLevelKeyword,\n startIndex = 0,\n): number | undefined {\n let index = startIndex;\n let depth = 0;\n while (index < sql.length) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n\n const char = sql[index];\n if (char === \"(\") {\n depth += 1;\n } else if (char === \")\" && depth > 0) {\n depth -= 1;\n } else if (depth === 0 && keywordMatches(sql, index, keyword)) {\n return index;\n }\n index += 1;\n }\n return undefined;\n}\n\nfunction findTopLevelChar(\n sql: string,\n target: string,\n startIndex: number,\n endIndex: number,\n): number | undefined {\n let index = startIndex;\n let depth = 0;\n while (index < endIndex) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n\n const char = sql[index];\n if (char === target && depth === 0) {\n return index;\n }\n if (char === \"(\") {\n depth += 1;\n } else if (char === \")\" && depth > 0) {\n depth -= 1;\n }\n index += 1;\n }\n return undefined;\n}\n\nfunction selectParamsAfterWhere(\n statementSql: string,\n whereIndex: number,\n params: readonly SqlParam[],\n): readonly SqlParam[] {\n return params.slice(countPlaceholders(statementSql.slice(0, whereIndex)));\n}\n\nfunction buildSelectPlan(\n operation: WriteBackupOperation,\n statementSql: string,\n targetSql: string,\n whereIndex: number | undefined,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const target = targetSql.trim();\n if (target.length === 0) {\n throw new QueryError(`${operation.toUpperCase()} backup requires a target table`);\n }\n if (whereIndex === undefined) {\n return { operation, statementSql, selectSql: `SELECT * FROM ${target}`, selectParams: [] };\n }\n\n const whereSql = statementSql.slice(whereIndex + \"WHERE\".length).trim();\n if (whereSql.length === 0) {\n throw new QueryError(`${operation.toUpperCase()} backup requires a non-empty WHERE clause`);\n }\n return {\n operation,\n statementSql,\n selectSql: `SELECT * FROM ${target} WHERE ${whereSql}`,\n selectParams: selectParamsAfterWhere(statementSql, whereIndex, params),\n };\n}\n\nfunction buildUpdateBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const updateIndex = findTopLevelKeyword(statementSql, \"UPDATE\");\n const setIndex =\n updateIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"SET\", updateIndex + \"UPDATE\".length);\n if (updateIndex === undefined || setIndex === undefined) {\n throw new QueryError(\"UPDATE backup requires UPDATE <target> SET syntax\");\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", setIndex + \"SET\".length);\n return buildSelectPlan(\n \"update\",\n statementSql,\n statementSql.slice(updateIndex + \"UPDATE\".length, setIndex),\n whereIndex,\n params,\n );\n}\n\nfunction buildUpsertBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const upsertIndex = findTopLevelKeyword(statementSql, \"UPSERT\");\n const valuesIndex =\n upsertIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"VALUES\", upsertIndex + \"UPSERT\".length);\n if (upsertIndex === undefined || valuesIndex === undefined) {\n throw new QueryError(\"UPSERT backup requires UPSERT <target> VALUES syntax\");\n }\n\n const targetStart = upsertIndex + \"UPSERT\".length;\n const columnListIndex = findTopLevelChar(statementSql, \"(\", targetStart, valuesIndex);\n const targetEnd = columnListIndex ?? valuesIndex;\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", valuesIndex + \"VALUES\".length);\n return buildSelectPlan(\n \"upsert\",\n statementSql,\n statementSql.slice(targetStart, targetEnd),\n whereIndex,\n params,\n );\n}\n\nfunction buildDeleteBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const deleteIndex = findTopLevelKeyword(statementSql, \"DELETE\");\n const fromIndex =\n deleteIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"FROM\", deleteIndex + \"DELETE\".length);\n if (deleteIndex === undefined || fromIndex === undefined) {\n throw new QueryError(\"DELETE backup requires DELETE FROM <target> syntax\");\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", fromIndex + \"FROM\".length);\n const targetEnd = whereIndex ?? statementSql.length;\n return buildSelectPlan(\n \"delete\",\n statementSql,\n statementSql.slice(fromIndex + \"FROM\".length, targetEnd),\n whereIndex,\n params,\n );\n}\n\nfunction backupTimestamp(now: Date): string {\n return now.toISOString().replace(/:/g, \"\").replace(\".\", \"\");\n}\n\nfunction backupMonth(now: Date): string {\n const year = String(now.getUTCFullYear());\n const month = String(now.getUTCMonth() + 1).padStart(2, \"0\");\n return `${year}${month}`;\n}\n\nfunction sanitizePathPart(value: string | undefined): string {\n const trimmed = value?.trim() ?? \"\";\n const normalized = trimmed\n .replace(/[^A-Za-z0-9._-]+/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n return normalized.length > 0 ? normalized : \"unknown-target\";\n}\n\nfunction backupBaseName(input: SqlBackupWriteInput, now: Date): string {\n return [sanitizePathPart(input.selector), input.operation, backupTimestamp(now)].join(\"-\");\n}\n\nexport function cfHanaBackupRoot(saptoolsRoot?: string): string {\n return join(saptoolsRoot ?? defaultSaptoolsRoot(), CF_HANA_DIR_NAME, BACKUPS_DIR_NAME);\n}\n\nexport function buildWriteBackupPlan(\n sql: string,\n params: readonly SqlParam[] = [],\n): WriteBackupPlan | undefined {\n const statementSql = trimStatementSql(sql);\n const keyword = firstKeyword(statementSql);\n if (keyword !== \"UPDATE\" && keyword !== \"UPSERT\" && keyword !== \"DELETE\") {\n return undefined;\n }\n\n assertParamArity(statementSql, params);\n if (keyword === \"UPDATE\") {\n return buildUpdateBackupPlan(statementSql, params);\n }\n if (keyword === \"UPSERT\") {\n return buildUpsertBackupPlan(statementSql, params);\n }\n return buildDeleteBackupPlan(statementSql, params);\n}\n\nexport async function writeSqlBackup(\n input: SqlBackupWriteInput,\n options: SqlBackupWriteOptions = {},\n): Promise<SqlBackupRecord> {\n const now = options.now ?? new Date();\n const directory = join(cfHanaBackupRoot(options.saptoolsRoot), backupMonth(now));\n const baseName = backupBaseName(input, now);\n const statementPath = join(directory, `${baseName}.statement.sql`);\n const backupPath = join(directory, `${baseName}.sql`);\n const metadataPath = join(directory, `${baseName}.json`);\n const metadata = {\n selector: input.selector ?? null,\n operation: input.operation,\n statementPath,\n backupPath,\n rowCount: input.result.rowCount,\n createdAt: now.toISOString(),\n };\n\n await mkdir(directory, { recursive: true, mode: 0o700 });\n await Promise.all([\n writeFile(statementPath, `${input.statementSql}\\n`, { encoding: \"utf8\", mode: 0o600 }),\n writeFile(backupPath, formatCsv(input.result), { encoding: \"utf8\", mode: 0o600 }),\n writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n }),\n ]);\n\n return {\n directory,\n statementPath,\n backupPath,\n metadataPath,\n rowCount: input.result.rowCount,\n };\n}\n","export type CfHanaErrorCode =\n | \"CONFIG\"\n | \"CREDENTIALS_NOT_FOUND\"\n | \"AMBIGUOUS_BINDING\"\n | \"CONNECTION\"\n | \"QUERY\"\n | \"READ_ONLY_VIOLATION\"\n | \"DESTRUCTIVE_BLOCKED\"\n | \"TIMEOUT\"\n | \"POOL_CLOSED\";\n\nexport interface CfHanaErrorOptions {\n readonly cause?: unknown;\n}\n\nexport interface QueryErrorOptions extends CfHanaErrorOptions {\n readonly sqlState?: string;\n readonly databaseCode?: number;\n}\n\n/** Base error for every failure surfaced by `@saptools/cf-hana`. */\nexport class CfHanaError extends Error {\n readonly code: CfHanaErrorCode;\n\n constructor(code: CfHanaErrorCode, message: string, options?: CfHanaErrorOptions) {\n super(message, options);\n this.name = \"CfHanaError\";\n this.code = code;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** No HANA credentials could be resolved for the requested selector. */\nexport class CredentialsNotFoundError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"CREDENTIALS_NOT_FOUND\", message, options);\n this.name = \"CredentialsNotFoundError\";\n }\n}\n\n/** A SQL statement failed on the HANA server. */\nexport class QueryError extends CfHanaError {\n readonly sqlState: string | undefined;\n readonly databaseCode: number | undefined;\n\n constructor(message: string, options?: QueryErrorOptions) {\n super(\"QUERY\", message, options);\n this.name = \"QueryError\";\n this.sqlState = options?.sqlState;\n this.databaseCode = options?.databaseCode;\n }\n}\n\nfunction isDatabaseErrorShape(error: unknown): error is { readonly code?: unknown } {\n return typeof error === \"object\" && error !== null && \"code\" in error;\n}\n\nfunction safeDatabaseCode(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isSafeInteger(value)) {\n return value;\n }\n if (typeof value !== \"string\" || !/^\\d+$/.test(value)) {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) ? parsed : undefined;\n}\n\n/** Extract a numeric HANA database error code from wrapped query failures. */\nexport function databaseCode(error: unknown): number | undefined {\n if (error instanceof QueryError) {\n return error.databaseCode ?? databaseCode(error.cause);\n }\n if (isDatabaseErrorShape(error)) {\n return safeDatabaseCode(error.code);\n }\n return undefined;\n}\n\n/** A write/DDL statement was issued on a read-only client. */\nexport class ReadOnlyViolationError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"READ_ONLY_VIOLATION\", message, options);\n this.name = \"ReadOnlyViolationError\";\n }\n}\n\n/** A destructive statement was blocked because it was not explicitly allowed. */\nexport class DestructiveStatementError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"DESTRUCTIVE_BLOCKED\", message, options);\n this.name = \"DestructiveStatementError\";\n }\n}\n\n/** Narrow an unknown thrown value to a human-readable message. */\nexport function errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n return String(error);\n}\n","/** HANA column types whose Buffer values represent text rather than binary bytes. */\nconst TEXT_LOB_TYPES = new Set([\"CLOB\", \"NCLOB\"]);\n\nfunction normalizeTypeName(typeName: string | undefined): string {\n return typeName?.trim().toUpperCase() ?? \"\";\n}\n\nexport function isTextLobType(typeName: string | undefined): boolean {\n return TEXT_LOB_TYPES.has(normalizeTypeName(typeName));\n}\n","import { isTextLobType } from \"./lob.js\";\nimport type { SqlParam } from \"./types.js\";\n\nexport type PreviewUnit = \"chars\" | \"bytes\";\n\nexport interface CellPreview {\n readonly text: string;\n readonly truncated: boolean;\n readonly originalLength: number;\n readonly unit: PreviewUnit;\n}\n\nfunction normalizePreviewChar(value: string): string {\n return value === \"\\r\" || value === \"\\n\" || value === \"\\t\" ? \" \" : value;\n}\n\nfunction previewText(value: string, limit: number): CellPreview {\n let originalLength = 0;\n let text = \"\";\n for (const char of value) {\n if (originalLength < limit) {\n text += normalizePreviewChar(char);\n }\n originalLength += 1;\n }\n return {\n text,\n truncated: originalLength > limit,\n originalLength,\n unit: \"chars\",\n };\n}\n\nfunction previewBuffer(value: Buffer, limit: number): CellPreview {\n const fullLength = 2 + value.length * 2;\n const visibleBytes = Math.max(0, Math.floor((limit - 2) / 2));\n const hex = value.subarray(0, visibleBytes).toString(\"hex\");\n return {\n text: `0x${hex}`.slice(0, limit),\n truncated: fullLength > limit,\n originalLength: value.length,\n unit: \"bytes\",\n };\n}\n\nfunction scalarText(value: Exclude<SqlParam, string | Buffer | null>): string {\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n return value.toString();\n}\n\n/** Produce a bounded, single-line representation of one result cell. */\nexport function previewCell(value: SqlParam, limit: number, typeName?: string): CellPreview {\n if (value === null) {\n return { text: \"\", truncated: false, originalLength: 0, unit: \"chars\" };\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(typeName)\n ? previewText(value.toString(\"utf8\"), limit)\n : previewBuffer(value, limit);\n }\n if (typeof value === \"string\") {\n return previewText(value, limit);\n }\n return previewText(scalarText(value), limit);\n}\n","import { isTextLobType } from \"./lob.js\";\nimport { previewCell } from \"./result-preview.js\";\nimport type { OutputFormat, QueryResult, QueryResultColumn, SqlParam } from \"./types.js\";\n\ntype JsonCell = string | number | boolean | null;\n\nfunction cellText(value: SqlParam, nullText: string, column?: QueryResultColumn): string {\n if (value === null) {\n return nullText;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(column?.typeName)\n ? value.toString(\"utf8\")\n : `0x${value.toString(\"hex\")}`;\n }\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n return typeof value === \"number\" ? value.toString() : value;\n}\n\nfunction serializeCell(value: SqlParam, column?: QueryResultColumn): JsonCell {\n if (value === null) {\n return null;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(column?.typeName)\n ? value.toString(\"utf8\")\n : `0x${value.toString(\"hex\")}`;\n }\n return value;\n}\n\nfunction csvEscape(text: string): string {\n if (/[\",\\r\\n]/.test(text)) {\n return `\"${text.replace(/\"/g, '\"\"')}\"`;\n }\n return text;\n}\n\nexport interface CompactCsv {\n readonly text: string;\n readonly truncatedCells: number;\n}\n\n/** Render a result as an aligned ASCII table. */\nexport function formatTable(result: QueryResult): string {\n if (result.columns.length === 0) {\n return `(${String(result.rowCount)} row(s) affected)`;\n }\n\n const headers = result.columns.map((column) => column.name);\n const rows = result.rows.map((row) =>\n result.columns.map((column) => cellText(row[column.name] ?? null, \"NULL\", column)),\n );\n const widths = headers.map((header, index) => {\n const widest = rows.reduce(\n (max, cells) => Math.max(max, (cells[index] ?? \"\").length),\n header.length,\n );\n return widest;\n });\n\n const renderRow = (cells: readonly string[]): string =>\n cells.map((cell, index) => cell.padEnd(widths[index] ?? 0)).join(\" | \");\n const separator = widths.map((width) => \"-\".repeat(width)).join(\"-+-\");\n const body = rows.map((cells) => renderRow(cells));\n\n return [renderRow(headers), separator, ...body].join(\"\\n\");\n}\n\n/** Render a result's rows as pretty-printed JSON. */\nexport function formatJson(result: QueryResult): string {\n const rows = result.rows.map((row) => {\n const serialized: Record<string, JsonCell> = {};\n for (const [key, value] of Object.entries(row)) {\n const column = result.columns.find((item) => item.name === key);\n serialized[key] = serializeCell(value, column);\n }\n return serialized;\n });\n return JSON.stringify(rows, null, 2);\n}\n\n/** Render a result as RFC 4180 CSV. */\nexport function formatCsv(result: QueryResult): string {\n const headers = result.columns.map((column) => column.name);\n const lines = [headers.map((header) => csvEscape(header)).join(\",\")];\n for (const row of result.rows) {\n lines.push(\n result.columns\n .map((column) => csvEscape(cellText(row[column.name] ?? null, \"\", column)))\n .join(\",\"),\n );\n }\n return lines.join(\"\\r\\n\");\n}\n\n/** Render bounded CSV for CLI SELECT output without mutating the source result. */\nexport function formatCompactCsv(result: QueryResult, cellLimit: number): CompactCsv {\n const headers = result.columns.map((column) => column.name);\n const lines = [headers.map((header) => csvEscape(header)).join(\",\")];\n let truncatedCells = 0;\n for (const row of result.rows) {\n const cells = result.columns.map((column) => {\n const preview = previewCell(row[column.name] ?? null, cellLimit, column.typeName);\n if (preview.truncated) {\n truncatedCells += 1;\n }\n return csvEscape(preview.text);\n });\n lines.push(cells.join(\",\"));\n }\n return { text: lines.join(\"\\r\\n\"), truncatedCells };\n}\n\n/** Render a query result in the requested output format. */\nexport function formatResult(result: QueryResult, format: OutputFormat): string {\n switch (format) {\n case \"table\":\n return formatTable(result);\n case \"json\":\n return formatJson(result);\n case \"csv\":\n return formatCsv(result);\n }\n}\n","import { QueryError } from \"./errors.js\";\nimport type { SqlParam, StatementKind } from \"./types.js\";\n\nconst LEADING_NOISE = /^(?:\\s|--[^\\n]*\\n?|\\/\\*[\\s\\S]*?\\*\\/)+/;\n\nconst SELECT_KEYWORDS = new Set([\"SELECT\", \"WITH\"]);\nconst DML_KEYWORDS = new Set([\"INSERT\", \"UPDATE\", \"DELETE\", \"MERGE\", \"UPSERT\", \"REPLACE\"]);\nconst DDL_KEYWORDS = new Set([\"CREATE\", \"DROP\", \"ALTER\", \"TRUNCATE\", \"RENAME\", \"COMMENT\"]);\n\n/** The leading SQL keyword, upper-cased, skipping comments and whitespace. */\nexport function firstKeyword(sql: string): string {\n const stripped = sql.replace(LEADING_NOISE, \"\");\n const match = /^[A-Za-z]+/.exec(stripped);\n return (match?.[0] ?? \"\").toUpperCase();\n}\n\n/** Classify a SQL statement by its leading keyword. */\nexport function classifyStatement(sql: string): StatementKind {\n const keyword = firstKeyword(sql);\n if (SELECT_KEYWORDS.has(keyword)) {\n return \"select\";\n }\n if (DML_KEYWORDS.has(keyword)) {\n return \"dml\";\n }\n if (DDL_KEYWORDS.has(keyword)) {\n return \"ddl\";\n }\n return \"unknown\";\n}\n\n/** Quote a SQL identifier (table/column name) for safe interpolation. */\nexport function quoteIdentifier(identifier: string): string {\n if (identifier.length === 0) {\n throw new QueryError(\"A SQL identifier must not be empty\");\n }\n if (identifier.includes(\"\\0\")) {\n throw new QueryError(\"A SQL identifier must not contain a NUL character\");\n }\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\n/** Build a `\"schema\".\"table\"` qualified, quoted name. */\nexport function qualifiedName(schema: string, table: string): string {\n return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;\n}\n\n/** Count `?` placeholders, skipping string literals, quoted identifiers, and comments. */\nexport function countPlaceholders(sql: string): number {\n let count = 0;\n let index = 0;\n const length = sql.length;\n\n while (index < length) {\n const char = sql[index];\n\n if (char === \"'\" || char === '\"') {\n const quote = char;\n index += 1;\n while (index < length) {\n if (sql[index] === quote) {\n if (sql[index + 1] === quote) {\n index += 2;\n continue;\n }\n index += 1;\n break;\n }\n index += 1;\n }\n continue;\n }\n\n if (char === \"-\" && sql[index + 1] === \"-\") {\n index += 2;\n while (index < length && sql[index] !== \"\\n\") {\n index += 1;\n }\n continue;\n }\n\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index += 2;\n while (index < length && !(sql[index] === \"*\" && sql[index + 1] === \"/\")) {\n index += 1;\n }\n index += 2;\n continue;\n }\n\n if (char === \"?\") {\n count += 1;\n }\n index += 1;\n }\n\n return count;\n}\n\n/** Throw when the number of `?` placeholders does not match the parameter count. */\nexport function assertParamArity(sql: string, params: readonly SqlParam[]): void {\n const expected = countPlaceholders(sql);\n if (expected !== params.length) {\n throw new QueryError(\n `SQL expects ${String(expected)} bound parameter(s) ` +\n `but received ${String(params.length)} value(s)`,\n );\n }\n}\n","import { QueryError } from \"./errors.js\";\nimport { qualifiedName, quoteIdentifier } from \"./statements.js\";\nimport type { BuiltStatement, SelectSpec, SqlParam } from \"./types.js\";\n\ninterface WhereClause {\n readonly clause: string;\n readonly params: readonly SqlParam[];\n}\n\nfunction buildWhere(where: Readonly<Record<string, SqlParam>> | undefined): WhereClause {\n if (where === undefined) {\n return { clause: \"\", params: [] };\n }\n const entries = Object.entries(where);\n if (entries.length === 0) {\n return { clause: \"\", params: [] };\n }\n const conditions = entries.map(([column]) => `${quoteIdentifier(column)} = ?`);\n return {\n clause: ` WHERE ${conditions.join(\" AND \")}`,\n params: entries.map(([, value]) => value),\n };\n}\n\n/** Build a parameterized `SELECT` statement from a typed spec. */\nexport function buildSelect(spec: SelectSpec): BuiltStatement {\n const columns =\n spec.columns === undefined || spec.columns.length === 0\n ? \"*\"\n : spec.columns.map((column) => quoteIdentifier(column)).join(\", \");\n const where = buildWhere(spec.where);\n const clauses: string[] = [\n `SELECT ${columns} FROM ${qualifiedName(spec.schema, spec.table)}${where.clause}`,\n ];\n\n if (spec.orderBy !== undefined && spec.orderBy.length > 0) {\n clauses.push(`ORDER BY ${spec.orderBy.map((column) => quoteIdentifier(column)).join(\", \")}`);\n }\n if (spec.limit !== undefined) {\n clauses.push(`LIMIT ${String(spec.limit)}`);\n }\n if (spec.offset !== undefined) {\n clauses.push(`OFFSET ${String(spec.offset)}`);\n }\n\n return { sql: clauses.join(\" \"), params: where.params };\n}\n\n/** Build a parameterized `SELECT COUNT(*)` statement. */\nexport function buildCount(\n spec: Pick<SelectSpec, \"schema\" | \"table\" | \"where\">,\n): BuiltStatement {\n const where = buildWhere(spec.where);\n return {\n sql: `SELECT COUNT(*) AS \"COUNT\" FROM ${qualifiedName(spec.schema, spec.table)}${where.clause}`,\n params: where.params,\n };\n}\n\n/** Build a parameterized single-row `INSERT` statement. */\nexport function buildInsert(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const entries = Object.entries(values);\n if (entries.length === 0) {\n throw new QueryError(\"INSERT requires at least one column value\");\n }\n const columns = entries.map(([column]) => quoteIdentifier(column)).join(\", \");\n const placeholders = entries.map(() => \"?\").join(\", \");\n return {\n sql: `INSERT INTO ${qualifiedName(schema, table)} (${columns}) VALUES (${placeholders})`,\n params: entries.map(([, value]) => value),\n };\n}\n\n/** Build a parameterized `UPDATE` statement. A non-empty `where` is required. */\nexport function buildUpdate(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n where: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const valueEntries = Object.entries(values);\n if (valueEntries.length === 0) {\n throw new QueryError(\"UPDATE requires at least one column value\");\n }\n const whereClause = buildWhere(where);\n if (whereClause.clause === \"\") {\n throw new QueryError(\"UPDATE requires a non-empty WHERE filter to avoid a full-table write\");\n }\n const assignments = valueEntries\n .map(([column]) => `${quoteIdentifier(column)} = ?`)\n .join(\", \");\n return {\n sql: `UPDATE ${qualifiedName(schema, table)} SET ${assignments}${whereClause.clause}`,\n params: [...valueEntries.map(([, value]) => value), ...whereClause.params],\n };\n}\n\n/** Build a parameterized `DELETE` statement. A non-empty `where` is required. */\nexport function buildDelete(\n schema: string,\n table: string,\n where: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const whereClause = buildWhere(where);\n if (whereClause.clause === \"\") {\n throw new QueryError(\"DELETE requires a non-empty WHERE filter to avoid a full-table delete\");\n }\n return {\n sql: `DELETE FROM ${qualifiedName(schema, table)}${whereClause.clause}`,\n params: whereClause.params,\n };\n}\n","import type { Connection } from \"./connection.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\nimport type { ColumnInfo, TableInfo } from \"./types.js\";\n\ninterface SchemaRow {\n readonly SCHEMA_NAME: string;\n}\n\ninterface TableRow {\n readonly SCHEMA_NAME: string;\n readonly TABLE_NAME: string;\n readonly TABLE_TYPE: string;\n}\n\ninterface CatalogObjectRow {\n readonly SCHEMA_NAME: string;\n readonly OBJECT_NAME: string;\n readonly OBJECT_TYPE: \"TABLE\" | \"VIEW\";\n}\n\ninterface ColumnRow {\n readonly COLUMN_NAME: string;\n readonly DATA_TYPE_NAME: string;\n readonly LENGTH: number | null;\n readonly SCALE: number | null;\n readonly IS_NULLABLE: string;\n readonly POSITION: number;\n}\n\nexport interface TableDescription {\n readonly table: TableInfo | undefined;\n readonly columns: readonly ColumnInfo[];\n}\n\n/** List every schema visible to the current user. */\nexport async function listSchemas(connection: Connection): Promise<readonly string[]> {\n const result = await connection.query<SchemaRow>(\n \"SELECT SCHEMA_NAME FROM SYS.SCHEMAS ORDER BY SCHEMA_NAME\",\n [],\n { autoLimit: false },\n );\n return result.rows.map((row) => row.SCHEMA_NAME);\n}\n\n/** List the tables in a schema. */\nexport async function listTables(\n connection: Connection,\n schema: string,\n): Promise<readonly TableInfo[]> {\n const result = await connection.query<TableRow>(\n \"SELECT SCHEMA_NAME, TABLE_NAME, TABLE_TYPE FROM SYS.TABLES \" +\n \"WHERE SCHEMA_NAME = ? ORDER BY TABLE_NAME\",\n [schema],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n schema: row.SCHEMA_NAME,\n name: row.TABLE_NAME,\n type: row.TABLE_TYPE,\n rowCount: undefined,\n }));\n}\n\n/** List table and view names in a schema for typo recovery suggestions. */\nexport async function listCatalogObjects(\n connection: Connection,\n schema: string,\n): Promise<readonly CatalogObjectInfo[]> {\n const result = await connection.query<CatalogObjectRow>(\n \"SELECT SCHEMA_NAME, TABLE_NAME AS OBJECT_NAME, 'TABLE' AS OBJECT_TYPE FROM SYS.TABLES \" +\n \"WHERE SCHEMA_NAME = ? UNION ALL \" +\n \"SELECT SCHEMA_NAME, VIEW_NAME AS OBJECT_NAME, 'VIEW' AS OBJECT_TYPE FROM SYS.VIEWS \" +\n \"WHERE SCHEMA_NAME = ? ORDER BY OBJECT_NAME\",\n [schema, schema],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n schema: row.SCHEMA_NAME,\n name: row.OBJECT_NAME,\n type: row.OBJECT_TYPE,\n }));\n}\n\n/** List the columns of a table, ordered by position. */\nexport async function listColumns(\n connection: Connection,\n schema: string,\n table: string,\n): Promise<readonly ColumnInfo[]> {\n const result = await connection.query<ColumnRow>(\n \"SELECT COLUMN_NAME, DATA_TYPE_NAME, LENGTH, SCALE, IS_NULLABLE, POSITION \" +\n \"FROM SYS.TABLE_COLUMNS WHERE SCHEMA_NAME = ? AND TABLE_NAME = ? ORDER BY POSITION\",\n [schema, table],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n name: row.COLUMN_NAME,\n dataType: row.DATA_TYPE_NAME,\n length: row.LENGTH ?? undefined,\n scale: row.SCALE ?? undefined,\n nullable: row.IS_NULLABLE === \"TRUE\",\n position: row.POSITION,\n }));\n}\n\n/** Describe a table: its catalog entry plus its columns. */\nexport async function describeTable(\n connection: Connection,\n schema: string,\n table: string,\n): Promise<TableDescription> {\n const tables = await listTables(connection, schema);\n const columns = await listColumns(connection, schema, table);\n return {\n table: tables.find((info) => info.name === table),\n columns,\n };\n}\n","export const CLI_NAME = \"cf-hana\";\nexport const CLI_VERSION = \"0.3.2\";\nexport const ENV_PREFIX = \"CF_HANA\";\n\nexport const DEFAULT_QUERY_TIMEOUT_MS = 30_000;\nexport const DEFAULT_CONNECT_TIMEOUT_MS = 30_000;\nexport const DEFAULT_POOL_MAX = 4;\nexport const DEFAULT_POOL_IDLE_MS = 60_000;\nexport const DEFAULT_AUTO_LIMIT = 100;\nexport const DEFAULT_CELL_LIMIT = 128;\nexport const MAX_CELL_LIMIT = 10_000;\nexport const DEFAULT_RESULT_TTL_MINUTES = 10_080;\nexport const DEFAULT_RESULT_SEARCH_LIMIT = 20;\nexport const MAX_RESULT_STORE_BYTES = 256 * 1024 * 1024;\nexport const HANA_CLOUD_DEFAULT_PORT = 443;\n\n/** Build a `CF_HANA_*` environment variable name from a suffix. */\nexport function envName(suffix: string): string {\n return `${ENV_PREFIX}_${suffix}`;\n}\n\n/** Read an environment variable, treating blank values as absent. */\nexport function readEnv(name: string): string | undefined {\n const value = process.env[name];\n if (value === undefined) {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length === 0 ? undefined : trimmed;\n}\n\nexport interface SapCredentials {\n readonly email: string;\n readonly password: string;\n}\n\nexport interface SapCredentialOverrides {\n readonly email?: string | undefined;\n readonly password?: string | undefined;\n}\n\n/**\n * Resolve SAP BTP credentials from explicit overrides, falling back to the\n * repo-wide `SAP_EMAIL` / `SAP_PASSWORD` environment variables. Returns\n * `undefined` when either half is missing.\n */\nexport function readSapCredentials(\n overrides?: SapCredentialOverrides,\n): SapCredentials | undefined {\n const email = overrides?.email ?? readEnv(\"SAP_EMAIL\");\n const password = overrides?.password ?? readEnv(\"SAP_PASSWORD\");\n if (email === undefined || password === undefined) {\n return undefined;\n }\n return { email, password };\n}\n","import { execFile } from \"node:child_process\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nimport type { HanaBinding } from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nconst MAX_BUFFER = 16 * 1024 * 1024;\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst CF_RETRY_ATTEMPTS = 3;\nconst CF_RETRY_BASE_DELAY_MS = 120;\n\n/** Minimal context for an isolated CF CLI invocation. */\nexport interface CfExecContext {\n readonly cfHome: string;\n}\n\n/** Data from `cf target`. */\nexport interface CurrentCfTarget {\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly regionKey?: string;\n}\n\nconst REGION_API_MAP: Record<string, string> = {\n ae01: \"https://api.cf.ae01.hana.ondemand.com\",\n ap01: \"https://api.cf.ap01.hana.ondemand.com\",\n ap10: \"https://api.cf.ap10.hana.ondemand.com\",\n ap11: \"https://api.cf.ap11.hana.ondemand.com\",\n ap12: \"https://api.cf.ap12.hana.ondemand.com\",\n ap20: \"https://api.cf.ap20.hana.ondemand.com\",\n ap21: \"https://api.cf.ap21.hana.ondemand.com\",\n ap30: \"https://api.cf.ap30.hana.ondemand.com\",\n br10: \"https://api.cf.br10.hana.ondemand.com\",\n br20: \"https://api.cf.br20.hana.ondemand.com\",\n br30: \"https://api.cf.br30.hana.ondemand.com\",\n ca10: \"https://api.cf.ca10.hana.ondemand.com\",\n ca20: \"https://api.cf.ca20.hana.ondemand.com\",\n ch20: \"https://api.cf.ch20.hana.ondemand.com\",\n eu10: \"https://api.cf.eu10.hana.ondemand.com\",\n eu11: \"https://api.cf.eu11.hana.ondemand.com\",\n eu12: \"https://api.cf.eu12.hana.ondemand.com\",\n eu20: \"https://api.cf.eu20.hana.ondemand.com\",\n eu21: \"https://api.cf.eu21.hana.ondemand.com\",\n eu30: \"https://api.cf.eu30.hana.ondemand.com\",\n \"eu10-002\": \"https://api.cf.eu10-002.hana.ondemand.com\",\n jp10: \"https://api.cf.jp10.hana.ondemand.com\",\n jp20: \"https://api.cf.jp20.hana.ondemand.com\",\n jp30: \"https://api.cf.jp30.hana.ondemand.com\",\n us10: \"https://api.cf.us10.hana.ondemand.com\",\n us11: \"https://api.cf.us11.hana.ondemand.com\",\n us20: \"https://api.cf.us20.hana.ondemand.com\",\n us21: \"https://api.cf.us21.hana.ondemand.com\",\n us30: \"https://api.cf.us30.hana.ondemand.com\",\n in30: \"https://api.cf.in30.hana.ondemand.com\",\n};\n\nexport function getApiEndpointForRegion(regionKey: string): string | undefined {\n return REGION_API_MAP[regionKey];\n}\n\nexport function getRegionKeyForApi(apiEndpoint: string): string | undefined {\n const norm = apiEndpoint.trim().replace(/\\/+$/, \"\").toLowerCase();\n for (const [key, endpoint] of Object.entries(REGION_API_MAP)) {\n if (endpoint.toLowerCase() === norm) {\n return key;\n }\n }\n return undefined;\n}\n\n/** Run work inside a fresh temporary CF_HOME. Directory is always cleaned. */\nexport async function withCfSession<T>(work: (ctx: CfExecContext) => Promise<T>): Promise<T> {\n const cfHome = await mkdtemp(join(tmpdir(), \"saptools-cf-hana-\"));\n const ctx: CfExecContext = { cfHome };\n try {\n return await work(ctx);\n } finally {\n await rm(cfHome, { recursive: true, force: true });\n }\n}\n\nfunction resolveCfBin(): { bin: string; argsPrefix: readonly string[] } {\n const raw = process.env[\"CF_HANA_CF_BIN\"] ?? \"cf\";\n if (/\\.(?:c|m)?js$/i.test(raw)) {\n return { bin: process.execPath, argsPrefix: [raw] };\n }\n return { bin: raw, argsPrefix: [] };\n}\n\nfunction buildEnv(ctx: CfExecContext, overrides: Record<string, string> = {}): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env, ...overrides };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n env[\"CF_HOME\"] = ctx.cfHome;\n return env;\n}\n\nasync function runCf(\n args: readonly string[],\n ctx: CfExecContext,\n overrides: Record<string, string> = {},\n): Promise<string> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = buildEnv(ctx, overrides);\n\n let lastErr: unknown;\n\n for (let attempt = 0; attempt < CF_RETRY_ATTEMPTS; attempt++) {\n try {\n const { stdout } = await execFileAsync(bin, [...argsPrefix, ...args], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: DEFAULT_TIMEOUT_MS,\n });\n return stdout;\n } catch (err) {\n lastErr = err;\n if (attempt < CF_RETRY_ATTEMPTS - 1) {\n await new Promise((r) => setTimeout(r, CF_RETRY_BASE_DELAY_MS * (attempt + 1)));\n }\n }\n }\n\n const e = lastErr as { stderr?: string | Buffer; message?: string } | undefined;\n const detail = e?.stderr ? String(e.stderr) : (e?.message ?? \"\");\n const cmd = args[0] === \"auth\" ? \"cf auth\" : `cf ${args.join(\" \")}`;\n throw new Error(`${cmd} failed: ${detail}`.trim(), { cause: lastErr });\n}\n\nexport async function cfApi(apiEndpoint: string, ctx: CfExecContext): Promise<void> {\n await runCf([\"api\", apiEndpoint], ctx);\n}\n\n/** Auth using env vars (professional, matches cf-events pattern). */\nexport async function cfAuth(email: string, password: string, ctx: CfExecContext): Promise<void> {\n await runCf([\"auth\"], ctx, {\n CF_USERNAME: email,\n CF_PASSWORD: password,\n });\n}\n\nexport async function cfTargetSpace(\n orgName: string,\n spaceName: string,\n ctx: CfExecContext,\n): Promise<void> {\n await runCf([\"target\", \"-o\", orgName, \"-s\", spaceName], ctx);\n}\n\nexport async function cfEnv(appName: string, ctx: CfExecContext): Promise<string> {\n return await runCf([\"env\", appName], ctx);\n}\n\n/**\n * Direct current user CF context for bare app names.\n * No isolated CF_HOME or forced re-authentication: the current target supplies the app scope.\n */\nexport async function cfEnvDirect(appName: string): Promise<string> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = { ...process.env };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n const { stdout } = await execFileAsync(bin, [...argsPrefix, \"env\", appName], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: DEFAULT_TIMEOUT_MS,\n });\n return stdout;\n}\n\nexport async function readCurrentCfTarget(): Promise<CurrentCfTarget | undefined> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = { ...process.env };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n\n try {\n const { stdout } = await execFileAsync(bin, [...argsPrefix, \"target\"], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: 10_000,\n });\n return parseCfTargetOutput(stdout);\n } catch {\n return undefined;\n }\n}\n\nexport function parseCfTargetOutput(stdout: string): CurrentCfTarget | undefined {\n const fields = parseTargetFields(stdout);\n const api = fields.get(\"api endpoint\");\n const org = fields.get(\"org\");\n const space = fields.get(\"space\");\n if (!api || !org || !space) {\n return undefined;\n }\n const regionKey = getRegionKeyForApi(api);\n return {\n apiEndpoint: api,\n orgName: org,\n spaceName: space,\n ...(regionKey ? { regionKey } : {}),\n };\n}\n\nfunction parseTargetFields(stdout: string): Map<string, string> {\n const map = new Map<string, string>();\n for (const line of stdout.split(/\\r?\\n/)) {\n const idx = line.indexOf(\":\");\n if (idx < 0) {continue;}\n const key = line.slice(0, idx).trim().toLowerCase();\n const val = line.slice(idx + 1).trim();\n if (key && val) {map.set(key, val);}\n }\n return map;\n}\n\nexport function formatCurrentCfAppSelector(target: CurrentCfTarget, appName: string): string {\n const name = appName.trim();\n if (!name) {throw new Error(\"App name is required.\");}\n if (!target.regionKey) {\n throw new Error(\n `Current CF API endpoint \"${target.apiEndpoint}\" does not match a known SAP region. Pass a full region/org/space/app selector.`,\n );\n }\n return `${target.regionKey}/${target.orgName}/${target.spaceName}/${name}`;\n}\n\n/* VCAP parser */\n\nfunction extractVcapSection(stdout: string): string {\n const start = stdout.indexOf(\"VCAP_SERVICES:\");\n if (start === -1) {throw new Error(\"VCAP_SERVICES section not found in cf env output\");}\n const after = stdout.slice(start + \"VCAP_SERVICES:\".length);\n const end = after.indexOf(\"VCAP_APPLICATION:\");\n const block = end === -1 ? after : after.slice(0, end);\n return block.trim();\n}\n\ninterface RawHanaCreds {\n host: string;\n port: string;\n user: string;\n password: string;\n schema: string;\n hdi_user: string;\n hdi_password: string;\n url: string;\n database_id: string;\n certificate: string;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction assertCreds(raw: unknown): RawHanaCreds {\n if (!isRecord(raw)) {throw new Error(\"HANA credentials must be an object\");}\n const req = [\"host\", \"port\", \"user\", \"password\", \"schema\", \"hdi_user\", \"hdi_password\", \"url\", \"database_id\", \"certificate\"];\n for (const k of req) {\n if (typeof raw[k] !== \"string\") {throw new Error(`Missing/invalid HANA credential field: \"${k}\"`);}\n }\n return raw as unknown as RawHanaCreds;\n}\n\nfunction mapCreds(raw: RawHanaCreds): HanaBinding[\"credentials\"] {\n return {\n host: raw.host,\n port: raw.port,\n user: raw.user,\n password: raw.password,\n schema: raw.schema,\n hdiUser: raw.hdi_user,\n hdiPassword: raw.hdi_password,\n ...(raw.url ? { url: raw.url } : {}),\n databaseId: raw.database_id,\n certificate: raw.certificate,\n };\n}\n\nexport function extractHanaBindingsFromCfEnv(stdout: string): readonly HanaBinding[] {\n const jsonText = extractVcapSection(stdout);\n let vcap: unknown;\n try {\n vcap = JSON.parse(jsonText);\n } catch {\n throw new Error(\"VCAP_SERVICES is not valid JSON\");\n }\n if (!isRecord(vcap)) {throw new Error(\"VCAP_SERVICES must be an object\");}\n\n const hana = vcap[\"hana\"];\n if (hana === undefined) {return [];}\n if (!Array.isArray(hana)) {throw new Error(\"VCAP_SERVICES.hana must be an array when present\");}\n\n return hana.map((b: unknown) => {\n if (!isRecord(b)) {throw new Error(\"HANA binding must be an object\");}\n const credsRaw = assertCreds(b[\"credentials\"]);\n const name = typeof b[\"name\"] === \"string\" ? b[\"name\"] : undefined;\n return {\n ...(name ? { name } : {}),\n credentials: mapCreds(credsRaw),\n } as HanaBinding;\n });\n}\n\n/**\n * Professional classification: only re-auth for real session/unauth problems.\n */\nexport function classifyCfError(stderr: string | undefined = \"\", stdout: string | undefined = \"\"): {\n readonly isAuthError: boolean;\n readonly reason: string;\n} {\n const text = `${stderr} ${stdout}`.toLowerCase();\n if (\n text.includes(\"not logged in\") ||\n text.includes(\"unauthorized\") ||\n text.includes(\"forbidden\") ||\n text.includes(\"credentials were rejected\") ||\n text.includes(\"authentication failed\") ||\n text.includes(\"cf auth\") ||\n text.includes(\"token\") ||\n text.includes(\"expired\") ||\n text.includes(\"session\")\n ) {\n return { isAuthError: true, reason: \"auth/session issue\" };\n }\n return { isAuthError: false, reason: \"\" };\n}\n","import {\n cfApi,\n cfAuth,\n cfEnv,\n cfEnvDirect,\n cfTargetSpace,\n classifyCfError,\n extractHanaBindingsFromCfEnv,\n formatCurrentCfAppSelector,\n getApiEndpointForRegion,\n readCurrentCfTarget,\n withCfSession,\n} from \"./cf.js\";\nimport { readSapCredentials } from \"./config.js\";\nimport { CfHanaError, CredentialsNotFoundError } from \"./errors.js\";\nimport type { CredentialSource, DbUserRole, HanaBinding } from \"./types.js\";\n\nexport interface ResolveBindingsOptions {\n readonly refresh?: boolean;\n readonly email?: string;\n readonly password?: string;\n}\n\nexport interface ResolvedBindings {\n readonly selector: string;\n readonly appName: string;\n readonly bindings: readonly HanaBinding[];\n readonly source: CredentialSource;\n}\n\nexport interface BindingSelector {\n readonly bindingName?: string;\n readonly bindingIndex?: number;\n}\n\nexport interface SelectedConnectionTarget {\n readonly host: string;\n readonly port: number;\n readonly user: string;\n readonly password: string;\n readonly schema: string;\n readonly certificate: string;\n readonly databaseId: string;\n}\n\n/**\n * Resolve an app's HANA bindings.\n *\n * Bare app name: resolve it against the current `cf target`.\n * - First try the user's *existing* CF session directly via cfEnvDirect (no re-auth).\n * - Only fall back to SAP + isolated re-auth if the error is classified as auth/session problem.\n * Explicit selector: Always full authenticated isolated path.\n *\n * This is the professional realization of the request:\n * When only an app is provided, the current CF target supplies org and space.\n * Auth/re-auth ONLY on session/unauthorize (per user feedback).\n */\nexport async function resolveAppBindings(\n rawSelector: string,\n options: ResolveBindingsOptions,\n): Promise<ResolvedBindings> {\n const selector = rawSelector.trim();\n if (!selector) {\n throw new CfHanaError(\"CONFIG\", \"App selector is required\");\n }\n\n let target: {\n selector: string;\n apiEndpoint?: string | undefined;\n orgName: string;\n spaceName: string;\n appName: string;\n };\n\n const isBare = !selector.includes(\"/\");\n\n if (isBare) {\n // A bare app inherits region, org, and space from the current CF target.\n const current = await readCurrentCfTarget();\n if (!current) {\n throw new CfHanaError(\n \"CONFIG\",\n \"No current CF target found. Run `cf target -o <org> -s <space>` or pass a full region/org/space/app selector.\",\n );\n }\n const displaySelector = current.regionKey\n ? formatCurrentCfAppSelector(current, selector)\n : `current/${current.orgName}/${current.spaceName}/${selector}`;\n target = {\n selector: displaySelector,\n apiEndpoint: current.regionKey ? getApiEndpointForRegion(current.regionKey) : undefined,\n orgName: current.orgName,\n spaceName: current.spaceName,\n appName: selector,\n };\n } else {\n // Explicit: region/org/space/app\n const parts = selector.split(\"/\").map((p) => p.trim());\n if (parts.length !== 4 || !parts[0] || !parts[1] || !parts[2] || !parts[3]) {\n throw new CfHanaError(\n \"CONFIG\",\n `Invalid selector \"${selector}\". Use region/org/space/app or a bare app name.`,\n );\n }\n const [regionKey, orgName, spaceName, appName] = parts as [string, string, string, string];\n const apiEndpoint = getApiEndpointForRegion(regionKey);\n if (!apiEndpoint) {\n throw new CfHanaError(\n \"CONFIG\",\n `Unknown region key \"${regionKey}\". Use a known region or the current CF target.`,\n );\n }\n target = { selector, apiEndpoint, orgName, spaceName, appName };\n }\n\n let bindings: readonly HanaBinding[];\n const source: CredentialSource = \"live\";\n\n if (isBare) {\n // Preferred fast path for bare: use whatever CF context the user already has.\n // NO re-auth, NO new CF_HOME.\n try {\n const stdout = await cfEnvDirect(target.appName);\n bindings = extractHanaBindingsFromCfEnv(stdout);\n } catch (directError: unknown) {\n // Professional classification: only re-auth for real auth/session problems.\n let stderr = '';\n if (directError && typeof directError === 'object') {\n const e = directError as { stderr?: unknown; message?: unknown };\n stderr = (typeof e.stderr === 'string' ? e.stderr : '') || (typeof e.message === 'string' ? e.message : '');\n }\n const classified = classifyCfError(stderr);\n if (classified.isAuthError) {\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (!sap) {\n throw new CredentialsNotFoundError(\n `Current CF session problem for bare app \"${target.appName}\" (${classified.reason}).\\n` +\n `Run \"cf login\" + \"cf target\", or provide SAP_EMAIL + SAP_PASSWORD.`,\n { cause: directError }\n );\n }\n if (!target.apiEndpoint) {\n throw new CfHanaError(\"CONFIG\", \"Cannot determine API endpoint for fallback auth.\");\n }\n const api = target.apiEndpoint;\n bindings = await withCfSession(async (ctx) => {\n await cfApi(api, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n const stdout = await cfEnv(target.appName, ctx);\n return extractHanaBindingsFromCfEnv(stdout);\n });\n } else {\n // Not auth-related (e.g. app not present in current space)\n throw new CfHanaError(\n \"CONFIG\",\n `Failed to get HANA bindings for bare app \"${target.appName}\" using current target (org=${target.orgName}, space=${target.spaceName}). ` +\n `Verify with \"cf target\" and \"cf env ${target.appName}\". ${stderr ? `Details: ${stderr}` : \"\"}`,\n { cause: directError }\n );\n }\n }\n } else {\n // Explicit selector always uses full authenticated isolated path\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (!sap) {\n throw new CredentialsNotFoundError(\n `SAP_EMAIL and SAP_PASSWORD are required to fetch HANA bindings for explicit selector \"${selector}\".`,\n );\n }\n if (!target.apiEndpoint) {\n throw new CfHanaError(\"CONFIG\", \"Invalid explicit selector.\");\n }\n const api = target.apiEndpoint;\n bindings = await withCfSession(async (ctx) => {\n await cfApi(api, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n const stdout = await cfEnv(target.appName, ctx);\n return extractHanaBindingsFromCfEnv(stdout);\n });\n }\n\n if (bindings.length === 0) {\n throw new CredentialsNotFoundError(`App \"${target.selector}\" has no HANA service binding.`);\n }\n\n return {\n selector: target.selector,\n appName: target.appName,\n bindings,\n source,\n };\n}\n\n/** Pick a single HANA binding from an app's bindings. */\nexport function selectBinding(\n bindings: readonly HanaBinding[],\n selector: BindingSelector,\n): HanaBinding {\n if (selector.bindingName !== undefined) {\n const match = bindings.find((binding) => binding.name === selector.bindingName);\n if (match === undefined) {\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `No HANA binding named \"${selector.bindingName}\"`,\n );\n }\n return match;\n }\n\n if (selector.bindingIndex !== undefined) {\n const match = bindings[selector.bindingIndex];\n if (match === undefined) {\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `No HANA binding at index ${String(selector.bindingIndex)}`,\n );\n }\n return match;\n }\n\n const first = bindings[0];\n if (first === undefined) {\n throw new CredentialsNotFoundError(\"No HANA bindings are available for this app\");\n }\n if (bindings.length > 1) {\n const labels = bindings\n .map((binding, index) => binding.name ?? `#${String(index)}`)\n .join(\", \");\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `App has multiple HANA bindings (${labels}); ` +\n `choose one with bindingName or bindingIndex`,\n );\n }\n return first;\n}\n\n/** Map a HANA binding to concrete connection parameters for the chosen role. */\nexport function toConnectionTarget(\n binding: HanaBinding,\n role: DbUserRole,\n): SelectedConnectionTarget {\n const credentials = binding.credentials;\n const port = Number.parseInt(credentials.port, 10);\n if (!Number.isInteger(port) || port <= 0) {\n throw new CfHanaError(\"CONFIG\", `Invalid HANA port in binding: \"${credentials.port}\"`);\n }\n return {\n host: credentials.host,\n port,\n user: role === \"hdi\" ? credentials.hdiUser : credentials.user,\n password: role === \"hdi\" ? credentials.hdiPassword : credentials.password,\n schema: credentials.schema,\n certificate: credentials.certificate,\n databaseId: credentials.databaseId ?? \"\",\n };\n}\n","import { appendFile } from \"node:fs/promises\";\n\nimport { envName, readEnv } from \"../config.js\";\nimport { QueryError } from \"../errors.js\";\nimport { classifyStatement } from \"../statements.js\";\nimport type { SqlParam } from \"../types.js\";\n\nimport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\nlet catalogFailureInjected = false;\n\n/**\n * Deterministic in-memory driver used by hermetic end-to-end tests and offline\n * smoke checks. Selected via `CF_HANA_DRIVER=fake`. It never opens a socket.\n */\ninterface FakeCatalogObjectRow extends Record<string, SqlParam> {\n readonly SCHEMA_NAME: string;\n readonly OBJECT_NAME: string;\n readonly OBJECT_TYPE: \"TABLE\" | \"VIEW\";\n}\n\nfunction catalogObjects(): readonly FakeCatalogObjectRow[] {\n return [\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"EXISTING_TABLE\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"MISSING_TABLE_FIXED\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"MISSING_TABLE_VIEW\", OBJECT_TYPE: \"VIEW\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"STATUS_ITEMS\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"CORE_AUTH_SCOPE\", OBJECT_TYPE: \"TABLE\" },\n ];\n}\n\nfunction tableColumns(): readonly Record<string, SqlParam>[] {\n return [\n { COLUMN_NAME: \"ID\", DATA_TYPE_NAME: \"INTEGER\", LENGTH: null, SCALE: null, IS_NULLABLE: \"FALSE\", POSITION: 1 },\n { COLUMN_NAME: \"IS_ACTIVE\", DATA_TYPE_NAME: \"BOOLEAN\", LENGTH: null, SCALE: null, IS_NULLABLE: \"TRUE\", POSITION: 2 },\n { COLUMN_NAME: \"SCOPE_NAME\", DATA_TYPE_NAME: \"NVARCHAR\", LENGTH: 255, SCALE: null, IS_NULLABLE: \"TRUE\", POSITION: 3 },\n ];\n}\n\nfunction fakeExec(sql: string): DriverExecResult {\n const kind = classifyStatement(sql);\n const forcedFailure = readEnv(envName(\"FAKE_FAIL_STATEMENT\"))?.toLowerCase();\n if (forcedFailure === kind) {\n throw new Error(`fake driver forced ${kind.toUpperCase()} failure`);\n }\n\n const upperSql = sql.toUpperCase();\n if (upperSql.includes(\"SYS.TABLES\") && upperSql.includes(\"SYS.VIEWS\")) {\n if (readEnv(envName(\"FAKE_FAIL_CATALOG_ONCE\")) === \"1\" && !catalogFailureInjected) {\n catalogFailureInjected = true;\n throw new QueryError(\"fake transient catalog metadata failure\");\n }\n return {\n rows: catalogObjects(),\n columns: [\n { name: \"SCHEMA_NAME\", typeName: \"NVARCHAR\" },\n { name: \"OBJECT_NAME\", typeName: \"NVARCHAR\" },\n { name: \"OBJECT_TYPE\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n }\n\n if (upperSql.includes(\"SYS.TABLE_COLUMNS\")) {\n return {\n rows: tableColumns(),\n columns: [\n { name: \"COLUMN_NAME\", typeName: \"NVARCHAR\" },\n { name: \"DATA_TYPE_NAME\", typeName: \"NVARCHAR\" },\n { name: \"LENGTH\", typeName: \"INTEGER\" },\n { name: \"SCALE\", typeName: \"INTEGER\" },\n { name: \"IS_NULLABLE\", typeName: \"NVARCHAR\" },\n { name: \"POSITION\", typeName: \"INTEGER\" },\n ],\n affectedRows: 0,\n };\n }\n\n if (upperSql.includes(\"MISSING_TABLE\") || upperSql.includes(\"MISSING_TABLES\")) {\n throw new QueryError(\"invalid table name: MISSING_TABLE\", { sqlState: \"42S02\" });\n }\n\n if (upperSql.includes(\"ISACTIVE\")) {\n throw new QueryError(\"invalid column name: ISACTIVE: line 1 col 8 (at pos 7)\", { databaseCode: 260 });\n }\n\n if (upperSql.includes(\"LOB_ORDER_ERROR\")) {\n throw new QueryError(\"inconsistent datatype: LOB type is not allowed in ORDER BY clause\", { databaseCode: 266 });\n }\n\n if (upperSql.includes(\"LOB_GROUP_ERROR\")) {\n throw new QueryError(\"inconsistent datatype: LOB type is not allowed in GROUP BY clause\", { databaseCode: 274 });\n }\n\n if (sql.toUpperCase().includes(\"LOB_FIXTURE\")) {\n return {\n rows: [\n {\n LOG_CONTENT: Buffer.from(\"Example log entry\", \"utf8\"),\n CLOB_CONTENT: Buffer.from(\"Clob log entry\", \"utf8\"),\n PAYLOAD: Buffer.from([0, 1, 2, 255]),\n },\n ],\n columns: [\n { name: \"LOG_CONTENT\", typeName: \"NCLOB\" },\n { name: \"CLOB_CONTENT\", typeName: \"CLOB\" },\n { name: \"PAYLOAD\", typeName: \"BLOB\" },\n ],\n affectedRows: 0,\n };\n }\n\n if (sql.toUpperCase().includes(\"DUMMY\")) {\n return {\n rows: [{ \"1\": 1 }],\n columns: [{ name: \"1\", typeName: \"INTEGER\" }],\n affectedRows: 0,\n };\n }\n\n if (kind === \"select\") {\n return {\n rows: [\n { ID: 1, NAME: \"sample-row\" },\n { ID: 2, NAME: \"second-row\" },\n ],\n columns: [\n { name: \"ID\", typeName: \"INTEGER\" },\n { name: \"NAME\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n }\n if (kind === \"dml\") {\n return { rows: [], columns: [], affectedRows: 1 };\n }\n return { rows: [], columns: [], affectedRows: 0 };\n}\n\n/** Opt-in fake-driver trace; parameter values stay out of test artifacts. */\nasync function traceFakeExec(sql: string, params: readonly SqlParam[]): Promise<void> {\n const tracePath = readEnv(envName(\"FAKE_TRACE_FILE\"));\n if (tracePath === undefined) {\n return;\n }\n const entry = { sql, paramCount: params.length };\n await appendFile(tracePath, `${JSON.stringify(entry)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n}\n\nclass FakeConnection implements DriverConnection {\n private closed = false;\n\n async exec(sql: string, params: readonly SqlParam[]): Promise<DriverExecResult> {\n await traceFakeExec(sql, params);\n return fakeExec(sql);\n }\n\n setAutoCommit(_enabled: boolean): Promise<void> {\n return Promise.resolve();\n }\n\n commit(): Promise<void> {\n return Promise.resolve();\n }\n\n rollback(): Promise<void> {\n return Promise.resolve();\n }\n\n close(): Promise<void> {\n this.closed = true;\n return Promise.resolve();\n }\n\n isClosed(): boolean {\n return this.closed;\n }\n}\n\n/** Build the deterministic test-only fake HANA driver. */\nexport function createFakeDriver(): HanaDriver {\n return {\n name: \"fake\",\n connect: (_params: DriverConnectParams): Promise<DriverConnection> =>\n Promise.resolve(new FakeConnection()),\n };\n}\n","import { createClient } from \"hdb\";\nimport type { HdbClient, HdbColumnMetadata, HdbStatement } from \"hdb\";\n\nimport { CfHanaError, QueryError, databaseCode } from \"../errors.js\";\nimport { quoteIdentifier } from \"../statements.js\";\nimport type { QueryResultColumn, SqlParam } from \"../types.js\";\n\nimport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\nconst TYPE_NAMES: Readonly<Record<number, string>> = {\n 0: \"NULL\",\n 1: \"TINYINT\",\n 2: \"SMALLINT\",\n 3: \"INTEGER\",\n 4: \"BIGINT\",\n 5: \"DECIMAL\",\n 6: \"REAL\",\n 7: \"DOUBLE\",\n 8: \"CHAR\",\n 9: \"VARCHAR\",\n 10: \"NCHAR\",\n 11: \"NVARCHAR\",\n 12: \"BINARY\",\n 13: \"VARBINARY\",\n 14: \"DATE\",\n 15: \"TIME\",\n 16: \"TIMESTAMP\",\n 25: \"CLOB\",\n 26: \"NCLOB\",\n 27: \"BLOB\",\n 28: \"BOOLEAN\",\n 29: \"STRING\",\n 30: \"NSTRING\",\n 47: \"DECIMAL\",\n 51: \"TEXT\",\n 52: \"SHORTTEXT\",\n 62: \"DECIMAL\",\n};\n\nfunction typeName(code: number): string {\n return TYPE_NAMES[code] ?? `TYPE_${String(code)}`;\n}\n\nfunction extractSqlState(error: Error): string | undefined {\n const value = (error as { readonly sqlState?: unknown }).sqlState;\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction toQueryError(error: Error): QueryError {\n const sqlState = extractSqlState(error);\n const code = databaseCode(error);\n return new QueryError(error.message, {\n cause: error,\n ...(sqlState === undefined ? {} : { sqlState }),\n ...(code === undefined ? {} : { databaseCode: code }),\n });\n}\n\nfunction toColumns(\n metadata: readonly HdbColumnMetadata[] | undefined,\n): readonly QueryResultColumn[] {\n if (metadata === undefined) {\n return [];\n }\n return metadata.map((column) => ({\n name: column.columnDisplayName ?? column.columnName ?? \"\",\n typeName: typeName(column.dataType),\n }));\n}\n\nfunction toExecResult(statement: HdbStatement, raw: unknown): DriverExecResult {\n if (typeof raw === \"number\") {\n return { rows: [], columns: [], affectedRows: raw };\n }\n if (Array.isArray(raw)) {\n return {\n rows: raw as readonly Record<string, SqlParam>[],\n columns: toColumns(statement.resultSetMetadata),\n affectedRows: 0,\n };\n }\n return { rows: [], columns: [], affectedRows: 0 };\n}\n\nclass HdbConnection implements DriverConnection {\n private closed = false;\n\n constructor(private readonly client: HdbClient) {}\n\n async exec(sql: string, params: readonly SqlParam[]): Promise<DriverExecResult> {\n const statement = await this.prepareStatement(sql);\n try {\n const raw = await this.executeStatement(statement, params);\n return toExecResult(statement, raw);\n } finally {\n dropStatementQuietly(statement);\n }\n }\n\n setAutoCommit(enabled: boolean): Promise<void> {\n this.client.setAutoCommit(enabled);\n return Promise.resolve();\n }\n\n async commit(): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n this.client.commit((error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n }\n\n async rollback(): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n this.client.rollback((error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return;\n }\n this.closed = true;\n await new Promise<void>((resolve) => {\n this.client.disconnect(() => {\n resolve();\n });\n });\n this.client.close();\n }\n\n isClosed(): boolean {\n return (\n this.closed ||\n this.client.readyState === \"closed\" ||\n this.client.readyState === \"disconnected\"\n );\n }\n\n private async prepareStatement(sql: string): Promise<HdbStatement> {\n return await new Promise<HdbStatement>((resolve, reject) => {\n this.client.prepare(sql, (error, statement) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve(statement);\n }\n });\n });\n }\n\n private async executeStatement(\n statement: HdbStatement,\n params: readonly SqlParam[],\n ): Promise<unknown> {\n return await new Promise<unknown>((resolve, reject) => {\n statement.exec([...params], (error, result) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve(result);\n }\n });\n });\n }\n}\n\nfunction dropStatementQuietly(statement: HdbStatement): void {\n try {\n statement.drop();\n } catch {\n // Best-effort cleanup; preserve the query result or original query error.\n }\n}\n\nfunction openClient(client: HdbClient, timeoutMs: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) {\n return;\n }\n settled = true;\n client.close();\n reject(\n new CfHanaError(\n \"TIMEOUT\",\n `HANA connection timed out after ${String(timeoutMs)}ms`,\n ),\n );\n }, timeoutMs);\n timer.unref();\n client.connect((error) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n if (error) {\n reject(\n new CfHanaError(\"CONNECTION\", `Failed to connect to HANA: ${error.message}`, {\n cause: error,\n }),\n );\n } else {\n resolve();\n }\n });\n });\n}\n\nasync function closeClientQuietly(client: HdbClient): Promise<void> {\n try {\n await new Promise<void>((resolve) => {\n client.disconnect(() => {\n resolve();\n });\n });\n } catch {\n // Best-effort cleanup after a partially opened connection.\n }\n try {\n client.close();\n } catch {\n // Best-effort cleanup after a partially opened connection.\n }\n}\n\nfunction setCurrentSchema(client: HdbClient, schema: string): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n client.exec(`SET SCHEMA ${quoteIdentifier(schema)}`, (error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n}\n\nasync function connectHdb(params: DriverConnectParams): Promise<DriverConnection> {\n const client = createClient({\n host: params.host,\n port: params.port,\n user: params.user,\n password: params.password,\n ca: params.certificate,\n useTLS: true,\n });\n await openClient(client, params.connectTimeoutMs);\n try {\n await setCurrentSchema(client, params.schema);\n } catch (error) {\n await closeClientQuietly(client);\n throw error;\n }\n return new HdbConnection(client);\n}\n\n/** Build the production HANA driver backed by the pure-JavaScript `hdb` library. */\nexport function createHdbDriver(): HanaDriver {\n return {\n name: \"hdb\",\n connect: connectHdb,\n };\n}\n","import { envName, readEnv } from \"../config.js\";\nimport { CfHanaError } from \"../errors.js\";\n\nimport { createFakeDriver } from \"./fake.js\";\nimport { createHdbDriver } from \"./hdb.js\";\nimport type { HanaDriver } from \"./types.js\";\n\nexport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\n/**\n * Create a HANA driver by name. Defaults to `hdb`; the `CF_HANA_DRIVER`\n * environment variable overrides the default when no name is passed.\n */\nexport function createDriver(name?: string): HanaDriver {\n const resolved = name ?? readEnv(envName(\"DRIVER\")) ?? \"hdb\";\n switch (resolved) {\n case \"hdb\":\n return createHdbDriver();\n case \"fake\":\n return createFakeDriver();\n default:\n throw new CfHanaError(\"CONFIG\", `Unknown HANA driver: ${resolved}`);\n }\n}\n","import { appendFile, mkdir, readdir, rm } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { DbUserRole, StatementKind } from \"./types.js\";\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst HISTORIES_DIR_NAME = \"histories\";\nconst HISTORY_RETENTION_DAYS = 5;\nconst HISTORY_FILE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}\\.jsonl$/;\n\nexport type SqlHistoryOperation = \"query\" | \"execute\";\n\nexport interface SqlHistoryEntryInput {\n readonly version: string;\n readonly operation: SqlHistoryOperation;\n readonly selector: string;\n readonly appName: string;\n readonly schema: string;\n readonly role: DbUserRole;\n readonly statement: StatementKind;\n readonly sql: string;\n readonly paramCount: number;\n readonly rowCount: number;\n readonly truncated: boolean;\n readonly elapsedMs: number;\n}\n\nexport interface SqlHistoryEntry extends SqlHistoryEntryInput {\n readonly at: string;\n}\n\nexport interface SqlHistoryWriteOptions {\n readonly now?: Date;\n readonly saptoolsRoot?: string;\n}\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction padDatePart(value: number): string {\n return value.toString().padStart(2, \"0\");\n}\n\nfunction dateKey(date: Date): string {\n return [\n date.getFullYear().toString(),\n padDatePart(date.getMonth() + 1),\n padDatePart(date.getDate()),\n ].join(\"-\");\n}\n\nfunction retentionCutoffKey(now: Date): string {\n const cutoff = new Date(now);\n cutoff.setHours(0, 0, 0, 0);\n cutoff.setDate(cutoff.getDate() - HISTORY_RETENTION_DAYS);\n return dateKey(cutoff);\n}\n\nfunction resolveSaptoolsRoot(root: string | undefined): string {\n return root ?? defaultSaptoolsRoot();\n}\n\nexport function cfHanaHistoryDirectory(saptoolsRoot?: string): string {\n return join(resolveSaptoolsRoot(saptoolsRoot), CF_HANA_DIR_NAME, HISTORIES_DIR_NAME);\n}\n\nexport function sqlHistoryFilePath(now: Date = new Date(), saptoolsRoot?: string): string {\n return join(cfHanaHistoryDirectory(saptoolsRoot), `${dateKey(now)}.jsonl`);\n}\n\nasync function pruneSqlHistory(now: Date, saptoolsRoot?: string): Promise<void> {\n const historyDir = cfHanaHistoryDirectory(saptoolsRoot);\n let files: readonly string[];\n try {\n files = await readdir(historyDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n\n const cutoffKey = retentionCutoffKey(now);\n await Promise.all(\n files\n .filter((file) => HISTORY_FILE_PATTERN.test(file))\n .filter((file) => file.slice(0, 10) < cutoffKey)\n .map(async (file) => {\n await rm(join(historyDir, file), { force: true });\n }),\n );\n}\n\nexport async function appendSqlHistory(\n input: SqlHistoryEntryInput,\n options: SqlHistoryWriteOptions = {},\n): Promise<SqlHistoryEntry> {\n const now = options.now ?? new Date();\n const historyDir = cfHanaHistoryDirectory(options.saptoolsRoot);\n const entry: SqlHistoryEntry = {\n at: now.toISOString(),\n ...input,\n };\n\n await mkdir(historyDir, { recursive: true, mode: 0o700 });\n await appendFile(sqlHistoryFilePath(now, options.saptoolsRoot), `${JSON.stringify(entry)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n try {\n await pruneSqlHistory(now, options.saptoolsRoot);\n } catch {\n // Retention is best-effort; the SQL history entry was already recorded.\n }\n\n return entry;\n}\n","import { classifyStatement, firstKeyword } from \"./statements.js\";\nimport type { StatementKind } from \"./types.js\";\n\nconst DESTRUCTIVE_DDL_KEYWORDS = new Set([\"DROP\", \"TRUNCATE\", \"ALTER\"]);\nconst UNSCOPED_WRITE_KEYWORDS = new Set([\"UPDATE\", \"DELETE\"]);\n\nexport type GuardViolation = \"read-only\" | \"destructive\";\n\nexport interface GuardConfig {\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n}\n\nexport interface GuardDecision {\n readonly allowed: boolean;\n readonly destructive: boolean;\n readonly violation: GuardViolation | undefined;\n readonly reason: string | undefined;\n}\n\nexport interface StatementInspection {\n readonly kind: StatementKind;\n readonly destructive: boolean;\n}\n\nexport interface AutoLimitResult {\n readonly sql: string;\n readonly applied: boolean;\n readonly requestedLimit?: number;\n}\n\nfunction skipQuotedText(sql: string, start: number): number {\n const quote = sql[start];\n let index = start + 1;\n while (index < sql.length) {\n if (sql[index] === quote) {\n if (sql[index + 1] === quote) {\n index += 2;\n continue;\n }\n index += 1;\n break;\n }\n index += 1;\n }\n return index;\n}\n\nfunction skipLineComment(sql: string, start: number): number {\n let index = start + 2;\n while (index < sql.length && sql[index] !== \"\\n\") {\n index += 1;\n }\n return index;\n}\n\nfunction skipBlockComment(sql: string, start: number): number {\n let index = start + 2;\n while (index < sql.length && !(sql[index] === \"*\" && sql[index + 1] === \"/\")) {\n index += 1;\n }\n return Math.min(index + 2, sql.length);\n}\n\nfunction maskIgnoredSqlText(sql: string): string {\n let masked = \"\";\n let index = 0;\n while (index < sql.length) {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n const end = skipQuotedText(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n const end = skipLineComment(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n const end = skipBlockComment(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n masked += char ?? \"\";\n index += 1;\n }\n return masked;\n}\n\nfunction hasWhereClause(sql: string): boolean {\n return /\\bwhere\\b/i.test(maskIgnoredSqlText(sql));\n}\n\nfunction trailingLineCommentIndex(sql: string): number | undefined {\n let index = 0;\n while (index < sql.length) {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n index = skipQuotedText(sql, index);\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index = skipBlockComment(sql, index);\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n const lineEnd = sql.indexOf(\"\\n\", index + 2);\n if (lineEnd === -1 || sql.slice(lineEnd + 1).trim().length === 0) {\n return index;\n }\n index = lineEnd + 1;\n continue;\n }\n index += 1;\n }\n return undefined;\n}\n\nfunction appendLimit(sql: string, limit: number): string {\n const trimmed = sql.replace(/[\\s;]+$/, \"\");\n const commentIndex = trailingLineCommentIndex(trimmed);\n if (commentIndex === undefined) {\n return `${trimmed} LIMIT ${String(limit)}`;\n }\n const beforeComment = trimmed.slice(0, commentIndex).replace(/[\\s;]+$/, \"\");\n const comment = trimmed.slice(commentIndex);\n return `${beforeComment} LIMIT ${String(limit)} ${comment}`;\n}\n\n/** Inspect a statement's kind and whether it is destructive. */\nexport function inspectStatement(sql: string): StatementInspection {\n const kind = classifyStatement(sql);\n const keyword = firstKeyword(sql);\n if (kind === \"ddl\") {\n return { kind, destructive: DESTRUCTIVE_DDL_KEYWORDS.has(keyword) };\n }\n if (kind === \"dml\") {\n return {\n kind,\n destructive: UNSCOPED_WRITE_KEYWORDS.has(keyword) && !hasWhereClause(sql),\n };\n }\n return { kind, destructive: false };\n}\n\n/** Decide whether a statement may run under the given safety configuration. */\nexport function evaluateGuard(sql: string, config: GuardConfig): GuardDecision {\n const inspection = inspectStatement(sql);\n\n if (config.readOnly && inspection.kind !== \"select\") {\n return {\n allowed: false,\n destructive: inspection.destructive,\n violation: \"read-only\",\n reason:\n inspection.kind === \"unknown\"\n ? \"read-only mode only permits SELECT/WITH statements\"\n : `read-only mode blocks ${inspection.kind.toUpperCase()} statements`,\n };\n }\n\n if (inspection.destructive && !config.allowDestructive) {\n return {\n allowed: false,\n destructive: true,\n violation: \"destructive\",\n reason:\n \"destructive statement blocked (DROP/TRUNCATE/ALTER or unscoped UPDATE/DELETE); \" +\n \"allow it explicitly to proceed\",\n };\n }\n\n return {\n allowed: true,\n destructive: inspection.destructive,\n violation: undefined,\n reason: undefined,\n };\n}\n\n/** Append a `LIMIT` clause to a bare SELECT that has no row cap of its own. */\nexport function applyAutoLimit(sql: string, limit: number | false): AutoLimitResult {\n if (limit === false || classifyStatement(sql) !== \"select\") {\n return { sql, applied: false };\n }\n\n const stripped = maskIgnoredSqlText(sql);\n if (/\\blimit\\b/i.test(stripped) || /\\btop\\s+\\d/i.test(stripped)) {\n return { sql, applied: false };\n }\n\n return {\n sql: appendLimit(sql, limit + 1),\n applied: true,\n requestedLimit: limit,\n };\n}\n","import type { DriverConnection, HanaDriver } from \"./driver/types.js\";\nimport { CfHanaError, DestructiveStatementError, ReadOnlyViolationError } from \"./errors.js\";\nimport { applyAutoLimit, evaluateGuard } from \"./safety.js\";\nimport { assertParamArity, classifyStatement } from \"./statements.js\";\nimport type { QueryOptions, QueryResult, QueryRow, SqlParam } from \"./types.js\";\n\nexport interface ConnectionConfig {\n readonly host: string;\n readonly port: number;\n readonly user: string;\n readonly password: string;\n readonly schema: string;\n readonly certificate: string;\n readonly connectTimeoutMs: number;\n readonly queryTimeoutMs: number;\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n readonly autoLimit: number | false;\n}\n\ninterface RunOptions {\n readonly bypassSafety?: boolean;\n}\n\nfunction assertValidAutoLimit(value: number | false): void {\n if (\n value !== false &&\n (!Number.isSafeInteger(value) || value <= 0 || value >= Number.MAX_SAFE_INTEGER)\n ) {\n throw new CfHanaError(\"CONFIG\", \"autoLimit must be a positive safe integer\");\n }\n}\n\nfunction boundedRows(\n rows: readonly Record<string, SqlParam>[],\n requestedLimit: number | undefined,\n): {\n readonly rows: readonly Record<string, SqlParam>[];\n readonly truncated: boolean;\n} {\n if (requestedLimit === undefined) {\n return { rows, truncated: false };\n }\n return {\n rows: rows.slice(0, requestedLimit),\n truncated: rows.length > requestedLimit,\n };\n}\n\nasync function withTimeout<T>(\n work: Promise<T>,\n timeoutMs: number,\n onTimeout: () => void,\n): Promise<T> {\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n onTimeout();\n reject(\n new CfHanaError(\"TIMEOUT\", `Statement timed out after ${String(timeoutMs)}ms`),\n );\n }, timeoutMs);\n timer.unref();\n });\n\n try {\n return await Promise.race([work, timeout]);\n } finally {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n }\n}\n\n/** A single HANA connection: applies the safety guard, auto-limit, and timeouts. */\nexport class Connection {\n private constructor(\n private readonly driverConnection: DriverConnection,\n private readonly config: ConnectionConfig,\n ) {}\n\n static async open(driver: HanaDriver, config: ConnectionConfig): Promise<Connection> {\n const driverConnection = await driver.connect({\n host: config.host,\n port: config.port,\n user: config.user,\n password: config.password,\n schema: config.schema,\n certificate: config.certificate,\n connectTimeoutMs: config.connectTimeoutMs,\n });\n return new Connection(driverConnection, config);\n }\n\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n const result = await this.run(sql, params ?? [], options ?? {});\n // The driver returns untyped rows; the caller asserts the row shape via TRow.\n return result as unknown as QueryResult<TRow>;\n }\n\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.run(sql, params ?? [], options ?? {});\n }\n\n assertAllowed(sql: string, options?: QueryOptions): void {\n this.evaluateSafety(sql, options ?? {});\n }\n\n async executeInternal(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.run(sql, params ?? [], options ?? {}, { bypassSafety: true });\n }\n\n async setAutoCommit(enabled: boolean): Promise<void> {\n await this.driverConnection.setAutoCommit(enabled);\n }\n\n async commit(): Promise<void> {\n await this.driverConnection.commit();\n }\n\n async rollback(): Promise<void> {\n await this.driverConnection.rollback();\n }\n\n async close(): Promise<void> {\n await this.driverConnection.close();\n }\n\n get isClosed(): boolean {\n return this.driverConnection.isClosed();\n }\n\n private async run(\n sql: string,\n params: readonly SqlParam[],\n options: QueryOptions,\n runOptions: RunOptions = {},\n ): Promise<QueryResult> {\n assertParamArity(sql, params);\n if (runOptions.bypassSafety !== true) {\n this.evaluateSafety(sql, options);\n }\n\n const kind = classifyStatement(sql);\n const autoLimit = options.autoLimit ?? this.config.autoLimit;\n assertValidAutoLimit(autoLimit);\n const limited =\n kind === \"select\" ? applyAutoLimit(sql, autoLimit) : { sql, applied: false };\n const timeoutMs = options.timeoutMs ?? this.config.queryTimeoutMs;\n\n const started = Date.now();\n const execResult = await withTimeout(\n this.driverConnection.exec(limited.sql, params),\n timeoutMs,\n () => {\n void this.closeQuietly();\n },\n );\n const elapsedMs = Date.now() - started;\n const selected = boundedRows(execResult.rows, limited.requestedLimit);\n\n return {\n rows: selected.rows,\n columns: execResult.columns,\n rowCount: kind === \"select\" ? selected.rows.length : execResult.affectedRows,\n statement: kind,\n truncated: selected.truncated,\n elapsedMs,\n };\n }\n\n private async closeQuietly(): Promise<void> {\n try {\n await this.driverConnection.close();\n } catch {\n // Best-effort close after a timeout; the connection is already unusable.\n }\n }\n\n private evaluateSafety(sql: string, options: QueryOptions): void {\n const decision = evaluateGuard(sql, {\n readOnly: this.config.readOnly,\n allowDestructive: options.allowDestructive ?? this.config.allowDestructive,\n });\n if (decision.allowed) {\n return;\n }\n if (decision.violation === \"read-only\") {\n throw new ReadOnlyViolationError(\n decision.reason ?? \"read-only mode blocks this statement\",\n );\n }\n throw new DestructiveStatementError(\n decision.reason ?? \"destructive statement blocked\",\n );\n }\n}\n","import { DEFAULT_POOL_IDLE_MS, DEFAULT_POOL_MAX } from \"./config.js\";\nimport { Connection } from \"./connection.js\";\nimport type { ConnectionConfig } from \"./connection.js\";\nimport type { HanaDriver } from \"./driver/types.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type { PoolOptions } from \"./types.js\";\n\ninterface IdleEntry {\n readonly connection: Connection;\n readonly since: number;\n}\n\ninterface Waiter {\n readonly resolve: (connection: Connection) => void;\n readonly reject: (error: unknown) => void;\n}\n\nasync function closeQuietly(connection: Connection): Promise<void> {\n try {\n await connection.close();\n } catch {\n // Best-effort close.\n }\n}\n\n/**\n * A process-local, in-memory pool of HANA connections. It holds no shared disk\n * state, so multiple pools (in this or other processes) are fully independent.\n */\nexport class ConnectionPool {\n private readonly idle: IdleEntry[] = [];\n private readonly busy = new Set<Connection>();\n private readonly waiters: Waiter[] = [];\n private readonly maxSize: number;\n private readonly idleTimeoutMs: number;\n private created = 0;\n private draining = false;\n\n constructor(\n private readonly driver: HanaDriver,\n private readonly config: ConnectionConfig,\n options?: PoolOptions,\n ) {\n this.maxSize = Math.max(1, options?.max ?? DEFAULT_POOL_MAX);\n this.idleTimeoutMs = options?.idleTimeoutMs ?? DEFAULT_POOL_IDLE_MS;\n }\n\n /** Total connections currently owned by the pool (idle + busy). */\n get size(): number {\n return this.created;\n }\n\n /** Connections currently idle and immediately reusable. */\n get available(): number {\n return this.idle.length;\n }\n\n /** Borrow a connection, opening or queueing as needed. */\n async acquire(): Promise<Connection> {\n if (this.draining) {\n throw new CfHanaError(\"POOL_CLOSED\", \"Connection pool is draining\");\n }\n\n const reused = this.takeIdleConnection();\n if (reused !== undefined) {\n this.busy.add(reused);\n return reused;\n }\n\n if (this.created < this.maxSize) {\n return await this.openBusyConnection();\n }\n\n return await new Promise<Connection>((resolve, reject) => {\n this.waiters.push({ resolve, reject });\n });\n }\n\n /** Return a borrowed connection to the pool. */\n release(connection: Connection): void {\n if (!this.busy.delete(connection)) {\n return;\n }\n\n if (connection.isClosed) {\n this.created -= 1;\n this.servePendingWaiters();\n return;\n }\n\n const waiter = this.waiters.shift();\n if (waiter !== undefined) {\n this.busy.add(connection);\n waiter.resolve(connection);\n return;\n }\n\n if (this.draining) {\n this.created -= 1;\n void closeQuietly(connection);\n return;\n }\n\n this.idle.push({ connection, since: Date.now() });\n }\n\n /** Run `work` with a borrowed connection, releasing it afterwards. */\n async withConnection<T>(work: (connection: Connection) => Promise<T>): Promise<T> {\n const connection = await this.acquire();\n try {\n return await work(connection);\n } finally {\n this.release(connection);\n }\n }\n\n /** Reject queued waiters and close idle connections. */\n async drain(): Promise<void> {\n this.draining = true;\n\n while (this.waiters.length > 0) {\n const waiter = this.waiters.shift();\n if (waiter !== undefined) {\n waiter.reject(new CfHanaError(\"POOL_CLOSED\", \"Connection pool was drained\"));\n }\n }\n\n const idleConnections = this.idle.splice(0).map((entry) => entry.connection);\n this.created -= idleConnections.length;\n await Promise.all(idleConnections.map((connection) => closeQuietly(connection)));\n }\n\n private takeIdleConnection(): Connection | undefined {\n for (;;) {\n const entry = this.idle.pop();\n if (entry === undefined) {\n return undefined;\n }\n if (entry.connection.isClosed) {\n this.created -= 1;\n continue;\n }\n if (this.idleTimeoutMs > 0 && Date.now() - entry.since > this.idleTimeoutMs) {\n this.created -= 1;\n void closeQuietly(entry.connection);\n continue;\n }\n return entry.connection;\n }\n }\n\n private async openBusyConnection(): Promise<Connection> {\n this.created += 1;\n let connection: Connection;\n try {\n connection = await Connection.open(this.driver, this.config);\n } catch (error) {\n this.created -= 1;\n throw error;\n }\n this.busy.add(connection);\n return connection;\n }\n\n private servePendingWaiters(): void {\n while (this.waiters.length > 0 && this.created < this.maxSize) {\n const waiter = this.waiters.shift();\n if (waiter === undefined) {\n return;\n }\n this.created += 1;\n void Connection.open(this.driver, this.config).then(\n (connection) => {\n this.busy.add(connection);\n waiter.resolve(connection);\n },\n (error: unknown) => {\n this.created -= 1;\n waiter.reject(error);\n this.servePendingWaiters();\n },\n );\n }\n }\n}\n","import type { Connection } from \"./connection.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type { QueryOptions, QueryResult, QueryRow, SqlParam } from \"./types.js\";\n\n/** A HANA transaction bound to one connection with autocommit disabled. */\nexport class Transaction {\n private finished = false;\n\n constructor(private readonly connection: Connection) {}\n\n /** Whether the transaction has already been committed or rolled back. */\n get isFinished(): boolean {\n return this.finished;\n }\n\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n this.assertActive();\n return await this.connection.query<TRow>(sql, params, options);\n }\n\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n this.assertActive();\n return await this.connection.execute(sql, params, options);\n }\n\n async commit(): Promise<void> {\n this.assertActive();\n this.finished = true;\n await this.connection.commit();\n }\n\n async rollback(): Promise<void> {\n this.assertActive();\n this.finished = true;\n await this.connection.rollback();\n }\n\n private assertActive(): void {\n if (this.finished) {\n throw new CfHanaError(\n \"QUERY\",\n \"This transaction has already been committed or rolled back\",\n );\n }\n }\n}\n","import { buildWriteBackupPlan, writeSqlBackup } from \"./backup.js\";\nimport type { SqlBackupRecord } from \"./backup.js\";\nimport { buildCount, buildDelete, buildInsert, buildSelect, buildUpdate } from \"./builder.js\";\nimport { listCatalogObjects, listColumns, listSchemas, listTables } from \"./catalog.js\";\nimport {\n DEFAULT_AUTO_LIMIT,\n CLI_VERSION,\n DEFAULT_CONNECT_TIMEOUT_MS,\n DEFAULT_QUERY_TIMEOUT_MS,\n} from \"./config.js\";\nimport type { ConnectionConfig } from \"./connection.js\";\nimport { resolveAppBindings, selectBinding, toConnectionTarget } from \"./credentials.js\";\nimport { createDriver } from \"./driver/index.js\";\nimport { appendSqlHistory } from \"./history.js\";\nimport type { SqlHistoryOperation } from \"./history.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\nimport { ConnectionPool } from \"./pool.js\";\nimport { Transaction } from \"./transaction.js\";\nimport type {\n ColumnInfo,\n ConnectOptions,\n DbUserRole,\n HanaClientInfo,\n PoolOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SelectSpec,\n SqlParam,\n TableInfo,\n} from \"./types.js\";\n\nlet explainStatementCounter = 0;\n\nfunction nextExplainStatementName(): string {\n explainStatementCounter = (explainStatementCounter + 1) % Number.MAX_SAFE_INTEGER;\n return `cf_hana_${String(process.pid)}_${String(Date.now())}_${String(explainStatementCounter)}`;\n}\n\n/**\n * The high-level entry point: a pooled, reusable client for the HANA database\n * bound to a single Cloud Foundry app.\n */\nexport class HanaClient {\n constructor(\n private readonly pool: ConnectionPool,\n readonly info: HanaClientInfo,\n ) {}\n\n /** Open a client for a `region/org/space/app` selector (or a bare app name). */\n static async connect(selector: string, options: ConnectOptions = {}): Promise<HanaClient> {\n const resolved = await resolveAppBindings(selector, options);\n const role: DbUserRole = options.role ?? \"runtime\";\n const binding = selectBinding(resolved.bindings, options);\n const target = toConnectionTarget(binding, role);\n const driver = createDriver();\n\n const config: ConnectionConfig = {\n host: target.host,\n port: target.port,\n user: target.user,\n password: target.password,\n schema: target.schema,\n certificate: target.certificate,\n connectTimeoutMs: options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,\n queryTimeoutMs: options.queryTimeoutMs ?? DEFAULT_QUERY_TIMEOUT_MS,\n readOnly: options.readOnly ?? false,\n allowDestructive: options.allowDestructive ?? false,\n autoLimit: options.autoLimit ?? DEFAULT_AUTO_LIMIT,\n };\n const poolOptions: PoolOptions =\n options.pool === false ? { max: 1 } : (options.pool ?? {});\n\n const info: HanaClientInfo = {\n selector: resolved.selector,\n appName: resolved.appName,\n host: target.host,\n schema: target.schema,\n role,\n driver: driver.name,\n credentialSource: resolved.source,\n };\n return new HanaClient(new ConnectionPool(driver, config, poolOptions), info);\n }\n\n /** Run a SELECT (or any read) statement and return typed rows. */\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n const resolvedParams = params ?? [];\n const result = await this.runQuery<TRow>(sql, resolvedParams, options);\n await this.recordSqlHistory(\"query\", sql, resolvedParams, result);\n return result;\n }\n\n /** Run a DML/DDL statement and return its affected-row count. */\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n const resolvedParams = params ?? [];\n const result = await this.runExecute(sql, resolvedParams, options);\n await this.recordSqlHistory(\"execute\", sql, resolvedParams, result);\n return result;\n }\n\n /** Back up rows matched by an UPDATE or DELETE before the caller runs it. */\n async backupWriteStatement(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<SqlBackupRecord | undefined> {\n const resolvedParams = params ?? [];\n const plan = buildWriteBackupPlan(sql, resolvedParams);\n if (plan === undefined) {\n return undefined;\n }\n\n return await this.pool.withConnection(async (connection) => {\n connection.assertAllowed(plan.statementSql, options);\n const backupQueryOptions: QueryOptions = {\n autoLimit: false,\n ...(options?.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),\n };\n const result = await connection.query(plan.selectSql, plan.selectParams, backupQueryOptions);\n return await writeSqlBackup({\n operation: plan.operation,\n statementSql: plan.statementSql,\n result,\n selector: this.info.selector,\n });\n });\n }\n\n /** Run a typed `SELECT` built from a spec. */\n async selectFrom<TRow = QueryRow>(spec: SelectSpec): Promise<QueryResult<TRow>> {\n const built = buildSelect(spec);\n return await this.runQuery<TRow>(built.sql, built.params);\n }\n\n /** Count rows in a table, optionally filtered. */\n async count(spec: Pick<SelectSpec, \"schema\" | \"table\" | \"where\">): Promise<number> {\n const built = buildCount(spec);\n const result = await this.runQuery<{ COUNT: number }>(built.sql, built.params);\n return result.rows[0]?.COUNT ?? 0;\n }\n\n /** Insert a single row. */\n async insertInto(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildInsert(schema, table, values);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Update rows matching a non-empty `where` filter. */\n async update(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n where: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildUpdate(schema, table, values, where);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Delete rows matching a non-empty `where` filter. */\n async deleteFrom(\n schema: string,\n table: string,\n where: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildDelete(schema, table, where);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Run `work` inside a transaction, auto-committing on success. */\n async transaction<T>(work: (tx: Transaction) => Promise<T>): Promise<T> {\n return await this.pool.withConnection(async (connection) => {\n await connection.setAutoCommit(false);\n const tx = new Transaction(connection);\n try {\n const result = await work(tx);\n if (!tx.isFinished) {\n await tx.commit();\n }\n return result;\n } catch (error) {\n if (!tx.isFinished) {\n try {\n await tx.rollback();\n } catch {\n // Preserve the original error; ignore a rollback failure.\n }\n }\n throw error;\n } finally {\n await connection.setAutoCommit(true);\n }\n });\n }\n\n /** List every schema visible to the connected user. */\n async listSchemas(): Promise<readonly string[]> {\n return await this.pool.withConnection((connection) => listSchemas(connection));\n }\n\n /** List the tables in a schema. */\n async listTables(schema: string): Promise<readonly TableInfo[]> {\n return await this.pool.withConnection((connection) => listTables(connection, schema));\n }\n\n /** List table and view names in a schema for typo suggestions. */\n async listCatalogObjects(schema: string): Promise<readonly CatalogObjectInfo[]> {\n return await this.pool.withConnection((connection) => listCatalogObjects(connection, schema));\n }\n\n /** List the columns of a table. */\n async listColumns(schema: string, table: string): Promise<readonly ColumnInfo[]> {\n return await this.pool.withConnection((connection) =>\n listColumns(connection, schema, table),\n );\n }\n\n /** Return the HANA execution plan for a statement. */\n async explain(sql: string, params?: readonly SqlParam[]): Promise<QueryResult> {\n return await this.pool.withConnection(async (connection) => {\n connection.assertAllowed(sql);\n const statementName = nextExplainStatementName();\n await connection.executeInternal(\n `EXPLAIN PLAN SET STATEMENT_NAME = '${statementName}' FOR ${sql}`,\n params,\n );\n const cleanup = async (): Promise<void> => {\n await connection.executeInternal(\n \"DELETE FROM EXPLAIN_PLAN_TABLE WHERE STATEMENT_NAME = ?\",\n [statementName],\n );\n };\n let queryCompleted = false;\n try {\n const result = await connection.query(\n \"SELECT OPERATOR_NAME, TABLE_NAME, TABLE_TYPE, EXECUTION_ENGINE \" +\n \"FROM EXPLAIN_PLAN_TABLE WHERE STATEMENT_NAME = ? ORDER BY OPERATOR_ID\",\n [statementName],\n );\n queryCompleted = true;\n await cleanup();\n return result;\n } catch (error) {\n if (!queryCompleted) {\n try {\n await cleanup();\n } catch {\n // Preserve the original explain-plan read error.\n }\n }\n throw error;\n }\n });\n }\n\n /** Close every pooled connection. The client must not be used afterwards. */\n async close(): Promise<void> {\n await this.pool.drain();\n }\n\n private async runQuery<TRow = QueryRow>(\n sql: string,\n params: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n return await this.pool.withConnection((connection) =>\n connection.query<TRow>(sql, params, options),\n );\n }\n\n private async runExecute(\n sql: string,\n params: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.pool.withConnection((connection) =>\n connection.execute(sql, params, options),\n );\n }\n\n private async recordSqlHistory<TRow>(\n operation: SqlHistoryOperation,\n sql: string,\n params: readonly SqlParam[],\n result: QueryResult<TRow>,\n ): Promise<void> {\n try {\n await appendSqlHistory({\n version: CLI_VERSION,\n operation,\n selector: this.info.selector,\n appName: this.info.appName,\n schema: this.info.schema,\n role: this.info.role,\n statement: result.statement,\n sql,\n paramCount: params.length,\n rowCount: result.rowCount,\n truncated: result.truncated,\n elapsedMs: result.elapsedMs,\n });\n } catch {\n // History is diagnostic local state; never fail a successful SQL statement.\n }\n }\n}\n","import { HanaClient } from \"./client.js\";\nimport type {\n ConnectOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SqlParam,\n} from \"./types.js\";\n\n/**\n * Open a reusable, pooled client for the HANA database bound to a Cloud Foundry\n * app, addressed by a `region/org/space/app` selector or a bare app name.\n */\nexport async function connect(\n selector: string,\n options?: ConnectOptions,\n): Promise<HanaClient> {\n return await HanaClient.connect(selector, options);\n}\n\n/**\n * Connect, run a single query, and close — the one-shot convenience for scripts.\n */\nexport async function query<TRow = QueryRow>(\n selector: string,\n sql: string,\n params?: readonly SqlParam[],\n options?: ConnectOptions & QueryOptions,\n): Promise<QueryResult<TRow>> {\n const client = await HanaClient.connect(selector, options);\n try {\n return await client.query<TRow>(sql, params, options);\n } finally {\n await client.close();\n }\n}\n\n/** Run `work` with a client that is closed automatically afterwards. */\nexport async function withConnection<T>(\n selector: string,\n work: (client: HanaClient) => Promise<T>,\n options?: ConnectOptions,\n): Promise<T> {\n const client = await HanaClient.connect(selector, options);\n try {\n return await work(client);\n } finally {\n await client.close();\n }\n}\n","import { writeFile } from \"node:fs/promises\";\n\nimport type { Command } from \"commander\";\n\nimport {\n DEFAULT_CELL_LIMIT,\n DEFAULT_RESULT_SEARCH_LIMIT,\n MAX_CELL_LIMIT,\n} from \"./config.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport { formatCompactCsv } from \"./format.js\";\nimport { isTextLobType } from \"./lob.js\";\nimport {\n inspectJsonCell,\n readCellWindow,\n searchResultSession,\n selectResultCell,\n selectResultRow,\n} from \"./result-inspect.js\";\nimport {\n clearResultSessions,\n listResultSessions,\n pruneResultSessions,\n readResultSession,\n} from \"./result-store.js\";\nimport type {\n QueryResult,\n QueryResultColumn,\n QueryRow,\n SqlParam,\n} from \"./types.js\";\n\ninterface ShowOptions {\n readonly row?: number;\n readonly column?: string;\n readonly offset?: number;\n readonly length?: number;\n readonly path?: string;\n}\n\ninterface SearchOptions {\n readonly row?: number;\n readonly column?: string;\n readonly limit?: number;\n readonly length?: number;\n}\n\ninterface ExportOptions {\n readonly row?: number;\n readonly column?: string;\n readonly output?: string;\n}\n\nfunction print(text: string): void {\n process.stdout.write(`${text}\\n`);\n}\n\nfunction parseIntOption(value: string): number {\n const trimmed = value.trim();\n if (!/^-?\\d+$/.test(trimmed)) {\n throw new CfHanaError(\"CONFIG\", `Expected an integer but received \"${value}\"`);\n }\n const parsed = Number(trimmed);\n if (!Number.isSafeInteger(parsed)) {\n throw new CfHanaError(\"CONFIG\", `Expected a safe integer but received \"${value}\"`);\n }\n return parsed;\n}\n\nfunction positive(name: string, value: number | undefined, fallback: number): number {\n const resolved = value ?? fallback;\n if (!Number.isSafeInteger(resolved) || resolved <= 0) {\n throw new CfHanaError(\"CONFIG\", `${name} must be a positive safe integer`);\n }\n return resolved;\n}\n\nfunction boundedLength(value: number | undefined): number {\n const resolved = positive(\"--length\", value, DEFAULT_CELL_LIMIT);\n if (resolved > MAX_CELL_LIMIT) {\n throw new CfHanaError(\"CONFIG\", `--length must be at most ${String(MAX_CELL_LIMIT)}`);\n }\n return resolved;\n}\n\nfunction nonNegative(name: string, value: number | undefined): number {\n const resolved = value ?? 0;\n if (!Number.isSafeInteger(resolved) || resolved < 0) {\n throw new CfHanaError(\"CONFIG\", `${name} must be a non-negative safe integer`);\n }\n return resolved;\n}\n\nfunction resultFromRows(\n rows: readonly QueryRow[],\n columns: readonly QueryResultColumn[],\n): QueryResult {\n return {\n rows,\n columns,\n rowCount: rows.length,\n statement: \"select\",\n truncated: false,\n elapsedMs: 0,\n };\n}\n\nfunction csv(rows: readonly QueryRow[], columns: readonly string[], limit: number): string {\n const result = resultFromRows(\n rows,\n columns.map((name) => ({ name, typeName: \"\" })),\n );\n return formatCompactCsv(result, limit).text;\n}\n\nasync function runShow(ref: string, options: ShowOptions): Promise<void> {\n const session = await readResultSession(ref);\n const length = boundedLength(options.length);\n if (options.row === undefined) {\n if (\n options.column !== undefined ||\n options.path !== undefined ||\n options.offset !== undefined\n ) {\n throw new CfHanaError(\"CONFIG\", \"--column, --path, and --offset require --row\");\n }\n print(summaryCsv(session, length));\n return;\n }\n if (options.column === undefined) {\n if (options.path !== undefined || options.offset !== undefined) {\n throw new CfHanaError(\"CONFIG\", \"--path and --offset require --column\");\n }\n const row = selectResultRow(session, options.row);\n print(formatCompactCsv(resultFromRows([row], session.result.columns), length).text);\n return;\n }\n const selected = selectResultCell(session, options.row, options.column);\n if (options.path !== undefined) {\n const rows = inspectJsonCell(selected.value, options.path, length).map((row) => ({\n PATH: row.path,\n TYPE: row.type,\n VALUE: row.value,\n }));\n print(csv(rows, [\"PATH\", \"TYPE\", \"VALUE\"], length));\n return;\n }\n const window = readCellWindow(\n selected.value,\n nonNegative(\"--offset\", options.offset),\n length,\n selected.typeName,\n );\n print(\n csv(\n [\n {\n ROW: selected.row,\n COLUMN: selected.column,\n TYPE: window.type,\n ORIGINAL_LENGTH: window.originalLength,\n OFFSET: window.offset,\n VALUE: window.value,\n },\n ],\n [\"ROW\", \"COLUMN\", \"TYPE\", \"ORIGINAL_LENGTH\", \"OFFSET\", \"VALUE\"],\n length,\n ),\n );\n}\n\nfunction summaryCsv(session: Awaited<ReturnType<typeof readResultSession>>, length: number): string {\n const compact = formatCompactCsv(session.result, DEFAULT_CELL_LIMIT);\n return csv(\n [\n {\n REF: session.ref,\n ROWS: session.result.rowCount,\n COLUMNS: session.result.columns.length,\n ROW_TRUNCATED: session.result.truncated,\n TRUNCATED_CELLS: compact.truncatedCells,\n EXPIRES_AT: session.expiresAt,\n },\n ],\n [\"REF\", \"ROWS\", \"COLUMNS\", \"ROW_TRUNCATED\", \"TRUNCATED_CELLS\", \"EXPIRES_AT\"],\n length,\n );\n}\n\nasync function runSearch(ref: string, text: string, options: SearchOptions): Promise<void> {\n const session = await readResultSession(ref);\n const length = boundedLength(options.length);\n const matches = searchResultSession(session, text, {\n limit: positive(\"--limit\", options.limit, DEFAULT_RESULT_SEARCH_LIMIT),\n previewLength: length,\n ...(options.row === undefined ? {} : { row: options.row }),\n ...(options.column === undefined ? {} : { column: options.column }),\n });\n const rows = matches.map((match) => ({\n ROW: match.row,\n COLUMN: match.column,\n OFFSET: match.offset ?? null,\n PATH: match.path,\n PREVIEW: match.preview,\n }));\n print(csv(rows, [\"ROW\", \"COLUMN\", \"OFFSET\", \"PATH\", \"PREVIEW\"], length));\n}\n\nfunction cellExportValue(value: SqlParam, typeName?: string): string | Buffer {\n if (Buffer.isBuffer(value)) {\n return isTextLobType(typeName) ? value.toString(\"utf8\") : value;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (value === null) {\n return \"\";\n }\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n return value.toString();\n}\n\nasync function runExport(ref: string, options: ExportOptions): Promise<void> {\n if (options.row === undefined || options.column === undefined) {\n throw new CfHanaError(\"CONFIG\", \"result export requires --row and --column\");\n }\n if (options.output === undefined || options.output.trim().length === 0) {\n throw new CfHanaError(\"CONFIG\", \"result export requires --output\");\n }\n const session = await readResultSession(ref);\n const selected = selectResultCell(session, options.row, options.column);\n await writeFile(options.output, cellExportValue(selected.value, selected.typeName), {\n mode: 0o600,\n });\n print(`wrote=${options.output}`);\n}\n\nasync function runList(): Promise<void> {\n const summaries = await listResultSessions();\n const rows = summaries.map((summary) => ({\n REF: summary.ref,\n ROWS: summary.rowCount,\n COLUMNS: summary.columnCount,\n ROW_TRUNCATED: summary.truncated,\n EXPIRES_AT: summary.expiresAt,\n }));\n print(csv(rows, [\"REF\", \"ROWS\", \"COLUMNS\", \"ROW_TRUNCATED\", \"EXPIRES_AT\"], DEFAULT_CELL_LIMIT));\n}\n\nasync function runPrune(): Promise<void> {\n print(`removed=${String(await pruneResultSessions())}`);\n}\n\nasync function runClear(): Promise<void> {\n print(`removed=${String(await clearResultSessions())}`);\n}\n\nexport function registerResultCommands(program: Command): void {\n const result = program.command(\"result\").description(\"inspect saved query refs\");\n result\n .command(\"show <ref>\")\n .description(\"show a saved result, row, cell, or JSON path\")\n .option(\"--row <n>\", \"one-based result row\", parseIntOption)\n .option(\"--column <name>\", \"exact column name\")\n .option(\"--offset <n>\", \"text code-point or binary byte offset\", parseIntOption)\n .option(\"--length <n>\", \"maximum characters or bytes to print\", parseIntOption)\n .option(\"--path <pointer>\", \"JSON Pointer inside a saved text cell\")\n .action(async (ref: string, _options: unknown, command: Command) => {\n await runShow(ref, command.opts<ShowOptions>());\n });\n result\n .command(\"search <ref> <text>\")\n .description(\"search saved text and JSON values\")\n .option(\"--row <n>\", \"one-based result row\", parseIntOption)\n .option(\"--column <name>\", \"exact column name\")\n .option(\"--limit <n>\", \"maximum matches to print\", parseIntOption)\n .option(\"--length <n>\", \"maximum preview characters\", parseIntOption)\n .action(async (ref: string, text: string, _options: unknown, command: Command) => {\n await runSearch(ref, text, command.opts<SearchOptions>());\n });\n result\n .command(\"export <ref>\")\n .description(\"write one exact saved cell to a file\")\n .requiredOption(\"--output <path>\", \"output file path\")\n .option(\"--row <n>\", \"one-based result row\", parseIntOption)\n .option(\"--column <name>\", \"exact column name\")\n .action(async (ref: string, _options: unknown, command: Command) => {\n await runExport(ref, command.opts<ExportOptions>());\n });\n result.command(\"list\").description(\"list active saved refs\").action(async () => {\n await runList();\n });\n result.command(\"prune\").description(\"remove expired saved refs\").action(async () => {\n await runPrune();\n });\n result.command(\"clear\").description(\"remove all saved refs\").action(async () => {\n await runClear();\n });\n}\n","import { CfHanaError } from \"./errors.js\";\nimport { isTextLobType } from \"./lob.js\";\nimport { previewCell } from \"./result-preview.js\";\nimport type { ResultSession } from \"./result-store.js\";\nimport type { QueryRow, SqlParam } from \"./types.js\";\n\nexport interface SelectedResultCell {\n readonly row: number;\n readonly column: string;\n readonly typeName: string;\n readonly value: SqlParam;\n}\n\nexport interface CellWindow {\n readonly type: \"text\" | \"binary\" | \"scalar\";\n readonly originalLength: number;\n readonly offset: number;\n readonly value: string;\n}\n\nexport interface JsonInspectionRow {\n readonly path: string;\n readonly type: string;\n readonly value: string;\n}\n\nexport interface ResultSearchOptions {\n readonly row?: number;\n readonly column?: string;\n readonly limit: number;\n readonly previewLength?: number;\n}\n\nexport interface ResultSearchMatch {\n readonly row: number;\n readonly column: string;\n readonly offset?: number;\n readonly path: string;\n readonly preview: string;\n}\n\nfunction assertPositiveInteger(name: string, value: number): void {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new CfHanaError(\n \"CONFIG\",\n `${name} ${String(value)} must be a positive safe integer`,\n );\n }\n}\n\n/** Select one saved result row using one-based numbering. */\nexport function selectResultRow(session: ResultSession, rowNumber: number): QueryRow {\n assertPositiveInteger(\"row\", rowNumber);\n const row = session.result.rows[rowNumber - 1];\n if (row === undefined) {\n throw new CfHanaError(\"QUERY\", `Saved result row ${String(rowNumber)} not found`);\n }\n return row;\n}\n\n/** Select one exact saved cell by its case-sensitive SQL display name. */\nexport function selectResultCell(\n session: ResultSession,\n rowNumber: number,\n columnName: string,\n): SelectedResultCell {\n const row = selectResultRow(session, rowNumber);\n const column = session.result.columns.find((item) => item.name === columnName);\n if (column === undefined) {\n throw new CfHanaError(\"QUERY\", `Saved result column \"${columnName}\" not found`);\n }\n return {\n row: rowNumber,\n column: column.name,\n typeName: column.typeName,\n value: row[column.name] ?? null,\n };\n}\n\nfunction textRange(value: string, offset: number, length: number): CellWindow {\n let index = 0;\n let selected = \"\";\n for (const char of value) {\n if (index >= offset && index < offset + length) {\n selected += char;\n }\n index += 1;\n }\n return { type: \"text\", originalLength: index, offset, value: selected };\n}\n\n/** Read a bounded range from an exact saved cell. */\nexport function readCellWindow(\n value: SqlParam,\n offset: number,\n length: number,\n typeName?: string,\n): CellWindow {\n if (!Number.isSafeInteger(offset) || offset < 0) {\n throw new CfHanaError(\"CONFIG\", \"offset must be a non-negative safe integer\");\n }\n assertPositiveInteger(\"length\", length);\n if (Buffer.isBuffer(value)) {\n if (isTextLobType(typeName)) {\n return textRange(value.toString(\"utf8\"), offset, length);\n }\n return {\n type: \"binary\",\n originalLength: value.length,\n offset,\n value: `0x${value.subarray(offset, offset + length).toString(\"hex\")}`,\n };\n }\n if (typeof value === \"string\") {\n return textRange(value, offset, length);\n }\n const text = previewCell(value, Number.MAX_SAFE_INTEGER).text;\n const window = textRange(text, offset, length);\n return { ...window, type: \"scalar\" };\n}\n\nfunction decodePointerToken(token: string): string {\n if (/~(?:[^01]|$)/.test(token)) {\n throw new CfHanaError(\"CONFIG\", \"Invalid JSON Pointer escape\");\n }\n return token.replaceAll(\"~1\", \"/\").replaceAll(\"~0\", \"~\");\n}\n\nfunction pointerTokens(pointer: string): readonly string[] {\n if (pointer === \"\") {\n return [];\n }\n if (!pointer.startsWith(\"/\")) {\n throw new CfHanaError(\"CONFIG\", \"JSON Pointer must be empty or start with /\");\n }\n return pointer.slice(1).split(\"/\").map(decodePointerToken);\n}\n\nfunction resolvePointer(root: unknown, pointer: string): unknown {\n let current = root;\n for (const token of pointerTokens(pointer)) {\n if (Array.isArray(current)) {\n const index = Number(token);\n if (!Number.isSafeInteger(index) || index < 0 || index >= current.length) {\n throw new CfHanaError(\"QUERY\", `JSON Pointer path \"${pointer}\" not found`);\n }\n current = current[index];\n continue;\n }\n if (typeof current === \"object\" && current !== null && token in current) {\n current = (current as Record<string, unknown>)[token];\n continue;\n }\n throw new CfHanaError(\"QUERY\", `JSON Pointer path \"${pointer}\" not found`);\n }\n return current;\n}\n\nfunction escapePointerToken(token: string): string {\n return token.replaceAll(\"~\", \"~0\").replaceAll(\"/\", \"~1\");\n}\n\nfunction jsonType(value: unknown): string {\n if (value === null) {\n return \"null\";\n }\n if (Array.isArray(value)) {\n return \"array\";\n }\n return typeof value;\n}\n\nfunction jsonValueText(value: unknown, limit: number): string {\n if (Array.isArray(value)) {\n return `items=${String(value.length)}`;\n }\n if (typeof value === \"object\" && value !== null) {\n return `keys=${String(Object.keys(value).length)}`;\n }\n if (typeof value === \"string\") {\n return previewCell(value, limit).text;\n }\n if (value === null) {\n return \"null\";\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return \"\";\n}\n\nfunction jsonSearchText(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value === null) {\n return \"null\";\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return \"\";\n}\n\nfunction inspectionRow(path: string, value: unknown, limit: number): JsonInspectionRow {\n return { path, type: jsonType(value), value: jsonValueText(value, limit) };\n}\n\n/** Resolve a JSON Pointer and describe the selected value or its immediate children. */\nexport function inspectJsonCell(\n value: SqlParam,\n pointer: string,\n limit: number,\n): readonly JsonInspectionRow[] {\n if (typeof value !== \"string\") {\n throw new CfHanaError(\"QUERY\", \"JSON Pointer requires a text cell\");\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(value) as unknown;\n } catch (error) {\n throw new CfHanaError(\"QUERY\", \"Saved result cell does not contain valid JSON\", {\n cause: error,\n });\n }\n const selected = resolvePointer(parsed, pointer);\n if (Array.isArray(selected)) {\n return selected.map((item, index) =>\n inspectionRow(`${pointer}/${String(index)}`, item, limit),\n );\n }\n if (typeof selected === \"object\" && selected !== null) {\n return Object.entries(selected).map(([key, item]) =>\n inspectionRow(`${pointer}/${escapePointerToken(key)}`, item, limit),\n );\n }\n return [inspectionRow(pointer, selected, limit)];\n}\n\nfunction plainTextMatches(\n text: string,\n term: string,\n row: number,\n column: string,\n limit: number,\n previewLength: number,\n): readonly ResultSearchMatch[] {\n const matches: ResultSearchMatch[] = [];\n const lowerText = text.toLowerCase();\n let offset = lowerText.indexOf(term);\n while (offset >= 0 && matches.length < limit) {\n const start = Math.max(0, offset - 32);\n matches.push({\n row,\n column,\n offset,\n path: \"\",\n preview: textRange(text, start, previewLength).value.replaceAll(/[\\r\\n\\t]/g, \" \"),\n });\n offset = lowerText.indexOf(term, offset + Math.max(1, term.length));\n }\n return matches;\n}\n\nfunction jsonSearchMatches(\n root: unknown,\n term: string,\n row: number,\n column: string,\n limit: number,\n previewLength: number,\n): readonly ResultSearchMatch[] {\n const matches: ResultSearchMatch[] = [];\n const stack: { readonly path: string; readonly value: unknown }[] = [\n { path: \"\", value: root },\n ];\n while (stack.length > 0 && matches.length < limit) {\n const entry = stack.pop();\n if (entry === undefined) {\n break;\n }\n if (typeof entry.value === \"object\" && entry.value !== null) {\n const entries = Array.isArray(entry.value)\n ? entry.value.map((item, index) => [String(index), item] as const)\n : Object.entries(entry.value);\n for (const [key, value] of entries.reverse()) {\n const path = `${entry.path}/${escapePointerToken(key)}`;\n if (key.toLowerCase().includes(term)) {\n matches.push({ row, column, path, preview: jsonValueText(value, previewLength) });\n if (matches.length >= limit) {\n break;\n }\n }\n stack.push({ path, value });\n }\n continue;\n }\n const text = jsonSearchText(entry.value);\n if (text.toLowerCase().includes(term)) {\n matches.push({\n row,\n column,\n path: entry.path,\n preview: previewCell(text, previewLength).text,\n });\n }\n }\n return matches;\n}\n\nfunction searchCell(\n value: SqlParam,\n term: string,\n row: number,\n column: string,\n typeName: string | undefined,\n limit: number,\n previewLength: number,\n): readonly ResultSearchMatch[] {\n const text = Buffer.isBuffer(value) && isTextLobType(typeName)\n ? value.toString(\"utf8\")\n : value;\n if (typeof text !== \"string\") {\n return [];\n }\n try {\n const parsed: unknown = JSON.parse(text);\n if (typeof parsed === \"object\" && parsed !== null) {\n return jsonSearchMatches(parsed, term, row, column, limit, previewLength);\n }\n } catch {\n // Non-JSON text is searched literally below.\n }\n return plainTextMatches(text, term, row, column, limit, previewLength);\n}\n\n/** Search exact saved text and JSON values without loading binary cells into output. */\nexport function searchResultSession(\n session: ResultSession,\n searchTerm: string,\n options: ResultSearchOptions,\n): readonly ResultSearchMatch[] {\n assertPositiveInteger(\"limit\", options.limit);\n const term = searchTerm.trim().toLowerCase();\n if (term.length === 0) {\n throw new CfHanaError(\"CONFIG\", \"search text must not be empty\");\n }\n const previewLength = options.previewLength ?? 128;\n assertPositiveInteger(\"preview length\", previewLength);\n const rows = options.row === undefined\n ? session.result.rows.map((row, index) => ({ row, rowNumber: index + 1 }))\n : [{ row: selectResultRow(session, options.row), rowNumber: options.row }];\n const columns = options.column === undefined\n ? session.result.columns\n : [selectResultCell(session, rows[0]?.rowNumber ?? 1, options.column)]\n .map((item) => ({ name: item.column, typeName: item.typeName }));\n const matches: ResultSearchMatch[] = [];\n for (const item of rows) {\n for (const column of columns) {\n const remaining = options.limit - matches.length;\n matches.push(\n ...searchCell(\n item.row[column.name] ?? null,\n term,\n item.rowNumber,\n column.name,\n column.typeName,\n remaining,\n previewLength,\n ),\n );\n if (matches.length >= options.limit) {\n return matches;\n }\n }\n }\n return matches;\n}\n","import { randomBytes } from \"node:crypto\";\nimport { mkdir, readFile, readdir, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport {\n DEFAULT_RESULT_TTL_MINUTES,\n MAX_RESULT_STORE_BYTES,\n} from \"./config.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type {\n HanaClientInfo,\n QueryResult,\n QueryResultColumn,\n QueryRow,\n SqlParam,\n StatementKind,\n} from \"./types.js\";\n\nconst RESULT_REF_PATTERN = /^q[0-9a-f]{8}$/;\nconst MANIFEST_FILE_NAME = \"manifest.json\";\n\ntype StoredCell =\n | { readonly kind: \"null\" }\n | { readonly kind: \"string\"; readonly value: string }\n | { readonly kind: \"number\"; readonly value: number }\n | { readonly kind: \"boolean\"; readonly value: boolean }\n | { readonly kind: \"date\"; readonly value: string }\n | { readonly kind: \"buffer\"; readonly value: string };\n\ninterface StoredResult {\n readonly columns: readonly QueryResultColumn[];\n readonly rows: readonly (readonly StoredCell[])[];\n readonly rowCount: number;\n readonly statement: StatementKind;\n readonly truncated: boolean;\n readonly elapsedMs: number;\n}\n\ninterface StoredResultSession {\n readonly version: 1;\n readonly ref: string;\n readonly createdAt: string;\n readonly expiresAt: string;\n readonly ttlMinutes: number;\n readonly info: HanaClientInfo;\n readonly result: StoredResult;\n}\n\nexport interface CreateResultSessionInput {\n readonly result: QueryResult;\n readonly info: HanaClientInfo;\n readonly ttlMinutes?: number;\n}\n\nexport interface ResultStoreOptions {\n readonly saptoolsRoot?: string;\n readonly now?: () => Date;\n readonly ref?: string;\n readonly maxBytes?: number;\n}\n\nexport interface ResultSession {\n readonly ref: string;\n readonly createdAt: string;\n readonly expiresAt: string;\n readonly ttlMinutes: number;\n readonly info: HanaClientInfo;\n readonly result: QueryResult;\n readonly directory: string;\n readonly path: string;\n}\n\nexport interface ResultSessionSummary {\n readonly ref: string;\n readonly createdAt: string;\n readonly expiresAt: string;\n readonly rowCount: number;\n readonly columnCount: number;\n readonly truncated: boolean;\n}\n\nfunction resultsRoot(saptoolsRoot?: string): string {\n return join(saptoolsRoot ?? join(homedir(), \".saptools\"), \"cf-hana\", \"results\");\n}\n\nfunction sessionDirectory(ref: string, saptoolsRoot?: string): string {\n return join(resultsRoot(saptoolsRoot), ref);\n}\n\nfunction manifestPath(ref: string, saptoolsRoot?: string): string {\n return join(sessionDirectory(ref, saptoolsRoot), MANIFEST_FILE_NAME);\n}\n\nfunction encodeCell(value: SqlParam): StoredCell {\n if (value === null) {\n return { kind: \"null\" };\n }\n if (Buffer.isBuffer(value)) {\n return { kind: \"buffer\", value: value.toString(\"base64\") };\n }\n if (value instanceof Date) {\n return { kind: \"date\", value: value.toISOString() };\n }\n if (typeof value === \"string\") {\n return { kind: \"string\", value };\n }\n if (typeof value === \"number\") {\n return { kind: \"number\", value };\n }\n return { kind: \"boolean\", value };\n}\n\nfunction decodeCell(cell: StoredCell): SqlParam {\n switch (cell.kind) {\n case \"null\":\n return null;\n case \"buffer\":\n return Buffer.from(cell.value, \"base64\");\n case \"date\":\n return new Date(cell.value);\n case \"string\":\n return cell.value;\n case \"number\":\n return cell.value;\n case \"boolean\":\n return cell.value;\n }\n}\n\nfunction assertUniqueColumns(columns: readonly QueryResultColumn[]): void {\n const names = new Set<string>();\n for (const column of columns) {\n if (names.has(column.name)) {\n throw new CfHanaError(\n \"CONFIG\",\n `Saved results require unique SQL aliases; duplicate column \"${column.name}\"`,\n );\n }\n names.add(column.name);\n }\n}\n\nfunction encodeResult(result: QueryResult): StoredResult {\n assertUniqueColumns(result.columns);\n return {\n columns: result.columns,\n rows: result.rows.map((row) =>\n result.columns.map((column) => encodeCell(row[column.name] ?? null)),\n ),\n rowCount: result.rowCount,\n statement: result.statement,\n truncated: result.truncated,\n elapsedMs: result.elapsedMs,\n };\n}\n\nfunction decodeResult(result: StoredResult): QueryResult {\n const rows: QueryRow[] = result.rows.map((cells) => {\n const row: QueryRow = {};\n let index = 0;\n for (const column of result.columns) {\n row[column.name] = decodeCell(cells[index] ?? { kind: \"null\" });\n index += 1;\n }\n return row;\n });\n return { ...result, rows };\n}\n\nfunction resolveRef(value: string | undefined): string {\n const ref = value ?? `q${randomBytes(4).toString(\"hex\")}`;\n if (!RESULT_REF_PATTERN.test(ref)) {\n throw new CfHanaError(\"CONFIG\", \"Invalid saved result ref\");\n }\n return ref;\n}\n\nfunction resolveTtl(value: number | undefined): number {\n const ttl = value ?? DEFAULT_RESULT_TTL_MINUTES;\n if (!Number.isSafeInteger(ttl) || ttl <= 0) {\n throw new CfHanaError(\"CONFIG\", \"Result TTL must be a positive safe integer\");\n }\n return ttl;\n}\n\nfunction toStoredSession(\n input: CreateResultSessionInput,\n ref: string,\n now: Date,\n): StoredResultSession {\n const ttlMinutes = resolveTtl(input.ttlMinutes);\n return {\n version: 1,\n ref,\n createdAt: now.toISOString(),\n expiresAt: new Date(now.getTime() + ttlMinutes * 60_000).toISOString(),\n ttlMinutes,\n info: input.info,\n result: encodeResult(input.result),\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isStoredSession(value: unknown): value is StoredResultSession {\n if (!isRecord(value) || !isRecord(value[\"result\"]) || !isRecord(value[\"info\"])) {\n return false;\n }\n const result = value[\"result\"];\n return (\n value[\"version\"] === 1 &&\n typeof value[\"ref\"] === \"string\" &&\n typeof value[\"createdAt\"] === \"string\" &&\n typeof value[\"expiresAt\"] === \"string\" &&\n typeof value[\"ttlMinutes\"] === \"number\" &&\n Array.isArray(result[\"columns\"]) &&\n Array.isArray(result[\"rows\"])\n );\n}\n\nasync function readStoredSession(path: string): Promise<StoredResultSession | undefined> {\n try {\n const parsed: unknown = JSON.parse(await readFile(path, \"utf8\"));\n return isStoredSession(parsed) ? parsed : undefined;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n return undefined;\n }\n}\n\nfunction toSession(stored: StoredResultSession, saptoolsRoot?: string): ResultSession {\n return {\n ...stored,\n result: decodeResult(stored.result),\n directory: sessionDirectory(stored.ref, saptoolsRoot),\n path: manifestPath(stored.ref, saptoolsRoot),\n };\n}\n\nasync function listSessionRefs(saptoolsRoot?: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(resultsRoot(saptoolsRoot), { withFileTypes: true });\n return entries\n .filter((entry) => entry.isDirectory() && RESULT_REF_PATTERN.test(entry.name))\n .map((entry) => entry.name);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/** Save one exact CLI SELECT result and return its temporary ref. */\nexport async function createResultSession(\n input: CreateResultSessionInput,\n options: ResultStoreOptions = {},\n): Promise<ResultSession> {\n await pruneResultSessions(options);\n const ref = resolveRef(options.ref);\n const stored = toStoredSession(input, ref, options.now?.() ?? new Date());\n const serialized = `${JSON.stringify(stored)}\\n`;\n if (Buffer.byteLength(serialized) > (options.maxBytes ?? MAX_RESULT_STORE_BYTES)) {\n throw new CfHanaError(\"CONFIG\", \"Saved result exceeds the storage limit\");\n }\n\n const root = resultsRoot(options.saptoolsRoot);\n const finalDirectory = sessionDirectory(ref, options.saptoolsRoot);\n const tempDirectory = `${finalDirectory}.tmp-${process.pid.toString()}`;\n await mkdir(root, { recursive: true, mode: 0o700 });\n await rm(tempDirectory, { recursive: true, force: true });\n await mkdir(tempDirectory, { mode: 0o700 });\n try {\n await writeFile(join(tempDirectory, MANIFEST_FILE_NAME), serialized, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n await rename(tempDirectory, finalDirectory);\n } catch (error) {\n await rm(tempDirectory, { recursive: true, force: true });\n throw error;\n }\n return toSession(stored, options.saptoolsRoot);\n}\n\n/** Read one active saved result by ref. */\nexport async function readResultSession(\n ref: string,\n options: ResultStoreOptions = {},\n): Promise<ResultSession> {\n const resolvedRef = resolveRef(ref);\n await pruneResultSessions(options);\n const stored = await readStoredSession(manifestPath(resolvedRef, options.saptoolsRoot));\n if (stored === undefined) {\n throw new CfHanaError(\"QUERY\", \"Saved result not found or expired\");\n }\n return toSession(stored, options.saptoolsRoot);\n}\n\n/** List active saved results without loading their full decoded values. */\nexport async function listResultSessions(\n options: ResultStoreOptions = {},\n): Promise<readonly ResultSessionSummary[]> {\n await pruneResultSessions(options);\n const refs = await listSessionRefs(options.saptoolsRoot);\n const stored = await Promise.all(\n refs.map(async (ref) => await readStoredSession(manifestPath(ref, options.saptoolsRoot))),\n );\n return stored\n .filter((item): item is StoredResultSession => item !== undefined)\n .map((item) => ({\n ref: item.ref,\n createdAt: item.createdAt,\n expiresAt: item.expiresAt,\n rowCount: item.result.rowCount,\n columnCount: item.result.columns.length,\n truncated: item.result.truncated,\n }))\n .sort((left, right) => left.ref.localeCompare(right.ref));\n}\n\n/** Remove expired or malformed saved result sessions. */\nexport async function pruneResultSessions(options: ResultStoreOptions = {}): Promise<number> {\n const refs = await listSessionRefs(options.saptoolsRoot);\n const now = (options.now?.() ?? new Date()).getTime();\n let removed = 0;\n for (const ref of refs) {\n const stored = await readStoredSession(manifestPath(ref, options.saptoolsRoot));\n if (stored === undefined || Date.parse(stored.expiresAt) <= now) {\n await rm(sessionDirectory(ref, options.saptoolsRoot), { recursive: true, force: true });\n removed += 1;\n }\n }\n return removed;\n}\n\n/** Remove every saved result session. */\nexport async function clearResultSessions(options: ResultStoreOptions = {}): Promise<number> {\n const refs = await listSessionRefs(options.saptoolsRoot);\n await Promise.all(\n refs.map(async (ref) => {\n await rm(sessionDirectory(ref, options.saptoolsRoot), { recursive: true, force: true });\n }),\n );\n return refs.length;\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { HanaClientInfo } from \"./types.js\";\n\nexport const METADATA_CACHE_TTL_MS = 30 * 60_000;\n\nexport interface CatalogObjectInfo {\n readonly schema: string;\n readonly name: string;\n readonly type: \"TABLE\" | \"VIEW\";\n}\n\ninterface StoredMetadataCache {\n readonly version: 1;\n readonly createdAt: string;\n readonly scope: MetadataCacheScope;\n readonly objects: readonly CatalogObjectInfo[];\n}\n\nexport interface MetadataCacheScope {\n readonly selector: string;\n readonly appName: string;\n readonly host: string;\n readonly schema: string;\n readonly role: string;\n readonly driver: string;\n}\n\nexport interface MetadataCacheOptions {\n readonly saptoolsRoot?: string;\n readonly now?: () => Date;\n}\n\nfunction metadataCacheRoot(saptoolsRoot?: string): string {\n return join(saptoolsRoot ?? join(homedir(), \".saptools\"), \"cf-hana\", \"metadata\");\n}\n\nexport function toMetadataCacheScope(info: HanaClientInfo): MetadataCacheScope {\n return {\n selector: info.selector,\n appName: info.appName,\n host: info.host,\n schema: info.schema,\n role: info.role,\n driver: info.driver,\n };\n}\n\nexport function metadataCacheKey(scope: MetadataCacheScope): string {\n return createHash(\"sha256\").update(JSON.stringify(scope)).digest(\"hex\");\n}\n\nfunction metadataCachePath(scope: MetadataCacheScope, saptoolsRoot?: string): string {\n return join(metadataCacheRoot(saptoolsRoot), `${metadataCacheKey(scope)}.json`);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isCatalogObject(value: unknown): value is CatalogObjectInfo {\n return (\n isRecord(value) &&\n typeof value[\"schema\"] === \"string\" &&\n typeof value[\"name\"] === \"string\" &&\n (value[\"type\"] === \"TABLE\" || value[\"type\"] === \"VIEW\")\n );\n}\n\nfunction isScope(value: unknown): value is MetadataCacheScope {\n return (\n isRecord(value) &&\n typeof value[\"selector\"] === \"string\" &&\n typeof value[\"appName\"] === \"string\" &&\n typeof value[\"host\"] === \"string\" &&\n typeof value[\"schema\"] === \"string\" &&\n typeof value[\"role\"] === \"string\" &&\n typeof value[\"driver\"] === \"string\"\n );\n}\n\nfunction scopesEqual(left: MetadataCacheScope, right: MetadataCacheScope): boolean {\n return metadataCacheKey(left) === metadataCacheKey(right);\n}\n\nfunction isStored(value: unknown): value is StoredMetadataCache {\n return (\n isRecord(value) &&\n value[\"version\"] === 1 &&\n typeof value[\"createdAt\"] === \"string\" &&\n isScope(value[\"scope\"]) &&\n Array.isArray(value[\"objects\"]) &&\n value[\"objects\"].every(isCatalogObject)\n );\n}\n\nexport async function readMetadataCache(\n scope: MetadataCacheScope,\n options: MetadataCacheOptions = {},\n): Promise<readonly CatalogObjectInfo[] | undefined> {\n try {\n const parsed: unknown = JSON.parse(\n await readFile(metadataCachePath(scope, options.saptoolsRoot), \"utf8\"),\n );\n if (!isStored(parsed) || !scopesEqual(parsed.scope, scope)) {\n return undefined;\n }\n const createdAt = Date.parse(parsed.createdAt);\n const now = options.now?.() ?? new Date();\n const ageMs = now.getTime() - createdAt;\n if (!Number.isFinite(createdAt) || ageMs < 0 || ageMs >= METADATA_CACHE_TTL_MS) {\n return undefined;\n }\n return parsed.objects;\n } catch {\n return undefined;\n }\n}\n\nexport async function writeMetadataCache(\n scope: MetadataCacheScope,\n objects: readonly CatalogObjectInfo[],\n options: MetadataCacheOptions = {},\n): Promise<void> {\n const root = metadataCacheRoot(options.saptoolsRoot);\n const path = metadataCachePath(scope, options.saptoolsRoot);\n const tempPath = `${path}.tmp-${process.pid.toString()}`;\n const stored: StoredMetadataCache = {\n version: 1,\n createdAt: (options.now?.() ?? new Date()).toISOString(),\n scope,\n objects,\n };\n await mkdir(root, { recursive: true, mode: 0o700 });\n await rm(tempPath, { force: true });\n await writeFile(tempPath, `${JSON.stringify(stored)}\\n`, { encoding: \"utf8\", mode: 0o600 });\n await rename(tempPath, path);\n}\n\nexport async function loadCatalogObjectsWithCache(\n scope: MetadataCacheScope,\n refresh: boolean,\n loader: () => Promise<readonly CatalogObjectInfo[]>,\n options: MetadataCacheOptions = {},\n): Promise<readonly CatalogObjectInfo[]> {\n if (!refresh) {\n const cached = await readMetadataCache(scope, options);\n if (cached !== undefined) {\n return cached;\n }\n }\n const objects = await loader();\n try {\n await writeMetadataCache(scope, objects, options);\n } catch {\n // A cache write failure must not suppress suggestions built from fresh metadata.\n }\n return objects;\n}\n","import { QueryError } from \"./errors.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\n\nexport interface MissingObjectName {\n readonly schema?: string;\n readonly name: string;\n}\n\nconst INVALID_OBJECT_PATTERNS = [\n /invalid\\s+(?:table|view|object)\\s+name/i,\n /(?:table|view|object)\\s+[^\\n]*does\\s+not\\s+exist/i,\n /could\\s+not\\s+find\\s+(?:table|view|object)/i,\n];\n\nconst REF_KEYWORDS = new Set([\"FROM\", \"JOIN\", \"UPDATE\", \"INTO\", \"TABLE\"]);\nconst STOP_WORDS = new Set([\n \"AS\",\n \"ON\",\n \"WHERE\",\n \"SET\",\n \"VALUES\",\n \"USING\",\n \"WHEN\",\n \"INNER\",\n \"LEFT\",\n \"RIGHT\",\n \"FULL\",\n \"OUTER\",\n \"CROSS\",\n \"JOIN\",\n]);\nconst CTE_FOLLOWERS = new Set([\"AS\"]);\n\ntype TokenKind = \"word\" | \"quoted\" | \"dot\" | \"comma\" | \"open\" | \"close\" | \"other\";\n\ninterface Token {\n readonly kind: TokenKind;\n readonly text: string;\n}\n\nexport function isInvalidCatalogObjectError(error: unknown): boolean {\n if (!(error instanceof QueryError)) {\n return false;\n }\n if (error.sqlState === \"42S02\" || error.sqlState === \"42S01\") {\n return true;\n }\n return INVALID_OBJECT_PATTERNS.some((pattern) => pattern.test(error.message));\n}\n\nfunction skipLineComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && sql[cursor] !== \"\\n\") {\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipBlockComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && !(sql[cursor] === \"*\" && sql[cursor + 1] === \"/\")) {\n cursor += 1;\n }\n return Math.min(cursor + 2, sql.length);\n}\n\nfunction skipStringLiteral(sql: string, index: number): number {\n let cursor = index + 1;\n while (cursor < sql.length) {\n if (sql[cursor] === \"'\" && sql[cursor + 1] === \"'\") {\n cursor += 2;\n continue;\n }\n if (sql[cursor] === \"'\") {\n return cursor + 1;\n }\n cursor += 1;\n }\n return cursor;\n}\n\nfunction readQuotedIdentifier(sql: string, index: number): { readonly text: string; readonly next: number } {\n let cursor = index + 1;\n let text = \"\";\n while (cursor < sql.length) {\n if (sql[cursor] === '\"' && sql[cursor + 1] === '\"') {\n text += '\"';\n cursor += 2;\n continue;\n }\n if (sql[cursor] === '\"') {\n return { text, next: cursor + 1 };\n }\n text += sql.charAt(cursor);\n cursor += 1;\n }\n return { text, next: cursor };\n}\n\nfunction readBareWord(sql: string, index: number): { readonly text: string; readonly next: number } {\n let cursor = index;\n let text = \"\";\n while (cursor < sql.length && /[A-Za-z0-9_#$]/.test(sql.charAt(cursor))) {\n text += sql.charAt(cursor);\n cursor += 1;\n }\n return { text, next: cursor };\n}\n\nfunction tokenize(sql: string): readonly Token[] {\n const tokens: Token[] = [];\n let index = 0;\n while (index < sql.length) {\n const char = sql.charAt(index);\n if (/\\s/.test(char)) {\n index += 1;\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n index = skipLineComment(sql, index);\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index = skipBlockComment(sql, index);\n continue;\n }\n if (char === \"'\") {\n index = skipStringLiteral(sql, index);\n continue;\n }\n if (char === '\"') {\n const quoted = readQuotedIdentifier(sql, index);\n tokens.push({ kind: \"quoted\", text: quoted.text });\n index = quoted.next;\n continue;\n }\n if (/[A-Za-z_#$]/.test(char)) {\n const word = readBareWord(sql, index);\n tokens.push({ kind: \"word\", text: word.text });\n index = word.next;\n continue;\n }\n if (char === \".\") {\n tokens.push({ kind: \"dot\", text: char });\n } else if (char === \",\") {\n tokens.push({ kind: \"comma\", text: char });\n } else if (char === \"(\") {\n tokens.push({ kind: \"open\", text: char });\n } else if (char === \")\") {\n tokens.push({ kind: \"close\", text: char });\n } else {\n tokens.push({ kind: \"other\", text: char });\n }\n index += 1;\n }\n return tokens;\n}\n\nfunction upper(token: Token | undefined): string {\n return token?.text.toUpperCase() ?? \"\";\n}\n\nfunction isIdentifier(token: Token | undefined): token is Token {\n return token?.kind === \"word\" || token?.kind === \"quoted\";\n}\n\nfunction readName(\n tokens: readonly Token[],\n start: number,\n allowFollowingParens = false,\n): { readonly name: MissingObjectName; readonly next: number } | undefined {\n const first = tokens[start];\n if (!isIdentifier(first)) {\n return undefined;\n }\n\n let next = start + 1;\n let schema: string | undefined;\n let name = first.text;\n const maybeObject = tokens[next + 1];\n if (tokens[next]?.kind === \"dot\" && isIdentifier(maybeObject)) {\n schema = name;\n name = maybeObject.text;\n next += 2;\n }\n if (!allowFollowingParens && tokens[next]?.kind === \"open\") {\n return undefined;\n }\n return { name: schema === undefined ? { name } : { schema, name }, next };\n}\n\n\nfunction firstNameFromText(text: string): MissingObjectName | undefined {\n const tokens = tokenize(text);\n for (let index = 0; index < tokens.length; index += 1) {\n const read = readName(tokens, index, true);\n if (read !== undefined) {\n return read.name;\n }\n }\n return undefined;\n}\n\nexport function extractMissingObjectNameFromError(error: unknown): MissingObjectName | undefined {\n if (!(error instanceof QueryError)) {\n return undefined;\n }\n\n const message = error.message;\n const invalidName = /invalid\\s+(?:table|view|object)\\s+name\\s*:?\\s*(.+)$/i.exec(message);\n if (invalidName?.[1] !== undefined) {\n return firstNameFromText(invalidName[1]);\n }\n\n const missingObject = /(?:table|view|object)\\s+(.+?)\\s+(?:does\\s+not\\s+exist|not\\s+found)/i.exec(message);\n if (missingObject?.[1] !== undefined) {\n return firstNameFromText(missingObject[1]);\n }\n\n return undefined;\n}\n\nfunction cteNames(tokens: readonly Token[]): ReadonlySet<string> {\n const names = new Set<string>();\n if (upper(tokens[0]) !== \"WITH\") {\n return names;\n }\n\n let depth = 0;\n for (let index = 1; index < tokens.length; index += 1) {\n const token = tokens[index];\n if (depth === 0 && upper(token) === \"SELECT\") {\n break;\n }\n if (depth === 0 && isIdentifier(token) && CTE_FOLLOWERS.has(upper(tokens[index + 1]))) {\n names.add(token.text.toUpperCase());\n }\n if (token?.kind === \"open\") {\n depth += 1;\n } else if (token?.kind === \"close\" && depth > 0) {\n depth -= 1;\n }\n }\n return names;\n}\n\nexport function extractMissingObjectName(sql: string): MissingObjectName | undefined {\n const tokens = tokenize(sql.replace(/^;+|;+$/g, \"\"));\n const ctes = cteNames(tokens);\n let candidate: MissingObjectName | undefined;\n for (let index = 0; index < tokens.length; index += 1) {\n const word = upper(tokens[index]);\n if (!REF_KEYWORDS.has(word)) {\n continue;\n }\n if (word === \"TABLE\" && upper(tokens[index - 1]) !== \"TRUNCATE\") {\n continue;\n }\n if (\n word === \"INTO\" &&\n !(upper(tokens[index - 1]) === \"INSERT\" || upper(tokens[index - 1]) === \"MERGE\")\n ) {\n continue;\n }\n const read = readName(tokens, index + 1, word === \"INTO\");\n if (read === undefined) {\n continue;\n }\n if (read.name.schema === undefined && ctes.has(read.name.name.toUpperCase())) {\n continue;\n }\n if (STOP_WORDS.has(read.name.name.toUpperCase())) {\n continue;\n }\n candidate = read.name;\n let next = read.next;\n if (isIdentifier(tokens[next]) && !STOP_WORDS.has(upper(tokens[next]))) {\n next += 1;\n }\n while (tokens[next]?.kind === \"comma\") {\n const commaRead = readName(tokens, next + 1);\n if (commaRead === undefined) {\n break;\n }\n if (!(commaRead.name.schema === undefined && ctes.has(commaRead.name.name.toUpperCase()))) {\n candidate = commaRead.name;\n }\n next = commaRead.next;\n if (isIdentifier(tokens[next]) && !STOP_WORDS.has(upper(tokens[next]))) {\n next += 1;\n }\n }\n }\n return candidate;\n}\n\nfunction singular(value: string): string {\n if (value.endsWith(\"ES\")) {\n return value.slice(0, -2);\n }\n if (value.endsWith(\"S\")) {\n return value.slice(0, -1);\n }\n return value;\n}\n\nfunction norm(value: string): string {\n return value.toUpperCase().replace(/[^A-Z0-9]+/g, \"\");\n}\n\nfunction distance(a: string, b: string): number {\n const previous = Array.from({ length: b.length + 1 }, (_value, index) => index);\n for (let leftIndex = 1; leftIndex <= a.length; leftIndex += 1) {\n let last = leftIndex - 1;\n previous[0] = leftIndex;\n for (let rightIndex = 1; rightIndex <= b.length; rightIndex += 1) {\n const old = previous[rightIndex] ?? 0;\n previous[rightIndex] = Math.min(\n (previous[rightIndex] ?? 0) + 1,\n (previous[rightIndex - 1] ?? 0) + 1,\n last + (a.charAt(leftIndex - 1) === b.charAt(rightIndex - 1) ? 0 : 1),\n );\n last = old;\n }\n }\n return previous[b.length] ?? 0;\n}\n\nfunction score(requested: MissingObjectName, candidate: CatalogObjectInfo): number {\n const requestedName = norm(requested.name);\n const candidateName = norm(candidate.name);\n if (requested.schema !== undefined && norm(requested.schema) !== norm(candidate.schema)) {\n return 0;\n }\n if (requestedName === candidateName) {\n return 100;\n }\n if (singular(requestedName) === singular(candidateName)) {\n return 92;\n }\n let value = 0;\n if (candidateName.startsWith(requestedName) || requestedName.startsWith(candidateName)) {\n value = Math.max(value, 80 - Math.abs(candidateName.length - requestedName.length));\n }\n if (candidateName.endsWith(requestedName) || requestedName.endsWith(candidateName)) {\n value = Math.max(value, 70 - Math.abs(candidateName.length - requestedName.length));\n }\n const editDistance = distance(requestedName, candidateName);\n const max = Math.max(requestedName.length, candidateName.length, 1);\n if (editDistance <= Math.max(3, Math.floor(max * 0.35))) {\n value = Math.max(value, Math.round(75 * (1 - editDistance / max)));\n }\n return value;\n}\n\nexport interface NameSuggestion {\n readonly name: string;\n}\n\nexport function extractInvalidColumnNameFromError(error: unknown): string | undefined {\n if (!(error instanceof QueryError)) {\n return undefined;\n }\n const match = /invalid column name:\\s*([^:]+)/i.exec(error.message);\n const name = match?.[1]?.trim();\n return name === undefined || name.length === 0 ? undefined : name;\n}\n\nexport function rankCatalogSuggestions(\n requested: MissingObjectName,\n candidates: readonly CatalogObjectInfo[],\n limit = 5,\n): readonly CatalogObjectInfo[] {\n return candidates\n .map((candidate) => ({ candidate, score: score(requested, candidate) }))\n .filter((item) => item.score >= 45)\n .sort(\n (left, right) =>\n right.score - left.score ||\n left.candidate.schema.localeCompare(right.candidate.schema) ||\n (left.candidate.type === right.candidate.type\n ? 0\n : left.candidate.type === \"TABLE\"\n ? -1\n : 1) ||\n left.candidate.name.localeCompare(right.candidate.name),\n )\n .slice(0, limit)\n .map((item) => item.candidate);\n}\n\nexport function formatSuggestions(suggestions: readonly CatalogObjectInfo[]): string | undefined {\n if (suggestions.length === 0) {\n return undefined;\n }\n return [\n \"Did you mean:\",\n ...suggestions.map((item) => ` ${item.schema}.${item.name} (${item.type})`),\n ].join(\"\\n\");\n}\n\nexport function rankNameSuggestions<T extends NameSuggestion>(\n requested: string,\n candidates: readonly T[],\n limit = 5,\n): readonly T[] {\n const requestedName = { name: requested };\n return candidates\n .map((candidate) => ({\n candidate,\n score: score(requestedName, { schema: \"\", name: candidate.name, type: \"TABLE\" }),\n }))\n .filter((item) => item.score >= 45)\n .sort(\n (left, right) =>\n right.score - left.score || left.candidate.name.localeCompare(right.candidate.name),\n )\n .slice(0, limit)\n .map((item) => item.candidate);\n}\n\nexport function formatColumnSuggestions(suggestions: readonly NameSuggestion[]): string | undefined {\n if (suggestions.length === 0) {\n return undefined;\n }\n return [\n \"Did you mean column:\",\n ...suggestions.map((item) => ` ${item.name}`),\n ].join(\"\\n\");\n}\n"],"mappings":"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","names":["typeName","typeName","join","norm","appendFile","mkdir","rm","homedir","join","SAPTOOLS_DIR_NAME","CF_HANA_DIR_NAME","defaultSaptoolsRoot","skipQuotedText","skipLineComment","skipBlockComment","writeFile","typeName","mkdir","readdir","rm","writeFile","homedir","join","join","homedir","isRecord","readdir","mkdir","rm","writeFile","typeName","writeFile","mkdir","readFile","rename","rm","writeFile","homedir","join","isRecord","skipLineComment","skipBlockComment","print","parseIntOption"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/backup.ts","../src/errors.ts","../src/lob.ts","../src/result-preview.ts","../src/format.ts","../src/statements.ts","../src/builder.ts","../src/catalog.ts","../src/config.ts","../src/cf.ts","../src/credentials.ts","../src/driver/fake.ts","../src/driver/hdb.ts","../src/driver/index.ts","../src/history.ts","../src/safety.ts","../src/connection.ts","../src/pool.ts","../src/transaction.ts","../src/client.ts","../src/api.ts","../src/cli-results.ts","../src/result-inspect.ts","../src/result-store.ts","../src/metadata-cache.ts","../src/suggestions.ts"],"sourcesContent":["import { Command } from \"commander\";\n\nimport { connect } from \"./api.js\";\nimport { registerResultCommands } from \"./cli-results.js\";\nimport type { HanaClient } from \"./client.js\";\nimport {\n CLI_NAME,\n CLI_VERSION,\n DEFAULT_AUTO_LIMIT,\n DEFAULT_CELL_LIMIT,\n MAX_CELL_LIMIT,\n} from \"./config.js\";\nimport { CfHanaError, QueryError, databaseCode, errorMessage } from \"./errors.js\";\nimport { formatCompactCsv, formatResult, formatTable } from \"./format.js\";\nimport { loadCatalogObjectsWithCache, toMetadataCacheScope } from \"./metadata-cache.js\";\nimport { createResultSession } from \"./result-store.js\";\nimport { classifyStatement } from \"./statements.js\";\nimport {\n extractInvalidColumnNameFromError,\n extractMissingObjectName,\n extractMissingObjectNameFromError,\n formatColumnSuggestions,\n formatSuggestions,\n isInvalidCatalogObjectError,\n rankCatalogSuggestions,\n rankNameSuggestions,\n} from \"./suggestions.js\";\nimport type {\n ConnectOptions,\n DbUserRole,\n HanaClientInfo,\n OutputFormat,\n QueryResult,\n QueryRow,\n} from \"./types.js\";\n\ninterface ConnectionCliOptions {\n readonly refresh: boolean;\n readonly role: string;\n readonly binding?: string;\n readonly bindingIndex?: number;\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n readonly timeout?: number;\n readonly limit?: number;\n readonly autoLimit: boolean;\n readonly refreshMetadata: boolean;\n}\n\ninterface FormattedCliOptions extends ConnectionCliOptions {\n readonly format: string;\n}\n\ninterface QueryCliOptions extends ConnectionCliOptions {\n readonly param?: readonly string[];\n readonly save: boolean;\n readonly cellLimit?: number;\n readonly resultTtlMinutes?: number;\n}\n\nfunction print(text: string): void {\n process.stdout.write(`${text}\\n`);\n}\n\nfunction fail(message: string): never {\n process.stderr.write(`${CLI_NAME}: ${message}\\n`);\n process.exit(1);\n}\n\nfunction parseIntOption(value: string): number {\n const trimmed = value.trim();\n if (!/^-?\\d+$/.test(trimmed)) {\n throw new CfHanaError(\"CONFIG\", `Expected an integer but received \"${value}\"`);\n }\n const parsed = Number(trimmed);\n if (!Number.isSafeInteger(parsed)) {\n throw new CfHanaError(\"CONFIG\", `Expected a safe integer but received \"${value}\"`);\n }\n return parsed;\n}\n\nfunction assertPositiveOption(name: string, value: number | undefined): void {\n if (value !== undefined && value <= 0) {\n throw new CfHanaError(\"CONFIG\", `${name} must be a positive integer`);\n }\n}\n\nfunction assertNonNegativeOption(name: string, value: number | undefined): void {\n if (value !== undefined && value < 0) {\n throw new CfHanaError(\"CONFIG\", `${name} must be a non-negative integer`);\n }\n}\n\nfunction collectParam(value: string, previous: readonly string[]): readonly string[] {\n return [...previous, value];\n}\n\nfunction parseRole(role: string): DbUserRole {\n if (role === \"runtime\" || role === \"hdi\") {\n return role;\n }\n throw new CfHanaError(\"CONFIG\", `Invalid --role \"${role}\" (expected runtime or hdi)`);\n}\n\nfunction parseFormat(format: string): OutputFormat {\n if (format === \"table\" || format === \"json\" || format === \"csv\") {\n return format;\n }\n throw new CfHanaError(\"CONFIG\", `Invalid --format \"${format}\" (expected table, json, or csv)`);\n}\n\nfunction parseQualifiedName(value: string): { readonly schema: string; readonly table: string } {\n const dot = value.indexOf(\".\");\n if (dot <= 0 || dot >= value.length - 1) {\n throw new CfHanaError(\"CONFIG\", `Expected schema.table but received \"${value}\"`);\n }\n return { schema: value.slice(0, dot), table: value.slice(dot + 1) };\n}\n\nfunction toConnectOptions(opts: ConnectionCliOptions): ConnectOptions {\n assertPositiveOption(\"--limit\", opts.limit);\n assertPositiveOption(\"--timeout\", opts.timeout);\n assertNonNegativeOption(\"--binding-index\", opts.bindingIndex);\n\n return {\n refresh: opts.refresh,\n role: parseRole(opts.role),\n readOnly: opts.readOnly,\n allowDestructive: opts.allowDestructive,\n autoLimit: opts.autoLimit ? (opts.limit ?? DEFAULT_AUTO_LIMIT) : false,\n ...(opts.binding === undefined ? {} : { bindingName: opts.binding }),\n ...(opts.bindingIndex === undefined ? {} : { bindingIndex: opts.bindingIndex }),\n ...(opts.timeout === undefined\n ? {}\n : { queryTimeoutMs: opts.timeout, connectTimeoutMs: opts.timeout }),\n };\n}\n\nfunction resolveCellLimit(value: number | undefined): number {\n const limit = value ?? DEFAULT_CELL_LIMIT;\n assertPositiveOption(\"--cell-limit\", limit);\n if (limit > MAX_CELL_LIMIT) {\n throw new CfHanaError(\"CONFIG\", `--cell-limit must be at most ${String(MAX_CELL_LIMIT)}`);\n }\n return limit;\n}\n\nfunction assertQueryOptions(sql: string, opts: QueryCliOptions): void {\n resolveCellLimit(opts.cellLimit);\n assertPositiveOption(\"--result-ttl-minutes\", opts.resultTtlMinutes);\n if (opts.save && classifyStatement(sql) !== \"select\") {\n throw new CfHanaError(\"CONFIG\", \"--save is only available for SELECT/WITH statements\");\n }\n}\n\nfunction rowsToResult(rows: readonly QueryRow[]): QueryResult {\n const first = rows[0];\n const columns =\n first === undefined\n ? []\n : Object.keys(first).map((name) => ({ name, typeName: \"\" }));\n return {\n rows,\n columns,\n rowCount: rows.length,\n statement: \"select\",\n truncated: false,\n elapsedMs: 0,\n };\n}\n\nfunction formatInfo(info: HanaClientInfo): string {\n return [\n `selector ${info.selector}`,\n `app ${info.appName}`,\n `host ${info.host}`,\n `schema ${info.schema}`,\n `role ${info.role}`,\n `driver ${info.driver}`,\n `credential source ${info.credentialSource}`,\n ].join(\"\\n\");\n}\n\nfunction withConnectionOptions(command: Command): Command {\n return command\n .option(\"--refresh\", \"deprecated compatibility flag; binding discovery is already live\", false)\n .option(\"--role <role>\", \"HANA user role: runtime or hdi\", \"runtime\")\n .option(\"--binding <name>\", \"select a HANA binding by service name\")\n .option(\"--binding-index <n>\", \"select a HANA binding by index\", parseIntOption)\n .option(\"--read-only\", \"block every DML and DDL statement\", false)\n .option(\"--allow-destructive\", \"permit destructive statements\", false)\n .option(\"--timeout <ms>\", \"connection and query timeout in milliseconds\", parseIntOption)\n .option(\"--limit <n>\", \"row cap auto-applied to bare SELECT statements\", parseIntOption)\n .option(\"--no-auto-limit\", \"disable the automatic SELECT row cap\")\n .option(\"--refresh-metadata\", \"bypass the 30-minute table/view metadata suggestion cache\", false);\n}\n\nfunction withFormattedConnectionOptions(command: Command): Command {\n return withConnectionOptions(command).option(\n \"--format <format>\",\n \"output format: table, json, or csv\",\n \"table\",\n );\n}\n\nasync function loadSuggestionCatalogObjects(\n client: HanaClient,\n refresh: boolean,\n): Promise<Awaited<ReturnType<HanaClient[\"listCatalogObjects\"]>>> {\n try {\n return await loadCatalogObjectsWithCache(\n toMetadataCacheScope(client.info),\n refresh,\n async () => await client.listCatalogObjects(client.info.schema),\n );\n } catch {\n // Retry one direct catalog read for transient metadata lookup failures. The\n // retry intentionally bypasses cache writes so another cache failure cannot\n // hide useful suggestions or the original query error.\n return await client.listCatalogObjects(client.info.schema);\n }\n}\n\nfunction isLobSortOrGroupError(error: unknown): boolean {\n const code = databaseCode(error);\n if (code !== 266 && code !== 274) {\n return false;\n }\n return (\n error instanceof QueryError &&\n /LOB type is not allowed in (?:ORDER BY|GROUP BY) clause/i.test(error.message)\n );\n}\n\nfunction printLobSortOrGroupHint(): void {\n const lines = [\n `${CLI_NAME}: HANA cannot ORDER BY or GROUP BY NCLOB/CLOB/BLOB columns directly.`,\n `${CLI_NAME}: Remove the LOB column from ORDER BY/GROUP BY or wrap it as TO_VARCHAR(<column>).`,\n ];\n process.stderr.write(`${lines.join(\"\\n\")}\\n`);\n}\n\nasync function printColumnSuggestions(\n error: unknown,\n client: HanaClient,\n sql: string,\n): Promise<void> {\n if (databaseCode(error) !== 260) {\n return;\n }\n const columnName = extractInvalidColumnNameFromError(error);\n const tableName = extractMissingObjectName(sql);\n if (columnName === undefined || tableName === undefined) {\n return;\n }\n\n try {\n const columns = await client.listColumns(\n tableName.schema ?? client.info.schema,\n tableName.name,\n );\n const text = formatColumnSuggestions(rankNameSuggestions(columnName, columns));\n if (text !== undefined) {\n process.stderr.write(`${text}\\n`);\n }\n } catch {\n // Column metadata failures are intentionally silent: stderr should stay\n // focused on the original query failure unless reliable suggestions exist.\n }\n}\n\nasync function printCatalogObjectSuggestions(\n error: unknown,\n client: HanaClient,\n sql: string,\n refresh: boolean,\n): Promise<void> {\n if (!isInvalidCatalogObjectError(error)) {\n return;\n }\n const requested = extractMissingObjectNameFromError(error) ?? extractMissingObjectName(sql);\n if (requested === undefined) {\n return;\n }\n try {\n const objects = await loadSuggestionCatalogObjects(client, refresh);\n const text = formatSuggestions(rankCatalogSuggestions(requested, objects));\n if (text !== undefined) {\n process.stderr.write(`${text}\\n`);\n }\n } catch {\n // Metadata lookup failures are intentionally silent: stderr should stay\n // focused on the original query failure unless reliable suggestions exist.\n }\n}\n\nasync function enrichAndRethrowQueryError(\n error: unknown,\n client: HanaClient,\n sql: string,\n refresh: boolean,\n): Promise<never> {\n if (isLobSortOrGroupError(error)) {\n printLobSortOrGroupHint();\n throw error;\n }\n\n await printColumnSuggestions(error, client, sql);\n await printCatalogObjectSuggestions(error, client, sql, refresh);\n throw error;\n}\n\nasync function runQuery(selector: string, sql: string, command: Command): Promise<void> {\n const opts = command.opts<QueryCliOptions>();\n assertQueryOptions(sql, opts);\n const cellLimit = resolveCellLimit(opts.cellLimit);\n const client = await connect(selector, toConnectOptions(opts));\n try {\n const params = opts.param ?? [];\n let backup: Awaited<ReturnType<HanaClient[\"backupWriteStatement\"]>>;\n try {\n backup = await client.backupWriteStatement(sql, params);\n } catch (error) {\n await enrichAndRethrowQueryError(error, client, sql, opts.refreshMetadata);\n }\n if (backup !== undefined) {\n process.stderr.write(`${CLI_NAME}: backup saved to ${backup.directory}\\n`);\n }\n const result = await client\n .query(sql, params)\n .catch(async (error: unknown): Promise<QueryResult> => {\n return await enrichAndRethrowQueryError(\n error,\n client,\n sql,\n opts.refreshMetadata,\n );\n });\n if (result.statement === \"select\") {\n const compact = formatCompactCsv(result, cellLimit);\n if (opts.save) {\n const session = await createResultSession({\n result,\n info: client.info,\n ...(opts.resultTtlMinutes === undefined ? {} : { ttlMinutes: opts.resultTtlMinutes }),\n });\n print(`ref=${session.ref}`);\n }\n print(compact.text);\n if (result.truncated) {\n process.stderr.write(`${CLI_NAME}: row limit reached; rerun with --limit for more rows\\n`);\n }\n if (compact.truncatedCells > 0) {\n process.stderr.write(\n `${CLI_NAME}: compacted ${String(compact.truncatedCells)} cell(s); ` +\n \"use --save to inspect exact values by ref\\n\",\n );\n }\n return;\n }\n print(formatTable(result));\n } finally {\n await client.close();\n }\n}\n\nasync function runTables(\n selector: string,\n schema: string | undefined,\n command: Command,\n): Promise<void> {\n const opts = command.opts<FormattedCliOptions>();\n const client = await connect(selector, toConnectOptions(opts));\n try {\n const tables = await client.listTables(schema ?? client.info.schema);\n const rows: readonly QueryRow[] = tables.map((table) => ({\n SCHEMA: table.schema,\n TABLE: table.name,\n TYPE: table.type,\n }));\n print(formatResult(rowsToResult(rows), parseFormat(opts.format)));\n } finally {\n await client.close();\n }\n}\n\nasync function runColumns(selector: string, target: string, command: Command): Promise<void> {\n const opts = command.opts<FormattedCliOptions>();\n const { schema, table } = parseQualifiedName(target);\n const client = await connect(selector, toConnectOptions(opts));\n try {\n const columns = await client.listColumns(schema, table);\n const rows: readonly QueryRow[] = columns.map((column) => ({\n COLUMN: column.name,\n TYPE: column.dataType,\n LENGTH: column.length ?? null,\n NULLABLE: column.nullable,\n POSITION: column.position,\n }));\n print(formatResult(rowsToResult(rows), parseFormat(opts.format)));\n } finally {\n await client.close();\n }\n}\n\nasync function runCount(selector: string, target: string, command: Command): Promise<void> {\n const opts = command.opts<ConnectionCliOptions>();\n const { schema, table } = parseQualifiedName(target);\n const client = await connect(selector, toConnectOptions(opts));\n try {\n const total = await client.count({ schema, table });\n print(String(total));\n } finally {\n await client.close();\n }\n}\n\nasync function runPing(selector: string, command: Command): Promise<void> {\n const opts = command.opts<ConnectionCliOptions>();\n const client = await connect(selector, toConnectOptions(opts));\n try {\n const started = Date.now();\n await client.query(\"SELECT 1 FROM DUMMY\");\n print(\n `OK ${client.info.host} schema=${client.info.schema} ` +\n `${String(Date.now() - started)}ms`,\n );\n } finally {\n await client.close();\n }\n}\n\nasync function runInfo(selector: string, command: Command): Promise<void> {\n const opts = command.opts<ConnectionCliOptions>();\n const client = await connect(selector, toConnectOptions(opts));\n try {\n print(formatInfo(client.info));\n } finally {\n await client.close();\n }\n}\n\nfunction buildProgram(): Command {\n const program = new Command();\n program\n .name(CLI_NAME)\n .description(\"Run SQL against SAP HANA Cloud databases bound to a Cloud Foundry app\")\n .version(CLI_VERSION);\n\n withConnectionOptions(\n program\n .command(\"query <selector> <sql>\")\n .description(\"run a single SQL statement\")\n .option(\"--param <value>\", \"bind a SQL parameter (repeatable)\", collectParam, [])\n .option(\"--save\", \"save exact returned rows for follow-up inspection\", false)\n .option(\"--cell-limit <n>\", \"maximum visible characters per data cell\", parseIntOption)\n .option(\n \"--result-ttl-minutes <n>\",\n \"minutes before a saved result expires\",\n parseIntOption,\n ),\n ).action(async (selector: string, sql: string, _options: unknown, command: Command) => {\n await runQuery(selector, sql, command);\n });\n\n withFormattedConnectionOptions(\n program.command(\"tables <selector> [schema]\").description(\"list tables in a schema\"),\n ).action(\n async (selector: string, schema: string | undefined, _options: unknown, command: Command) => {\n await runTables(selector, schema, command);\n },\n );\n\n withFormattedConnectionOptions(\n program\n .command(\"columns <selector> <schema.table>\")\n .description(\"list the columns of a table\"),\n ).action(async (selector: string, target: string, _options: unknown, command: Command) => {\n await runColumns(selector, target, command);\n });\n\n withConnectionOptions(\n program.command(\"count <selector> <schema.table>\").description(\"count rows in a table\"),\n ).action(async (selector: string, target: string, _options: unknown, command: Command) => {\n await runCount(selector, target, command);\n });\n\n withConnectionOptions(\n program.command(\"ping <selector>\").description(\"connect and measure round-trip latency\"),\n ).action(async (selector: string, _options: unknown, command: Command) => {\n await runPing(selector, command);\n });\n\n withConnectionOptions(\n program.command(\"info <selector>\").description(\"print the resolved connection metadata\"),\n ).action(async (selector: string, _options: unknown, command: Command) => {\n await runInfo(selector, command);\n });\n\n registerResultCommands(program);\n\n return program;\n}\n\ntry {\n await buildProgram().parseAsync(process.argv);\n} catch (error) {\n fail(errorMessage(error));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { QueryError } from \"./errors.js\";\nimport { formatCsv } from \"./format.js\";\nimport { assertParamArity, countPlaceholders, firstKeyword } from \"./statements.js\";\nimport type { QueryResult, SqlParam } from \"./types.js\";\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst BACKUPS_DIR_NAME = \"backups\";\n\nexport type WriteBackupOperation = \"update\" | \"upsert\" | \"delete\";\n\nexport interface WriteBackupPlan {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly selectSql: string;\n readonly selectParams: readonly SqlParam[];\n}\n\nexport interface SqlBackupWriteInput {\n readonly operation: WriteBackupOperation;\n readonly statementSql: string;\n readonly result: QueryResult;\n readonly selector?: string;\n}\n\nexport interface SqlBackupWriteOptions {\n readonly now?: Date;\n readonly saptoolsRoot?: string;\n}\n\nexport interface SqlBackupRecord {\n readonly directory: string;\n readonly statementPath: string;\n readonly backupPath: string;\n readonly metadataPath: string;\n readonly rowCount: number;\n}\n\ntype TopLevelKeyword = \"UPDATE\" | \"UPSERT\" | \"DELETE\" | \"SET\" | \"FROM\" | \"VALUES\" | \"WHERE\";\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction trimStatementSql(sql: string): string {\n return sql.trim().replace(/;+\\s*$/, \"\").trim();\n}\n\nfunction isIdentifierChar(char: string | undefined): boolean {\n return char !== undefined && /[A-Za-z0-9_$#]/.test(char);\n}\n\nfunction skipQuotedText(sql: string, index: number): number {\n const quote = sql[index];\n let cursor = index + 1;\n while (cursor < sql.length) {\n if (sql[cursor] === quote) {\n if (sql[cursor + 1] === quote) {\n cursor += 2;\n continue;\n }\n return cursor + 1;\n }\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipLineComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && sql[cursor] !== \"\\n\") {\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipBlockComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && !(sql[cursor] === \"*\" && sql[cursor + 1] === \"/\")) {\n cursor += 1;\n }\n return Math.min(cursor + 2, sql.length);\n}\n\nfunction skipNonCode(sql: string, index: number): number | undefined {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n return skipQuotedText(sql, index);\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n return skipLineComment(sql, index);\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n return skipBlockComment(sql, index);\n }\n return undefined;\n}\n\nfunction keywordMatches(sql: string, index: number, keyword: TopLevelKeyword): boolean {\n const end = index + keyword.length;\n return (\n sql.slice(index, end).toUpperCase() === keyword &&\n !isIdentifierChar(sql[index - 1]) &&\n !isIdentifierChar(sql[end])\n );\n}\n\nfunction findTopLevelKeyword(\n sql: string,\n keyword: TopLevelKeyword,\n startIndex = 0,\n): number | undefined {\n let index = startIndex;\n let depth = 0;\n while (index < sql.length) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n\n const char = sql[index];\n if (char === \"(\") {\n depth += 1;\n } else if (char === \")\" && depth > 0) {\n depth -= 1;\n } else if (depth === 0 && keywordMatches(sql, index, keyword)) {\n return index;\n }\n index += 1;\n }\n return undefined;\n}\n\nfunction findTopLevelChar(\n sql: string,\n target: string,\n startIndex: number,\n endIndex: number,\n): number | undefined {\n let index = startIndex;\n let depth = 0;\n while (index < endIndex) {\n const skipped = skipNonCode(sql, index);\n if (skipped !== undefined) {\n index = skipped;\n continue;\n }\n\n const char = sql[index];\n if (char === target && depth === 0) {\n return index;\n }\n if (char === \"(\") {\n depth += 1;\n } else if (char === \")\" && depth > 0) {\n depth -= 1;\n }\n index += 1;\n }\n return undefined;\n}\n\nfunction selectParamsAfterWhere(\n statementSql: string,\n whereIndex: number,\n params: readonly SqlParam[],\n): readonly SqlParam[] {\n return params.slice(countPlaceholders(statementSql.slice(0, whereIndex)));\n}\n\nfunction buildSelectPlan(\n operation: WriteBackupOperation,\n statementSql: string,\n targetSql: string,\n whereIndex: number | undefined,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const target = targetSql.trim();\n if (target.length === 0) {\n throw new QueryError(`${operation.toUpperCase()} backup requires a target table`);\n }\n if (whereIndex === undefined) {\n return { operation, statementSql, selectSql: `SELECT * FROM ${target}`, selectParams: [] };\n }\n\n const whereSql = statementSql.slice(whereIndex + \"WHERE\".length).trim();\n if (whereSql.length === 0) {\n throw new QueryError(`${operation.toUpperCase()} backup requires a non-empty WHERE clause`);\n }\n return {\n operation,\n statementSql,\n selectSql: `SELECT * FROM ${target} WHERE ${whereSql}`,\n selectParams: selectParamsAfterWhere(statementSql, whereIndex, params),\n };\n}\n\nfunction buildUpdateBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const updateIndex = findTopLevelKeyword(statementSql, \"UPDATE\");\n const setIndex =\n updateIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"SET\", updateIndex + \"UPDATE\".length);\n if (updateIndex === undefined || setIndex === undefined) {\n throw new QueryError(\"UPDATE backup requires UPDATE <target> SET syntax\");\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", setIndex + \"SET\".length);\n return buildSelectPlan(\n \"update\",\n statementSql,\n statementSql.slice(updateIndex + \"UPDATE\".length, setIndex),\n whereIndex,\n params,\n );\n}\n\nfunction buildUpsertBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const upsertIndex = findTopLevelKeyword(statementSql, \"UPSERT\");\n const valuesIndex =\n upsertIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"VALUES\", upsertIndex + \"UPSERT\".length);\n if (upsertIndex === undefined || valuesIndex === undefined) {\n throw new QueryError(\"UPSERT backup requires UPSERT <target> VALUES syntax\");\n }\n\n const targetStart = upsertIndex + \"UPSERT\".length;\n const columnListIndex = findTopLevelChar(statementSql, \"(\", targetStart, valuesIndex);\n const targetEnd = columnListIndex ?? valuesIndex;\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", valuesIndex + \"VALUES\".length);\n return buildSelectPlan(\n \"upsert\",\n statementSql,\n statementSql.slice(targetStart, targetEnd),\n whereIndex,\n params,\n );\n}\n\nfunction buildDeleteBackupPlan(\n statementSql: string,\n params: readonly SqlParam[],\n): WriteBackupPlan {\n const deleteIndex = findTopLevelKeyword(statementSql, \"DELETE\");\n const fromIndex =\n deleteIndex === undefined\n ? undefined\n : findTopLevelKeyword(statementSql, \"FROM\", deleteIndex + \"DELETE\".length);\n if (deleteIndex === undefined || fromIndex === undefined) {\n throw new QueryError(\"DELETE backup requires DELETE FROM <target> syntax\");\n }\n\n const whereIndex = findTopLevelKeyword(statementSql, \"WHERE\", fromIndex + \"FROM\".length);\n const targetEnd = whereIndex ?? statementSql.length;\n return buildSelectPlan(\n \"delete\",\n statementSql,\n statementSql.slice(fromIndex + \"FROM\".length, targetEnd),\n whereIndex,\n params,\n );\n}\n\nfunction backupTimestamp(now: Date): string {\n return now.toISOString().replace(/:/g, \"\").replace(\".\", \"\");\n}\n\nfunction backupMonth(now: Date): string {\n const year = String(now.getUTCFullYear());\n const month = String(now.getUTCMonth() + 1).padStart(2, \"0\");\n return `${year}${month}`;\n}\n\nfunction sanitizePathPart(value: string | undefined): string {\n const trimmed = value?.trim() ?? \"\";\n const normalized = trimmed\n .replace(/[^A-Za-z0-9._-]+/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n return normalized.length > 0 ? normalized : \"unknown-target\";\n}\n\nfunction backupBaseName(input: SqlBackupWriteInput, now: Date): string {\n return [sanitizePathPart(input.selector), input.operation, backupTimestamp(now)].join(\"-\");\n}\n\nexport function cfHanaBackupRoot(saptoolsRoot?: string): string {\n return join(saptoolsRoot ?? defaultSaptoolsRoot(), CF_HANA_DIR_NAME, BACKUPS_DIR_NAME);\n}\n\nexport function buildWriteBackupPlan(\n sql: string,\n params: readonly SqlParam[] = [],\n): WriteBackupPlan | undefined {\n const statementSql = trimStatementSql(sql);\n const keyword = firstKeyword(statementSql);\n if (keyword !== \"UPDATE\" && keyword !== \"UPSERT\" && keyword !== \"DELETE\") {\n return undefined;\n }\n\n assertParamArity(statementSql, params);\n if (keyword === \"UPDATE\") {\n return buildUpdateBackupPlan(statementSql, params);\n }\n if (keyword === \"UPSERT\") {\n return buildUpsertBackupPlan(statementSql, params);\n }\n return buildDeleteBackupPlan(statementSql, params);\n}\n\nexport async function writeSqlBackup(\n input: SqlBackupWriteInput,\n options: SqlBackupWriteOptions = {},\n): Promise<SqlBackupRecord> {\n const now = options.now ?? new Date();\n const directory = join(cfHanaBackupRoot(options.saptoolsRoot), backupMonth(now));\n const baseName = backupBaseName(input, now);\n const statementPath = join(directory, `${baseName}.statement.sql`);\n const backupPath = join(directory, `${baseName}.sql`);\n const metadataPath = join(directory, `${baseName}.json`);\n const metadata = {\n selector: input.selector ?? null,\n operation: input.operation,\n statementPath,\n backupPath,\n rowCount: input.result.rowCount,\n createdAt: now.toISOString(),\n };\n\n await mkdir(directory, { recursive: true, mode: 0o700 });\n await Promise.all([\n writeFile(statementPath, `${input.statementSql}\\n`, { encoding: \"utf8\", mode: 0o600 }),\n writeFile(backupPath, formatCsv(input.result), { encoding: \"utf8\", mode: 0o600 }),\n writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n }),\n ]);\n\n return {\n directory,\n statementPath,\n backupPath,\n metadataPath,\n rowCount: input.result.rowCount,\n };\n}\n","export type CfHanaErrorCode =\n | \"CONFIG\"\n | \"CREDENTIALS_NOT_FOUND\"\n | \"AMBIGUOUS_BINDING\"\n | \"CONNECTION\"\n | \"QUERY\"\n | \"READ_ONLY_VIOLATION\"\n | \"DESTRUCTIVE_BLOCKED\"\n | \"TIMEOUT\"\n | \"POOL_CLOSED\";\n\nexport interface CfHanaErrorOptions {\n readonly cause?: unknown;\n}\n\nexport interface QueryErrorOptions extends CfHanaErrorOptions {\n readonly sqlState?: string;\n readonly databaseCode?: number;\n}\n\n/** Base error for every failure surfaced by `@saptools/cf-hana`. */\nexport class CfHanaError extends Error {\n readonly code: CfHanaErrorCode;\n\n constructor(code: CfHanaErrorCode, message: string, options?: CfHanaErrorOptions) {\n super(message, options);\n this.name = \"CfHanaError\";\n this.code = code;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** No HANA credentials could be resolved for the requested selector. */\nexport class CredentialsNotFoundError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"CREDENTIALS_NOT_FOUND\", message, options);\n this.name = \"CredentialsNotFoundError\";\n }\n}\n\n/** A SQL statement failed on the HANA server. */\nexport class QueryError extends CfHanaError {\n readonly sqlState: string | undefined;\n readonly databaseCode: number | undefined;\n\n constructor(message: string, options?: QueryErrorOptions) {\n super(\"QUERY\", message, options);\n this.name = \"QueryError\";\n this.sqlState = options?.sqlState;\n this.databaseCode = options?.databaseCode;\n }\n}\n\nfunction isDatabaseErrorShape(error: unknown): error is { readonly code?: unknown } {\n return typeof error === \"object\" && error !== null && \"code\" in error;\n}\n\nfunction safeDatabaseCode(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isSafeInteger(value)) {\n return value;\n }\n if (typeof value !== \"string\" || !/^\\d+$/.test(value)) {\n return undefined;\n }\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) ? parsed : undefined;\n}\n\n/** Extract a numeric HANA database error code from wrapped query failures. */\nexport function databaseCode(error: unknown): number | undefined {\n if (error instanceof QueryError) {\n return error.databaseCode ?? databaseCode(error.cause);\n }\n if (isDatabaseErrorShape(error)) {\n return safeDatabaseCode(error.code);\n }\n return undefined;\n}\n\n/** A write/DDL statement was issued on a read-only client. */\nexport class ReadOnlyViolationError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"READ_ONLY_VIOLATION\", message, options);\n this.name = \"ReadOnlyViolationError\";\n }\n}\n\n/** A destructive statement was blocked because it was not explicitly allowed. */\nexport class DestructiveStatementError extends CfHanaError {\n constructor(message: string, options?: CfHanaErrorOptions) {\n super(\"DESTRUCTIVE_BLOCKED\", message, options);\n this.name = \"DestructiveStatementError\";\n }\n}\n\n/** Narrow an unknown thrown value to a human-readable message. */\nexport function errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n return String(error);\n}\n","/** HANA column types whose Buffer values represent text rather than binary bytes. */\nconst TEXT_LOB_TYPES = new Set([\"CLOB\", \"NCLOB\"]);\n\nfunction normalizeTypeName(typeName: string | undefined): string {\n return typeName?.trim().toUpperCase() ?? \"\";\n}\n\nexport function isTextLobType(typeName: string | undefined): boolean {\n return TEXT_LOB_TYPES.has(normalizeTypeName(typeName));\n}\n","import { isTextLobType } from \"./lob.js\";\nimport type { SqlParam } from \"./types.js\";\n\nexport type PreviewUnit = \"chars\" | \"bytes\";\n\nexport interface CellPreview {\n readonly text: string;\n readonly truncated: boolean;\n readonly originalLength: number;\n readonly unit: PreviewUnit;\n}\n\nfunction normalizePreviewChar(value: string): string {\n return value === \"\\r\" || value === \"\\n\" || value === \"\\t\" ? \" \" : value;\n}\n\nfunction previewText(value: string, limit: number): CellPreview {\n let originalLength = 0;\n let text = \"\";\n for (const char of value) {\n if (originalLength < limit) {\n text += normalizePreviewChar(char);\n }\n originalLength += 1;\n }\n return {\n text,\n truncated: originalLength > limit,\n originalLength,\n unit: \"chars\",\n };\n}\n\nfunction previewBuffer(value: Buffer, limit: number): CellPreview {\n const fullLength = 2 + value.length * 2;\n const visibleBytes = Math.max(0, Math.floor((limit - 2) / 2));\n const hex = value.subarray(0, visibleBytes).toString(\"hex\");\n return {\n text: `0x${hex}`.slice(0, limit),\n truncated: fullLength > limit,\n originalLength: value.length,\n unit: \"bytes\",\n };\n}\n\nfunction scalarText(value: Exclude<SqlParam, string | Buffer | null>): string {\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n return value.toString();\n}\n\n/** Produce a bounded, single-line representation of one result cell. */\nexport function previewCell(value: SqlParam, limit: number, typeName?: string): CellPreview {\n if (value === null) {\n return { text: \"\", truncated: false, originalLength: 0, unit: \"chars\" };\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(typeName)\n ? previewText(value.toString(\"utf8\"), limit)\n : previewBuffer(value, limit);\n }\n if (typeof value === \"string\") {\n return previewText(value, limit);\n }\n return previewText(scalarText(value), limit);\n}\n","import { isTextLobType } from \"./lob.js\";\nimport { previewCell } from \"./result-preview.js\";\nimport type { OutputFormat, QueryResult, QueryResultColumn, SqlParam } from \"./types.js\";\n\ntype JsonCell = string | number | boolean | null;\n\nfunction cellText(value: SqlParam, nullText: string, column?: QueryResultColumn): string {\n if (value === null) {\n return nullText;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(column?.typeName)\n ? value.toString(\"utf8\")\n : `0x${value.toString(\"hex\")}`;\n }\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n return typeof value === \"number\" ? value.toString() : value;\n}\n\nfunction serializeCell(value: SqlParam, column?: QueryResultColumn): JsonCell {\n if (value === null) {\n return null;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (Buffer.isBuffer(value)) {\n return isTextLobType(column?.typeName)\n ? value.toString(\"utf8\")\n : `0x${value.toString(\"hex\")}`;\n }\n return value;\n}\n\nfunction csvEscape(text: string): string {\n if (/[\",\\r\\n]/.test(text)) {\n return `\"${text.replace(/\"/g, '\"\"')}\"`;\n }\n return text;\n}\n\nexport interface CompactCsv {\n readonly text: string;\n readonly truncatedCells: number;\n}\n\n/** Render a result as an aligned ASCII table. */\nexport function formatTable(result: QueryResult): string {\n if (result.columns.length === 0) {\n return `(${String(result.rowCount)} row(s) affected)`;\n }\n\n const headers = result.columns.map((column) => column.name);\n const rows = result.rows.map((row) =>\n result.columns.map((column) => cellText(row[column.name] ?? null, \"NULL\", column)),\n );\n const widths = headers.map((header, index) => {\n const widest = rows.reduce(\n (max, cells) => Math.max(max, (cells[index] ?? \"\").length),\n header.length,\n );\n return widest;\n });\n\n const renderRow = (cells: readonly string[]): string =>\n cells.map((cell, index) => cell.padEnd(widths[index] ?? 0)).join(\" | \");\n const separator = widths.map((width) => \"-\".repeat(width)).join(\"-+-\");\n const body = rows.map((cells) => renderRow(cells));\n\n return [renderRow(headers), separator, ...body].join(\"\\n\");\n}\n\n/** Render a result's rows as pretty-printed JSON. */\nexport function formatJson(result: QueryResult): string {\n const rows = result.rows.map((row) => {\n const serialized: Record<string, JsonCell> = {};\n for (const [key, value] of Object.entries(row)) {\n const column = result.columns.find((item) => item.name === key);\n serialized[key] = serializeCell(value, column);\n }\n return serialized;\n });\n return JSON.stringify(rows, null, 2);\n}\n\n/** Render a result as RFC 4180 CSV. */\nexport function formatCsv(result: QueryResult): string {\n const headers = result.columns.map((column) => column.name);\n const lines = [headers.map((header) => csvEscape(header)).join(\",\")];\n for (const row of result.rows) {\n lines.push(\n result.columns\n .map((column) => csvEscape(cellText(row[column.name] ?? null, \"\", column)))\n .join(\",\"),\n );\n }\n return lines.join(\"\\r\\n\");\n}\n\n/** Render bounded CSV for CLI SELECT output without mutating the source result. */\nexport function formatCompactCsv(result: QueryResult, cellLimit: number): CompactCsv {\n const headers = result.columns.map((column) => column.name);\n const lines = [headers.map((header) => csvEscape(header)).join(\",\")];\n let truncatedCells = 0;\n for (const row of result.rows) {\n const cells = result.columns.map((column) => {\n const preview = previewCell(row[column.name] ?? null, cellLimit, column.typeName);\n if (preview.truncated) {\n truncatedCells += 1;\n }\n return csvEscape(preview.text);\n });\n lines.push(cells.join(\",\"));\n }\n return { text: lines.join(\"\\r\\n\"), truncatedCells };\n}\n\n/** Render a query result in the requested output format. */\nexport function formatResult(result: QueryResult, format: OutputFormat): string {\n switch (format) {\n case \"table\":\n return formatTable(result);\n case \"json\":\n return formatJson(result);\n case \"csv\":\n return formatCsv(result);\n }\n}\n","import { QueryError } from \"./errors.js\";\nimport type { SqlParam, StatementKind } from \"./types.js\";\n\nconst LEADING_NOISE = /^(?:\\s|--[^\\n]*\\n?|\\/\\*[\\s\\S]*?\\*\\/)+/;\n\nconst SELECT_KEYWORDS = new Set([\"SELECT\", \"WITH\"]);\nconst DML_KEYWORDS = new Set([\"INSERT\", \"UPDATE\", \"DELETE\", \"MERGE\", \"UPSERT\", \"REPLACE\"]);\nconst DDL_KEYWORDS = new Set([\"CREATE\", \"DROP\", \"ALTER\", \"TRUNCATE\", \"RENAME\", \"COMMENT\"]);\n\n/** The leading SQL keyword, upper-cased, skipping comments and whitespace. */\nexport function firstKeyword(sql: string): string {\n const stripped = sql.replace(LEADING_NOISE, \"\");\n const match = /^[A-Za-z]+/.exec(stripped);\n return (match?.[0] ?? \"\").toUpperCase();\n}\n\n/** Classify a SQL statement by its leading keyword. */\nexport function classifyStatement(sql: string): StatementKind {\n const keyword = firstKeyword(sql);\n if (SELECT_KEYWORDS.has(keyword)) {\n return \"select\";\n }\n if (DML_KEYWORDS.has(keyword)) {\n return \"dml\";\n }\n if (DDL_KEYWORDS.has(keyword)) {\n return \"ddl\";\n }\n return \"unknown\";\n}\n\n/** Quote a SQL identifier (table/column name) for safe interpolation. */\nexport function quoteIdentifier(identifier: string): string {\n if (identifier.length === 0) {\n throw new QueryError(\"A SQL identifier must not be empty\");\n }\n if (identifier.includes(\"\\0\")) {\n throw new QueryError(\"A SQL identifier must not contain a NUL character\");\n }\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\n/** Build a `\"schema\".\"table\"` qualified, quoted name. */\nexport function qualifiedName(schema: string, table: string): string {\n return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;\n}\n\n/** Count `?` placeholders, skipping string literals, quoted identifiers, and comments. */\nexport function countPlaceholders(sql: string): number {\n let count = 0;\n let index = 0;\n const length = sql.length;\n\n while (index < length) {\n const char = sql[index];\n\n if (char === \"'\" || char === '\"') {\n const quote = char;\n index += 1;\n while (index < length) {\n if (sql[index] === quote) {\n if (sql[index + 1] === quote) {\n index += 2;\n continue;\n }\n index += 1;\n break;\n }\n index += 1;\n }\n continue;\n }\n\n if (char === \"-\" && sql[index + 1] === \"-\") {\n index += 2;\n while (index < length && sql[index] !== \"\\n\") {\n index += 1;\n }\n continue;\n }\n\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index += 2;\n while (index < length && !(sql[index] === \"*\" && sql[index + 1] === \"/\")) {\n index += 1;\n }\n index += 2;\n continue;\n }\n\n if (char === \"?\") {\n count += 1;\n }\n index += 1;\n }\n\n return count;\n}\n\n/** Throw when the number of `?` placeholders does not match the parameter count. */\nexport function assertParamArity(sql: string, params: readonly SqlParam[]): void {\n const expected = countPlaceholders(sql);\n if (expected !== params.length) {\n throw new QueryError(\n `SQL expects ${String(expected)} bound parameter(s) ` +\n `but received ${String(params.length)} value(s)`,\n );\n }\n}\n","import { QueryError } from \"./errors.js\";\nimport { qualifiedName, quoteIdentifier } from \"./statements.js\";\nimport type { BuiltStatement, SelectSpec, SqlParam } from \"./types.js\";\n\ninterface WhereClause {\n readonly clause: string;\n readonly params: readonly SqlParam[];\n}\n\nfunction buildWhere(where: Readonly<Record<string, SqlParam>> | undefined): WhereClause {\n if (where === undefined) {\n return { clause: \"\", params: [] };\n }\n const entries = Object.entries(where);\n if (entries.length === 0) {\n return { clause: \"\", params: [] };\n }\n const conditions = entries.map(([column]) => `${quoteIdentifier(column)} = ?`);\n return {\n clause: ` WHERE ${conditions.join(\" AND \")}`,\n params: entries.map(([, value]) => value),\n };\n}\n\n/** Build a parameterized `SELECT` statement from a typed spec. */\nexport function buildSelect(spec: SelectSpec): BuiltStatement {\n const columns =\n spec.columns === undefined || spec.columns.length === 0\n ? \"*\"\n : spec.columns.map((column) => quoteIdentifier(column)).join(\", \");\n const where = buildWhere(spec.where);\n const clauses: string[] = [\n `SELECT ${columns} FROM ${qualifiedName(spec.schema, spec.table)}${where.clause}`,\n ];\n\n if (spec.orderBy !== undefined && spec.orderBy.length > 0) {\n clauses.push(`ORDER BY ${spec.orderBy.map((column) => quoteIdentifier(column)).join(\", \")}`);\n }\n if (spec.limit !== undefined) {\n clauses.push(`LIMIT ${String(spec.limit)}`);\n }\n if (spec.offset !== undefined) {\n clauses.push(`OFFSET ${String(spec.offset)}`);\n }\n\n return { sql: clauses.join(\" \"), params: where.params };\n}\n\n/** Build a parameterized `SELECT COUNT(*)` statement. */\nexport function buildCount(\n spec: Pick<SelectSpec, \"schema\" | \"table\" | \"where\">,\n): BuiltStatement {\n const where = buildWhere(spec.where);\n return {\n sql: `SELECT COUNT(*) AS \"COUNT\" FROM ${qualifiedName(spec.schema, spec.table)}${where.clause}`,\n params: where.params,\n };\n}\n\n/** Build a parameterized single-row `INSERT` statement. */\nexport function buildInsert(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const entries = Object.entries(values);\n if (entries.length === 0) {\n throw new QueryError(\"INSERT requires at least one column value\");\n }\n const columns = entries.map(([column]) => quoteIdentifier(column)).join(\", \");\n const placeholders = entries.map(() => \"?\").join(\", \");\n return {\n sql: `INSERT INTO ${qualifiedName(schema, table)} (${columns}) VALUES (${placeholders})`,\n params: entries.map(([, value]) => value),\n };\n}\n\n/** Build a parameterized `UPDATE` statement. A non-empty `where` is required. */\nexport function buildUpdate(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n where: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const valueEntries = Object.entries(values);\n if (valueEntries.length === 0) {\n throw new QueryError(\"UPDATE requires at least one column value\");\n }\n const whereClause = buildWhere(where);\n if (whereClause.clause === \"\") {\n throw new QueryError(\"UPDATE requires a non-empty WHERE filter to avoid a full-table write\");\n }\n const assignments = valueEntries\n .map(([column]) => `${quoteIdentifier(column)} = ?`)\n .join(\", \");\n return {\n sql: `UPDATE ${qualifiedName(schema, table)} SET ${assignments}${whereClause.clause}`,\n params: [...valueEntries.map(([, value]) => value), ...whereClause.params],\n };\n}\n\n/** Build a parameterized `DELETE` statement. A non-empty `where` is required. */\nexport function buildDelete(\n schema: string,\n table: string,\n where: Readonly<Record<string, SqlParam>>,\n): BuiltStatement {\n const whereClause = buildWhere(where);\n if (whereClause.clause === \"\") {\n throw new QueryError(\"DELETE requires a non-empty WHERE filter to avoid a full-table delete\");\n }\n return {\n sql: `DELETE FROM ${qualifiedName(schema, table)}${whereClause.clause}`,\n params: whereClause.params,\n };\n}\n","import type { Connection } from \"./connection.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\nimport type { ColumnInfo, TableInfo } from \"./types.js\";\n\ninterface SchemaRow {\n readonly SCHEMA_NAME: string;\n}\n\ninterface TableRow {\n readonly SCHEMA_NAME: string;\n readonly TABLE_NAME: string;\n readonly TABLE_TYPE: string;\n}\n\ninterface CatalogObjectRow {\n readonly SCHEMA_NAME: string;\n readonly OBJECT_NAME: string;\n readonly OBJECT_TYPE: \"TABLE\" | \"VIEW\";\n}\n\ninterface ColumnRow {\n readonly COLUMN_NAME: string;\n readonly DATA_TYPE_NAME: string;\n readonly LENGTH: number | null;\n readonly SCALE: number | null;\n readonly IS_NULLABLE: string;\n readonly POSITION: number;\n}\n\nexport interface TableDescription {\n readonly table: TableInfo | undefined;\n readonly columns: readonly ColumnInfo[];\n}\n\n/** List every schema visible to the current user. */\nexport async function listSchemas(connection: Connection): Promise<readonly string[]> {\n const result = await connection.query<SchemaRow>(\n \"SELECT SCHEMA_NAME FROM SYS.SCHEMAS ORDER BY SCHEMA_NAME\",\n [],\n { autoLimit: false },\n );\n return result.rows.map((row) => row.SCHEMA_NAME);\n}\n\n/** List the tables in a schema. */\nexport async function listTables(\n connection: Connection,\n schema: string,\n): Promise<readonly TableInfo[]> {\n const result = await connection.query<TableRow>(\n \"SELECT SCHEMA_NAME, TABLE_NAME, TABLE_TYPE FROM SYS.TABLES \" +\n \"WHERE SCHEMA_NAME = ? ORDER BY TABLE_NAME\",\n [schema],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n schema: row.SCHEMA_NAME,\n name: row.TABLE_NAME,\n type: row.TABLE_TYPE,\n rowCount: undefined,\n }));\n}\n\n/** List table and view names in a schema for typo recovery suggestions. */\nexport async function listCatalogObjects(\n connection: Connection,\n schema: string,\n): Promise<readonly CatalogObjectInfo[]> {\n const result = await connection.query<CatalogObjectRow>(\n \"SELECT SCHEMA_NAME, TABLE_NAME AS OBJECT_NAME, 'TABLE' AS OBJECT_TYPE FROM SYS.TABLES \" +\n \"WHERE SCHEMA_NAME = ? UNION ALL \" +\n \"SELECT SCHEMA_NAME, VIEW_NAME AS OBJECT_NAME, 'VIEW' AS OBJECT_TYPE FROM SYS.VIEWS \" +\n \"WHERE SCHEMA_NAME = ? ORDER BY OBJECT_NAME\",\n [schema, schema],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n schema: row.SCHEMA_NAME,\n name: row.OBJECT_NAME,\n type: row.OBJECT_TYPE,\n }));\n}\n\n/** List the columns of a table, ordered by position. */\nexport async function listColumns(\n connection: Connection,\n schema: string,\n table: string,\n): Promise<readonly ColumnInfo[]> {\n const result = await connection.query<ColumnRow>(\n \"SELECT COLUMN_NAME, DATA_TYPE_NAME, LENGTH, SCALE, IS_NULLABLE, POSITION \" +\n \"FROM SYS.TABLE_COLUMNS WHERE SCHEMA_NAME = ? AND TABLE_NAME = ? ORDER BY POSITION\",\n [schema, table],\n { autoLimit: false },\n );\n return result.rows.map((row) => ({\n name: row.COLUMN_NAME,\n dataType: row.DATA_TYPE_NAME,\n length: row.LENGTH ?? undefined,\n scale: row.SCALE ?? undefined,\n nullable: row.IS_NULLABLE === \"TRUE\",\n position: row.POSITION,\n }));\n}\n\n/** Describe a table: its catalog entry plus its columns. */\nexport async function describeTable(\n connection: Connection,\n schema: string,\n table: string,\n): Promise<TableDescription> {\n const tables = await listTables(connection, schema);\n const columns = await listColumns(connection, schema, table);\n return {\n table: tables.find((info) => info.name === table),\n columns,\n };\n}\n","export const CLI_NAME = \"cf-hana\";\nexport const CLI_VERSION = \"0.3.4\";\nexport const ENV_PREFIX = \"CF_HANA\";\n\nexport const DEFAULT_QUERY_TIMEOUT_MS = 30_000;\nexport const DEFAULT_CONNECT_TIMEOUT_MS = 30_000;\nexport const DEFAULT_POOL_MAX = 4;\nexport const DEFAULT_POOL_IDLE_MS = 60_000;\nexport const DEFAULT_AUTO_LIMIT = 100;\nexport const DEFAULT_CELL_LIMIT = 128;\nexport const MAX_CELL_LIMIT = 10_000;\nexport const DEFAULT_RESULT_TTL_MINUTES = 10_080;\nexport const DEFAULT_RESULT_SEARCH_LIMIT = 20;\nexport const MAX_RESULT_STORE_BYTES = 256 * 1024 * 1024;\nexport const HANA_CLOUD_DEFAULT_PORT = 443;\n\n/** Build a `CF_HANA_*` environment variable name from a suffix. */\nexport function envName(suffix: string): string {\n return `${ENV_PREFIX}_${suffix}`;\n}\n\n/** Read an environment variable, treating blank values as absent. */\nexport function readEnv(name: string): string | undefined {\n const value = process.env[name];\n if (value === undefined) {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed.length === 0 ? undefined : trimmed;\n}\n\nexport interface SapCredentials {\n readonly email: string;\n readonly password: string;\n}\n\nexport interface SapCredentialOverrides {\n readonly email?: string | undefined;\n readonly password?: string | undefined;\n}\n\n/**\n * Resolve SAP BTP credentials from explicit overrides, falling back to the\n * repo-wide `SAP_EMAIL` / `SAP_PASSWORD` environment variables. Returns\n * `undefined` when either half is missing.\n */\nexport function readSapCredentials(\n overrides?: SapCredentialOverrides,\n): SapCredentials | undefined {\n const email = overrides?.email ?? readEnv(\"SAP_EMAIL\");\n const password = overrides?.password ?? readEnv(\"SAP_PASSWORD\");\n if (email === undefined || password === undefined) {\n return undefined;\n }\n return { email, password };\n}\n","import { execFile } from \"node:child_process\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nimport type { HanaBinding } from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nconst MAX_BUFFER = 16 * 1024 * 1024;\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst CF_RETRY_ATTEMPTS = 3;\nconst CF_RETRY_BASE_DELAY_MS = 120;\n\n/** Minimal context for an isolated CF CLI invocation. */\nexport interface CfExecContext {\n readonly cfHome: string;\n}\n\n/** Data from `cf target`. */\nexport interface CurrentCfTarget {\n readonly apiEndpoint: string;\n readonly orgName: string;\n readonly spaceName: string;\n readonly regionKey?: string;\n}\n\nconst REGION_API_MAP: Record<string, string> = {\n ae01: \"https://api.cf.ae01.hana.ondemand.com\",\n ap01: \"https://api.cf.ap01.hana.ondemand.com\",\n ap10: \"https://api.cf.ap10.hana.ondemand.com\",\n ap11: \"https://api.cf.ap11.hana.ondemand.com\",\n ap12: \"https://api.cf.ap12.hana.ondemand.com\",\n ap20: \"https://api.cf.ap20.hana.ondemand.com\",\n ap21: \"https://api.cf.ap21.hana.ondemand.com\",\n ap30: \"https://api.cf.ap30.hana.ondemand.com\",\n ap31: \"https://api.cf.ap31.hana.ondemand.com\",\n br10: \"https://api.cf.br10.hana.ondemand.com\",\n br20: \"https://api.cf.br20.hana.ondemand.com\",\n br30: \"https://api.cf.br30.hana.ondemand.com\",\n ca10: \"https://api.cf.ca10.hana.ondemand.com\",\n ca20: \"https://api.cf.ca20.hana.ondemand.com\",\n ch20: \"https://api.cf.ch20.hana.ondemand.com\",\n cn20: \"https://api.cf.cn20.platform.sapcloud.cn\",\n cn40: \"https://api.cf.cn40.platform.sapcloud.cn\",\n eu01: \"https://api.cf.eu01.hana.ondemand.com\",\n eu02: \"https://api.cf.eu02.hana.ondemand.com\",\n eu10: \"https://api.cf.eu10.hana.ondemand.com\",\n \"eu10-002\": \"https://api.cf.eu10-002.hana.ondemand.com\",\n \"eu10-003\": \"https://api.cf.eu10-003.hana.ondemand.com\",\n \"eu10-004\": \"https://api.cf.eu10-004.hana.ondemand.com\",\n \"eu10-005\": \"https://api.cf.eu10-005.hana.ondemand.com\",\n \"eu10-006\": \"https://api.cf.eu10-006.hana.ondemand.com\",\n eu11: \"https://api.cf.eu11.hana.ondemand.com\",\n eu12: \"https://api.cf.eu12.hana.ondemand.com\",\n eu13: \"https://api.cf.eu13.hana.ondemand.com\",\n eu20: \"https://api.cf.eu20.hana.ondemand.com\",\n \"eu20-001\": \"https://api.cf.eu20-001.hana.ondemand.com\",\n \"eu20-002\": \"https://api.cf.eu20-002.hana.ondemand.com\",\n eu21: \"https://api.cf.eu21.hana.ondemand.com\",\n eu22: \"https://api.cf.eu22.hana.ondemand.com\",\n eu30: \"https://api.cf.eu30.hana.ondemand.com\",\n eu31: \"https://api.cf.eu31.hana.ondemand.com\",\n il30: \"https://api.cf.il30.hana.ondemand.com\",\n in30: \"https://api.cf.in30.hana.ondemand.com\",\n jp01: \"https://api.cf.jp01.hana.ondemand.com\",\n jp10: \"https://api.cf.jp10.hana.ondemand.com\",\n jp20: \"https://api.cf.jp20.hana.ondemand.com\",\n jp30: \"https://api.cf.jp30.hana.ondemand.com\",\n jp31: \"https://api.cf.jp31.hana.ondemand.com\",\n sa30: \"https://api.cf.sa30.hana.ondemand.com\",\n sa31: \"https://api.cf.sa31.hana.ondemand.com\",\n uk20: \"https://api.cf.uk20.hana.ondemand.com\",\n us01: \"https://api.cf.us01.hana.ondemand.com\",\n us02: \"https://api.cf.us02.hana.ondemand.com\",\n us10: \"https://api.cf.us10.hana.ondemand.com\",\n \"us10-001\": \"https://api.cf.us10-001.hana.ondemand.com\",\n \"us10-002\": \"https://api.cf.us10-002.hana.ondemand.com\",\n \"us10-003\": \"https://api.cf.us10-003.hana.ondemand.com\",\n us11: \"https://api.cf.us11.hana.ondemand.com\",\n us20: \"https://api.cf.us20.hana.ondemand.com\",\n us21: \"https://api.cf.us21.hana.ondemand.com\",\n \"us21-001\": \"https://api.cf.us21-001.hana.ondemand.com\",\n us22: \"https://api.cf.us22.hana.ondemand.com\",\n us30: \"https://api.cf.us30.hana.ondemand.com\",\n us32: \"https://api.cf.us32.hana.ondemand.com\",\n};\n\nexport function normalizeSapCfApiEndpoint(apiEndpoint: string): string {\n const trimmed = apiEndpoint.trim();\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n if (/^https:\\/\\/[^/]*:\\d+(?:[/?#]|$)/i.test(trimmed)) {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n if (\n parsed.protocol !== \"https:\" ||\n parsed.username !== \"\" ||\n parsed.password !== \"\" ||\n parsed.port !== \"\" ||\n parsed.pathname.replace(/\\/+$/, \"\") !== \"\" ||\n parsed.search !== \"\" ||\n parsed.hash !== \"\"\n ) {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n const hostname = parsed.hostname.toLowerCase();\n const match = /^api\\.cf\\.([a-z]{2}\\d{2}(?:-\\d{3})?)\\.(hana\\.ondemand\\.com|platform\\.sapcloud\\.cn)$/.exec(hostname);\n if (!match) {\n throw new Error(`Invalid or untrusted CF API endpoint \"${apiEndpoint}\".`);\n }\n return `https://${hostname}`;\n}\n\nexport function getApiEndpointForRegion(regionKey: string): string | undefined {\n return REGION_API_MAP[regionKey.trim().toLowerCase()];\n}\n\nexport function getRegionKeyForApi(apiEndpoint: string): string | undefined {\n let normalized: string;\n try {\n normalized = normalizeSapCfApiEndpoint(apiEndpoint);\n } catch {\n return undefined;\n }\n for (const [key, endpoint] of Object.entries(REGION_API_MAP)) {\n if (endpoint.toLowerCase() === normalized) {\n return key;\n }\n }\n return /^https:\\/\\/api\\.cf\\.([a-z]{2}\\d{2}(?:-\\d{3})?)\\.hana\\.ondemand\\.com$/.exec(normalized)?.[1];\n}\n\n/** Run work inside a fresh temporary CF_HOME. Directory is always cleaned. */\nexport async function withCfSession<T>(work: (ctx: CfExecContext) => Promise<T>): Promise<T> {\n const cfHome = await mkdtemp(join(tmpdir(), \"saptools-cf-hana-\"));\n const ctx: CfExecContext = { cfHome };\n try {\n return await work(ctx);\n } finally {\n await rm(cfHome, { recursive: true, force: true });\n }\n}\n\nfunction resolveCfBin(): { bin: string; argsPrefix: readonly string[] } {\n const raw = process.env[\"CF_HANA_CF_BIN\"] ?? \"cf\";\n if (/\\.(?:c|m)?js$/i.test(raw)) {\n return { bin: process.execPath, argsPrefix: [raw] };\n }\n return { bin: raw, argsPrefix: [] };\n}\n\nfunction buildEnv(ctx: CfExecContext, overrides: Record<string, string> = {}): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env, ...overrides };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n env[\"CF_HOME\"] = ctx.cfHome;\n return env;\n}\n\nasync function runCf(\n args: readonly string[],\n ctx: CfExecContext,\n overrides: Record<string, string> = {},\n): Promise<string> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = buildEnv(ctx, overrides);\n\n let lastErr: unknown;\n\n for (let attempt = 0; attempt < CF_RETRY_ATTEMPTS; attempt++) {\n try {\n const { stdout } = await execFileAsync(bin, [...argsPrefix, ...args], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: DEFAULT_TIMEOUT_MS,\n });\n return stdout;\n } catch (err) {\n lastErr = err;\n if (attempt < CF_RETRY_ATTEMPTS - 1) {\n await new Promise((r) => setTimeout(r, CF_RETRY_BASE_DELAY_MS * (attempt + 1)));\n }\n }\n }\n\n const e = lastErr as { stderr?: string | Buffer; message?: string } | undefined;\n const detail = e?.stderr ? String(e.stderr) : (e?.message ?? \"\");\n const cmd = args[0] === \"auth\" ? \"cf auth\" : `cf ${args.join(\" \")}`;\n throw new Error(`${cmd} failed: ${detail}`.trim(), { cause: lastErr });\n}\n\nexport async function cfApi(apiEndpoint: string, ctx: CfExecContext): Promise<void> {\n await runCf([\"api\", apiEndpoint], ctx);\n}\n\n/** Auth using env vars (professional, matches cf-events pattern). */\nexport async function cfAuth(email: string, password: string, ctx: CfExecContext): Promise<void> {\n await runCf([\"auth\"], ctx, {\n CF_USERNAME: email,\n CF_PASSWORD: password,\n });\n}\n\nexport async function cfTargetSpace(\n orgName: string,\n spaceName: string,\n ctx: CfExecContext,\n): Promise<void> {\n await runCf([\"target\", \"-o\", orgName, \"-s\", spaceName], ctx);\n}\n\nexport async function cfEnv(appName: string, ctx: CfExecContext): Promise<string> {\n return await runCf([\"env\", appName], ctx);\n}\n\n/**\n * Direct current user CF context for bare app names.\n * No isolated CF_HOME or forced re-authentication: the current target supplies the app scope.\n */\nexport async function cfEnvDirect(appName: string): Promise<string> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = { ...process.env };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n const { stdout } = await execFileAsync(bin, [...argsPrefix, \"env\", appName], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: DEFAULT_TIMEOUT_MS,\n });\n return stdout;\n}\n\nexport async function readCurrentCfTarget(): Promise<CurrentCfTarget | undefined> {\n const { bin, argsPrefix } = resolveCfBin();\n const env = { ...process.env };\n delete env[\"SAP_EMAIL\"];\n delete env[\"SAP_PASSWORD\"];\n\n try {\n const { stdout } = await execFileAsync(bin, [...argsPrefix, \"target\"], {\n env,\n maxBuffer: MAX_BUFFER,\n timeout: 10_000,\n });\n return parseCfTargetOutput(stdout);\n } catch {\n return undefined;\n }\n}\n\nexport function parseCfTargetOutput(stdout: string): CurrentCfTarget | undefined {\n const fields = parseTargetFields(stdout);\n const api = fields.get(\"api endpoint\");\n const org = fields.get(\"org\");\n const space = fields.get(\"space\");\n if (!api || !org || !space) {\n return undefined;\n }\n let normalizedApi: string;\n try {\n normalizedApi = normalizeSapCfApiEndpoint(api);\n } catch {\n return undefined;\n }\n const regionKey = getRegionKeyForApi(normalizedApi);\n return {\n apiEndpoint: normalizedApi,\n orgName: org,\n spaceName: space,\n ...(regionKey ? { regionKey } : {}),\n };\n}\n\nfunction parseTargetFields(stdout: string): Map<string, string> {\n const map = new Map<string, string>();\n for (const line of stdout.split(/\\r?\\n/)) {\n const idx = line.indexOf(\":\");\n if (idx < 0) {continue;}\n const key = line.slice(0, idx).trim().toLowerCase();\n const val = line.slice(idx + 1).trim();\n if (key && val) {map.set(key, val);}\n }\n return map;\n}\n\nexport function formatCurrentCfAppSelector(target: CurrentCfTarget, appName: string): string {\n const name = appName.trim();\n if (!name) {throw new Error(\"App name is required.\");}\n const region = target.regionKey ?? \"current\";\n return `${region}/${target.orgName}/${target.spaceName}/${name}`;\n}\n\n/* VCAP parser */\n\nfunction extractVcapSection(stdout: string): string {\n const start = stdout.indexOf(\"VCAP_SERVICES:\");\n if (start === -1) {throw new Error(\"VCAP_SERVICES section not found in cf env output\");}\n const after = stdout.slice(start + \"VCAP_SERVICES:\".length);\n const end = after.indexOf(\"VCAP_APPLICATION:\");\n const block = end === -1 ? after : after.slice(0, end);\n return block.trim();\n}\n\ninterface RawHanaCreds {\n host: string;\n port: string;\n user: string;\n password: string;\n schema: string;\n hdi_user: string;\n hdi_password: string;\n url: string;\n database_id: string;\n certificate: string;\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nfunction assertCreds(raw: unknown): RawHanaCreds {\n if (!isRecord(raw)) {throw new Error(\"HANA credentials must be an object\");}\n const req = [\"host\", \"port\", \"user\", \"password\", \"schema\", \"hdi_user\", \"hdi_password\", \"url\", \"database_id\", \"certificate\"];\n for (const k of req) {\n if (typeof raw[k] !== \"string\") {throw new Error(`Missing/invalid HANA credential field: \"${k}\"`);}\n }\n return raw as unknown as RawHanaCreds;\n}\n\nfunction mapCreds(raw: RawHanaCreds): HanaBinding[\"credentials\"] {\n return {\n host: raw.host,\n port: raw.port,\n user: raw.user,\n password: raw.password,\n schema: raw.schema,\n hdiUser: raw.hdi_user,\n hdiPassword: raw.hdi_password,\n ...(raw.url ? { url: raw.url } : {}),\n databaseId: raw.database_id,\n certificate: raw.certificate,\n };\n}\n\nexport function extractHanaBindingsFromCfEnv(stdout: string): readonly HanaBinding[] {\n const jsonText = extractVcapSection(stdout);\n let vcap: unknown;\n try {\n vcap = JSON.parse(jsonText);\n } catch {\n throw new Error(\"VCAP_SERVICES is not valid JSON\");\n }\n if (!isRecord(vcap)) {throw new Error(\"VCAP_SERVICES must be an object\");}\n\n const hana = vcap[\"hana\"];\n if (hana === undefined) {return [];}\n if (!Array.isArray(hana)) {throw new Error(\"VCAP_SERVICES.hana must be an array when present\");}\n\n return hana.map((b: unknown) => {\n if (!isRecord(b)) {throw new Error(\"HANA binding must be an object\");}\n const credsRaw = assertCreds(b[\"credentials\"]);\n const name = typeof b[\"name\"] === \"string\" ? b[\"name\"] : undefined;\n return {\n ...(name ? { name } : {}),\n credentials: mapCreds(credsRaw),\n } as HanaBinding;\n });\n}\n\n/**\n * Professional classification: only re-auth for real session/unauth problems.\n */\nexport function classifyCfError(stderr: string | undefined = \"\", stdout: string | undefined = \"\"): {\n readonly isAuthError: boolean;\n readonly reason: string;\n} {\n const text = `${stderr} ${stdout}`.toLowerCase();\n if (\n text.includes(\"not logged in\") ||\n text.includes(\"unauthorized\") ||\n text.includes(\"forbidden\") ||\n text.includes(\"credentials were rejected\") ||\n text.includes(\"authentication failed\") ||\n text.includes(\"cf auth\") ||\n text.includes(\"token\") ||\n text.includes(\"expired\") ||\n text.includes(\"session\")\n ) {\n return { isAuthError: true, reason: \"auth/session issue\" };\n }\n return { isAuthError: false, reason: \"\" };\n}\n","import {\n cfApi,\n cfAuth,\n cfEnv,\n cfEnvDirect,\n cfTargetSpace,\n classifyCfError,\n extractHanaBindingsFromCfEnv,\n formatCurrentCfAppSelector,\n getApiEndpointForRegion,\n normalizeSapCfApiEndpoint,\n readCurrentCfTarget,\n withCfSession,\n} from \"./cf.js\";\nimport { readSapCredentials } from \"./config.js\";\nimport { CfHanaError, CredentialsNotFoundError } from \"./errors.js\";\nimport type { CredentialSource, DbUserRole, HanaBinding } from \"./types.js\";\n\nexport interface ResolveBindingsOptions {\n /** Deprecated compatibility flag. Binding discovery is always live. */\n readonly refresh?: boolean;\n readonly email?: string;\n readonly password?: string;\n}\n\nfunction errorMessageFromUnknown(error: unknown): string {\n return error instanceof Error ? error.message : \"Invalid or untrusted CF API endpoint.\";\n}\n\nexport interface ResolvedBindings {\n readonly selector: string;\n readonly appName: string;\n readonly bindings: readonly HanaBinding[];\n readonly source: CredentialSource;\n}\n\nexport interface BindingSelector {\n readonly bindingName?: string;\n readonly bindingIndex?: number;\n}\n\nexport interface SelectedConnectionTarget {\n readonly host: string;\n readonly port: number;\n readonly user: string;\n readonly password: string;\n readonly schema: string;\n readonly certificate: string;\n readonly databaseId: string;\n}\n\n/**\n * Resolve an app's HANA bindings.\n *\n * Bare app name: resolve it against the current `cf target`.\n * - First try the user's *existing* CF session directly via cfEnvDirect (no re-auth).\n * - Only fall back to SAP + isolated re-auth if the error is classified as auth/session problem.\n * Explicit selector: Always full authenticated isolated path.\n *\n * This is the professional realization of the request:\n * When only an app is provided, the current CF target supplies org and space.\n * Auth/re-auth ONLY on session/unauthorize (per user feedback).\n */\nexport async function resolveAppBindings(\n rawSelector: string,\n options: ResolveBindingsOptions,\n): Promise<ResolvedBindings> {\n const selector = rawSelector.trim();\n if (!selector) {\n throw new CfHanaError(\"CONFIG\", \"App selector is required\");\n }\n\n let target: {\n selector: string;\n apiEndpoint: string;\n orgName: string;\n spaceName: string;\n appName: string;\n };\n\n const isBare = !selector.includes(\"/\");\n\n if (isBare) {\n // A bare app inherits region, org, and space from the current CF target.\n const current = await readCurrentCfTarget();\n if (!current) {\n throw new CfHanaError(\n \"CONFIG\",\n \"No current CF target found. Run `cf target -o <org> -s <space>` or pass a full region/org/space/app selector.\",\n );\n }\n const displaySelector = current.regionKey\n ? formatCurrentCfAppSelector(current, selector)\n : `current/${current.orgName}/${current.spaceName}/${selector}`;\n target = {\n selector: displaySelector,\n apiEndpoint: current.apiEndpoint,\n orgName: current.orgName,\n spaceName: current.spaceName,\n appName: selector,\n };\n } else {\n // Explicit: region/org/space/app\n const parts = selector.split(\"/\").map((p) => p.trim());\n if (parts.length !== 4 || !parts[0] || !parts[1] || !parts[2] || !parts[3]) {\n throw new CfHanaError(\n \"CONFIG\",\n `Invalid selector \"${selector}\". Use region/org/space/app or a bare app name.`,\n );\n }\n const [regionKey, orgName, spaceName, appName] = parts as [string, string, string, string];\n const apiEndpoint = getApiEndpointForRegion(regionKey);\n if (!apiEndpoint) {\n throw new CfHanaError(\n \"CONFIG\",\n `Unknown SAP CF region \"${regionKey}\". Verify the current SAP region list or use the current CF target.`,\n );\n }\n let normalizedApiEndpoint: string;\n try {\n normalizedApiEndpoint = normalizeSapCfApiEndpoint(apiEndpoint);\n } catch (error) {\n throw new CfHanaError(\"CONFIG\", errorMessageFromUnknown(error), { cause: error });\n }\n target = { selector, apiEndpoint: normalizedApiEndpoint, orgName, spaceName, appName };\n }\n\n let bindings: readonly HanaBinding[];\n const source: CredentialSource = \"live\";\n\n if (isBare) {\n // Preferred fast path for bare: use whatever CF context the user already has.\n // NO re-auth, NO new CF_HOME.\n try {\n const stdout = await cfEnvDirect(target.appName);\n bindings = extractHanaBindingsFromCfEnv(stdout);\n } catch (directError: unknown) {\n // Professional classification: only re-auth for real auth/session problems.\n let stderr = \"\";\n if (directError && typeof directError === \"object\") {\n const e = directError as { stderr?: unknown; message?: unknown };\n stderr =\n (typeof e.stderr === \"string\" ? e.stderr : \"\") ||\n (typeof e.message === \"string\" ? e.message : \"\");\n }\n const classified = classifyCfError(stderr);\n if (classified.isAuthError) {\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (!sap) {\n throw new CredentialsNotFoundError(\n `Current CF session problem for bare app \"${target.appName}\" (${classified.reason}).\\n` +\n `Run \"cf login\" + \"cf target\", or provide SAP_EMAIL + SAP_PASSWORD.`,\n { cause: directError },\n );\n }\n const api = target.apiEndpoint;\n bindings = await withCfSession(async (ctx) => {\n await cfApi(api, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n const stdout = await cfEnv(target.appName, ctx);\n return extractHanaBindingsFromCfEnv(stdout);\n });\n } else {\n // Not auth-related (e.g. app not present in current space)\n throw new CfHanaError(\n \"CONFIG\",\n `Failed to get HANA bindings for bare app \"${target.appName}\" using current target (org=${target.orgName}, space=${target.spaceName}). ` +\n `Verify with \"cf target\" and \"cf env ${target.appName}\". ${stderr ? `Details: ${stderr}` : \"\"}`,\n { cause: directError },\n );\n }\n }\n } else {\n // Explicit selector always uses full authenticated isolated path\n const sap = readSapCredentials({ email: options.email, password: options.password });\n if (!sap) {\n throw new CredentialsNotFoundError(\n `SAP_EMAIL and SAP_PASSWORD are required to fetch HANA bindings for explicit selector \"${selector}\".`,\n );\n }\n const api = target.apiEndpoint;\n bindings = await withCfSession(async (ctx) => {\n await cfApi(api, ctx);\n await cfAuth(sap.email, sap.password, ctx);\n await cfTargetSpace(target.orgName, target.spaceName, ctx);\n const stdout = await cfEnv(target.appName, ctx);\n return extractHanaBindingsFromCfEnv(stdout);\n });\n }\n\n if (bindings.length === 0) {\n throw new CredentialsNotFoundError(`App \"${target.selector}\" has no HANA service binding.`);\n }\n\n return {\n selector: target.selector,\n appName: target.appName,\n bindings,\n source,\n };\n}\n\n/** Pick a single HANA binding from an app's bindings. */\nexport function selectBinding(\n bindings: readonly HanaBinding[],\n selector: BindingSelector,\n): HanaBinding {\n if (selector.bindingName !== undefined) {\n const match = bindings.find((binding) => binding.name === selector.bindingName);\n if (match === undefined) {\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `No HANA binding named \"${selector.bindingName}\"`,\n );\n }\n return match;\n }\n\n if (selector.bindingIndex !== undefined) {\n const match = bindings[selector.bindingIndex];\n if (match === undefined) {\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `No HANA binding at index ${String(selector.bindingIndex)}`,\n );\n }\n return match;\n }\n\n const first = bindings[0];\n if (first === undefined) {\n throw new CredentialsNotFoundError(\"No HANA bindings are available for this app\");\n }\n if (bindings.length > 1) {\n const labels = bindings\n .map((binding, index) => binding.name ?? `#${String(index)}`)\n .join(\", \");\n throw new CfHanaError(\n \"AMBIGUOUS_BINDING\",\n `App has multiple HANA bindings (${labels}); ` +\n `choose one with bindingName or bindingIndex`,\n );\n }\n return first;\n}\n\n/** Map a HANA binding to concrete connection parameters for the chosen role. */\nexport function toConnectionTarget(\n binding: HanaBinding,\n role: DbUserRole,\n): SelectedConnectionTarget {\n const credentials = binding.credentials;\n const port = Number.parseInt(credentials.port, 10);\n if (!Number.isInteger(port) || port <= 0) {\n throw new CfHanaError(\"CONFIG\", `Invalid HANA port in binding: \"${credentials.port}\"`);\n }\n return {\n host: credentials.host,\n port,\n user: role === \"hdi\" ? credentials.hdiUser : credentials.user,\n password: role === \"hdi\" ? credentials.hdiPassword : credentials.password,\n schema: credentials.schema,\n certificate: credentials.certificate,\n databaseId: credentials.databaseId ?? \"\",\n };\n}\n","import { appendFile } from \"node:fs/promises\";\n\nimport { envName, readEnv } from \"../config.js\";\nimport { QueryError } from \"../errors.js\";\nimport { classifyStatement } from \"../statements.js\";\nimport type { SqlParam } from \"../types.js\";\n\nimport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\nlet catalogFailureInjected = false;\n\n/**\n * Deterministic in-memory driver used by hermetic end-to-end tests and offline\n * smoke checks. Selected via `CF_HANA_DRIVER=fake`. It never opens a socket.\n */\ninterface FakeCatalogObjectRow extends Record<string, SqlParam> {\n readonly SCHEMA_NAME: string;\n readonly OBJECT_NAME: string;\n readonly OBJECT_TYPE: \"TABLE\" | \"VIEW\";\n}\n\nfunction catalogObjects(): readonly FakeCatalogObjectRow[] {\n return [\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"EXISTING_TABLE\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"MISSING_TABLE_FIXED\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"MISSING_TABLE_VIEW\", OBJECT_TYPE: \"VIEW\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"STATUS_ITEMS\", OBJECT_TYPE: \"TABLE\" },\n { SCHEMA_NAME: \"APP_SCHEMA\", OBJECT_NAME: \"CORE_AUTH_SCOPE\", OBJECT_TYPE: \"TABLE\" },\n ];\n}\n\nfunction tableColumns(): readonly Record<string, SqlParam>[] {\n return [\n { COLUMN_NAME: \"ID\", DATA_TYPE_NAME: \"INTEGER\", LENGTH: null, SCALE: null, IS_NULLABLE: \"FALSE\", POSITION: 1 },\n { COLUMN_NAME: \"IS_ACTIVE\", DATA_TYPE_NAME: \"BOOLEAN\", LENGTH: null, SCALE: null, IS_NULLABLE: \"TRUE\", POSITION: 2 },\n { COLUMN_NAME: \"SCOPE_NAME\", DATA_TYPE_NAME: \"NVARCHAR\", LENGTH: 255, SCALE: null, IS_NULLABLE: \"TRUE\", POSITION: 3 },\n ];\n}\n\nfunction fakeExec(sql: string): DriverExecResult {\n const kind = classifyStatement(sql);\n const forcedFailure = readEnv(envName(\"FAKE_FAIL_STATEMENT\"))?.toLowerCase();\n if (forcedFailure === kind) {\n throw new Error(`fake driver forced ${kind.toUpperCase()} failure`);\n }\n\n const upperSql = sql.toUpperCase();\n if (upperSql.includes(\"SYS.TABLES\") && upperSql.includes(\"SYS.VIEWS\")) {\n if (readEnv(envName(\"FAKE_FAIL_CATALOG_ONCE\")) === \"1\" && !catalogFailureInjected) {\n catalogFailureInjected = true;\n throw new QueryError(\"fake transient catalog metadata failure\");\n }\n return {\n rows: catalogObjects(),\n columns: [\n { name: \"SCHEMA_NAME\", typeName: \"NVARCHAR\" },\n { name: \"OBJECT_NAME\", typeName: \"NVARCHAR\" },\n { name: \"OBJECT_TYPE\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n }\n\n if (upperSql.includes(\"SYS.TABLE_COLUMNS\")) {\n return {\n rows: tableColumns(),\n columns: [\n { name: \"COLUMN_NAME\", typeName: \"NVARCHAR\" },\n { name: \"DATA_TYPE_NAME\", typeName: \"NVARCHAR\" },\n { name: \"LENGTH\", typeName: \"INTEGER\" },\n { name: \"SCALE\", typeName: \"INTEGER\" },\n { name: \"IS_NULLABLE\", typeName: \"NVARCHAR\" },\n { name: \"POSITION\", typeName: \"INTEGER\" },\n ],\n affectedRows: 0,\n };\n }\n\n if (upperSql.includes(\"MISSING_TABLE\") || upperSql.includes(\"MISSING_TABLES\")) {\n throw new QueryError(\"invalid table name: MISSING_TABLE\", { sqlState: \"42S02\" });\n }\n\n if (upperSql.includes(\"ISACTIVE\")) {\n throw new QueryError(\"invalid column name: ISACTIVE: line 1 col 8 (at pos 7)\", { databaseCode: 260 });\n }\n\n if (upperSql.includes(\"LOB_ORDER_ERROR\")) {\n throw new QueryError(\"inconsistent datatype: LOB type is not allowed in ORDER BY clause\", { databaseCode: 266 });\n }\n\n if (upperSql.includes(\"LOB_GROUP_ERROR\")) {\n throw new QueryError(\"inconsistent datatype: LOB type is not allowed in GROUP BY clause\", { databaseCode: 274 });\n }\n\n if (sql.toUpperCase().includes(\"LOB_FIXTURE\")) {\n return {\n rows: [\n {\n LOG_CONTENT: Buffer.from(\"Example log entry\", \"utf8\"),\n CLOB_CONTENT: Buffer.from(\"Clob log entry\", \"utf8\"),\n PAYLOAD: Buffer.from([0, 1, 2, 255]),\n },\n ],\n columns: [\n { name: \"LOG_CONTENT\", typeName: \"NCLOB\" },\n { name: \"CLOB_CONTENT\", typeName: \"CLOB\" },\n { name: \"PAYLOAD\", typeName: \"BLOB\" },\n ],\n affectedRows: 0,\n };\n }\n\n if (sql.toUpperCase().includes(\"DUMMY\")) {\n return {\n rows: [{ \"1\": 1 }],\n columns: [{ name: \"1\", typeName: \"INTEGER\" }],\n affectedRows: 0,\n };\n }\n\n if (kind === \"select\") {\n return {\n rows: [\n { ID: 1, NAME: \"sample-row\" },\n { ID: 2, NAME: \"second-row\" },\n ],\n columns: [\n { name: \"ID\", typeName: \"INTEGER\" },\n { name: \"NAME\", typeName: \"NVARCHAR\" },\n ],\n affectedRows: 0,\n };\n }\n if (kind === \"dml\") {\n return { rows: [], columns: [], affectedRows: 1 };\n }\n return { rows: [], columns: [], affectedRows: 0 };\n}\n\n/** Opt-in fake-driver trace; parameter values stay out of test artifacts. */\nasync function traceFakeExec(sql: string, params: readonly SqlParam[]): Promise<void> {\n const tracePath = readEnv(envName(\"FAKE_TRACE_FILE\"));\n if (tracePath === undefined) {\n return;\n }\n const entry = { sql, paramCount: params.length };\n await appendFile(tracePath, `${JSON.stringify(entry)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n}\n\nclass FakeConnection implements DriverConnection {\n private closed = false;\n\n async exec(sql: string, params: readonly SqlParam[]): Promise<DriverExecResult> {\n await traceFakeExec(sql, params);\n return fakeExec(sql);\n }\n\n setAutoCommit(_enabled: boolean): Promise<void> {\n return Promise.resolve();\n }\n\n commit(): Promise<void> {\n return Promise.resolve();\n }\n\n rollback(): Promise<void> {\n return Promise.resolve();\n }\n\n close(): Promise<void> {\n this.closed = true;\n return Promise.resolve();\n }\n\n isClosed(): boolean {\n return this.closed;\n }\n}\n\n/** Build the deterministic test-only fake HANA driver. */\nexport function createFakeDriver(): HanaDriver {\n return {\n name: \"fake\",\n connect: (_params: DriverConnectParams): Promise<DriverConnection> =>\n Promise.resolve(new FakeConnection()),\n };\n}\n","import { createClient } from \"hdb\";\nimport type { HdbClient, HdbColumnMetadata, HdbStatement } from \"hdb\";\n\nimport { CfHanaError, QueryError, databaseCode } from \"../errors.js\";\nimport { quoteIdentifier } from \"../statements.js\";\nimport type { QueryResultColumn, SqlParam } from \"../types.js\";\n\nimport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\nconst TYPE_NAMES: Readonly<Record<number, string>> = {\n 0: \"NULL\",\n 1: \"TINYINT\",\n 2: \"SMALLINT\",\n 3: \"INTEGER\",\n 4: \"BIGINT\",\n 5: \"DECIMAL\",\n 6: \"REAL\",\n 7: \"DOUBLE\",\n 8: \"CHAR\",\n 9: \"VARCHAR\",\n 10: \"NCHAR\",\n 11: \"NVARCHAR\",\n 12: \"BINARY\",\n 13: \"VARBINARY\",\n 14: \"DATE\",\n 15: \"TIME\",\n 16: \"TIMESTAMP\",\n 25: \"CLOB\",\n 26: \"NCLOB\",\n 27: \"BLOB\",\n 28: \"BOOLEAN\",\n 29: \"STRING\",\n 30: \"NSTRING\",\n 47: \"DECIMAL\",\n 51: \"TEXT\",\n 52: \"SHORTTEXT\",\n 62: \"DECIMAL\",\n};\n\nfunction typeName(code: number): string {\n return TYPE_NAMES[code] ?? `TYPE_${String(code)}`;\n}\n\nfunction extractSqlState(error: Error): string | undefined {\n const value = (error as { readonly sqlState?: unknown }).sqlState;\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction toQueryError(error: Error): QueryError {\n const sqlState = extractSqlState(error);\n const code = databaseCode(error);\n return new QueryError(error.message, {\n cause: error,\n ...(sqlState === undefined ? {} : { sqlState }),\n ...(code === undefined ? {} : { databaseCode: code }),\n });\n}\n\nfunction toColumns(\n metadata: readonly HdbColumnMetadata[] | undefined,\n): readonly QueryResultColumn[] {\n if (metadata === undefined) {\n return [];\n }\n return metadata.map((column) => ({\n name: column.columnDisplayName ?? column.columnName ?? \"\",\n typeName: typeName(column.dataType),\n }));\n}\n\nfunction toExecResult(statement: HdbStatement, raw: unknown): DriverExecResult {\n if (typeof raw === \"number\") {\n return { rows: [], columns: [], affectedRows: raw };\n }\n if (Array.isArray(raw)) {\n return {\n rows: raw as readonly Record<string, SqlParam>[],\n columns: toColumns(statement.resultSetMetadata),\n affectedRows: 0,\n };\n }\n return { rows: [], columns: [], affectedRows: 0 };\n}\n\nclass HdbConnection implements DriverConnection {\n private closed = false;\n\n constructor(private readonly client: HdbClient) {}\n\n async exec(sql: string, params: readonly SqlParam[]): Promise<DriverExecResult> {\n const statement = await this.prepareStatement(sql);\n try {\n const raw = await this.executeStatement(statement, params);\n return toExecResult(statement, raw);\n } finally {\n dropStatementQuietly(statement);\n }\n }\n\n setAutoCommit(enabled: boolean): Promise<void> {\n this.client.setAutoCommit(enabled);\n return Promise.resolve();\n }\n\n async commit(): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n this.client.commit((error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n }\n\n async rollback(): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n this.client.rollback((error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return;\n }\n this.closed = true;\n await new Promise<void>((resolve) => {\n this.client.disconnect(() => {\n resolve();\n });\n });\n this.client.close();\n }\n\n isClosed(): boolean {\n return (\n this.closed ||\n this.client.readyState === \"closed\" ||\n this.client.readyState === \"disconnected\"\n );\n }\n\n private async prepareStatement(sql: string): Promise<HdbStatement> {\n return await new Promise<HdbStatement>((resolve, reject) => {\n this.client.prepare(sql, (error, statement) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve(statement);\n }\n });\n });\n }\n\n private async executeStatement(\n statement: HdbStatement,\n params: readonly SqlParam[],\n ): Promise<unknown> {\n return await new Promise<unknown>((resolve, reject) => {\n statement.exec([...params], (error, result) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve(result);\n }\n });\n });\n }\n}\n\nfunction dropStatementQuietly(statement: HdbStatement): void {\n try {\n statement.drop();\n } catch {\n // Best-effort cleanup; preserve the query result or original query error.\n }\n}\n\nfunction openClient(client: HdbClient, timeoutMs: number): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) {\n return;\n }\n settled = true;\n client.close();\n reject(\n new CfHanaError(\n \"TIMEOUT\",\n `HANA connection timed out after ${String(timeoutMs)}ms`,\n ),\n );\n }, timeoutMs);\n timer.unref();\n client.connect((error) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n if (error) {\n reject(\n new CfHanaError(\"CONNECTION\", `Failed to connect to HANA: ${error.message}`, {\n cause: error,\n }),\n );\n } else {\n resolve();\n }\n });\n });\n}\n\nasync function closeClientQuietly(client: HdbClient): Promise<void> {\n try {\n await new Promise<void>((resolve) => {\n client.disconnect(() => {\n resolve();\n });\n });\n } catch {\n // Best-effort cleanup after a partially opened connection.\n }\n try {\n client.close();\n } catch {\n // Best-effort cleanup after a partially opened connection.\n }\n}\n\nfunction setCurrentSchema(client: HdbClient, schema: string): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n client.exec(`SET SCHEMA ${quoteIdentifier(schema)}`, (error) => {\n if (error) {\n reject(toQueryError(error));\n } else {\n resolve();\n }\n });\n });\n}\n\nasync function connectHdb(params: DriverConnectParams): Promise<DriverConnection> {\n const client = createClient({\n host: params.host,\n port: params.port,\n user: params.user,\n password: params.password,\n ca: params.certificate,\n useTLS: true,\n });\n await openClient(client, params.connectTimeoutMs);\n try {\n await setCurrentSchema(client, params.schema);\n } catch (error) {\n await closeClientQuietly(client);\n throw error;\n }\n return new HdbConnection(client);\n}\n\n/** Build the production HANA driver backed by the pure-JavaScript `hdb` library. */\nexport function createHdbDriver(): HanaDriver {\n return {\n name: \"hdb\",\n connect: connectHdb,\n };\n}\n","import { envName, readEnv } from \"../config.js\";\nimport { CfHanaError } from \"../errors.js\";\n\nimport { createFakeDriver } from \"./fake.js\";\nimport { createHdbDriver } from \"./hdb.js\";\nimport type { HanaDriver } from \"./types.js\";\n\nexport type {\n DriverConnectParams,\n DriverConnection,\n DriverExecResult,\n HanaDriver,\n} from \"./types.js\";\n\n/**\n * Create a HANA driver by name. Defaults to `hdb`; the `CF_HANA_DRIVER`\n * environment variable overrides the default when no name is passed.\n */\nexport function createDriver(name?: string): HanaDriver {\n const resolved = name ?? readEnv(envName(\"DRIVER\")) ?? \"hdb\";\n switch (resolved) {\n case \"hdb\":\n return createHdbDriver();\n case \"fake\":\n return createFakeDriver();\n default:\n throw new CfHanaError(\"CONFIG\", `Unknown HANA driver: ${resolved}`);\n }\n}\n","import { appendFile, mkdir, readdir, rm } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { DbUserRole, StatementKind } from \"./types.js\";\n\nconst SAPTOOLS_DIR_NAME = \".saptools\";\nconst CF_HANA_DIR_NAME = \"cf-hana\";\nconst HISTORIES_DIR_NAME = \"histories\";\nconst HISTORY_RETENTION_DAYS = 5;\nconst HISTORY_FILE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}\\.jsonl$/;\n\nexport type SqlHistoryOperation = \"query\" | \"execute\";\n\nexport interface SqlHistoryEntryInput {\n readonly version: string;\n readonly operation: SqlHistoryOperation;\n readonly selector: string;\n readonly appName: string;\n readonly schema: string;\n readonly role: DbUserRole;\n readonly statement: StatementKind;\n readonly sql: string;\n readonly paramCount: number;\n readonly rowCount: number;\n readonly truncated: boolean;\n readonly elapsedMs: number;\n}\n\nexport interface SqlHistoryEntry extends SqlHistoryEntryInput {\n readonly at: string;\n}\n\nexport interface SqlHistoryWriteOptions {\n readonly now?: Date;\n readonly saptoolsRoot?: string;\n}\n\nfunction defaultSaptoolsRoot(): string {\n return join(homedir(), SAPTOOLS_DIR_NAME);\n}\n\nfunction padDatePart(value: number): string {\n return value.toString().padStart(2, \"0\");\n}\n\nfunction dateKey(date: Date): string {\n return [\n date.getFullYear().toString(),\n padDatePart(date.getMonth() + 1),\n padDatePart(date.getDate()),\n ].join(\"-\");\n}\n\nfunction retentionCutoffKey(now: Date): string {\n const cutoff = new Date(now);\n cutoff.setHours(0, 0, 0, 0);\n cutoff.setDate(cutoff.getDate() - HISTORY_RETENTION_DAYS);\n return dateKey(cutoff);\n}\n\nfunction resolveSaptoolsRoot(root: string | undefined): string {\n return root ?? defaultSaptoolsRoot();\n}\n\nexport function cfHanaHistoryDirectory(saptoolsRoot?: string): string {\n return join(resolveSaptoolsRoot(saptoolsRoot), CF_HANA_DIR_NAME, HISTORIES_DIR_NAME);\n}\n\nexport function sqlHistoryFilePath(now: Date = new Date(), saptoolsRoot?: string): string {\n return join(cfHanaHistoryDirectory(saptoolsRoot), `${dateKey(now)}.jsonl`);\n}\n\nasync function pruneSqlHistory(now: Date, saptoolsRoot?: string): Promise<void> {\n const historyDir = cfHanaHistoryDirectory(saptoolsRoot);\n let files: readonly string[];\n try {\n files = await readdir(historyDir);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n\n const cutoffKey = retentionCutoffKey(now);\n await Promise.all(\n files\n .filter((file) => HISTORY_FILE_PATTERN.test(file))\n .filter((file) => file.slice(0, 10) < cutoffKey)\n .map(async (file) => {\n await rm(join(historyDir, file), { force: true });\n }),\n );\n}\n\nexport async function appendSqlHistory(\n input: SqlHistoryEntryInput,\n options: SqlHistoryWriteOptions = {},\n): Promise<SqlHistoryEntry> {\n const now = options.now ?? new Date();\n const historyDir = cfHanaHistoryDirectory(options.saptoolsRoot);\n const entry: SqlHistoryEntry = {\n at: now.toISOString(),\n ...input,\n };\n\n await mkdir(historyDir, { recursive: true, mode: 0o700 });\n await appendFile(sqlHistoryFilePath(now, options.saptoolsRoot), `${JSON.stringify(entry)}\\n`, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n try {\n await pruneSqlHistory(now, options.saptoolsRoot);\n } catch {\n // Retention is best-effort; the SQL history entry was already recorded.\n }\n\n return entry;\n}\n","import { classifyStatement, firstKeyword } from \"./statements.js\";\nimport type { StatementKind } from \"./types.js\";\n\nconst DESTRUCTIVE_DDL_KEYWORDS = new Set([\"DROP\", \"TRUNCATE\", \"ALTER\"]);\nconst UNSCOPED_WRITE_KEYWORDS = new Set([\"UPDATE\", \"DELETE\"]);\n\nexport type GuardViolation = \"read-only\" | \"destructive\";\n\nexport interface GuardConfig {\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n}\n\nexport interface GuardDecision {\n readonly allowed: boolean;\n readonly destructive: boolean;\n readonly violation: GuardViolation | undefined;\n readonly reason: string | undefined;\n}\n\nexport interface StatementInspection {\n readonly kind: StatementKind;\n readonly destructive: boolean;\n}\n\nexport interface AutoLimitResult {\n readonly sql: string;\n readonly applied: boolean;\n readonly requestedLimit?: number;\n}\n\nfunction skipQuotedText(sql: string, start: number): number {\n const quote = sql[start];\n let index = start + 1;\n while (index < sql.length) {\n if (sql[index] === quote) {\n if (sql[index + 1] === quote) {\n index += 2;\n continue;\n }\n index += 1;\n break;\n }\n index += 1;\n }\n return index;\n}\n\nfunction skipLineComment(sql: string, start: number): number {\n let index = start + 2;\n while (index < sql.length && sql[index] !== \"\\n\") {\n index += 1;\n }\n return index;\n}\n\nfunction skipBlockComment(sql: string, start: number): number {\n let index = start + 2;\n while (index < sql.length && !(sql[index] === \"*\" && sql[index + 1] === \"/\")) {\n index += 1;\n }\n return Math.min(index + 2, sql.length);\n}\n\nfunction maskIgnoredSqlText(sql: string): string {\n let masked = \"\";\n let index = 0;\n while (index < sql.length) {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n const end = skipQuotedText(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n const end = skipLineComment(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n const end = skipBlockComment(sql, index);\n masked += \" \".repeat(end - index);\n index = end;\n continue;\n }\n masked += char ?? \"\";\n index += 1;\n }\n return masked;\n}\n\nfunction hasWhereClause(sql: string): boolean {\n return /\\bwhere\\b/i.test(maskIgnoredSqlText(sql));\n}\n\nfunction trailingLineCommentIndex(sql: string): number | undefined {\n let index = 0;\n while (index < sql.length) {\n const char = sql[index];\n if (char === \"'\" || char === '\"') {\n index = skipQuotedText(sql, index);\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index = skipBlockComment(sql, index);\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n const lineEnd = sql.indexOf(\"\\n\", index + 2);\n if (lineEnd === -1 || sql.slice(lineEnd + 1).trim().length === 0) {\n return index;\n }\n index = lineEnd + 1;\n continue;\n }\n index += 1;\n }\n return undefined;\n}\n\nfunction appendLimit(sql: string, limit: number): string {\n const trimmed = sql.replace(/[\\s;]+$/, \"\");\n const commentIndex = trailingLineCommentIndex(trimmed);\n if (commentIndex === undefined) {\n return `${trimmed} LIMIT ${String(limit)}`;\n }\n const beforeComment = trimmed.slice(0, commentIndex).replace(/[\\s;]+$/, \"\");\n const comment = trimmed.slice(commentIndex);\n return `${beforeComment} LIMIT ${String(limit)} ${comment}`;\n}\n\n/** Inspect a statement's kind and whether it is destructive. */\nexport function inspectStatement(sql: string): StatementInspection {\n const kind = classifyStatement(sql);\n const keyword = firstKeyword(sql);\n if (kind === \"ddl\") {\n return { kind, destructive: DESTRUCTIVE_DDL_KEYWORDS.has(keyword) };\n }\n if (kind === \"dml\") {\n return {\n kind,\n destructive: UNSCOPED_WRITE_KEYWORDS.has(keyword) && !hasWhereClause(sql),\n };\n }\n return { kind, destructive: false };\n}\n\n/** Decide whether a statement may run under the given safety configuration. */\nexport function evaluateGuard(sql: string, config: GuardConfig): GuardDecision {\n const inspection = inspectStatement(sql);\n\n if (config.readOnly && inspection.kind !== \"select\") {\n return {\n allowed: false,\n destructive: inspection.destructive,\n violation: \"read-only\",\n reason:\n inspection.kind === \"unknown\"\n ? \"read-only mode only permits SELECT/WITH statements\"\n : `read-only mode blocks ${inspection.kind.toUpperCase()} statements`,\n };\n }\n\n if (inspection.destructive && !config.allowDestructive) {\n return {\n allowed: false,\n destructive: true,\n violation: \"destructive\",\n reason:\n \"destructive statement blocked (DROP/TRUNCATE/ALTER or unscoped UPDATE/DELETE); \" +\n \"allow it explicitly to proceed\",\n };\n }\n\n return {\n allowed: true,\n destructive: inspection.destructive,\n violation: undefined,\n reason: undefined,\n };\n}\n\n/** Append a `LIMIT` clause to a bare SELECT that has no row cap of its own. */\nexport function applyAutoLimit(sql: string, limit: number | false): AutoLimitResult {\n if (limit === false || classifyStatement(sql) !== \"select\") {\n return { sql, applied: false };\n }\n\n const stripped = maskIgnoredSqlText(sql);\n if (/\\blimit\\b/i.test(stripped) || /\\btop\\s+\\d/i.test(stripped)) {\n return { sql, applied: false };\n }\n\n return {\n sql: appendLimit(sql, limit + 1),\n applied: true,\n requestedLimit: limit,\n };\n}\n","import type { DriverConnection, HanaDriver } from \"./driver/types.js\";\nimport { CfHanaError, DestructiveStatementError, ReadOnlyViolationError } from \"./errors.js\";\nimport { applyAutoLimit, evaluateGuard } from \"./safety.js\";\nimport { assertParamArity, classifyStatement } from \"./statements.js\";\nimport type { QueryOptions, QueryResult, QueryRow, SqlParam } from \"./types.js\";\n\nexport interface ConnectionConfig {\n readonly host: string;\n readonly port: number;\n readonly user: string;\n readonly password: string;\n readonly schema: string;\n readonly certificate: string;\n readonly connectTimeoutMs: number;\n readonly queryTimeoutMs: number;\n readonly readOnly: boolean;\n readonly allowDestructive: boolean;\n readonly autoLimit: number | false;\n}\n\ninterface RunOptions {\n readonly bypassSafety?: boolean;\n}\n\nfunction assertValidAutoLimit(value: number | false): void {\n if (\n value !== false &&\n (!Number.isSafeInteger(value) || value <= 0 || value >= Number.MAX_SAFE_INTEGER)\n ) {\n throw new CfHanaError(\"CONFIG\", \"autoLimit must be a positive safe integer\");\n }\n}\n\nfunction boundedRows(\n rows: readonly Record<string, SqlParam>[],\n requestedLimit: number | undefined,\n): {\n readonly rows: readonly Record<string, SqlParam>[];\n readonly truncated: boolean;\n} {\n if (requestedLimit === undefined) {\n return { rows, truncated: false };\n }\n return {\n rows: rows.slice(0, requestedLimit),\n truncated: rows.length > requestedLimit,\n };\n}\n\nasync function withTimeout<T>(\n work: Promise<T>,\n timeoutMs: number,\n onTimeout: () => void,\n): Promise<T> {\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n onTimeout();\n reject(\n new CfHanaError(\"TIMEOUT\", `Statement timed out after ${String(timeoutMs)}ms`),\n );\n }, timeoutMs);\n timer.unref();\n });\n\n try {\n return await Promise.race([work, timeout]);\n } finally {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n }\n}\n\n/** A single HANA connection: applies the safety guard, auto-limit, and timeouts. */\nexport class Connection {\n private constructor(\n private readonly driverConnection: DriverConnection,\n private readonly config: ConnectionConfig,\n ) {}\n\n static async open(driver: HanaDriver, config: ConnectionConfig): Promise<Connection> {\n const driverConnection = await driver.connect({\n host: config.host,\n port: config.port,\n user: config.user,\n password: config.password,\n schema: config.schema,\n certificate: config.certificate,\n connectTimeoutMs: config.connectTimeoutMs,\n });\n return new Connection(driverConnection, config);\n }\n\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n const result = await this.run(sql, params ?? [], options ?? {});\n // The driver returns untyped rows; the caller asserts the row shape via TRow.\n return result as unknown as QueryResult<TRow>;\n }\n\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.run(sql, params ?? [], options ?? {});\n }\n\n assertAllowed(sql: string, options?: QueryOptions): void {\n this.evaluateSafety(sql, options ?? {});\n }\n\n async executeInternal(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.run(sql, params ?? [], options ?? {}, { bypassSafety: true });\n }\n\n async setAutoCommit(enabled: boolean): Promise<void> {\n await this.driverConnection.setAutoCommit(enabled);\n }\n\n async commit(): Promise<void> {\n await this.driverConnection.commit();\n }\n\n async rollback(): Promise<void> {\n await this.driverConnection.rollback();\n }\n\n async close(): Promise<void> {\n await this.driverConnection.close();\n }\n\n get isClosed(): boolean {\n return this.driverConnection.isClosed();\n }\n\n private async run(\n sql: string,\n params: readonly SqlParam[],\n options: QueryOptions,\n runOptions: RunOptions = {},\n ): Promise<QueryResult> {\n assertParamArity(sql, params);\n if (runOptions.bypassSafety !== true) {\n this.evaluateSafety(sql, options);\n }\n\n const kind = classifyStatement(sql);\n const autoLimit = options.autoLimit ?? this.config.autoLimit;\n assertValidAutoLimit(autoLimit);\n const limited =\n kind === \"select\" ? applyAutoLimit(sql, autoLimit) : { sql, applied: false };\n const timeoutMs = options.timeoutMs ?? this.config.queryTimeoutMs;\n\n const started = Date.now();\n const execResult = await withTimeout(\n this.driverConnection.exec(limited.sql, params),\n timeoutMs,\n () => {\n void this.closeQuietly();\n },\n );\n const elapsedMs = Date.now() - started;\n const selected = boundedRows(execResult.rows, limited.requestedLimit);\n\n return {\n rows: selected.rows,\n columns: execResult.columns,\n rowCount: kind === \"select\" ? selected.rows.length : execResult.affectedRows,\n statement: kind,\n truncated: selected.truncated,\n elapsedMs,\n };\n }\n\n private async closeQuietly(): Promise<void> {\n try {\n await this.driverConnection.close();\n } catch {\n // Best-effort close after a timeout; the connection is already unusable.\n }\n }\n\n private evaluateSafety(sql: string, options: QueryOptions): void {\n const decision = evaluateGuard(sql, {\n readOnly: this.config.readOnly,\n allowDestructive: options.allowDestructive ?? this.config.allowDestructive,\n });\n if (decision.allowed) {\n return;\n }\n if (decision.violation === \"read-only\") {\n throw new ReadOnlyViolationError(\n decision.reason ?? \"read-only mode blocks this statement\",\n );\n }\n throw new DestructiveStatementError(\n decision.reason ?? \"destructive statement blocked\",\n );\n }\n}\n","import { DEFAULT_POOL_IDLE_MS, DEFAULT_POOL_MAX } from \"./config.js\";\nimport { Connection } from \"./connection.js\";\nimport type { ConnectionConfig } from \"./connection.js\";\nimport type { HanaDriver } from \"./driver/types.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type { PoolOptions } from \"./types.js\";\n\ninterface IdleEntry {\n readonly connection: Connection;\n readonly since: number;\n}\n\ninterface Waiter {\n readonly resolve: (connection: Connection) => void;\n readonly reject: (error: unknown) => void;\n}\n\nasync function closeQuietly(connection: Connection): Promise<void> {\n try {\n await connection.close();\n } catch {\n // Best-effort close.\n }\n}\n\n/**\n * A process-local, in-memory pool of HANA connections. It holds no shared disk\n * state, so multiple pools (in this or other processes) are fully independent.\n */\nexport class ConnectionPool {\n private readonly idle: IdleEntry[] = [];\n private readonly busy = new Set<Connection>();\n private readonly waiters: Waiter[] = [];\n private readonly maxSize: number;\n private readonly idleTimeoutMs: number;\n private created = 0;\n private draining = false;\n\n constructor(\n private readonly driver: HanaDriver,\n private readonly config: ConnectionConfig,\n options?: PoolOptions,\n ) {\n this.maxSize = Math.max(1, options?.max ?? DEFAULT_POOL_MAX);\n this.idleTimeoutMs = options?.idleTimeoutMs ?? DEFAULT_POOL_IDLE_MS;\n }\n\n /** Total connections currently owned by the pool (idle + busy). */\n get size(): number {\n return this.created;\n }\n\n /** Connections currently idle and immediately reusable. */\n get available(): number {\n return this.idle.length;\n }\n\n /** Borrow a connection, opening or queueing as needed. */\n async acquire(): Promise<Connection> {\n if (this.draining) {\n throw new CfHanaError(\"POOL_CLOSED\", \"Connection pool is draining\");\n }\n\n const reused = this.takeIdleConnection();\n if (reused !== undefined) {\n this.busy.add(reused);\n return reused;\n }\n\n if (this.created < this.maxSize) {\n return await this.openBusyConnection();\n }\n\n return await new Promise<Connection>((resolve, reject) => {\n this.waiters.push({ resolve, reject });\n });\n }\n\n /** Return a borrowed connection to the pool. */\n release(connection: Connection): void {\n if (!this.busy.delete(connection)) {\n return;\n }\n\n if (connection.isClosed) {\n this.created -= 1;\n this.servePendingWaiters();\n return;\n }\n\n const waiter = this.waiters.shift();\n if (waiter !== undefined) {\n this.busy.add(connection);\n waiter.resolve(connection);\n return;\n }\n\n if (this.draining) {\n this.created -= 1;\n void closeQuietly(connection);\n return;\n }\n\n this.idle.push({ connection, since: Date.now() });\n }\n\n /** Run `work` with a borrowed connection, releasing it afterwards. */\n async withConnection<T>(work: (connection: Connection) => Promise<T>): Promise<T> {\n const connection = await this.acquire();\n try {\n return await work(connection);\n } finally {\n this.release(connection);\n }\n }\n\n /** Reject queued waiters and close idle connections. */\n async drain(): Promise<void> {\n this.draining = true;\n\n while (this.waiters.length > 0) {\n const waiter = this.waiters.shift();\n if (waiter !== undefined) {\n waiter.reject(new CfHanaError(\"POOL_CLOSED\", \"Connection pool was drained\"));\n }\n }\n\n const idleConnections = this.idle.splice(0).map((entry) => entry.connection);\n this.created -= idleConnections.length;\n await Promise.all(idleConnections.map((connection) => closeQuietly(connection)));\n }\n\n private takeIdleConnection(): Connection | undefined {\n for (;;) {\n const entry = this.idle.pop();\n if (entry === undefined) {\n return undefined;\n }\n if (entry.connection.isClosed) {\n this.created -= 1;\n continue;\n }\n if (this.idleTimeoutMs > 0 && Date.now() - entry.since > this.idleTimeoutMs) {\n this.created -= 1;\n void closeQuietly(entry.connection);\n continue;\n }\n return entry.connection;\n }\n }\n\n private async openBusyConnection(): Promise<Connection> {\n this.created += 1;\n let connection: Connection;\n try {\n connection = await Connection.open(this.driver, this.config);\n } catch (error) {\n this.created -= 1;\n throw error;\n }\n this.busy.add(connection);\n return connection;\n }\n\n private servePendingWaiters(): void {\n while (this.waiters.length > 0 && this.created < this.maxSize) {\n const waiter = this.waiters.shift();\n if (waiter === undefined) {\n return;\n }\n this.created += 1;\n void Connection.open(this.driver, this.config).then(\n (connection) => {\n this.busy.add(connection);\n waiter.resolve(connection);\n },\n (error: unknown) => {\n this.created -= 1;\n waiter.reject(error);\n this.servePendingWaiters();\n },\n );\n }\n }\n}\n","import type { Connection } from \"./connection.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type { QueryOptions, QueryResult, QueryRow, SqlParam } from \"./types.js\";\n\n/** A HANA transaction bound to one connection with autocommit disabled. */\nexport class Transaction {\n private finished = false;\n\n constructor(private readonly connection: Connection) {}\n\n /** Whether the transaction has already been committed or rolled back. */\n get isFinished(): boolean {\n return this.finished;\n }\n\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n this.assertActive();\n return await this.connection.query<TRow>(sql, params, options);\n }\n\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n this.assertActive();\n return await this.connection.execute(sql, params, options);\n }\n\n async commit(): Promise<void> {\n this.assertActive();\n this.finished = true;\n await this.connection.commit();\n }\n\n async rollback(): Promise<void> {\n this.assertActive();\n this.finished = true;\n await this.connection.rollback();\n }\n\n private assertActive(): void {\n if (this.finished) {\n throw new CfHanaError(\n \"QUERY\",\n \"This transaction has already been committed or rolled back\",\n );\n }\n }\n}\n","import { buildWriteBackupPlan, writeSqlBackup } from \"./backup.js\";\nimport type { SqlBackupRecord } from \"./backup.js\";\nimport { buildCount, buildDelete, buildInsert, buildSelect, buildUpdate } from \"./builder.js\";\nimport { listCatalogObjects, listColumns, listSchemas, listTables } from \"./catalog.js\";\nimport {\n DEFAULT_AUTO_LIMIT,\n CLI_VERSION,\n DEFAULT_CONNECT_TIMEOUT_MS,\n DEFAULT_QUERY_TIMEOUT_MS,\n} from \"./config.js\";\nimport type { ConnectionConfig } from \"./connection.js\";\nimport { resolveAppBindings, selectBinding, toConnectionTarget } from \"./credentials.js\";\nimport { createDriver } from \"./driver/index.js\";\nimport { appendSqlHistory } from \"./history.js\";\nimport type { SqlHistoryOperation } from \"./history.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\nimport { ConnectionPool } from \"./pool.js\";\nimport { Transaction } from \"./transaction.js\";\nimport type {\n ColumnInfo,\n ConnectOptions,\n DbUserRole,\n HanaClientInfo,\n PoolOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SelectSpec,\n SqlParam,\n TableInfo,\n} from \"./types.js\";\n\nlet explainStatementCounter = 0;\n\nfunction nextExplainStatementName(): string {\n explainStatementCounter = (explainStatementCounter + 1) % Number.MAX_SAFE_INTEGER;\n return `cf_hana_${String(process.pid)}_${String(Date.now())}_${String(explainStatementCounter)}`;\n}\n\n/**\n * The high-level entry point: a pooled, reusable client for the HANA database\n * bound to a single Cloud Foundry app.\n */\nexport class HanaClient {\n constructor(\n private readonly pool: ConnectionPool,\n readonly info: HanaClientInfo,\n ) {}\n\n /** Open a client for a `region/org/space/app` selector (or a bare app name). */\n static async connect(selector: string, options: ConnectOptions = {}): Promise<HanaClient> {\n const resolved = await resolveAppBindings(selector, options);\n const role: DbUserRole = options.role ?? \"runtime\";\n const binding = selectBinding(resolved.bindings, options);\n const target = toConnectionTarget(binding, role);\n const driver = createDriver();\n\n const config: ConnectionConfig = {\n host: target.host,\n port: target.port,\n user: target.user,\n password: target.password,\n schema: target.schema,\n certificate: target.certificate,\n connectTimeoutMs: options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,\n queryTimeoutMs: options.queryTimeoutMs ?? DEFAULT_QUERY_TIMEOUT_MS,\n readOnly: options.readOnly ?? false,\n allowDestructive: options.allowDestructive ?? false,\n autoLimit: options.autoLimit ?? DEFAULT_AUTO_LIMIT,\n };\n const poolOptions: PoolOptions =\n options.pool === false ? { max: 1 } : (options.pool ?? {});\n\n const info: HanaClientInfo = {\n selector: resolved.selector,\n appName: resolved.appName,\n host: target.host,\n schema: target.schema,\n role,\n driver: driver.name,\n credentialSource: resolved.source,\n };\n return new HanaClient(new ConnectionPool(driver, config, poolOptions), info);\n }\n\n /** Run a SELECT (or any read) statement and return typed rows. */\n async query<TRow = QueryRow>(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n const resolvedParams = params ?? [];\n const result = await this.runQuery<TRow>(sql, resolvedParams, options);\n await this.recordSqlHistory(\"query\", sql, resolvedParams, result);\n return result;\n }\n\n /** Run a DML/DDL statement and return its affected-row count. */\n async execute(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n const resolvedParams = params ?? [];\n const result = await this.runExecute(sql, resolvedParams, options);\n await this.recordSqlHistory(\"execute\", sql, resolvedParams, result);\n return result;\n }\n\n /** Back up rows matched by an UPDATE or DELETE before the caller runs it. */\n async backupWriteStatement(\n sql: string,\n params?: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<SqlBackupRecord | undefined> {\n const resolvedParams = params ?? [];\n const plan = buildWriteBackupPlan(sql, resolvedParams);\n if (plan === undefined) {\n return undefined;\n }\n\n return await this.pool.withConnection(async (connection) => {\n connection.assertAllowed(plan.statementSql, options);\n const backupQueryOptions: QueryOptions = {\n autoLimit: false,\n ...(options?.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),\n };\n const result = await connection.query(plan.selectSql, plan.selectParams, backupQueryOptions);\n return await writeSqlBackup({\n operation: plan.operation,\n statementSql: plan.statementSql,\n result,\n selector: this.info.selector,\n });\n });\n }\n\n /** Run a typed `SELECT` built from a spec. */\n async selectFrom<TRow = QueryRow>(spec: SelectSpec): Promise<QueryResult<TRow>> {\n const built = buildSelect(spec);\n return await this.runQuery<TRow>(built.sql, built.params);\n }\n\n /** Count rows in a table, optionally filtered. */\n async count(spec: Pick<SelectSpec, \"schema\" | \"table\" | \"where\">): Promise<number> {\n const built = buildCount(spec);\n const result = await this.runQuery<{ COUNT: number }>(built.sql, built.params);\n return result.rows[0]?.COUNT ?? 0;\n }\n\n /** Insert a single row. */\n async insertInto(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildInsert(schema, table, values);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Update rows matching a non-empty `where` filter. */\n async update(\n schema: string,\n table: string,\n values: Readonly<Record<string, SqlParam>>,\n where: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildUpdate(schema, table, values, where);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Delete rows matching a non-empty `where` filter. */\n async deleteFrom(\n schema: string,\n table: string,\n where: Readonly<Record<string, SqlParam>>,\n ): Promise<QueryResult> {\n const built = buildDelete(schema, table, where);\n return await this.runExecute(built.sql, built.params);\n }\n\n /** Run `work` inside a transaction, auto-committing on success. */\n async transaction<T>(work: (tx: Transaction) => Promise<T>): Promise<T> {\n return await this.pool.withConnection(async (connection) => {\n await connection.setAutoCommit(false);\n const tx = new Transaction(connection);\n try {\n const result = await work(tx);\n if (!tx.isFinished) {\n await tx.commit();\n }\n return result;\n } catch (error) {\n if (!tx.isFinished) {\n try {\n await tx.rollback();\n } catch {\n // Preserve the original error; ignore a rollback failure.\n }\n }\n throw error;\n } finally {\n await connection.setAutoCommit(true);\n }\n });\n }\n\n /** List every schema visible to the connected user. */\n async listSchemas(): Promise<readonly string[]> {\n return await this.pool.withConnection((connection) => listSchemas(connection));\n }\n\n /** List the tables in a schema. */\n async listTables(schema: string): Promise<readonly TableInfo[]> {\n return await this.pool.withConnection((connection) => listTables(connection, schema));\n }\n\n /** List table and view names in a schema for typo suggestions. */\n async listCatalogObjects(schema: string): Promise<readonly CatalogObjectInfo[]> {\n return await this.pool.withConnection((connection) => listCatalogObjects(connection, schema));\n }\n\n /** List the columns of a table. */\n async listColumns(schema: string, table: string): Promise<readonly ColumnInfo[]> {\n return await this.pool.withConnection((connection) =>\n listColumns(connection, schema, table),\n );\n }\n\n /** Return the HANA execution plan for a statement. */\n async explain(sql: string, params?: readonly SqlParam[]): Promise<QueryResult> {\n return await this.pool.withConnection(async (connection) => {\n connection.assertAllowed(sql);\n const statementName = nextExplainStatementName();\n await connection.executeInternal(\n `EXPLAIN PLAN SET STATEMENT_NAME = '${statementName}' FOR ${sql}`,\n params,\n );\n const cleanup = async (): Promise<void> => {\n await connection.executeInternal(\n \"DELETE FROM EXPLAIN_PLAN_TABLE WHERE STATEMENT_NAME = ?\",\n [statementName],\n );\n };\n let queryCompleted = false;\n try {\n const result = await connection.query(\n \"SELECT OPERATOR_NAME, TABLE_NAME, TABLE_TYPE, EXECUTION_ENGINE \" +\n \"FROM EXPLAIN_PLAN_TABLE WHERE STATEMENT_NAME = ? ORDER BY OPERATOR_ID\",\n [statementName],\n );\n queryCompleted = true;\n await cleanup();\n return result;\n } catch (error) {\n if (!queryCompleted) {\n try {\n await cleanup();\n } catch {\n // Preserve the original explain-plan read error.\n }\n }\n throw error;\n }\n });\n }\n\n /** Close every pooled connection. The client must not be used afterwards. */\n async close(): Promise<void> {\n await this.pool.drain();\n }\n\n private async runQuery<TRow = QueryRow>(\n sql: string,\n params: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult<TRow>> {\n return await this.pool.withConnection((connection) =>\n connection.query<TRow>(sql, params, options),\n );\n }\n\n private async runExecute(\n sql: string,\n params: readonly SqlParam[],\n options?: QueryOptions,\n ): Promise<QueryResult> {\n return await this.pool.withConnection((connection) =>\n connection.execute(sql, params, options),\n );\n }\n\n private async recordSqlHistory<TRow>(\n operation: SqlHistoryOperation,\n sql: string,\n params: readonly SqlParam[],\n result: QueryResult<TRow>,\n ): Promise<void> {\n try {\n await appendSqlHistory({\n version: CLI_VERSION,\n operation,\n selector: this.info.selector,\n appName: this.info.appName,\n schema: this.info.schema,\n role: this.info.role,\n statement: result.statement,\n sql,\n paramCount: params.length,\n rowCount: result.rowCount,\n truncated: result.truncated,\n elapsedMs: result.elapsedMs,\n });\n } catch {\n // History is diagnostic local state; never fail a successful SQL statement.\n }\n }\n}\n","import { HanaClient } from \"./client.js\";\nimport type {\n ConnectOptions,\n QueryOptions,\n QueryResult,\n QueryRow,\n SqlParam,\n} from \"./types.js\";\n\n/**\n * Open a reusable, pooled client for the HANA database bound to a Cloud Foundry\n * app, addressed by a `region/org/space/app` selector or a bare app name.\n */\nexport async function connect(\n selector: string,\n options?: ConnectOptions,\n): Promise<HanaClient> {\n return await HanaClient.connect(selector, options);\n}\n\n/**\n * Connect, run a single query, and close — the one-shot convenience for scripts.\n */\nexport async function query<TRow = QueryRow>(\n selector: string,\n sql: string,\n params?: readonly SqlParam[],\n options?: ConnectOptions & QueryOptions,\n): Promise<QueryResult<TRow>> {\n const client = await HanaClient.connect(selector, options);\n try {\n return await client.query<TRow>(sql, params, options);\n } finally {\n await client.close();\n }\n}\n\n/** Run `work` with a client that is closed automatically afterwards. */\nexport async function withConnection<T>(\n selector: string,\n work: (client: HanaClient) => Promise<T>,\n options?: ConnectOptions,\n): Promise<T> {\n const client = await HanaClient.connect(selector, options);\n try {\n return await work(client);\n } finally {\n await client.close();\n }\n}\n","import { writeFile } from \"node:fs/promises\";\n\nimport type { Command } from \"commander\";\n\nimport {\n DEFAULT_CELL_LIMIT,\n DEFAULT_RESULT_SEARCH_LIMIT,\n MAX_CELL_LIMIT,\n} from \"./config.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport { formatCompactCsv } from \"./format.js\";\nimport { isTextLobType } from \"./lob.js\";\nimport {\n inspectJsonCell,\n readCellWindow,\n searchResultSession,\n selectResultCell,\n selectResultRow,\n} from \"./result-inspect.js\";\nimport {\n clearResultSessions,\n listResultSessions,\n pruneResultSessions,\n readResultSession,\n} from \"./result-store.js\";\nimport type {\n QueryResult,\n QueryResultColumn,\n QueryRow,\n SqlParam,\n} from \"./types.js\";\n\ninterface ShowOptions {\n readonly row?: number;\n readonly column?: string;\n readonly offset?: number;\n readonly length?: number;\n readonly path?: string;\n}\n\ninterface SearchOptions {\n readonly row?: number;\n readonly column?: string;\n readonly limit?: number;\n readonly length?: number;\n}\n\ninterface ExportOptions {\n readonly row?: number;\n readonly column?: string;\n readonly output?: string;\n}\n\nfunction print(text: string): void {\n process.stdout.write(`${text}\\n`);\n}\n\nfunction parseIntOption(value: string): number {\n const trimmed = value.trim();\n if (!/^-?\\d+$/.test(trimmed)) {\n throw new CfHanaError(\"CONFIG\", `Expected an integer but received \"${value}\"`);\n }\n const parsed = Number(trimmed);\n if (!Number.isSafeInteger(parsed)) {\n throw new CfHanaError(\"CONFIG\", `Expected a safe integer but received \"${value}\"`);\n }\n return parsed;\n}\n\nfunction positive(name: string, value: number | undefined, fallback: number): number {\n const resolved = value ?? fallback;\n if (!Number.isSafeInteger(resolved) || resolved <= 0) {\n throw new CfHanaError(\"CONFIG\", `${name} must be a positive safe integer`);\n }\n return resolved;\n}\n\nfunction boundedLength(value: number | undefined): number {\n const resolved = positive(\"--length\", value, DEFAULT_CELL_LIMIT);\n if (resolved > MAX_CELL_LIMIT) {\n throw new CfHanaError(\"CONFIG\", `--length must be at most ${String(MAX_CELL_LIMIT)}`);\n }\n return resolved;\n}\n\nfunction nonNegative(name: string, value: number | undefined): number {\n const resolved = value ?? 0;\n if (!Number.isSafeInteger(resolved) || resolved < 0) {\n throw new CfHanaError(\"CONFIG\", `${name} must be a non-negative safe integer`);\n }\n return resolved;\n}\n\nfunction resultFromRows(\n rows: readonly QueryRow[],\n columns: readonly QueryResultColumn[],\n): QueryResult {\n return {\n rows,\n columns,\n rowCount: rows.length,\n statement: \"select\",\n truncated: false,\n elapsedMs: 0,\n };\n}\n\nfunction csv(rows: readonly QueryRow[], columns: readonly string[], limit: number): string {\n const result = resultFromRows(\n rows,\n columns.map((name) => ({ name, typeName: \"\" })),\n );\n return formatCompactCsv(result, limit).text;\n}\n\nasync function runShow(ref: string, options: ShowOptions): Promise<void> {\n const session = await readResultSession(ref);\n const length = boundedLength(options.length);\n if (options.row === undefined) {\n if (\n options.column !== undefined ||\n options.path !== undefined ||\n options.offset !== undefined\n ) {\n throw new CfHanaError(\"CONFIG\", \"--column, --path, and --offset require --row\");\n }\n print(summaryCsv(session, length));\n return;\n }\n if (options.column === undefined) {\n if (options.path !== undefined || options.offset !== undefined) {\n throw new CfHanaError(\"CONFIG\", \"--path and --offset require --column\");\n }\n const row = selectResultRow(session, options.row);\n print(formatCompactCsv(resultFromRows([row], session.result.columns), length).text);\n return;\n }\n const selected = selectResultCell(session, options.row, options.column);\n if (options.path !== undefined) {\n const rows = inspectJsonCell(selected.value, options.path, length).map((row) => ({\n PATH: row.path,\n TYPE: row.type,\n VALUE: row.value,\n }));\n print(csv(rows, [\"PATH\", \"TYPE\", \"VALUE\"], length));\n return;\n }\n const window = readCellWindow(\n selected.value,\n nonNegative(\"--offset\", options.offset),\n length,\n selected.typeName,\n );\n print(\n csv(\n [\n {\n ROW: selected.row,\n COLUMN: selected.column,\n TYPE: window.type,\n ORIGINAL_LENGTH: window.originalLength,\n OFFSET: window.offset,\n VALUE: window.value,\n },\n ],\n [\"ROW\", \"COLUMN\", \"TYPE\", \"ORIGINAL_LENGTH\", \"OFFSET\", \"VALUE\"],\n length,\n ),\n );\n}\n\nfunction summaryCsv(session: Awaited<ReturnType<typeof readResultSession>>, length: number): string {\n const compact = formatCompactCsv(session.result, DEFAULT_CELL_LIMIT);\n return csv(\n [\n {\n REF: session.ref,\n ROWS: session.result.rowCount,\n COLUMNS: session.result.columns.length,\n ROW_TRUNCATED: session.result.truncated,\n TRUNCATED_CELLS: compact.truncatedCells,\n EXPIRES_AT: session.expiresAt,\n },\n ],\n [\"REF\", \"ROWS\", \"COLUMNS\", \"ROW_TRUNCATED\", \"TRUNCATED_CELLS\", \"EXPIRES_AT\"],\n length,\n );\n}\n\nasync function runSearch(ref: string, text: string, options: SearchOptions): Promise<void> {\n const session = await readResultSession(ref);\n const length = boundedLength(options.length);\n const matches = searchResultSession(session, text, {\n limit: positive(\"--limit\", options.limit, DEFAULT_RESULT_SEARCH_LIMIT),\n previewLength: length,\n ...(options.row === undefined ? {} : { row: options.row }),\n ...(options.column === undefined ? {} : { column: options.column }),\n });\n const rows = matches.map((match) => ({\n ROW: match.row,\n COLUMN: match.column,\n OFFSET: match.offset ?? null,\n PATH: match.path,\n PREVIEW: match.preview,\n }));\n print(csv(rows, [\"ROW\", \"COLUMN\", \"OFFSET\", \"PATH\", \"PREVIEW\"], length));\n}\n\nfunction cellExportValue(value: SqlParam, typeName?: string): string | Buffer {\n if (Buffer.isBuffer(value)) {\n return isTextLobType(typeName) ? value.toString(\"utf8\") : value;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (value === null) {\n return \"\";\n }\n if (typeof value === \"boolean\") {\n return value ? \"true\" : \"false\";\n }\n return value.toString();\n}\n\nasync function runExport(ref: string, options: ExportOptions): Promise<void> {\n if (options.row === undefined || options.column === undefined) {\n throw new CfHanaError(\"CONFIG\", \"result export requires --row and --column\");\n }\n if (options.output === undefined || options.output.trim().length === 0) {\n throw new CfHanaError(\"CONFIG\", \"result export requires --output\");\n }\n const session = await readResultSession(ref);\n const selected = selectResultCell(session, options.row, options.column);\n await writeFile(options.output, cellExportValue(selected.value, selected.typeName), {\n mode: 0o600,\n });\n print(`wrote=${options.output}`);\n}\n\nasync function runList(): Promise<void> {\n const summaries = await listResultSessions();\n const rows = summaries.map((summary) => ({\n REF: summary.ref,\n ROWS: summary.rowCount,\n COLUMNS: summary.columnCount,\n ROW_TRUNCATED: summary.truncated,\n EXPIRES_AT: summary.expiresAt,\n }));\n print(csv(rows, [\"REF\", \"ROWS\", \"COLUMNS\", \"ROW_TRUNCATED\", \"EXPIRES_AT\"], DEFAULT_CELL_LIMIT));\n}\n\nasync function runPrune(): Promise<void> {\n print(`removed=${String(await pruneResultSessions())}`);\n}\n\nasync function runClear(): Promise<void> {\n print(`removed=${String(await clearResultSessions())}`);\n}\n\nexport function registerResultCommands(program: Command): void {\n const result = program.command(\"result\").description(\"inspect saved query refs\");\n result\n .command(\"show <ref>\")\n .description(\"show a saved result, row, cell, or JSON path\")\n .option(\"--row <n>\", \"one-based result row\", parseIntOption)\n .option(\"--column <name>\", \"exact column name\")\n .option(\"--offset <n>\", \"text code-point or binary byte offset\", parseIntOption)\n .option(\"--length <n>\", \"maximum characters or bytes to print\", parseIntOption)\n .option(\"--path <pointer>\", \"JSON Pointer inside a saved text cell\")\n .action(async (ref: string, _options: unknown, command: Command) => {\n await runShow(ref, command.opts<ShowOptions>());\n });\n result\n .command(\"search <ref> <text>\")\n .description(\"search saved text and JSON values\")\n .option(\"--row <n>\", \"one-based result row\", parseIntOption)\n .option(\"--column <name>\", \"exact column name\")\n .option(\"--limit <n>\", \"maximum matches to print\", parseIntOption)\n .option(\"--length <n>\", \"maximum preview characters\", parseIntOption)\n .action(async (ref: string, text: string, _options: unknown, command: Command) => {\n await runSearch(ref, text, command.opts<SearchOptions>());\n });\n result\n .command(\"export <ref>\")\n .description(\"write one exact saved cell to a file\")\n .requiredOption(\"--output <path>\", \"output file path\")\n .option(\"--row <n>\", \"one-based result row\", parseIntOption)\n .option(\"--column <name>\", \"exact column name\")\n .action(async (ref: string, _options: unknown, command: Command) => {\n await runExport(ref, command.opts<ExportOptions>());\n });\n result.command(\"list\").description(\"list active saved refs\").action(async () => {\n await runList();\n });\n result.command(\"prune\").description(\"remove expired saved refs\").action(async () => {\n await runPrune();\n });\n result.command(\"clear\").description(\"remove all saved refs\").action(async () => {\n await runClear();\n });\n}\n","import { CfHanaError } from \"./errors.js\";\nimport { isTextLobType } from \"./lob.js\";\nimport { previewCell } from \"./result-preview.js\";\nimport type { ResultSession } from \"./result-store.js\";\nimport type { QueryRow, SqlParam } from \"./types.js\";\n\nexport interface SelectedResultCell {\n readonly row: number;\n readonly column: string;\n readonly typeName: string;\n readonly value: SqlParam;\n}\n\nexport interface CellWindow {\n readonly type: \"text\" | \"binary\" | \"scalar\";\n readonly originalLength: number;\n readonly offset: number;\n readonly value: string;\n}\n\nexport interface JsonInspectionRow {\n readonly path: string;\n readonly type: string;\n readonly value: string;\n}\n\nexport interface ResultSearchOptions {\n readonly row?: number;\n readonly column?: string;\n readonly limit: number;\n readonly previewLength?: number;\n}\n\nexport interface ResultSearchMatch {\n readonly row: number;\n readonly column: string;\n readonly offset?: number;\n readonly path: string;\n readonly preview: string;\n}\n\nfunction assertPositiveInteger(name: string, value: number): void {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new CfHanaError(\n \"CONFIG\",\n `${name} ${String(value)} must be a positive safe integer`,\n );\n }\n}\n\n/** Select one saved result row using one-based numbering. */\nexport function selectResultRow(session: ResultSession, rowNumber: number): QueryRow {\n assertPositiveInteger(\"row\", rowNumber);\n const row = session.result.rows[rowNumber - 1];\n if (row === undefined) {\n throw new CfHanaError(\"QUERY\", `Saved result row ${String(rowNumber)} not found`);\n }\n return row;\n}\n\n/** Select one exact saved cell by its case-sensitive SQL display name. */\nexport function selectResultCell(\n session: ResultSession,\n rowNumber: number,\n columnName: string,\n): SelectedResultCell {\n const row = selectResultRow(session, rowNumber);\n const column = session.result.columns.find((item) => item.name === columnName);\n if (column === undefined) {\n throw new CfHanaError(\"QUERY\", `Saved result column \"${columnName}\" not found`);\n }\n return {\n row: rowNumber,\n column: column.name,\n typeName: column.typeName,\n value: row[column.name] ?? null,\n };\n}\n\nfunction textRange(value: string, offset: number, length: number): CellWindow {\n let index = 0;\n let selected = \"\";\n for (const char of value) {\n if (index >= offset && index < offset + length) {\n selected += char;\n }\n index += 1;\n }\n return { type: \"text\", originalLength: index, offset, value: selected };\n}\n\n/** Read a bounded range from an exact saved cell. */\nexport function readCellWindow(\n value: SqlParam,\n offset: number,\n length: number,\n typeName?: string,\n): CellWindow {\n if (!Number.isSafeInteger(offset) || offset < 0) {\n throw new CfHanaError(\"CONFIG\", \"offset must be a non-negative safe integer\");\n }\n assertPositiveInteger(\"length\", length);\n if (Buffer.isBuffer(value)) {\n if (isTextLobType(typeName)) {\n return textRange(value.toString(\"utf8\"), offset, length);\n }\n return {\n type: \"binary\",\n originalLength: value.length,\n offset,\n value: `0x${value.subarray(offset, offset + length).toString(\"hex\")}`,\n };\n }\n if (typeof value === \"string\") {\n return textRange(value, offset, length);\n }\n const text = previewCell(value, Number.MAX_SAFE_INTEGER).text;\n const window = textRange(text, offset, length);\n return { ...window, type: \"scalar\" };\n}\n\nfunction decodePointerToken(token: string): string {\n if (/~(?:[^01]|$)/.test(token)) {\n throw new CfHanaError(\"CONFIG\", \"Invalid JSON Pointer escape\");\n }\n return token.replaceAll(\"~1\", \"/\").replaceAll(\"~0\", \"~\");\n}\n\nfunction pointerTokens(pointer: string): readonly string[] {\n if (pointer === \"\") {\n return [];\n }\n if (!pointer.startsWith(\"/\")) {\n throw new CfHanaError(\"CONFIG\", \"JSON Pointer must be empty or start with /\");\n }\n return pointer.slice(1).split(\"/\").map(decodePointerToken);\n}\n\nfunction resolvePointer(root: unknown, pointer: string): unknown {\n let current = root;\n for (const token of pointerTokens(pointer)) {\n if (Array.isArray(current)) {\n const index = Number(token);\n if (!Number.isSafeInteger(index) || index < 0 || index >= current.length) {\n throw new CfHanaError(\"QUERY\", `JSON Pointer path \"${pointer}\" not found`);\n }\n current = current[index];\n continue;\n }\n if (typeof current === \"object\" && current !== null && token in current) {\n current = (current as Record<string, unknown>)[token];\n continue;\n }\n throw new CfHanaError(\"QUERY\", `JSON Pointer path \"${pointer}\" not found`);\n }\n return current;\n}\n\nfunction escapePointerToken(token: string): string {\n return token.replaceAll(\"~\", \"~0\").replaceAll(\"/\", \"~1\");\n}\n\nfunction jsonType(value: unknown): string {\n if (value === null) {\n return \"null\";\n }\n if (Array.isArray(value)) {\n return \"array\";\n }\n return typeof value;\n}\n\nfunction jsonValueText(value: unknown, limit: number): string {\n if (Array.isArray(value)) {\n return `items=${String(value.length)}`;\n }\n if (typeof value === \"object\" && value !== null) {\n return `keys=${String(Object.keys(value).length)}`;\n }\n if (typeof value === \"string\") {\n return previewCell(value, limit).text;\n }\n if (value === null) {\n return \"null\";\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return \"\";\n}\n\nfunction jsonSearchText(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value === null) {\n return \"null\";\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return \"\";\n}\n\nfunction inspectionRow(path: string, value: unknown, limit: number): JsonInspectionRow {\n return { path, type: jsonType(value), value: jsonValueText(value, limit) };\n}\n\n/** Resolve a JSON Pointer and describe the selected value or its immediate children. */\nexport function inspectJsonCell(\n value: SqlParam,\n pointer: string,\n limit: number,\n): readonly JsonInspectionRow[] {\n if (typeof value !== \"string\") {\n throw new CfHanaError(\"QUERY\", \"JSON Pointer requires a text cell\");\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(value) as unknown;\n } catch (error) {\n throw new CfHanaError(\"QUERY\", \"Saved result cell does not contain valid JSON\", {\n cause: error,\n });\n }\n const selected = resolvePointer(parsed, pointer);\n if (Array.isArray(selected)) {\n return selected.map((item, index) =>\n inspectionRow(`${pointer}/${String(index)}`, item, limit),\n );\n }\n if (typeof selected === \"object\" && selected !== null) {\n return Object.entries(selected).map(([key, item]) =>\n inspectionRow(`${pointer}/${escapePointerToken(key)}`, item, limit),\n );\n }\n return [inspectionRow(pointer, selected, limit)];\n}\n\nfunction plainTextMatches(\n text: string,\n term: string,\n row: number,\n column: string,\n limit: number,\n previewLength: number,\n): readonly ResultSearchMatch[] {\n const matches: ResultSearchMatch[] = [];\n const lowerText = text.toLowerCase();\n let offset = lowerText.indexOf(term);\n while (offset >= 0 && matches.length < limit) {\n const start = Math.max(0, offset - 32);\n matches.push({\n row,\n column,\n offset,\n path: \"\",\n preview: textRange(text, start, previewLength).value.replaceAll(/[\\r\\n\\t]/g, \" \"),\n });\n offset = lowerText.indexOf(term, offset + Math.max(1, term.length));\n }\n return matches;\n}\n\nfunction jsonSearchMatches(\n root: unknown,\n term: string,\n row: number,\n column: string,\n limit: number,\n previewLength: number,\n): readonly ResultSearchMatch[] {\n const matches: ResultSearchMatch[] = [];\n const stack: { readonly path: string; readonly value: unknown }[] = [\n { path: \"\", value: root },\n ];\n while (stack.length > 0 && matches.length < limit) {\n const entry = stack.pop();\n if (entry === undefined) {\n break;\n }\n if (typeof entry.value === \"object\" && entry.value !== null) {\n const entries = Array.isArray(entry.value)\n ? entry.value.map((item, index) => [String(index), item] as const)\n : Object.entries(entry.value);\n for (const [key, value] of entries.reverse()) {\n const path = `${entry.path}/${escapePointerToken(key)}`;\n if (key.toLowerCase().includes(term)) {\n matches.push({ row, column, path, preview: jsonValueText(value, previewLength) });\n if (matches.length >= limit) {\n break;\n }\n }\n stack.push({ path, value });\n }\n continue;\n }\n const text = jsonSearchText(entry.value);\n if (text.toLowerCase().includes(term)) {\n matches.push({\n row,\n column,\n path: entry.path,\n preview: previewCell(text, previewLength).text,\n });\n }\n }\n return matches;\n}\n\nfunction searchCell(\n value: SqlParam,\n term: string,\n row: number,\n column: string,\n typeName: string | undefined,\n limit: number,\n previewLength: number,\n): readonly ResultSearchMatch[] {\n const text = Buffer.isBuffer(value) && isTextLobType(typeName)\n ? value.toString(\"utf8\")\n : value;\n if (typeof text !== \"string\") {\n return [];\n }\n try {\n const parsed: unknown = JSON.parse(text);\n if (typeof parsed === \"object\" && parsed !== null) {\n return jsonSearchMatches(parsed, term, row, column, limit, previewLength);\n }\n } catch {\n // Non-JSON text is searched literally below.\n }\n return plainTextMatches(text, term, row, column, limit, previewLength);\n}\n\n/** Search exact saved text and JSON values without loading binary cells into output. */\nexport function searchResultSession(\n session: ResultSession,\n searchTerm: string,\n options: ResultSearchOptions,\n): readonly ResultSearchMatch[] {\n assertPositiveInteger(\"limit\", options.limit);\n const term = searchTerm.trim().toLowerCase();\n if (term.length === 0) {\n throw new CfHanaError(\"CONFIG\", \"search text must not be empty\");\n }\n const previewLength = options.previewLength ?? 128;\n assertPositiveInteger(\"preview length\", previewLength);\n const rows = options.row === undefined\n ? session.result.rows.map((row, index) => ({ row, rowNumber: index + 1 }))\n : [{ row: selectResultRow(session, options.row), rowNumber: options.row }];\n const columns = options.column === undefined\n ? session.result.columns\n : [selectResultCell(session, rows[0]?.rowNumber ?? 1, options.column)]\n .map((item) => ({ name: item.column, typeName: item.typeName }));\n const matches: ResultSearchMatch[] = [];\n for (const item of rows) {\n for (const column of columns) {\n const remaining = options.limit - matches.length;\n matches.push(\n ...searchCell(\n item.row[column.name] ?? null,\n term,\n item.rowNumber,\n column.name,\n column.typeName,\n remaining,\n previewLength,\n ),\n );\n if (matches.length >= options.limit) {\n return matches;\n }\n }\n }\n return matches;\n}\n","import { randomBytes } from \"node:crypto\";\nimport { mkdir, readFile, readdir, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport {\n DEFAULT_RESULT_TTL_MINUTES,\n MAX_RESULT_STORE_BYTES,\n} from \"./config.js\";\nimport { CfHanaError } from \"./errors.js\";\nimport type {\n HanaClientInfo,\n QueryResult,\n QueryResultColumn,\n QueryRow,\n SqlParam,\n StatementKind,\n} from \"./types.js\";\n\nconst RESULT_REF_PATTERN = /^q[0-9a-f]{8}$/;\nconst MANIFEST_FILE_NAME = \"manifest.json\";\n\ntype StoredCell =\n | { readonly kind: \"null\" }\n | { readonly kind: \"string\"; readonly value: string }\n | { readonly kind: \"number\"; readonly value: number }\n | { readonly kind: \"boolean\"; readonly value: boolean }\n | { readonly kind: \"date\"; readonly value: string }\n | { readonly kind: \"buffer\"; readonly value: string };\n\ninterface StoredResult {\n readonly columns: readonly QueryResultColumn[];\n readonly rows: readonly (readonly StoredCell[])[];\n readonly rowCount: number;\n readonly statement: StatementKind;\n readonly truncated: boolean;\n readonly elapsedMs: number;\n}\n\ninterface StoredResultSession {\n readonly version: 1;\n readonly ref: string;\n readonly createdAt: string;\n readonly expiresAt: string;\n readonly ttlMinutes: number;\n readonly info: HanaClientInfo;\n readonly result: StoredResult;\n}\n\nexport interface CreateResultSessionInput {\n readonly result: QueryResult;\n readonly info: HanaClientInfo;\n readonly ttlMinutes?: number;\n}\n\nexport interface ResultStoreOptions {\n readonly saptoolsRoot?: string;\n readonly now?: () => Date;\n readonly ref?: string;\n readonly maxBytes?: number;\n}\n\nexport interface ResultSession {\n readonly ref: string;\n readonly createdAt: string;\n readonly expiresAt: string;\n readonly ttlMinutes: number;\n readonly info: HanaClientInfo;\n readonly result: QueryResult;\n readonly directory: string;\n readonly path: string;\n}\n\nexport interface ResultSessionSummary {\n readonly ref: string;\n readonly createdAt: string;\n readonly expiresAt: string;\n readonly rowCount: number;\n readonly columnCount: number;\n readonly truncated: boolean;\n}\n\nfunction resultsRoot(saptoolsRoot?: string): string {\n return join(saptoolsRoot ?? join(homedir(), \".saptools\"), \"cf-hana\", \"results\");\n}\n\nfunction sessionDirectory(ref: string, saptoolsRoot?: string): string {\n return join(resultsRoot(saptoolsRoot), ref);\n}\n\nfunction manifestPath(ref: string, saptoolsRoot?: string): string {\n return join(sessionDirectory(ref, saptoolsRoot), MANIFEST_FILE_NAME);\n}\n\nfunction encodeCell(value: SqlParam): StoredCell {\n if (value === null) {\n return { kind: \"null\" };\n }\n if (Buffer.isBuffer(value)) {\n return { kind: \"buffer\", value: value.toString(\"base64\") };\n }\n if (value instanceof Date) {\n return { kind: \"date\", value: value.toISOString() };\n }\n if (typeof value === \"string\") {\n return { kind: \"string\", value };\n }\n if (typeof value === \"number\") {\n return { kind: \"number\", value };\n }\n return { kind: \"boolean\", value };\n}\n\nfunction decodeCell(cell: StoredCell): SqlParam {\n switch (cell.kind) {\n case \"null\":\n return null;\n case \"buffer\":\n return Buffer.from(cell.value, \"base64\");\n case \"date\":\n return new Date(cell.value);\n case \"string\":\n return cell.value;\n case \"number\":\n return cell.value;\n case \"boolean\":\n return cell.value;\n }\n}\n\nfunction assertUniqueColumns(columns: readonly QueryResultColumn[]): void {\n const names = new Set<string>();\n for (const column of columns) {\n if (names.has(column.name)) {\n throw new CfHanaError(\n \"CONFIG\",\n `Saved results require unique SQL aliases; duplicate column \"${column.name}\"`,\n );\n }\n names.add(column.name);\n }\n}\n\nfunction encodeResult(result: QueryResult): StoredResult {\n assertUniqueColumns(result.columns);\n return {\n columns: result.columns,\n rows: result.rows.map((row) =>\n result.columns.map((column) => encodeCell(row[column.name] ?? null)),\n ),\n rowCount: result.rowCount,\n statement: result.statement,\n truncated: result.truncated,\n elapsedMs: result.elapsedMs,\n };\n}\n\nfunction decodeResult(result: StoredResult): QueryResult {\n const rows: QueryRow[] = result.rows.map((cells) => {\n const row: QueryRow = {};\n let index = 0;\n for (const column of result.columns) {\n row[column.name] = decodeCell(cells[index] ?? { kind: \"null\" });\n index += 1;\n }\n return row;\n });\n return { ...result, rows };\n}\n\nfunction resolveRef(value: string | undefined): string {\n const ref = value ?? `q${randomBytes(4).toString(\"hex\")}`;\n if (!RESULT_REF_PATTERN.test(ref)) {\n throw new CfHanaError(\"CONFIG\", \"Invalid saved result ref\");\n }\n return ref;\n}\n\nfunction resolveTtl(value: number | undefined): number {\n const ttl = value ?? DEFAULT_RESULT_TTL_MINUTES;\n if (!Number.isSafeInteger(ttl) || ttl <= 0) {\n throw new CfHanaError(\"CONFIG\", \"Result TTL must be a positive safe integer\");\n }\n return ttl;\n}\n\nfunction toStoredSession(\n input: CreateResultSessionInput,\n ref: string,\n now: Date,\n): StoredResultSession {\n const ttlMinutes = resolveTtl(input.ttlMinutes);\n return {\n version: 1,\n ref,\n createdAt: now.toISOString(),\n expiresAt: new Date(now.getTime() + ttlMinutes * 60_000).toISOString(),\n ttlMinutes,\n info: input.info,\n result: encodeResult(input.result),\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isStoredSession(value: unknown): value is StoredResultSession {\n if (!isRecord(value) || !isRecord(value[\"result\"]) || !isRecord(value[\"info\"])) {\n return false;\n }\n const result = value[\"result\"];\n return (\n value[\"version\"] === 1 &&\n typeof value[\"ref\"] === \"string\" &&\n typeof value[\"createdAt\"] === \"string\" &&\n typeof value[\"expiresAt\"] === \"string\" &&\n typeof value[\"ttlMinutes\"] === \"number\" &&\n Array.isArray(result[\"columns\"]) &&\n Array.isArray(result[\"rows\"])\n );\n}\n\nasync function readStoredSession(path: string): Promise<StoredResultSession | undefined> {\n try {\n const parsed: unknown = JSON.parse(await readFile(path, \"utf8\"));\n return isStoredSession(parsed) ? parsed : undefined;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return undefined;\n }\n return undefined;\n }\n}\n\nfunction toSession(stored: StoredResultSession, saptoolsRoot?: string): ResultSession {\n return {\n ...stored,\n result: decodeResult(stored.result),\n directory: sessionDirectory(stored.ref, saptoolsRoot),\n path: manifestPath(stored.ref, saptoolsRoot),\n };\n}\n\nasync function listSessionRefs(saptoolsRoot?: string): Promise<readonly string[]> {\n try {\n const entries = await readdir(resultsRoot(saptoolsRoot), { withFileTypes: true });\n return entries\n .filter((entry) => entry.isDirectory() && RESULT_REF_PATTERN.test(entry.name))\n .map((entry) => entry.name);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/** Save one exact CLI SELECT result and return its temporary ref. */\nexport async function createResultSession(\n input: CreateResultSessionInput,\n options: ResultStoreOptions = {},\n): Promise<ResultSession> {\n await pruneResultSessions(options);\n const ref = resolveRef(options.ref);\n const stored = toStoredSession(input, ref, options.now?.() ?? new Date());\n const serialized = `${JSON.stringify(stored)}\\n`;\n if (Buffer.byteLength(serialized) > (options.maxBytes ?? MAX_RESULT_STORE_BYTES)) {\n throw new CfHanaError(\"CONFIG\", \"Saved result exceeds the storage limit\");\n }\n\n const root = resultsRoot(options.saptoolsRoot);\n const finalDirectory = sessionDirectory(ref, options.saptoolsRoot);\n const tempDirectory = `${finalDirectory}.tmp-${process.pid.toString()}`;\n await mkdir(root, { recursive: true, mode: 0o700 });\n await rm(tempDirectory, { recursive: true, force: true });\n await mkdir(tempDirectory, { mode: 0o700 });\n try {\n await writeFile(join(tempDirectory, MANIFEST_FILE_NAME), serialized, {\n encoding: \"utf8\",\n mode: 0o600,\n });\n await rename(tempDirectory, finalDirectory);\n } catch (error) {\n await rm(tempDirectory, { recursive: true, force: true });\n throw error;\n }\n return toSession(stored, options.saptoolsRoot);\n}\n\n/** Read one active saved result by ref. */\nexport async function readResultSession(\n ref: string,\n options: ResultStoreOptions = {},\n): Promise<ResultSession> {\n const resolvedRef = resolveRef(ref);\n await pruneResultSessions(options);\n const stored = await readStoredSession(manifestPath(resolvedRef, options.saptoolsRoot));\n if (stored === undefined) {\n throw new CfHanaError(\"QUERY\", \"Saved result not found or expired\");\n }\n return toSession(stored, options.saptoolsRoot);\n}\n\n/** List active saved results without loading their full decoded values. */\nexport async function listResultSessions(\n options: ResultStoreOptions = {},\n): Promise<readonly ResultSessionSummary[]> {\n await pruneResultSessions(options);\n const refs = await listSessionRefs(options.saptoolsRoot);\n const stored = await Promise.all(\n refs.map(async (ref) => await readStoredSession(manifestPath(ref, options.saptoolsRoot))),\n );\n return stored\n .filter((item): item is StoredResultSession => item !== undefined)\n .map((item) => ({\n ref: item.ref,\n createdAt: item.createdAt,\n expiresAt: item.expiresAt,\n rowCount: item.result.rowCount,\n columnCount: item.result.columns.length,\n truncated: item.result.truncated,\n }))\n .sort((left, right) => left.ref.localeCompare(right.ref));\n}\n\n/** Remove expired or malformed saved result sessions. */\nexport async function pruneResultSessions(options: ResultStoreOptions = {}): Promise<number> {\n const refs = await listSessionRefs(options.saptoolsRoot);\n const now = (options.now?.() ?? new Date()).getTime();\n let removed = 0;\n for (const ref of refs) {\n const stored = await readStoredSession(manifestPath(ref, options.saptoolsRoot));\n if (stored === undefined || Date.parse(stored.expiresAt) <= now) {\n await rm(sessionDirectory(ref, options.saptoolsRoot), { recursive: true, force: true });\n removed += 1;\n }\n }\n return removed;\n}\n\n/** Remove every saved result session. */\nexport async function clearResultSessions(options: ResultStoreOptions = {}): Promise<number> {\n const refs = await listSessionRefs(options.saptoolsRoot);\n await Promise.all(\n refs.map(async (ref) => {\n await rm(sessionDirectory(ref, options.saptoolsRoot), { recursive: true, force: true });\n }),\n );\n return refs.length;\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { HanaClientInfo } from \"./types.js\";\n\nexport const METADATA_CACHE_TTL_MS = 30 * 60_000;\n\nexport interface CatalogObjectInfo {\n readonly schema: string;\n readonly name: string;\n readonly type: \"TABLE\" | \"VIEW\";\n}\n\ninterface StoredMetadataCache {\n readonly version: 1;\n readonly createdAt: string;\n readonly scope: MetadataCacheScope;\n readonly objects: readonly CatalogObjectInfo[];\n}\n\nexport interface MetadataCacheScope {\n readonly selector: string;\n readonly appName: string;\n readonly host: string;\n readonly schema: string;\n readonly role: string;\n readonly driver: string;\n}\n\nexport interface MetadataCacheOptions {\n readonly saptoolsRoot?: string;\n readonly now?: () => Date;\n}\n\nfunction metadataCacheRoot(saptoolsRoot?: string): string {\n return join(saptoolsRoot ?? join(homedir(), \".saptools\"), \"cf-hana\", \"metadata\");\n}\n\nexport function toMetadataCacheScope(info: HanaClientInfo): MetadataCacheScope {\n return {\n selector: info.selector,\n appName: info.appName,\n host: info.host,\n schema: info.schema,\n role: info.role,\n driver: info.driver,\n };\n}\n\nexport function metadataCacheKey(scope: MetadataCacheScope): string {\n return createHash(\"sha256\").update(JSON.stringify(scope)).digest(\"hex\");\n}\n\nfunction metadataCachePath(scope: MetadataCacheScope, saptoolsRoot?: string): string {\n return join(metadataCacheRoot(saptoolsRoot), `${metadataCacheKey(scope)}.json`);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isCatalogObject(value: unknown): value is CatalogObjectInfo {\n return (\n isRecord(value) &&\n typeof value[\"schema\"] === \"string\" &&\n typeof value[\"name\"] === \"string\" &&\n (value[\"type\"] === \"TABLE\" || value[\"type\"] === \"VIEW\")\n );\n}\n\nfunction isScope(value: unknown): value is MetadataCacheScope {\n return (\n isRecord(value) &&\n typeof value[\"selector\"] === \"string\" &&\n typeof value[\"appName\"] === \"string\" &&\n typeof value[\"host\"] === \"string\" &&\n typeof value[\"schema\"] === \"string\" &&\n typeof value[\"role\"] === \"string\" &&\n typeof value[\"driver\"] === \"string\"\n );\n}\n\nfunction scopesEqual(left: MetadataCacheScope, right: MetadataCacheScope): boolean {\n return metadataCacheKey(left) === metadataCacheKey(right);\n}\n\nfunction isStored(value: unknown): value is StoredMetadataCache {\n return (\n isRecord(value) &&\n value[\"version\"] === 1 &&\n typeof value[\"createdAt\"] === \"string\" &&\n isScope(value[\"scope\"]) &&\n Array.isArray(value[\"objects\"]) &&\n value[\"objects\"].every(isCatalogObject)\n );\n}\n\nexport async function readMetadataCache(\n scope: MetadataCacheScope,\n options: MetadataCacheOptions = {},\n): Promise<readonly CatalogObjectInfo[] | undefined> {\n try {\n const parsed: unknown = JSON.parse(\n await readFile(metadataCachePath(scope, options.saptoolsRoot), \"utf8\"),\n );\n if (!isStored(parsed) || !scopesEqual(parsed.scope, scope)) {\n return undefined;\n }\n const createdAt = Date.parse(parsed.createdAt);\n const now = options.now?.() ?? new Date();\n const ageMs = now.getTime() - createdAt;\n if (!Number.isFinite(createdAt) || ageMs < 0 || ageMs >= METADATA_CACHE_TTL_MS) {\n return undefined;\n }\n return parsed.objects;\n } catch {\n return undefined;\n }\n}\n\nexport async function writeMetadataCache(\n scope: MetadataCacheScope,\n objects: readonly CatalogObjectInfo[],\n options: MetadataCacheOptions = {},\n): Promise<void> {\n const root = metadataCacheRoot(options.saptoolsRoot);\n const path = metadataCachePath(scope, options.saptoolsRoot);\n const tempPath = `${path}.tmp-${process.pid.toString()}`;\n const stored: StoredMetadataCache = {\n version: 1,\n createdAt: (options.now?.() ?? new Date()).toISOString(),\n scope,\n objects,\n };\n await mkdir(root, { recursive: true, mode: 0o700 });\n await rm(tempPath, { force: true });\n await writeFile(tempPath, `${JSON.stringify(stored)}\\n`, { encoding: \"utf8\", mode: 0o600 });\n await rename(tempPath, path);\n}\n\nexport async function loadCatalogObjectsWithCache(\n scope: MetadataCacheScope,\n refresh: boolean,\n loader: () => Promise<readonly CatalogObjectInfo[]>,\n options: MetadataCacheOptions = {},\n): Promise<readonly CatalogObjectInfo[]> {\n if (!refresh) {\n const cached = await readMetadataCache(scope, options);\n if (cached !== undefined) {\n return cached;\n }\n }\n const objects = await loader();\n try {\n await writeMetadataCache(scope, objects, options);\n } catch {\n // A cache write failure must not suppress suggestions built from fresh metadata.\n }\n return objects;\n}\n","import { QueryError } from \"./errors.js\";\nimport type { CatalogObjectInfo } from \"./metadata-cache.js\";\n\nexport interface MissingObjectName {\n readonly schema?: string;\n readonly name: string;\n}\n\nconst INVALID_OBJECT_PATTERNS = [\n /invalid\\s+(?:table|view|object)\\s+name/i,\n /(?:table|view|object)\\s+[^\\n]*does\\s+not\\s+exist/i,\n /could\\s+not\\s+find\\s+(?:table|view|object)/i,\n];\n\nconst REF_KEYWORDS = new Set([\"FROM\", \"JOIN\", \"UPDATE\", \"INTO\", \"TABLE\"]);\nconst STOP_WORDS = new Set([\n \"AS\",\n \"ON\",\n \"WHERE\",\n \"SET\",\n \"VALUES\",\n \"USING\",\n \"WHEN\",\n \"INNER\",\n \"LEFT\",\n \"RIGHT\",\n \"FULL\",\n \"OUTER\",\n \"CROSS\",\n \"JOIN\",\n]);\nconst CTE_FOLLOWERS = new Set([\"AS\"]);\n\ntype TokenKind = \"word\" | \"quoted\" | \"dot\" | \"comma\" | \"open\" | \"close\" | \"other\";\n\ninterface Token {\n readonly kind: TokenKind;\n readonly text: string;\n}\n\nexport function isInvalidCatalogObjectError(error: unknown): boolean {\n if (!(error instanceof QueryError)) {\n return false;\n }\n if (error.sqlState === \"42S02\" || error.sqlState === \"42S01\") {\n return true;\n }\n return INVALID_OBJECT_PATTERNS.some((pattern) => pattern.test(error.message));\n}\n\nfunction skipLineComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && sql[cursor] !== \"\\n\") {\n cursor += 1;\n }\n return cursor;\n}\n\nfunction skipBlockComment(sql: string, index: number): number {\n let cursor = index + 2;\n while (cursor < sql.length && !(sql[cursor] === \"*\" && sql[cursor + 1] === \"/\")) {\n cursor += 1;\n }\n return Math.min(cursor + 2, sql.length);\n}\n\nfunction skipStringLiteral(sql: string, index: number): number {\n let cursor = index + 1;\n while (cursor < sql.length) {\n if (sql[cursor] === \"'\" && sql[cursor + 1] === \"'\") {\n cursor += 2;\n continue;\n }\n if (sql[cursor] === \"'\") {\n return cursor + 1;\n }\n cursor += 1;\n }\n return cursor;\n}\n\nfunction readQuotedIdentifier(sql: string, index: number): { readonly text: string; readonly next: number } {\n let cursor = index + 1;\n let text = \"\";\n while (cursor < sql.length) {\n if (sql[cursor] === '\"' && sql[cursor + 1] === '\"') {\n text += '\"';\n cursor += 2;\n continue;\n }\n if (sql[cursor] === '\"') {\n return { text, next: cursor + 1 };\n }\n text += sql.charAt(cursor);\n cursor += 1;\n }\n return { text, next: cursor };\n}\n\nfunction readBareWord(sql: string, index: number): { readonly text: string; readonly next: number } {\n let cursor = index;\n let text = \"\";\n while (cursor < sql.length && /[A-Za-z0-9_#$]/.test(sql.charAt(cursor))) {\n text += sql.charAt(cursor);\n cursor += 1;\n }\n return { text, next: cursor };\n}\n\nfunction tokenize(sql: string): readonly Token[] {\n const tokens: Token[] = [];\n let index = 0;\n while (index < sql.length) {\n const char = sql.charAt(index);\n if (/\\s/.test(char)) {\n index += 1;\n continue;\n }\n if (char === \"-\" && sql[index + 1] === \"-\") {\n index = skipLineComment(sql, index);\n continue;\n }\n if (char === \"/\" && sql[index + 1] === \"*\") {\n index = skipBlockComment(sql, index);\n continue;\n }\n if (char === \"'\") {\n index = skipStringLiteral(sql, index);\n continue;\n }\n if (char === '\"') {\n const quoted = readQuotedIdentifier(sql, index);\n tokens.push({ kind: \"quoted\", text: quoted.text });\n index = quoted.next;\n continue;\n }\n if (/[A-Za-z_#$]/.test(char)) {\n const word = readBareWord(sql, index);\n tokens.push({ kind: \"word\", text: word.text });\n index = word.next;\n continue;\n }\n if (char === \".\") {\n tokens.push({ kind: \"dot\", text: char });\n } else if (char === \",\") {\n tokens.push({ kind: \"comma\", text: char });\n } else if (char === \"(\") {\n tokens.push({ kind: \"open\", text: char });\n } else if (char === \")\") {\n tokens.push({ kind: \"close\", text: char });\n } else {\n tokens.push({ kind: \"other\", text: char });\n }\n index += 1;\n }\n return tokens;\n}\n\nfunction upper(token: Token | undefined): string {\n return token?.text.toUpperCase() ?? \"\";\n}\n\nfunction isIdentifier(token: Token | undefined): token is Token {\n return token?.kind === \"word\" || token?.kind === \"quoted\";\n}\n\nfunction readName(\n tokens: readonly Token[],\n start: number,\n allowFollowingParens = false,\n): { readonly name: MissingObjectName; readonly next: number } | undefined {\n const first = tokens[start];\n if (!isIdentifier(first)) {\n return undefined;\n }\n\n let next = start + 1;\n let schema: string | undefined;\n let name = first.text;\n const maybeObject = tokens[next + 1];\n if (tokens[next]?.kind === \"dot\" && isIdentifier(maybeObject)) {\n schema = name;\n name = maybeObject.text;\n next += 2;\n }\n if (!allowFollowingParens && tokens[next]?.kind === \"open\") {\n return undefined;\n }\n return { name: schema === undefined ? { name } : { schema, name }, next };\n}\n\n\nfunction firstNameFromText(text: string): MissingObjectName | undefined {\n const tokens = tokenize(text);\n for (let index = 0; index < tokens.length; index += 1) {\n const read = readName(tokens, index, true);\n if (read !== undefined) {\n return read.name;\n }\n }\n return undefined;\n}\n\nexport function extractMissingObjectNameFromError(error: unknown): MissingObjectName | undefined {\n if (!(error instanceof QueryError)) {\n return undefined;\n }\n\n const message = error.message;\n const invalidName = /invalid\\s+(?:table|view|object)\\s+name\\s*:?\\s*(.+)$/i.exec(message);\n if (invalidName?.[1] !== undefined) {\n return firstNameFromText(invalidName[1]);\n }\n\n const missingObject = /(?:table|view|object)\\s+(.+?)\\s+(?:does\\s+not\\s+exist|not\\s+found)/i.exec(message);\n if (missingObject?.[1] !== undefined) {\n return firstNameFromText(missingObject[1]);\n }\n\n return undefined;\n}\n\nfunction cteNames(tokens: readonly Token[]): ReadonlySet<string> {\n const names = new Set<string>();\n if (upper(tokens[0]) !== \"WITH\") {\n return names;\n }\n\n let depth = 0;\n for (let index = 1; index < tokens.length; index += 1) {\n const token = tokens[index];\n if (depth === 0 && upper(token) === \"SELECT\") {\n break;\n }\n if (depth === 0 && isIdentifier(token) && CTE_FOLLOWERS.has(upper(tokens[index + 1]))) {\n names.add(token.text.toUpperCase());\n }\n if (token?.kind === \"open\") {\n depth += 1;\n } else if (token?.kind === \"close\" && depth > 0) {\n depth -= 1;\n }\n }\n return names;\n}\n\nexport function extractMissingObjectName(sql: string): MissingObjectName | undefined {\n const tokens = tokenize(sql.replace(/^;+|;+$/g, \"\"));\n const ctes = cteNames(tokens);\n let candidate: MissingObjectName | undefined;\n for (let index = 0; index < tokens.length; index += 1) {\n const word = upper(tokens[index]);\n if (!REF_KEYWORDS.has(word)) {\n continue;\n }\n if (word === \"TABLE\" && upper(tokens[index - 1]) !== \"TRUNCATE\") {\n continue;\n }\n if (\n word === \"INTO\" &&\n !(upper(tokens[index - 1]) === \"INSERT\" || upper(tokens[index - 1]) === \"MERGE\")\n ) {\n continue;\n }\n const read = readName(tokens, index + 1, word === \"INTO\");\n if (read === undefined) {\n continue;\n }\n if (read.name.schema === undefined && ctes.has(read.name.name.toUpperCase())) {\n continue;\n }\n if (STOP_WORDS.has(read.name.name.toUpperCase())) {\n continue;\n }\n candidate = read.name;\n let next = read.next;\n if (isIdentifier(tokens[next]) && !STOP_WORDS.has(upper(tokens[next]))) {\n next += 1;\n }\n while (tokens[next]?.kind === \"comma\") {\n const commaRead = readName(tokens, next + 1);\n if (commaRead === undefined) {\n break;\n }\n if (!(commaRead.name.schema === undefined && ctes.has(commaRead.name.name.toUpperCase()))) {\n candidate = commaRead.name;\n }\n next = commaRead.next;\n if (isIdentifier(tokens[next]) && !STOP_WORDS.has(upper(tokens[next]))) {\n next += 1;\n }\n }\n }\n return candidate;\n}\n\nfunction singular(value: string): string {\n if (value.endsWith(\"ES\")) {\n return value.slice(0, -2);\n }\n if (value.endsWith(\"S\")) {\n return value.slice(0, -1);\n }\n return value;\n}\n\nfunction norm(value: string): string {\n return value.toUpperCase().replace(/[^A-Z0-9]+/g, \"\");\n}\n\nfunction distance(a: string, b: string): number {\n const previous = Array.from({ length: b.length + 1 }, (_value, index) => index);\n for (let leftIndex = 1; leftIndex <= a.length; leftIndex += 1) {\n let last = leftIndex - 1;\n previous[0] = leftIndex;\n for (let rightIndex = 1; rightIndex <= b.length; rightIndex += 1) {\n const old = previous[rightIndex] ?? 0;\n previous[rightIndex] = Math.min(\n (previous[rightIndex] ?? 0) + 1,\n (previous[rightIndex - 1] ?? 0) + 1,\n last + (a.charAt(leftIndex - 1) === b.charAt(rightIndex - 1) ? 0 : 1),\n );\n last = old;\n }\n }\n return previous[b.length] ?? 0;\n}\n\nfunction score(requested: MissingObjectName, candidate: CatalogObjectInfo): number {\n const requestedName = norm(requested.name);\n const candidateName = norm(candidate.name);\n if (requested.schema !== undefined && norm(requested.schema) !== norm(candidate.schema)) {\n return 0;\n }\n if (requestedName === candidateName) {\n return 100;\n }\n if (singular(requestedName) === singular(candidateName)) {\n return 92;\n }\n let value = 0;\n if (candidateName.startsWith(requestedName) || requestedName.startsWith(candidateName)) {\n value = Math.max(value, 80 - Math.abs(candidateName.length - requestedName.length));\n }\n if (candidateName.endsWith(requestedName) || requestedName.endsWith(candidateName)) {\n value = Math.max(value, 70 - Math.abs(candidateName.length - requestedName.length));\n }\n const editDistance = distance(requestedName, candidateName);\n const max = Math.max(requestedName.length, candidateName.length, 1);\n if (editDistance <= Math.max(3, Math.floor(max * 0.35))) {\n value = Math.max(value, Math.round(75 * (1 - editDistance / max)));\n }\n return value;\n}\n\nexport interface NameSuggestion {\n readonly name: string;\n}\n\nexport function extractInvalidColumnNameFromError(error: unknown): string | undefined {\n if (!(error instanceof QueryError)) {\n return undefined;\n }\n const match = /invalid column name:\\s*([^:]+)/i.exec(error.message);\n const name = match?.[1]?.trim();\n return name === undefined || name.length === 0 ? undefined : name;\n}\n\nexport function rankCatalogSuggestions(\n requested: MissingObjectName,\n candidates: readonly CatalogObjectInfo[],\n limit = 5,\n): readonly CatalogObjectInfo[] {\n return candidates\n .map((candidate) => ({ candidate, score: score(requested, candidate) }))\n .filter((item) => item.score >= 45)\n .sort(\n (left, right) =>\n right.score - left.score ||\n left.candidate.schema.localeCompare(right.candidate.schema) ||\n (left.candidate.type === right.candidate.type\n ? 0\n : left.candidate.type === \"TABLE\"\n ? -1\n : 1) ||\n left.candidate.name.localeCompare(right.candidate.name),\n )\n .slice(0, limit)\n .map((item) => item.candidate);\n}\n\nexport function formatSuggestions(suggestions: readonly CatalogObjectInfo[]): string | undefined {\n if (suggestions.length === 0) {\n return undefined;\n }\n return [\n \"Did you mean:\",\n ...suggestions.map((item) => ` ${item.schema}.${item.name} (${item.type})`),\n ].join(\"\\n\");\n}\n\nexport function rankNameSuggestions<T extends NameSuggestion>(\n requested: string,\n candidates: readonly T[],\n limit = 5,\n): readonly T[] {\n const requestedName = { name: requested };\n return candidates\n .map((candidate) => ({\n candidate,\n score: score(requestedName, { schema: \"\", name: candidate.name, type: \"TABLE\" }),\n }))\n .filter((item) => item.score >= 45)\n .sort(\n (left, right) =>\n right.score - left.score || left.candidate.name.localeCompare(right.candidate.name),\n )\n .slice(0, limit)\n .map((item) => item.candidate);\n}\n\nexport function formatColumnSuggestions(suggestions: readonly NameSuggestion[]): string | undefined {\n if (suggestions.length === 0) {\n return undefined;\n }\n return [\n \"Did you mean column:\",\n ...suggestions.map((item) => ` ${item.name}`),\n ].join(\"\\n\");\n}\n"],"mappings":"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","names":["typeName","typeName","join","appendFile","mkdir","rm","homedir","join","SAPTOOLS_DIR_NAME","CF_HANA_DIR_NAME","defaultSaptoolsRoot","skipQuotedText","skipLineComment","skipBlockComment","writeFile","typeName","mkdir","readdir","rm","writeFile","homedir","join","join","homedir","isRecord","readdir","mkdir","rm","writeFile","typeName","writeFile","mkdir","readFile","rename","rm","writeFile","homedir","join","isRecord","skipLineComment","skipBlockComment","print","parseIntOption"]}