You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
}

关键修正点

  1. 添加await:原代码未等待表创建完成就执行索引创建,触发事务中断。
  2. 表达式加括号:PostgreSQL要求生成列的表达式必须用括号完整包裹,否则解析失败。
  3. 指定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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 12:09:59