{"id":"ab128a9f538c6903","repo":"typeorm/typeorm","slug":"rename-table-queries-are-not-supported-by-spanner","errorCode":null,"errorMessage":"Rename table queries are not supported by Spanner driver.","messagePattern":"Rename table queries are not supported by Spanner driver\\.","errorType":"exception","errorClass":"TypeORMError","httpStatus":null,"severity":"error","filePath":"src/driver/spanner/SpannerQueryRunner.ts","lineNumber":816,"sourceCode":"        const downQueries: Query[] = []\n        upQueries.push(await this.deleteViewDefinitionSql(view))\n        upQueries.push(this.dropViewSql(view))\n        downQueries.push(await this.insertViewDefinitionSql(view))\n        downQueries.push(this.createViewSql(view))\n        await this.executeQueries(upQueries, downQueries)\n    }\n\n    /**\n     * Renames the given table.\n     *\n     * @param oldTableOrName\n     * @param newTableName\n     */\n    async renameTable(\n        oldTableOrName: Table | string,\n        newTableName: string,\n    ): Promise<void> {\n        throw new TypeORMError(\n            `Rename table queries are not supported by Spanner driver.`,\n        )\n    }\n\n    /**\n     * Creates a new column from the column in the table.\n     *\n     * @param tableOrName\n     * @param column\n     */\n    async addColumn(\n        tableOrName: Table | string,\n        column: TableColumn,\n    ): Promise<void> {\n        const table =\n            tableOrName instanceof Table\n                ? tableOrName\n                : await this.getCachedTable(tableOrName)","sourceCodeStart":798,"sourceCodeEnd":834,"githubUrl":"https://github.com/typeorm/typeorm/blob/04ff4daedcf60fa4ffd0d5d33bbafaac1a9bbc96/src/driver/spanner/SpannerQueryRunner.ts#L798-L834","documentation":"TypeORMError thrown unconditionally by renameTable(). Spanner DDL has no ALTER TABLE ... RENAME TO statement, so renaming a table is not possible in place; the driver refuses rather than emitting invalid DDL.","triggerScenarios":"Calling queryRunner.renameTable(old, new); migrations generated from entity renames that translate to renameTable.","commonSituations":"Renaming an entity and letting the migration generator emit a rename; cross-driver migration scripts that assume rename support.","solutions":["Replace the rename with an explicit CREATE TABLE new ... + copy data + DROP TABLE old, executed as DDL via updateDDL.","Generate the migration manually rather than relying on renameTable.","Keep table names stable; rename via a new table and a backfill/cutover."],"exampleFix":"// before\nawait qr.renameTable(\"old_users\", \"users\");\n\n// after\nawait qr.updateDDL(`CREATE TABLE users (... ) PRIMARY KEY (id)`);\n// copy rows, then:\nawait qr.updateDDL(`DROP TABLE old_users`);","handlingStrategy":"try-catch","validationCode":"async function safeRenameTable(qr: QueryRunner, oldName: string, newName: string, buildNewDdl: string): Promise<void> {\n  if ((qr.driver.options as any).type === \"spanner\") {\n    await qr.updateDDL(buildNewDdl);\n    // copy data, then drop old\n  } else {\n    await qr.renameTable(oldName, newName);\n  }\n}","typeGuard":"function supportsRenameTable(ds: DataSource): boolean {\n  return (ds.options as any).type !== \"spanner\";\n}","tryCatchPattern":"try {\n  await qr.renameTable(oldName, newName);\n} catch (e) {\n  if (/Rename table queries are not supported by Spanner/i.test(String(e?.message ?? e))) {\n    // fall through to create+copy+drop strategy\n    return;\n  }\n  throw e;\n}","preventionTips":["Avoid generated renames; keep table names stable on Spanner.","Convert rename migrations to create+copy+drop for Spanner targets.","Write migrations explicitly rather than relying on renameTable."],"tags":["spanner","ddl","unsupported","schema"],"analyzedSha":"04ff4daedcf60fa4ffd0d5d33bbafaac1a9bbc96","analyzedAt":"2026-08-03T18:27:32.281Z","schemaVersion":2}