Files
khadhroony-solana-project/crates/ksp-store-postgres-lib/src/schema.rs
2026-08-30 21:37:02 +02:00

1730 lines
76 KiB
Rust

// file: crates/ksp-store-postgres-lib/src/schema.rs
// version: 9
/// Immutable V000 physical schema resource inventory.
pub(crate) const V000_RESOURCES: &[SchemaResource] = &[SchemaResource {
id: "tables/001_ksp_store_schema_migrations.sql",
object: SchemaObjectContract::Table(TableContract {
columns: STORE_SCHEMA_MIGRATIONS_COLUMNS,
name: "ksp_store_schema_migrations",
primary_key_columns: std::option::Option::Some("version"),
}),
repair_existing: false,
sql: include_str!("../migrations/v000_bootstrap/tables/001_ksp_store_schema_migrations.sql"),
}];
/// Immutable V001 physical schema resource inventory.
pub(crate) const V001_RESOURCES: &[SchemaResource] = &[
SchemaResource {
id: "tables/001_ksp_store_identity.sql",
object: SchemaObjectContract::Table(TableContract {
columns: STORE_IDENTITY_COLUMNS,
name: "ksp_store_identity",
primary_key_columns: std::option::Option::None,
}),
repair_existing: false,
sql: include_str!("../migrations/v001_raw_transaction/tables/001_ksp_store_identity.sql"),
},
SchemaResource {
id: "tables/002_ksp_raw_transactions.sql",
object: SchemaObjectContract::Table(TableContract {
columns: RAW_TRANSACTIONS_COLUMNS,
name: "ksp_raw_transactions",
primary_key_columns: std::option::Option::None,
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/tables/002_ksp_raw_transactions.sql"),
},
SchemaResource {
id: "tables/003_ksp_raw_transaction_observations.sql",
object: SchemaObjectContract::Table(TableContract {
columns: RAW_TRANSACTION_OBSERVATIONS_COLUMNS,
name: "ksp_raw_transaction_observations",
primary_key_columns: std::option::Option::None,
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/tables/003_ksp_raw_transaction_observations.sql"),
},
SchemaResource {
id: "tables/004_ksp_raw_transaction_archive_payloads.sql",
object: SchemaObjectContract::Table(TableContract {
columns: RAW_TRANSACTION_ARCHIVE_PAYLOADS_COLUMNS,
name: "ksp_raw_transaction_archive_payloads",
primary_key_columns: std::option::Option::None,
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/tables/004_ksp_raw_transaction_archive_payloads.sql"),
},
SchemaResource {
id: "constraints/001_pk_ksp_store_identity.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "p", name: "pk_ksp_store_identity", table: "ksp_store_identity" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/001_pk_ksp_store_identity.sql"),
},
SchemaResource {
id: "constraints/002_ck_ksp_store_identity_singleton.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_store_identity_singleton", table: "ksp_store_identity" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/002_ck_ksp_store_identity_singleton.sql"),
},
SchemaResource {
id: "constraints/003_ck_ksp_store_identity_network.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_store_identity_network", table: "ksp_store_identity" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/003_ck_ksp_store_identity_network.sql"),
},
SchemaResource {
id: "constraints/004_pk_ksp_raw_transactions.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "p", name: "pk_ksp_raw_transactions", table: "ksp_raw_transactions" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/004_pk_ksp_raw_transactions.sql"),
},
SchemaResource {
id: "constraints/005_ck_ksp_raw_transactions_signature.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_transactions_signature", table: "ksp_raw_transactions" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/005_ck_ksp_raw_transactions_signature.sql"),
},
SchemaResource {
id: "constraints/006_ck_ksp_raw_transactions_slot.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_transactions_slot", table: "ksp_raw_transactions" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/006_ck_ksp_raw_transactions_slot.sql"),
},
SchemaResource {
id: "constraints/007_ck_ksp_raw_transactions_block_time.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_transactions_block_time", table: "ksp_raw_transactions" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/007_ck_ksp_raw_transactions_block_time.sql"),
},
SchemaResource {
id: "constraints/008_ck_ksp_raw_transactions_format_id.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_transactions_format_id", table: "ksp_raw_transactions" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/008_ck_ksp_raw_transactions_format_id.sql"),
},
SchemaResource {
id: "constraints/009_ck_ksp_raw_transactions_format_version.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transactions_format_version",
table: "ksp_raw_transactions",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/009_ck_ksp_raw_transactions_format_version.sql"),
},
SchemaResource {
id: "constraints/010_ck_ksp_raw_transactions_content_hash.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_transactions_content_hash", table: "ksp_raw_transactions" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/010_ck_ksp_raw_transactions_content_hash.sql"),
},
SchemaResource {
id: "constraints/011_ck_ksp_raw_transactions_payload.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_transactions_payload", table: "ksp_raw_transactions" }),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/011_ck_ksp_raw_transactions_payload.sql"),
},
SchemaResource {
id: "constraints/012_ck_ksp_raw_transactions_retention_state.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transactions_retention_state",
table: "ksp_raw_transactions",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/012_ck_ksp_raw_transactions_retention_state.sql"),
},
SchemaResource {
id: "constraints/013_ck_ksp_raw_transactions_payload_state.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transactions_payload_state",
table: "ksp_raw_transactions",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/013_ck_ksp_raw_transactions_payload_state.sql"),
},
SchemaResource {
id: "constraints/014_ck_ksp_raw_transactions_purged_block_time.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transactions_purged_block_time",
table: "ksp_raw_transactions",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/014_ck_ksp_raw_transactions_purged_block_time.sql"),
},
SchemaResource {
id: "constraints/015_pk_ksp_raw_transaction_observations.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "p",
name: "pk_ksp_raw_transaction_observations",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/015_pk_ksp_raw_transaction_observations.sql"),
},
SchemaResource {
id: "constraints/016_fk_ksp_raw_transaction_observations_transaction.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "f",
name: "fk_ksp_raw_transaction_observations_transaction",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/016_fk_ksp_raw_transaction_observations_transaction.sql"),
},
SchemaResource {
id: "constraints/017_ck_ksp_raw_transaction_observations_key.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_key",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/017_ck_ksp_raw_transaction_observations_key.sql"),
},
SchemaResource {
id: "constraints/018_ck_ksp_raw_transaction_observations_signature.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_signature",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/018_ck_ksp_raw_transaction_observations_signature.sql"),
},
SchemaResource {
id: "constraints/019_ck_ksp_raw_transaction_observations_provider.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_provider",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/019_ck_ksp_raw_transaction_observations_provider.sql"),
},
SchemaResource {
id: "constraints/020_ck_ksp_raw_transaction_observations_protocol.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_protocol",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/020_ck_ksp_raw_transaction_observations_protocol.sql"),
},
SchemaResource {
id: "constraints/021_ck_ksp_raw_transaction_observations_method.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_method",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/021_ck_ksp_raw_transaction_observations_method.sql"),
},
SchemaResource {
id: "constraints/022_ck_ksp_raw_transaction_observations_origin.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_origin",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/022_ck_ksp_raw_transaction_observations_origin.sql"),
},
SchemaResource {
id: "constraints/023_ck_ksp_raw_transaction_observations_received_at.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_received_at",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/023_ck_ksp_raw_transaction_observations_received_at.sql"),
},
SchemaResource {
id: "constraints/024_ck_ksp_raw_transaction_observations_capture_session.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_capture_session",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/024_ck_ksp_raw_transaction_observations_capture_session.sql"),
},
SchemaResource {
id: "constraints/025_ck_ksp_raw_transaction_observations_commitment.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_commitment",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/025_ck_ksp_raw_transaction_observations_commitment.sql"),
},
SchemaResource {
id: "constraints/026_ck_ksp_raw_transaction_observations_endpoint.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_endpoint",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/026_ck_ksp_raw_transaction_observations_endpoint.sql"),
},
SchemaResource {
id: "constraints/027_ck_ksp_raw_transaction_observations_filter.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_filter",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/027_ck_ksp_raw_transaction_observations_filter.sql"),
},
SchemaResource {
id: "constraints/028_ck_ksp_raw_transaction_observations_observed_at.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_observed_at",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/028_ck_ksp_raw_transaction_observations_observed_at.sql"),
},
SchemaResource {
id: "constraints/029_ck_ksp_raw_transaction_observations_time_order.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_time_order",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/029_ck_ksp_raw_transaction_observations_time_order.sql"),
},
SchemaResource {
id: "constraints/030_ck_ksp_raw_transaction_observations_source_hash.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_source_hash",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/030_ck_ksp_raw_transaction_observations_source_hash.sql"),
},
SchemaResource {
id: "constraints/031_ck_ksp_raw_transaction_observations_source_size.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_observations_source_size",
table: "ksp_raw_transaction_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/031_ck_ksp_raw_transaction_observations_source_size.sql"),
},
SchemaResource {
id: "constraints/032_pk_ksp_raw_transaction_archive_payloads.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "p",
name: "pk_ksp_raw_transaction_archive_payloads",
table: "ksp_raw_transaction_archive_payloads",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/032_pk_ksp_raw_transaction_archive_payloads.sql"),
},
SchemaResource {
id: "constraints/033_fk_ksp_raw_transaction_archive_payloads_transaction.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "f",
name: "fk_ksp_raw_transaction_archive_payloads_transaction",
table: "ksp_raw_transaction_archive_payloads",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/033_fk_ksp_raw_transaction_archive_payloads_transaction.sql"),
},
SchemaResource {
id: "constraints/034_ck_ksp_raw_transaction_archive_payloads_signature.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_archive_payloads_signature",
table: "ksp_raw_transaction_archive_payloads",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/034_ck_ksp_raw_transaction_archive_payloads_signature.sql"),
},
SchemaResource {
id: "constraints/035_ck_ksp_raw_transaction_archive_payloads_payload.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_transaction_archive_payloads_payload",
table: "ksp_raw_transaction_archive_payloads",
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/constraints/035_ck_ksp_raw_transaction_archive_payloads_payload.sql"),
},
SchemaResource {
id: "indexes/001_ix_ksp_raw_transactions_slot_signature.sql",
object: SchemaObjectContract::Index(IndexContract {
access_method: "btree",
key_fragment: "slot,signature",
name: "ix_ksp_raw_transactions_slot_signature",
predicate_fragment: std::option::Option::Some("retention_state<>'purged'"),
table: "ksp_raw_transactions",
unique: false,
}),
repair_existing: true,
sql: include_str!("../migrations/v001_raw_transaction/indexes/001_ix_ksp_raw_transactions_slot_signature.sql"),
},
];
/// Final V002 physical schema resource inventory for RAW account state persistence.
pub(crate) const V002_RESOURCES: &[SchemaResource] = &[
SchemaResource {
id: "tables/001_ksp_raw_account_states.sql",
object: SchemaObjectContract::Table(TableContract {
columns: RAW_ACCOUNT_STATES_COLUMNS,
name: "ksp_raw_account_states",
primary_key_columns: std::option::Option::None,
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/tables/001_ksp_raw_account_states.sql"),
},
SchemaResource {
id: "tables/002_ksp_raw_account_observations.sql",
object: SchemaObjectContract::Table(TableContract {
columns: RAW_ACCOUNT_OBSERVATIONS_COLUMNS,
name: "ksp_raw_account_observations",
primary_key_columns: std::option::Option::None,
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/tables/002_ksp_raw_account_observations.sql"),
},
SchemaResource {
id: "constraints/001_pk_ksp_raw_account_states.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "p", name: "pk_ksp_raw_account_states", table: "ksp_raw_account_states" }),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/001_pk_ksp_raw_account_states.sql"),
},
SchemaResource {
id: "constraints/002_pk_ksp_raw_account_observations.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "p",
name: "pk_ksp_raw_account_observations",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/002_pk_ksp_raw_account_observations.sql"),
},
SchemaResource {
id: "constraints/003_fk_ksp_raw_account_observations_state.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "f",
name: "fk_ksp_raw_account_observations_state",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/003_fk_ksp_raw_account_observations_state.sql"),
},
SchemaResource {
id: "constraints/004_ck_ksp_raw_account_states_pubkey.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_account_states_pubkey", table: "ksp_raw_account_states" }),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/004_ck_ksp_raw_account_states_pubkey.sql"),
},
SchemaResource {
id: "constraints/005_ck_ksp_raw_account_states_slot.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_account_states_slot", table: "ksp_raw_account_states" }),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/005_ck_ksp_raw_account_states_slot.sql"),
},
SchemaResource {
id: "constraints/006_ck_ksp_raw_account_states_state_hash.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_states_state_hash",
table: "ksp_raw_account_states",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/006_ck_ksp_raw_account_states_state_hash.sql"),
},
SchemaResource {
id: "constraints/007_ck_ksp_raw_account_states_lamports.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_account_states_lamports", table: "ksp_raw_account_states" }),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/007_ck_ksp_raw_account_states_lamports.sql"),
},
SchemaResource {
id: "constraints/008_ck_ksp_raw_account_states_owner.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_account_states_owner", table: "ksp_raw_account_states" }),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/008_ck_ksp_raw_account_states_owner.sql"),
},
SchemaResource {
id: "constraints/009_ck_ksp_raw_account_states_rent_epoch.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_states_rent_epoch",
table: "ksp_raw_account_states",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/009_ck_ksp_raw_account_states_rent_epoch.sql"),
},
SchemaResource {
id: "constraints/010_ck_ksp_raw_account_states_data.sql",
object: SchemaObjectContract::Constraint(ConstraintContract { kind: "c", name: "ck_ksp_raw_account_states_data", table: "ksp_raw_account_states" }),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/010_ck_ksp_raw_account_states_data.sql"),
},
SchemaResource {
id: "constraints/011_ck_ksp_raw_account_observations_key.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_key",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/011_ck_ksp_raw_account_observations_key.sql"),
},
SchemaResource {
id: "constraints/012_ck_ksp_raw_account_observations_account_pubkey.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_account_pubkey",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/012_ck_ksp_raw_account_observations_account_pubkey.sql"),
},
SchemaResource {
id: "constraints/013_ck_ksp_raw_account_observations_account_slot.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_account_slot",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/013_ck_ksp_raw_account_observations_account_slot.sql"),
},
SchemaResource {
id: "constraints/014_ck_ksp_raw_account_observations_account_state_hash.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_account_state_hash",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/014_ck_ksp_raw_account_observations_account_state_hash.sql"),
},
SchemaResource {
id: "constraints/015_ck_ksp_raw_account_observations_provider.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_provider",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/015_ck_ksp_raw_account_observations_provider.sql"),
},
SchemaResource {
id: "constraints/016_ck_ksp_raw_account_observations_protocol.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_protocol",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/016_ck_ksp_raw_account_observations_protocol.sql"),
},
SchemaResource {
id: "constraints/017_ck_ksp_raw_account_observations_method.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_method",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/017_ck_ksp_raw_account_observations_method.sql"),
},
SchemaResource {
id: "constraints/018_ck_ksp_raw_account_observations_origin.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_origin",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/018_ck_ksp_raw_account_observations_origin.sql"),
},
SchemaResource {
id: "constraints/019_ck_ksp_raw_account_observations_received_at.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_received_at",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/019_ck_ksp_raw_account_observations_received_at.sql"),
},
SchemaResource {
id: "constraints/020_ck_ksp_raw_account_observations_capture_session.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_capture_session",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/020_ck_ksp_raw_account_observations_capture_session.sql"),
},
SchemaResource {
id: "constraints/021_ck_ksp_raw_account_observations_commitment.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_commitment",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/021_ck_ksp_raw_account_observations_commitment.sql"),
},
SchemaResource {
id: "constraints/022_ck_ksp_raw_account_observations_endpoint.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_endpoint",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/022_ck_ksp_raw_account_observations_endpoint.sql"),
},
SchemaResource {
id: "constraints/023_ck_ksp_raw_account_observations_filter.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_filter",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/023_ck_ksp_raw_account_observations_filter.sql"),
},
SchemaResource {
id: "constraints/024_ck_ksp_raw_account_observations_observed_at.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_observed_at",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/024_ck_ksp_raw_account_observations_observed_at.sql"),
},
SchemaResource {
id: "constraints/025_ck_ksp_raw_account_observations_time_order.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_time_order",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/025_ck_ksp_raw_account_observations_time_order.sql"),
},
SchemaResource {
id: "constraints/026_ck_ksp_raw_account_observations_source_hash.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_source_hash",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/026_ck_ksp_raw_account_observations_source_hash.sql"),
},
SchemaResource {
id: "constraints/027_ck_ksp_raw_account_observations_source_size.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_source_size",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/027_ck_ksp_raw_account_observations_source_size.sql"),
},
SchemaResource {
id: "constraints/028_ck_ksp_raw_account_observations_transaction_signature.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_transaction_signature",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/028_ck_ksp_raw_account_observations_transaction_signature.sql"),
},
SchemaResource {
id: "constraints/029_ck_ksp_raw_account_observations_write_version.sql",
object: SchemaObjectContract::Constraint(ConstraintContract {
kind: "c",
name: "ck_ksp_raw_account_observations_write_version",
table: "ksp_raw_account_observations",
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/constraints/029_ck_ksp_raw_account_observations_write_version.sql"),
},
SchemaResource {
id: "indexes/001_ix_ksp_raw_account_states_slot_pubkey_state_hash.sql",
object: SchemaObjectContract::Index(IndexContract {
access_method: "btree",
key_fragment: "slot,pubkey,state_hash",
name: "ix_ksp_raw_account_states_slot_pubkey_state_hash",
predicate_fragment: std::option::Option::None,
table: "ksp_raw_account_states",
unique: false,
}),
repair_existing: true,
sql: include_str!("../migrations/v002_raw_account_state/indexes/001_ix_ksp_raw_account_states_slot_pubkey_state_hash.sql"),
},
];
const COLUMN_LOAD_SQL: &str = r#"SELECT column_name::TEXT, udt_name::TEXT, (is_nullable = 'YES') AS nullable, numeric_precision::INTEGER, numeric_scale::INTEGER, column_default::TEXT, is_identity::TEXT, is_generated::TEXT
FROM information_schema.columns
WHERE table_schema = current_schema() AND table_name = $1
ORDER BY ordinal_position"#;
const CONSTRAINT_LOAD_SQL: &str = r#"SELECT con.contype::TEXT, con.convalidated, con.condeferrable, con.condeferred, pg_get_constraintdef(con.oid, true)::TEXT
FROM pg_constraint con
JOIN pg_class rel ON rel.oid = con.conrelid
JOIN pg_namespace ns ON ns.oid = rel.relnamespace
WHERE ns.nspname = current_schema() AND rel.relname = $1 AND con.conname = $2"#;
const CONSTRAINT_FALLBACK_LOAD_SQL: &str = r#"SELECT con.contype::TEXT, con.convalidated, con.condeferrable, con.condeferred, pg_get_constraintdef(con.oid, true)::TEXT
FROM pg_constraint con
JOIN pg_class rel ON rel.oid = con.conrelid
JOIN pg_namespace ns ON ns.oid = rel.relnamespace
WHERE ns.nspname = current_schema() AND rel.relname = $1 AND con.contype::TEXT = $2
ORDER BY con.conname"#;
const INDEX_LOAD_SQL: &str = r#"SELECT idx.indisunique, am.amname::TEXT, pg_get_indexdef(index_rel.oid)::TEXT, pg_get_expr(idx.indpred, idx.indrelid, true)::TEXT
FROM pg_index idx
JOIN pg_class index_rel ON index_rel.oid = idx.indexrelid
JOIN pg_class table_rel ON table_rel.oid = idx.indrelid
JOIN pg_namespace ns ON ns.oid = table_rel.relnamespace
JOIN pg_am am ON am.oid = index_rel.relam
WHERE ns.nspname = current_schema() AND table_rel.relname = $1 AND index_rel.relname = $2"#;
const MANAGED_OBJECT_EXISTS_SQL: &str = r#"SELECT EXISTS (
SELECT 1 FROM information_schema.tables
WHERE table_schema = current_schema()
AND table_name IN ('ksp_store_identity', 'ksp_raw_transactions', 'ksp_raw_transaction_observations', 'ksp_raw_transaction_archive_payloads', 'ksp_raw_account_states', 'ksp_raw_account_observations')
AND table_type = 'BASE TABLE'
)"#;
const PRIMARY_KEY_LOAD_SQL: &str = r#"SELECT string_agg(att.attname::TEXT, ',' ORDER BY key_part.ord)::TEXT
FROM pg_constraint con
JOIN pg_class rel ON rel.oid = con.conrelid
JOIN pg_namespace ns ON ns.oid = rel.relnamespace
JOIN LATERAL unnest(con.conkey) WITH ORDINALITY AS key_part(attnum, ord) ON true
JOIN pg_attribute att ON att.attrelid = con.conrelid AND att.attnum = key_part.attnum
WHERE ns.nspname = current_schema() AND rel.relname = $1 AND con.contype = 'p'
GROUP BY con.oid"#;
const RULE_COUNT_SQL: &str = r#"SELECT COUNT(*)::BIGINT
FROM pg_rewrite rw
JOIN pg_class rel ON rel.oid = rw.ev_class
JOIN pg_namespace ns ON ns.oid = rel.relnamespace
WHERE ns.nspname = current_schema() AND rel.relname = $1 AND rw.rulename <> '_RETURN'"#;
const TABLE_LOAD_SQL: &str = r#"SELECT rel.relkind::TEXT, rel.relrowsecurity, rel.relforcerowsecurity
FROM pg_class rel
JOIN pg_namespace ns ON ns.oid = rel.relnamespace
WHERE ns.nspname = current_schema() AND rel.relname = $1"#;
const TRIGGER_COUNT_SQL: &str = r#"SELECT COUNT(*)::BIGINT
FROM pg_trigger trg
JOIN pg_class rel ON rel.oid = trg.tgrelid
JOIN pg_namespace ns ON ns.oid = rel.relnamespace
WHERE ns.nspname = current_schema() AND rel.relname = $1 AND NOT trg.tgisinternal AND trg.tgenabled <> 'D'"#;
const UNEXPECTED_CONSTRAINTS_SQL: &str = r#"SELECT con.conname::TEXT, con.contype::TEXT, con.convalidated, con.condeferrable, con.condeferred, pg_get_constraintdef(con.oid, true)::TEXT
FROM pg_constraint con
JOIN pg_class rel ON rel.oid = con.conrelid
JOIN pg_namespace ns ON ns.oid = rel.relnamespace
WHERE ns.nspname = current_schema() AND rel.relname = $1
ORDER BY con.conname"#;
const UNIQUE_INDEXES_SQL: &str = r#"SELECT index_rel.relname::TEXT, EXISTS (SELECT 1 FROM pg_constraint con WHERE con.conindid = idx.indexrelid) AS constraint_backed
FROM pg_index idx
JOIN pg_class index_rel ON index_rel.oid = idx.indexrelid
JOIN pg_class table_rel ON table_rel.oid = idx.indrelid
JOIN pg_namespace ns ON ns.oid = table_rel.relnamespace
WHERE ns.nspname = current_schema() AND table_rel.relname = $1 AND idx.indisunique
ORDER BY index_rel.relname"#;
#[derive(Clone, Copy)]
struct ColumnContract {
name: &'static str,
udt_name: &'static str,
nullable: bool,
numeric_precision: std::option::Option<i32>,
numeric_scale: std::option::Option<i32>,
}
#[derive(Clone, Copy)]
struct ConstraintContract {
kind: &'static str,
name: &'static str,
table: &'static str,
}
#[derive(Clone, Copy)]
struct IndexContract {
access_method: &'static str,
key_fragment: &'static str,
name: &'static str,
predicate_fragment: std::option::Option<&'static str>,
table: &'static str,
unique: bool,
}
#[derive(Clone, Copy)]
struct TableContract {
columns: &'static [ColumnContract],
name: &'static str,
primary_key_columns: std::option::Option<&'static str>,
}
#[derive(Clone, Copy)]
enum SchemaObjectContract {
Constraint(ConstraintContract),
Index(IndexContract),
Table(TableContract),
}
#[derive(Clone, Copy)]
/// Embedded physical schema resource owned by one logical migration.
pub(crate) struct SchemaResource {
/// Stable resource identifier relative to the logical migration directory.
pub(crate) id: &'static str,
object: SchemaObjectContract,
/// Whether an applied migration may safely recreate this resource when missing.
pub(crate) repair_existing: bool,
/// Embedded idempotent SQL used to create or additively repair the resource.
pub(crate) sql: &'static str,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
/// Compatibility state of one managed physical schema resource.
pub(crate) enum SchemaResourceState {
/// The effective PostgreSQL object satisfies the KSP contract.
Compatible,
/// An object exists but its effective structure can block or alter KSP semantics.
Incompatible,
/// The required managed object or one of its required additive parts is absent.
Missing,
}
const STORE_SCHEMA_MIGRATIONS_COLUMNS: &[ColumnContract] = &[
ColumnContract {
name: "version",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int8",
},
ColumnContract {
name: "name",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "checksum",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "applied_at",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "timestamptz",
},
];
const STORE_IDENTITY_COLUMNS: &[ColumnContract] = &[
ColumnContract {
name: "singleton",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int2",
},
ColumnContract {
name: "network",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
];
const RAW_TRANSACTIONS_COLUMNS: &[ColumnContract] = &[
ColumnContract {
name: "signature",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "slot",
nullable: false,
numeric_precision: std::option::Option::Some(20),
numeric_scale: std::option::Option::Some(0),
udt_name: "numeric",
},
ColumnContract {
name: "block_time_unix_millis",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int8",
},
ColumnContract {
name: "format_id",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "format_version",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int8",
},
ColumnContract {
name: "content_hash",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "payload",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "retention_state",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
];
const RAW_TRANSACTION_OBSERVATIONS_COLUMNS: &[ColumnContract] = &[
ColumnContract {
name: "observation_key",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "transaction_signature",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "provider",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "protocol",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "acquisition_method",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "origin",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "received_at_unix_millis",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int8",
},
ColumnContract {
name: "capture_session_id",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "commitment",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "endpoint_id",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "filter_id",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "observed_at_unix_millis",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int8",
},
ColumnContract {
name: "source_payload_hash",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "source_payload_size_bytes",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int8",
},
];
const RAW_ACCOUNT_STATES_COLUMNS: &[ColumnContract] = &[
ColumnContract {
name: "pubkey",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "slot",
nullable: false,
numeric_precision: std::option::Option::Some(20),
numeric_scale: std::option::Option::Some(0),
udt_name: "numeric",
},
ColumnContract {
name: "state_hash",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "lamports",
nullable: false,
numeric_precision: std::option::Option::Some(20),
numeric_scale: std::option::Option::Some(0),
udt_name: "numeric",
},
ColumnContract {
name: "owner",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "executable",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bool",
},
ColumnContract {
name: "rent_epoch",
nullable: false,
numeric_precision: std::option::Option::Some(20),
numeric_scale: std::option::Option::Some(0),
udt_name: "numeric",
},
ColumnContract {
name: "data",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
];
const RAW_ACCOUNT_OBSERVATIONS_COLUMNS: &[ColumnContract] = &[
ColumnContract {
name: "observation_key",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "account_pubkey",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "account_slot",
nullable: false,
numeric_precision: std::option::Option::Some(20),
numeric_scale: std::option::Option::Some(0),
udt_name: "numeric",
},
ColumnContract {
name: "account_state_hash",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "provider",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "protocol",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "acquisition_method",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "origin",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "received_at_unix_millis",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int8",
},
ColumnContract {
name: "capture_session_id",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "commitment",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "endpoint_id",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "filter_id",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "text",
},
ColumnContract {
name: "observed_at_unix_millis",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int8",
},
ColumnContract {
name: "source_payload_hash",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "source_payload_size_bytes",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "int8",
},
ColumnContract {
name: "is_startup",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bool",
},
ColumnContract {
name: "transaction_signature",
nullable: true,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "write_version",
nullable: true,
numeric_precision: std::option::Option::Some(20),
numeric_scale: std::option::Option::Some(0),
udt_name: "numeric",
},
];
const RAW_TRANSACTION_ARCHIVE_PAYLOADS_COLUMNS: &[ColumnContract] = &[
ColumnContract {
name: "signature",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
ColumnContract {
name: "payload",
nullable: false,
numeric_precision: std::option::Option::None,
numeric_scale: std::option::Option::None,
udt_name: "bytea",
},
];
const V001_TABLE_NAMES: &[&str] = &["ksp_store_identity", "ksp_raw_transactions", "ksp_raw_transaction_observations", "ksp_raw_transaction_archive_payloads"];
const V002_TABLE_NAMES: &[&str] = &["ksp_raw_account_states", "ksp_raw_account_observations"];
/// Inspects one embedded schema resource against the effective PostgreSQL catalog.
pub(crate) async fn inspect_resource(
transaction: &deadpool_postgres::Transaction<'_>,
resource: &SchemaResource,
) -> std::result::Result<SchemaResourceState, crate::PostgresBackendError> {
return match resource.object {
SchemaObjectContract::Constraint(contract) => inspect_constraint(transaction, contract, resource.sql).await,
SchemaObjectContract::Index(contract) => inspect_index(transaction, contract).await,
SchemaObjectContract::Table(contract) => inspect_table(transaction, contract).await,
};
}
/// Returns whether any KSP-managed Store base table already exists in the active schema.
pub(crate) async fn managed_schema_objects_exist(transaction: &deadpool_postgres::Transaction<'_>) -> std::result::Result<bool, crate::PostgresBackendError> {
let result = transaction.query_one(MANAGED_OBJECT_EXISTS_SQL, &[]).await;
let row = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return schema_query_error("schema_adoption_probe"),
};
return match row.try_get::<usize, bool>(0) {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(_) => schema_query_error("schema_adoption_probe_decode"),
};
}
/// Rejects external V001 schema extensions that can constrain or mutate KSP writes.
pub(crate) async fn verify_v001_external_compatibility(
transaction: &deadpool_postgres::Transaction<'_>,
) -> std::result::Result<(), crate::PostgresBackendError> {
return verify_external_compatibility(transaction, V001_TABLE_NAMES, V001_RESOURCES).await;
}
/// Rejects external V002 schema extensions that can constrain or mutate KSP writes.
pub(crate) async fn verify_v002_external_compatibility(
transaction: &deadpool_postgres::Transaction<'_>,
) -> std::result::Result<(), crate::PostgresBackendError> {
return verify_external_compatibility(transaction, V002_TABLE_NAMES, V002_RESOURCES).await;
}
async fn verify_external_compatibility(
transaction: &deadpool_postgres::Transaction<'_>,
tables: &[&str],
resources: &[SchemaResource],
) -> std::result::Result<(), crate::PostgresBackendError> {
for table in tables {
let table = *table;
let constraint_rows = transaction.query(UNEXPECTED_CONSTRAINTS_SQL, &[&table]).await;
let constraint_rows = match constraint_rows {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return schema_query_error("schema_constraint_inventory"),
};
for row in constraint_rows {
let name = row.try_get::<usize, std::string::String>(0);
let kind = row.try_get::<usize, std::string::String>(1);
let validated = row.try_get::<usize, bool>(2);
let deferrable = row.try_get::<usize, bool>(3);
let deferred = row.try_get::<usize, bool>(4);
let definition = row.try_get::<usize, std::string::String>(5);
let (name, kind, validated, deferrable, deferred, definition) = match (name, kind, validated, deferrable, deferred, definition) {
(
std::result::Result::Ok(name),
std::result::Result::Ok(kind),
std::result::Result::Ok(validated),
std::result::Result::Ok(deferrable),
std::result::Result::Ok(deferred),
std::result::Result::Ok(definition),
) => (name, kind, validated, deferrable, deferred, definition),
_ => return schema_query_error("schema_constraint_inventory_decode"),
};
if is_expected_constraint(resources, table, name.as_str()) {
continue;
}
let definition = normalize_catalog_sql(definition.as_str());
if !validated || deferrable || deferred || !matches_expected_constraint_definition(resources, table, kind.as_str(), definition.as_str()) {
return schema_incompatible("schema_external_constraint");
}
}
let unique_rows = transaction.query(UNIQUE_INDEXES_SQL, &[&table]).await;
let unique_rows = match unique_rows {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return schema_query_error("schema_unique_index_inventory"),
};
for row in unique_rows {
let name = row.try_get::<usize, std::string::String>(0);
let constraint_backed = row.try_get::<usize, bool>(1);
let (_name, constraint_backed) = match (name, constraint_backed) {
(std::result::Result::Ok(name), std::result::Result::Ok(constraint_backed)) => (name, constraint_backed),
_ => return schema_query_error("schema_unique_index_inventory_decode"),
};
if !constraint_backed {
return schema_incompatible("schema_external_unique_index");
}
}
let trigger_count = load_count(transaction, TRIGGER_COUNT_SQL, table, "schema_trigger_inventory").await;
let trigger_count = match trigger_count {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if trigger_count != 0 {
return schema_incompatible("schema_external_trigger");
}
let rule_count = load_count(transaction, RULE_COUNT_SQL, table, "schema_rule_inventory").await;
let rule_count = match rule_count {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if rule_count != 0 {
return schema_incompatible("schema_external_rule");
}
}
return std::result::Result::Ok(());
}
async fn inspect_constraint(
transaction: &deadpool_postgres::Transaction<'_>,
contract: ConstraintContract,
resource_sql: &str,
) -> std::result::Result<SchemaResourceState, crate::PostgresBackendError> {
let expected_definition = match expected_constraint_definition(resource_sql, contract.name) {
std::option::Option::Some(value) => value,
std::option::Option::None => return schema_query_error("schema_constraint_contract"),
};
let result = transaction.query_opt(CONSTRAINT_LOAD_SQL, &[&contract.table, &contract.name]).await;
let row = match result {
std::result::Result::Ok(std::option::Option::Some(value)) => value,
std::result::Result::Ok(std::option::Option::None) => {
return inspect_equivalent_constraint(transaction, contract, expected_definition.as_str()).await;
},
std::result::Result::Err(_) => return schema_query_error("schema_constraint_probe"),
};
let kind = row.try_get::<usize, std::string::String>(0);
let validated = row.try_get::<usize, bool>(1);
let deferrable = row.try_get::<usize, bool>(2);
let deferred = row.try_get::<usize, bool>(3);
let definition = row.try_get::<usize, std::string::String>(4);
let (kind, validated, deferrable, deferred, definition) = match (kind, validated, deferrable, deferred, definition) {
(
std::result::Result::Ok(kind),
std::result::Result::Ok(validated),
std::result::Result::Ok(deferrable),
std::result::Result::Ok(deferred),
std::result::Result::Ok(definition),
) => (kind, validated, deferrable, deferred, definition),
_ => return schema_query_error("schema_constraint_probe_decode"),
};
let definition = normalize_catalog_sql(definition.as_str());
if kind != contract.kind || !validated || deferrable || deferred || definition != expected_definition {
return std::result::Result::Ok(SchemaResourceState::Incompatible);
}
return std::result::Result::Ok(SchemaResourceState::Compatible);
}
async fn inspect_index(
transaction: &deadpool_postgres::Transaction<'_>,
contract: IndexContract,
) -> std::result::Result<SchemaResourceState, crate::PostgresBackendError> {
let result = transaction.query_opt(INDEX_LOAD_SQL, &[&contract.table, &contract.name]).await;
let row = match result {
std::result::Result::Ok(std::option::Option::Some(value)) => value,
std::result::Result::Ok(std::option::Option::None) => return std::result::Result::Ok(SchemaResourceState::Missing),
std::result::Result::Err(_) => return schema_query_error("schema_index_probe"),
};
let unique = row.try_get::<usize, bool>(0);
let access_method = row.try_get::<usize, std::string::String>(1);
let definition = row.try_get::<usize, std::string::String>(2);
let predicate = row.try_get::<usize, std::option::Option<std::string::String>>(3);
let (unique, access_method, definition, predicate) = match (unique, access_method, definition, predicate) {
(std::result::Result::Ok(unique), std::result::Result::Ok(access_method), std::result::Result::Ok(definition), std::result::Result::Ok(predicate)) => {
(unique, access_method, definition, predicate)
},
_ => return schema_query_error("schema_index_probe_decode"),
};
let definition = normalize_catalog_sql(definition.as_str());
let predicate = predicate.map(|value| return normalize_catalog_sql(value.as_str()));
let predicate_matches = match (contract.predicate_fragment, predicate.as_deref()) {
(std::option::Option::Some(expected), std::option::Option::Some(value)) => value.contains(expected),
(std::option::Option::None, std::option::Option::None) => true,
(std::option::Option::Some(_), std::option::Option::None) | (std::option::Option::None, std::option::Option::Some(_)) => false,
};
if unique != contract.unique || access_method != contract.access_method || !definition.contains(contract.key_fragment) || !predicate_matches {
return std::result::Result::Ok(SchemaResourceState::Incompatible);
}
return std::result::Result::Ok(SchemaResourceState::Compatible);
}
async fn inspect_table(
transaction: &deadpool_postgres::Transaction<'_>,
contract: TableContract,
) -> std::result::Result<SchemaResourceState, crate::PostgresBackendError> {
let table_result = transaction.query_opt(TABLE_LOAD_SQL, &[&contract.name]).await;
let table_row = match table_result {
std::result::Result::Ok(std::option::Option::Some(value)) => value,
std::result::Result::Ok(std::option::Option::None) => return std::result::Result::Ok(SchemaResourceState::Missing),
std::result::Result::Err(_) => return schema_query_error("schema_table_probe"),
};
let relkind = table_row.try_get::<usize, std::string::String>(0);
let row_security = table_row.try_get::<usize, bool>(1);
let force_row_security = table_row.try_get::<usize, bool>(2);
let (relkind, row_security, force_row_security) = match (relkind, row_security, force_row_security) {
(std::result::Result::Ok(relkind), std::result::Result::Ok(row_security), std::result::Result::Ok(force_row_security)) => {
(relkind, row_security, force_row_security)
},
_ => return schema_query_error("schema_table_probe_decode"),
};
if relkind != "r" || row_security || force_row_security {
return std::result::Result::Ok(SchemaResourceState::Incompatible);
}
let rows_result = transaction.query(COLUMN_LOAD_SQL, &[&contract.name]).await;
let rows = match rows_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return schema_query_error("schema_column_probe"),
};
let mut actual = std::vec::Vec::<ActualColumn>::with_capacity(rows.len());
for row in rows {
let decoded = ActualColumn::from_row(&row);
let decoded = match decoded {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
actual.push(decoded);
}
let mut missing = false;
for expected in contract.columns {
let found = actual.iter().find(|candidate| return candidate.name == expected.name);
let found = match found {
std::option::Option::Some(value) => value,
std::option::Option::None => {
missing = true;
continue;
},
};
if !found.matches(expected) {
return std::result::Result::Ok(SchemaResourceState::Incompatible);
}
}
for column in &actual {
if contract.columns.iter().any(|expected| return expected.name == column.name) {
continue;
}
if !column.is_non_blocking_extra() {
return std::result::Result::Ok(SchemaResourceState::Incompatible);
}
}
if let std::option::Option::Some(expected_key) = contract.primary_key_columns {
let key_result = transaction.query_opt(PRIMARY_KEY_LOAD_SQL, &[&contract.name]).await;
let key_row = match key_result {
std::result::Result::Ok(std::option::Option::Some(value)) => value,
std::result::Result::Ok(std::option::Option::None) => return std::result::Result::Ok(SchemaResourceState::Incompatible),
std::result::Result::Err(_) => return schema_query_error("schema_primary_key_probe"),
};
let key_columns = key_row.try_get::<usize, std::string::String>(0);
let key_columns = match key_columns {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return schema_query_error("schema_primary_key_probe_decode"),
};
if key_columns != expected_key {
return std::result::Result::Ok(SchemaResourceState::Incompatible);
}
}
if missing {
return std::result::Result::Ok(SchemaResourceState::Missing);
}
return std::result::Result::Ok(SchemaResourceState::Compatible);
}
struct ActualColumn {
default: std::option::Option<std::string::String>,
generated: std::string::String,
identity: std::string::String,
name: std::string::String,
nullable: bool,
numeric_precision: std::option::Option<i32>,
numeric_scale: std::option::Option<i32>,
udt_name: std::string::String,
}
impl ActualColumn {
fn from_row(row: &tokio_postgres::Row) -> std::result::Result<Self, crate::PostgresBackendError> {
let name = row.try_get::<usize, std::string::String>(0);
let udt_name = row.try_get::<usize, std::string::String>(1);
let nullable = row.try_get::<usize, bool>(2);
let numeric_precision = row.try_get::<usize, std::option::Option<i32>>(3);
let numeric_scale = row.try_get::<usize, std::option::Option<i32>>(4);
let default = row.try_get::<usize, std::option::Option<std::string::String>>(5);
let identity = row.try_get::<usize, std::string::String>(6);
let generated = row.try_get::<usize, std::string::String>(7);
return match (name, udt_name, nullable, numeric_precision, numeric_scale, default, identity, generated) {
(
std::result::Result::Ok(name),
std::result::Result::Ok(udt_name),
std::result::Result::Ok(nullable),
std::result::Result::Ok(numeric_precision),
std::result::Result::Ok(numeric_scale),
std::result::Result::Ok(default),
std::result::Result::Ok(identity),
std::result::Result::Ok(generated),
) => std::result::Result::Ok(Self { default, generated, identity, name, nullable, numeric_precision, numeric_scale, udt_name }),
_ => schema_query_error("schema_column_probe_decode"),
};
}
fn is_non_blocking_extra(&self) -> bool {
return self.nullable && self.default.is_none() && self.identity == "NO" && self.generated == "NEVER";
}
fn matches(&self, expected: &ColumnContract) -> bool {
let numeric_matches = if expected.udt_name == "numeric" {
self.numeric_precision == expected.numeric_precision && self.numeric_scale == expected.numeric_scale
} else {
true
};
return self.udt_name == expected.udt_name
&& self.nullable == expected.nullable
&& numeric_matches
&& self.identity == "NO"
&& self.generated == "NEVER";
}
}
async fn load_count(
transaction: &deadpool_postgres::Transaction<'_>,
sql: &str,
table: &str,
phase: &'static str,
) -> std::result::Result<i64, crate::PostgresBackendError> {
let result = transaction.query_one(sql, &[&table]).await;
let row = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return schema_query_error(phase),
};
return match row.try_get::<usize, i64>(0) {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(_) => schema_query_error("schema_inventory_decode"),
};
}
async fn inspect_equivalent_constraint(
transaction: &deadpool_postgres::Transaction<'_>,
contract: ConstraintContract,
expected_definition: &str,
) -> std::result::Result<SchemaResourceState, crate::PostgresBackendError> {
let rows = transaction.query(CONSTRAINT_FALLBACK_LOAD_SQL, &[&contract.table, &contract.kind]).await;
let rows = match rows {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return schema_query_error("schema_constraint_fallback_probe"),
};
for row in rows {
let validated = row.try_get::<usize, bool>(1);
let deferrable = row.try_get::<usize, bool>(2);
let deferred = row.try_get::<usize, bool>(3);
let definition = row.try_get::<usize, std::string::String>(4);
let (validated, deferrable, deferred, definition) = match (validated, deferrable, deferred, definition) {
(
std::result::Result::Ok(validated),
std::result::Result::Ok(deferrable),
std::result::Result::Ok(deferred),
std::result::Result::Ok(definition),
) => (validated, deferrable, deferred, definition),
_ => return schema_query_error("schema_constraint_fallback_probe_decode"),
};
let definition = normalize_catalog_sql(definition.as_str());
if validated && !deferrable && !deferred && definition == expected_definition {
return std::result::Result::Ok(SchemaResourceState::Compatible);
}
}
return std::result::Result::Ok(SchemaResourceState::Missing);
}
fn expected_constraint_definition(resource_sql: &str, name: &str) -> std::option::Option<std::string::String> {
let marker = std::format!("ADD CONSTRAINT {name} ");
let marker_start = match resource_sql.find(marker.as_str()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let start = match marker_start.checked_add(marker.len()) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let tail = match resource_sql.get(start..) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let end = match tail.find(';') {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
let definition = match tail.get(..end) {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::option::Option::None,
};
return std::option::Option::Some(normalize_catalog_sql(definition));
}
fn is_expected_constraint(resources: &[SchemaResource], table: &str, name: &str) -> bool {
for resource in resources {
let contract = match resource.object {
SchemaObjectContract::Constraint(value) => value,
SchemaObjectContract::Index(_) | SchemaObjectContract::Table(_) => continue,
};
if contract.table == table && contract.name == name {
return true;
}
}
return false;
}
fn matches_expected_constraint_definition(resources: &[SchemaResource], table: &str, kind: &str, definition: &str) -> bool {
for resource in resources {
let contract = match resource.object {
SchemaObjectContract::Constraint(value) => value,
SchemaObjectContract::Index(_) | SchemaObjectContract::Table(_) => continue,
};
if contract.table != table || contract.kind != kind {
continue;
}
let expected = expected_constraint_definition(resource.sql, contract.name);
if let std::option::Option::Some(expected) = expected
&& expected == definition
{
return true;
}
}
return false;
}
fn normalize_catalog_sql(value: &str) -> std::string::String {
let value = normalize_quoted_integral_cast_literals(value);
return value
.chars()
.filter(|character| return !character.is_whitespace() && *character != '"' && *character != '(' && *character != ')')
.collect::<std::string::String>()
.replace("::text", "")
.replace("::numeric", "")
.replace("::bigint", "")
.replace("::smallint", "")
.replace("::integer", "")
.replace("::int8", "")
.replace("::int4", "")
.replace("::int2", "")
.to_ascii_lowercase();
}
fn normalize_quoted_integral_cast_literals(value: &str) -> std::string::String {
const INTEGRAL_CASTS: &[&str] = &["::bigint", "::int2", "::int4", "::int8", "::integer", "::numeric", "::smallint"];
let mut normalized = std::string::String::with_capacity(value.len());
let mut remaining = value;
loop {
let (before_quote, after_quote) = match remaining.split_once('\'') {
std::option::Option::Some(value) => value,
std::option::Option::None => {
normalized.push_str(remaining);
break;
},
};
normalized.push_str(before_quote);
let (literal, after_literal) = match after_quote.split_once('\'') {
std::option::Option::Some(value) => value,
std::option::Option::None => {
normalized.push('\'');
normalized.push_str(after_quote);
break;
},
};
let has_digit = literal.chars().any(|character| return character.is_ascii_digit());
let integral_literal = !literal.is_empty()
&& has_digit
&& literal
.chars()
.enumerate()
.all(|(offset, character)| return character.is_ascii_digit() || (offset == 0 && (character == '+' || character == '-')));
let mut after_integral_cast = std::option::Option::None;
if integral_literal {
for cast in INTEGRAL_CASTS {
if let std::option::Option::Some(value) = after_literal.strip_prefix(*cast) {
after_integral_cast = std::option::Option::Some(value);
break;
}
}
}
if let std::option::Option::Some(value) = after_integral_cast {
normalized.push_str(literal);
remaining = value;
continue;
}
normalized.push('\'');
normalized.push_str(literal);
normalized.push('\'');
remaining = after_literal;
}
return normalized;
}
fn schema_incompatible<T>(phase: &'static str) -> std::result::Result<T, crate::PostgresBackendError> {
return std::result::Result::Err(crate::PostgresBackendError::new(crate::PostgresBackendErrorKind::MigrationMismatch, phase));
}
fn schema_query_error<T>(phase: &'static str) -> std::result::Result<T, crate::PostgresBackendError> {
return std::result::Result::Err(crate::PostgresBackendError::new(crate::PostgresBackendErrorKind::MigrationFailed, phase));
}
#[cfg(test)]
#[path = "../unit_tests/schema.rs"]
mod tests;