risingwave_meta_model_migration/
m20260624_000000_pending_sink_state_object_fk.rs1use sea_orm_migration::prelude::*;
2
3use crate::m20230908_072257_init::Object;
4use crate::sea_orm::{ConnectionTrait, DatabaseBackend, Statement, TransactionTrait};
5use crate::utils::ColumnDefExt;
6
7#[derive(DeriveMigrationName)]
8pub struct Migration;
9
10const FK_NAME: &str = "FK_pending_sink_state_object_id";
11const NEW_TABLE: &str = "pending_sink_state_new";
12
13#[async_trait::async_trait]
14impl MigrationTrait for Migration {
15 async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
16 let backend = manager.get_database_backend();
20 match backend {
21 DatabaseBackend::MySql | DatabaseBackend::Postgres => {
22 manager
23 .get_connection()
24 .execute(Statement::from_string(
25 backend,
26 "DELETE FROM pending_sink_state WHERE sink_id NOT IN (SELECT oid FROM object)",
27 ))
28 .await?;
29 manager
30 .alter_table(
31 Table::alter()
32 .table(PendingSinkState::Table)
33 .add_foreign_key(&object_foreign_key())
34 .to_owned(),
35 )
36 .await?;
37 }
38 DatabaseBackend::Sqlite => {
39 recreate_table(manager, true).await?;
41 }
42 }
43 Ok(())
44 }
45
46 async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
47 match manager.get_database_backend() {
48 DatabaseBackend::MySql | DatabaseBackend::Postgres => {
49 manager
50 .alter_table(
51 Table::alter()
52 .table(PendingSinkState::Table)
53 .drop_foreign_key(Alias::new(FK_NAME))
54 .to_owned(),
55 )
56 .await?;
57 }
58 DatabaseBackend::Sqlite => {
59 recreate_table(manager, false).await?;
60 }
61 }
62 Ok(())
63 }
64}
65
66fn object_foreign_key() -> TableForeignKey {
67 TableForeignKey::new()
68 .name(FK_NAME)
69 .from_tbl(PendingSinkState::Table)
70 .from_col(PendingSinkState::SinkId)
71 .to_tbl(Object::Table)
72 .to_col(Object::Oid)
73 .on_delete(ForeignKeyAction::Cascade)
74 .to_owned()
75}
76
77async fn recreate_table(manager: &SchemaManager<'_>, with_foreign_key: bool) -> Result<(), DbErr> {
81 let backend = manager.get_database_backend();
82 let txn = manager.get_connection().begin().await?;
85 {
86 let txn_manager = SchemaManager::new(&txn);
87
88 let mut create = Table::create();
89 create
90 .table(Alias::new(NEW_TABLE))
91 .col(
92 ColumnDef::new(PendingSinkState::SinkId)
93 .integer()
94 .not_null(),
95 )
96 .col(
97 ColumnDef::new(PendingSinkState::Epoch)
98 .big_integer()
99 .not_null(),
100 )
101 .col(
102 ColumnDef::new(PendingSinkState::SinkState)
103 .string()
104 .not_null(),
105 )
106 .col(
107 ColumnDef::new(PendingSinkState::Metadata)
108 .rw_binary(&txn_manager)
109 .null(),
110 )
111 .col(
112 ColumnDef::new(PendingSinkState::SchemaChange)
113 .rw_binary(&txn_manager)
114 .null(),
115 )
116 .primary_key(
117 Index::create()
118 .col(PendingSinkState::SinkId)
119 .col(PendingSinkState::Epoch),
120 );
121 if with_foreign_key {
122 create.foreign_key(
123 ForeignKey::create()
124 .name(FK_NAME)
125 .from_tbl(Alias::new(NEW_TABLE))
126 .from_col(PendingSinkState::SinkId)
127 .to_tbl(Object::Table)
128 .to_col(Object::Oid)
129 .on_delete(ForeignKeyAction::Cascade),
130 );
131 }
132 txn_manager.create_table(create).await?;
133
134 txn.execute(Statement::from_string(
135 backend,
136 "INSERT INTO pending_sink_state_new \
137 (sink_id, epoch, sink_state, metadata, schema_change) \
138 SELECT sink_id, epoch, sink_state, metadata, schema_change \
139 FROM pending_sink_state WHERE sink_id IN (SELECT oid FROM object)",
140 ))
141 .await?;
142
143 txn_manager
144 .drop_table(Table::drop().table(PendingSinkState::Table).to_owned())
145 .await?;
146 txn_manager
147 .rename_table(
148 Table::rename()
149 .table(Alias::new(NEW_TABLE), PendingSinkState::Table)
150 .to_owned(),
151 )
152 .await?;
153 }
154 txn.commit().await?;
155 Ok(())
156}
157
158#[derive(DeriveIden)]
159enum PendingSinkState {
160 Table,
161 SinkId,
162 Epoch,
163 SinkState,
164 Metadata,
165 SchemaChange,
166}