From 03c4fad36eb5f85461d808bb44e6fbae47e80d68 Mon Sep 17 00:00:00 2001 From: Simon Eisenmann Date: Tue, 6 Feb 2024 15:13:41 +0000 Subject: [PATCH] Add implicit sqlite rowid columns to print-schema output Whenever sqlite uses an implicit rowid it also need to be added as column to the corresponding schema. This change fixes the implicit primary key generator added in #3680 which was never tested as the test added in this pull request never actually is run. This change enables the test and enhances the schema printer to generate the missing column if the primary key is an implicit rowid column. Related: #2149 --- .../src/infer_schema_internals/sqlite.rs | 28 +++++++ diesel_cli/tests/print_schema.rs | 6 ++ .../sqlite/expected.snap | 74 +++++++++++++++++-- .../sqlite/schema.sql | 35 +++++++++ 4 files changed, 137 insertions(+), 6 deletions(-) diff --git a/diesel_cli/src/infer_schema_internals/sqlite.rs b/diesel_cli/src/infer_schema_internals/sqlite.rs index 3fc16779abdf..272a462c10e2 100644 --- a/diesel_cli/src/infer_schema_internals/sqlite.rs +++ b/diesel_cli/src/infer_schema_internals/sqlite.rs @@ -114,6 +114,13 @@ fn get_sqlite_version(conn: &mut SqliteConnection) -> QueryResult Ok(SqliteVersion::new(parts[0], parts[1], parts[2])) } +// In sqlite the rowid is a signed 64-bit integer. +// See: https://sqlite.org/rowidtable.html +// We should use BigInt here but to avoid type problems with foreign keys to +// rowid columns this is for now not done. A patch can be used after the schema +// is generated to convert the columns to BigInt as needed. +const ROWID_TYPE_NAME: &str = "Integer"; + pub fn get_table_data( conn: &mut SqliteConnection, table: &TableName, @@ -134,6 +141,27 @@ pub fn get_table_data( // See: https://github.com/diesel-rs/diesel/issues/3579 as to why we use a direct // `sql_query` with `QueryableByName` instead of using `sql::`. let mut result = sql_query(query).load::(conn)?; + // Add implicit rowid primary key column if the only primary key is rowid + // and ensure that the rowid column uses the right type. + let primary_key = get_primary_keys(conn, table)?; + if primary_key.len() == 1 { + let primary_key = primary_key.first().expect("guaranteed to have one element"); + if !result.iter_mut().any(|x| &x.column_name == primary_key) { + // Prepend implicit rowid column for the rowid implicit primary key. + result.insert( + 0, + ColumnInformation { + column_name: String::from(primary_key), + type_name: String::from(ROWID_TYPE_NAME), + type_schema: None, + nullable: false, + max_length: None, + comment: None, + }, + ); + } + } + match column_sorting { ColumnSorting::OrdinalPosition => {} ColumnSorting::Name => { diff --git a/diesel_cli/tests/print_schema.rs b/diesel_cli/tests/print_schema.rs index cdbdd16cafd1..dd298713b81a 100644 --- a/diesel_cli/tests/print_schema.rs +++ b/diesel_cli/tests/print_schema.rs @@ -268,6 +268,12 @@ fn print_schema_sqlite_implicit_foreign_key_reference() { test_print_schema("print_schema_sqlite_implicit_foreign_key_reference", vec![]); } +#[test] +#[cfg(feature = "sqlite")] +fn print_schema_sqlite_without_explicit_primary_key() { + test_print_schema("print_schema_sqlite_without_explicit_primary_key", vec![]) +} + #[test] #[cfg(feature = "postgres")] fn print_schema_respects_type_name_case() { diff --git a/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/expected.snap b/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/expected.snap index 98bf663e0820..20ce77fb7a64 100644 --- a/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/expected.snap +++ b/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/expected.snap @@ -7,23 +7,85 @@ description: "Test: print_schema_sqlite_without_explicit_primary_key" diesel::table! { no_explicit (rowid) { rowid -> Integer, - name -> Text, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_aliased_rowid (id) { + id -> Nullable, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_aliased_rowid_not_null (id) { + id -> Integer, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_pk_rowid (rowid) { + rowid -> Nullable, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_pk_rowid_autoincrement (rowid) { + rowid -> Nullable, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_pk_rowid_autoincrement_not_null (rowid) { + rowid -> Integer, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_pk_rowid_not_null (rowid) { + rowid -> Integer, + name -> Nullable, } } diesel::table! { with_explicit_rowid (oid) { oid -> Integer, - name -> Text, - rowid -> Text, + name -> Nullable, + rowid -> Nullable, } } diesel::table! { with_explicit_rowid_oid (_rowid_) { _rowid_ -> Integer, - name -> Text, - rowid -> Text, - oid -> Text, + name -> Nullable, + rowid -> Nullable, + oid -> Nullable, } } + +diesel::table! { + without_rowid (word) { + word -> Text, + cnt -> Nullable, + } +} + +diesel::allow_tables_to_appear_in_same_query!( + no_explicit, + with_explicit_aliased_rowid, + with_explicit_aliased_rowid_not_null, + with_explicit_pk_rowid, + with_explicit_pk_rowid_autoincrement, + with_explicit_pk_rowid_autoincrement_not_null, + with_explicit_pk_rowid_not_null, + with_explicit_rowid, + with_explicit_rowid_oid, + without_rowid, +); diff --git a/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/schema.sql b/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/schema.sql index c9d457fdaf34..d4824367defe 100644 --- a/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/schema.sql +++ b/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/schema.sql @@ -12,3 +12,38 @@ CREATE TABLE with_explicit_rowid_oid ( rowid TEXT, oid TEXT ); + +CREATE TABLE with_explicit_pk_rowid ( + rowid INTEGER PRIMARY KEY, + name TEXT +); + +CREATE TABLE with_explicit_pk_rowid_autoincrement ( + rowid INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT +); + +CREATE TABLE with_explicit_pk_rowid_not_null ( + rowid INTEGER PRIMARY KEY NOT NULL, + name TEXT +); + +CREATE TABLE with_explicit_pk_rowid_autoincrement_not_null ( + rowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + name TEXT +); + +CREATE TABLE with_explicit_aliased_rowid ( + id INTEGER PRIMARY KEY, + name TEXT +); + +CREATE TABLE with_explicit_aliased_rowid_not_null ( + id INTEGER PRIMARY KEY NOT NULL, + name TEXT +); + +CREATE TABLE without_rowid ( + word TEXT PRIMARY KEY, + cnt INTEGER +) WITHOUT ROWID;