SST RDS构造:Kysely迁移失败,PostgreSQL全文检索表创建报错
PostgreSQL全文检索表Kysely迁移报错解决
报错信息
Error: ERROR: current transaction is aborted, commands ignored until end of transaction block; SQLState: 25P02
迁移代码
import { Kysely, sql } from 'kysely'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export async function up(db: Kysely<any>): Promise<void> { db.schema .createTable('media') .addColumn('id', 'serial', (col) => col.primaryKey()) //...其他字段 .addColumn('description', 'text', (col) => col.notNull()) .addColumn('tsv', sql`tsvector`, (col) => col.generatedAlwaysAs(sql`to_tsvector('german', description)`)) .execute(); db.schema.createIndex('tsvector_idx').on('media').column('tsv').execute(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any export async function down(db: Kysely<any>): Promise<void> { await db.schema.dropIndex('tsvector_idx').execute(); await db.schema.dropTable('media').execute(); }
问题定位
经测试,错误出在生成tsv向量列的代码行:
.addColumn('tsv', sql`tsvector`, (col) => col.generatedAlwaysAs(sql`to_tsvector('german', description)`))
补充说明
通过调试获取到Kysely生成的SQL,确认问题出在SQL层面:
create table "media" ( "id" serial primary key, "media_id" varchar(50) not null, "format" varchar(20) not null, "width" integer, "height" integer, "copyright" text not null, "description" text not null, "tsv" tsvector generated always as (to_tsvector('german', description)) );
解决方案
问题根源有两点:一是PostgreSQL对生成列的语法要求,二是原迁移代码未正确处理异步操作。以下是修正后的代码:
import { Kysely, sql } from 'kysely'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export async function up(db: Kysely<any>): Promise<void> { // 必须添加await,确保表创建完成后再执行索引创建 await db.schema .createTable('media') .addColumn('id', 'serial', (col) => col.primaryKey()) .addColumn('media_id', 'varchar(50)', (col) => col.notNull()) .addColumn('format', 'varchar(20)', (col) => col.notNull()) .addColumn('width', 'integer') .addColumn('height', 'integer') .addColumn('copyright', 'text', (col) => col.notNull()) .addColumn('description', 'text', (col) => col.notNull()) // 修正:给表达式加括号,同时指定stored(tsvector类型必须用存储列) .addColumn('tsv', sql`tsvector`, (col) => col.generatedAlwaysAs(sql`(to_tsvector('german', "description"))`).stored() ) .execute(); await db.schema.createIndex('tsvector_idx').on('media').column('tsv').execute(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any export async function down(db: Kysely<any>): Promise<void> { await db.schema.dropIndex('tsvector_idx').execute(); await db.schema.dropTable('media').execute(); }
关键修正点
- 添加await:原代码未等待表创建完成就执行索引创建,触发事务中断。
- 表达式加括号:PostgreSQL要求生成列的表达式必须用括号完整包裹,否则解析失败。
- 指定stored:
tsvector类型不支持虚拟生成列,必须指定为存储列,通过Kysely的.stored()方法实现。
修正后生成的SQL符合PostgreSQL规范:
create table "media" ( "id" serial primary key, "media_id" varchar(50) not null, "format" varchar(20) not null, "width" integer, "height" integer, "copyright" text not null, "description" text not null, "tsv" tsvector generated always as (to_tsvector('german', "description")) stored );
内容的提问来源于stack exchange,提问作者bitstream
相关产品推荐
相关产品推荐

