From 3088ecd6ef4c9c351bc3bb32a1ae0e7fef74648f Mon Sep 17 00:00:00 2001 From: Ken Date: Fri, 23 Jan 2026 03:14:36 +0900 Subject: [PATCH 1/3] fix: prevent breaking default expr --- .../tests/re_introspection/sqlite.rs | 6 +++++ .../sql-schema-describer/src/sqlite.rs | 24 ++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/schema-engine/sql-introspection-tests/tests/re_introspection/sqlite.rs b/schema-engine/sql-introspection-tests/tests/re_introspection/sqlite.rs index 0909a46fda4d..7284cfdf2c98 100644 --- a/schema-engine/sql-introspection-tests/tests/re_introspection/sqlite.rs +++ b/schema-engine/sql-introspection-tests/tests/re_introspection/sqlite.rs @@ -13,6 +13,10 @@ async fn multiple_changed_relation_names_due_to_mapped_models(api: &mut TestApi) t.add_column("id", types::primary()); t.add_column("user_id", types::integer().nullable(false).unique(true)); t.add_column("user_id2", types::integer().nullable(false).unique(true)); + t.add_column( + "createdAt", + types::custom("INTEGER NOT NULL DEFAULT (CAST(unixepoch('subsec') * 1000 AS INTEGER))"), + ); t.add_foreign_key(&["user_id"], "User", &["id"]); t.add_foreign_key(&["user_id2"], "User", &["id"]); @@ -29,6 +33,7 @@ async fn multiple_changed_relation_names_due_to_mapped_models(api: &mut TestApi) id Int @id @default(autoincrement()) user_id Int @unique user_id2 Int @unique + createdAt Int @default(dbgenerated("(CAST(unixepoch('subsec') * 1000 AS INTEGER))")) custom_User Custom_User @relation("CustomRelationName", fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) custom_User2 Custom_User @relation("AnotherCustomRelationName", fields: [user_id2], references: [id], onDelete: NoAction, onUpdate: NoAction) } @@ -47,6 +52,7 @@ async fn multiple_changed_relation_names_due_to_mapped_models(api: &mut TestApi) id Int @id @default(autoincrement()) user_id Int @unique(map: "sqlite_autoindex_Post_1") user_id2 Int @unique(map: "sqlite_autoindex_Post_2") + createdAt Int @default(dbgenerated("(CAST(unixepoch('subsec') * 1000 AS INTEGER))")) custom_User2 Custom_User @relation("AnotherCustomRelationName", fields: [user_id2], references: [id], onDelete: NoAction, onUpdate: NoAction) custom_User Custom_User @relation("CustomRelationName", fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) } diff --git a/schema-engine/sql-schema-describer/src/sqlite.rs b/schema-engine/sql-schema-describer/src/sqlite.rs index 90b75c957077..4adf018d3314 100644 --- a/schema-engine/sql-schema-describer/src/sqlite.rs +++ b/schema-engine/sql-schema-describer/src/sqlite.rs @@ -270,6 +270,18 @@ impl<'a> SqlSchemaDescriber<'a> { } } +/// Wraps the given string in parentheses if it is not already. +/// The result of `PRAGMA table_info` removes parentheses from default values, +/// so we need to add parentheses when generating prisma schema. +/// See +fn wrap_in_parentheses(s: &str) -> Cow<'_, str> { + if s[0..1] != *"(" && s[s.len() - 1..] == *")" { + format!("({})", s).into() + } else { + s.into() + } +} + async fn push_columns( table_name: &str, container_id: Either, @@ -306,26 +318,26 @@ async fn push_columns( Some(match &tpe.family { ColumnTypeFamily::Int => match SqlSchemaDescriber::parse_int(&default_string) { Some(int_value) => DefaultValue::value(int_value), - None => DefaultValue::db_generated(default_string), + None => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), }, ColumnTypeFamily::BigInt => match SqlSchemaDescriber::parse_big_int(&default_string) { Some(int_value) => DefaultValue::value(int_value), - None => DefaultValue::db_generated(default_string), + None => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), }, ColumnTypeFamily::Float => match SqlSchemaDescriber::parse_float(&default_string) { Some(float_value) => DefaultValue::value(float_value), - None => DefaultValue::db_generated(default_string), + None => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), }, ColumnTypeFamily::Decimal => match SqlSchemaDescriber::parse_float(&default_string) { Some(float_value) => DefaultValue::value(float_value), - None => DefaultValue::db_generated(default_string), + None => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), }, ColumnTypeFamily::Boolean => match SqlSchemaDescriber::parse_int(&default_string) { Some(PrismaValue::Int(1)) => DefaultValue::value(true), Some(PrismaValue::Int(0)) => DefaultValue::value(false), _ => match SqlSchemaDescriber::parse_bool(&default_string) { Some(bool_value) => DefaultValue::value(bool_value), - None => DefaultValue::db_generated(default_string), + None => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), }, }, ColumnTypeFamily::String => { @@ -335,7 +347,7 @@ async fn push_columns( "current_timestamp" | "datetime(\'now\')" | "datetime(\'now\', \'localtime\')" => { DefaultValue::now() } - _ => DefaultValue::db_generated(default_string), + _ => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), }, ColumnTypeFamily::Json => DefaultValue::value(default_string), ColumnTypeFamily::Binary => DefaultValue::db_generated(default_string), From 5d7398deacd28671ca47f6e4c2a9c69a75928110 Mon Sep 17 00:00:00 2001 From: Ken Date: Tue, 10 Feb 2026 19:26:11 +0900 Subject: [PATCH 2/3] fix: handle multi byte char using `starts_with` & `ends_with` Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- schema-engine/sql-schema-describer/src/sqlite.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema-engine/sql-schema-describer/src/sqlite.rs b/schema-engine/sql-schema-describer/src/sqlite.rs index 4adf018d3314..6ff86a30e48b 100644 --- a/schema-engine/sql-schema-describer/src/sqlite.rs +++ b/schema-engine/sql-schema-describer/src/sqlite.rs @@ -275,7 +275,7 @@ impl<'a> SqlSchemaDescriber<'a> { /// so we need to add parentheses when generating prisma schema. /// See fn wrap_in_parentheses(s: &str) -> Cow<'_, str> { - if s[0..1] != *"(" && s[s.len() - 1..] == *")" { + if !s.starts_with('(') && s.ends_with(')') { format!("({})", s).into() } else { s.into() From a4dbe4e9c9c5129057e81890c136a37e175b1a6c Mon Sep 17 00:00:00 2001 From: Ken Date: Tue, 10 Feb 2026 19:33:53 +0900 Subject: [PATCH 3/3] fix: wrap all column types --- schema-engine/sql-schema-describer/src/sqlite.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/schema-engine/sql-schema-describer/src/sqlite.rs b/schema-engine/sql-schema-describer/src/sqlite.rs index 6ff86a30e48b..5ec372370c6e 100644 --- a/schema-engine/sql-schema-describer/src/sqlite.rs +++ b/schema-engine/sql-schema-describer/src/sqlite.rs @@ -350,11 +350,11 @@ async fn push_columns( _ => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), }, ColumnTypeFamily::Json => DefaultValue::value(default_string), - ColumnTypeFamily::Binary => DefaultValue::db_generated(default_string), - ColumnTypeFamily::Uuid => DefaultValue::db_generated(default_string), + ColumnTypeFamily::Binary => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), + ColumnTypeFamily::Uuid => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), ColumnTypeFamily::Enum(_) => DefaultValue::value(PrismaValue::Enum(default_string)), ColumnTypeFamily::Udt(_) | ColumnTypeFamily::Unsupported(_) => { - DefaultValue::db_generated(default_string) + DefaultValue::db_generated(wrap_in_parentheses(&default_string)) } }) }