Skip to content

Commit

Permalink
Add implicit sqlite rowid columns to print-schema output
Browse files Browse the repository at this point in the history
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
  • Loading branch information
longsleep committed Feb 8, 2024
1 parent dfeec4b commit b7803b6
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 6 deletions.
28 changes: 28 additions & 0 deletions diesel_cli/src/infer_schema_internals/sqlite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ fn get_sqlite_version(conn: &mut SqliteConnection) -> QueryResult<SqliteVersion>
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,
Expand All @@ -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::<pragma_table_info::SqlType>`.
let mut result = sql_query(query).load::<ColumnInformation>(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 => {
Expand Down
6 changes: 6 additions & 0 deletions diesel_cli/tests/print_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,85 @@ description: "Test: print_schema_sqlite_without_explicit_primary_key"
diesel::table! {
no_explicit (rowid) {
rowid -> Integer,
name -> Text,
name -> Nullable<Text>,
}
}

diesel::table! {
with_explicit_aliased_rowid (id) {
id -> Nullable<Integer>,
name -> Nullable<Text>,
}
}

diesel::table! {
with_explicit_aliased_rowid_not_null (id) {
id -> Integer,
name -> Nullable<Text>,
}
}

diesel::table! {
with_explicit_pk_rowid (rowid) {
rowid -> Nullable<Integer>,
name -> Nullable<Text>,
}
}

diesel::table! {
with_explicit_pk_rowid_autoincrement (rowid) {
rowid -> Nullable<Integer>,
name -> Nullable<Text>,
}
}

diesel::table! {
with_explicit_pk_rowid_autoincrement_not_null (rowid) {
rowid -> Integer,
name -> Nullable<Text>,
}
}

diesel::table! {
with_explicit_pk_rowid_not_null (rowid) {
rowid -> Integer,
name -> Nullable<Text>,
}
}

diesel::table! {
with_explicit_rowid (oid) {
oid -> Integer,
name -> Text,
rowid -> Text,
name -> Nullable<Text>,
rowid -> Nullable<Text>,
}
}

diesel::table! {
with_explicit_rowid_oid (_rowid_) {
_rowid_ -> Integer,
name -> Text,
rowid -> Text,
oid -> Text,
name -> Nullable<Text>,
rowid -> Nullable<Text>,
oid -> Nullable<Text>,
}
}

diesel::table! {
without_rowid (word) {
word -> Text,
cnt -> Nullable<Integer>,
}
}

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,
);
Original file line number Diff line number Diff line change
Expand Up @@ -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;

0 comments on commit b7803b6

Please sign in to comment.