fix: prevent breaking default expr in SQLite#5748
fix: prevent breaking default expr in SQLite#5748ken0x0a wants to merge 3 commits intoprisma:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes issue #29064 where SQLite's PRAGMA table_info removes parentheses from default value expressions, causing schema drift on re-introspection. A wrap_in_parentheses helper function is added to restore parentheses when generating Prisma schemas.
Changes:
- Added
wrap_in_parenthesesfunction to restore parentheses removed by SQLite's PRAGMA - Applied the function to db_generated defaults for Int, BigInt, Float, Decimal, Boolean, and DateTime types
- Added test case with complex default expression to verify the fix
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| schema-engine/sql-schema-describer/src/sqlite.rs | Implements wrap_in_parentheses helper and applies it to various column type default values |
| schema-engine/sql-introspection-tests/tests/re_introspection/sqlite.rs | Adds test case with CAST(unixepoch('subsec') * 1000 AS INTEGER) default to verify parentheses are preserved |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| _ => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), | ||
| }, | ||
| ColumnTypeFamily::Json => DefaultValue::value(default_string), | ||
| ColumnTypeFamily::Binary => DefaultValue::db_generated(default_string), |
There was a problem hiding this comment.
The wrap_in_parentheses function is not applied to the Binary column type, but it is applied to other column types (Int, BigInt, Float, Decimal, Boolean, DateTime). Since the issue being fixed is that SQLite's PRAGMA table_info removes parentheses from default values for all types, this should likely be applied consistently to Binary as well for consistency, unless there's a specific reason Binary defaults don't need parentheses wrapping.
| ColumnTypeFamily::Binary => DefaultValue::db_generated(default_string), | |
| ColumnTypeFamily::Binary => DefaultValue::db_generated(wrap_in_parentheses(&default_string)), |
There was a problem hiding this comment.
@ken0x0a I think this comment is valid and the function should be applied for all types
| /// so we need to add parentheses when generating prisma schema. | ||
| /// See <https://github.com/prisma/prisma/issues/29064> | ||
| fn wrap_in_parentheses(s: &str) -> Cow<'_, str> { | ||
| if s[0..1] != *"(" && s[s.len() - 1..] == *")" { |
There was a problem hiding this comment.
The condition logic is incorrect. This checks if the first character is NOT '(' AND the last character IS ')', which is the opposite of what should be checked. This will wrap strings that end with ')' but don't start with '(', and will not wrap strings that need wrapping.
The condition should be: !s.starts_with('(') || !s.ends_with(')') to check if either parenthesis is missing, or more likely: !(s.starts_with('(') && s.ends_with(')')) to check if the string is not already fully wrapped.
| if s[0..1] != *"(" && s[s.len() - 1..] == *")" { | |
| if !(s.starts_with('(') && s.ends_with(')')) { |
There was a problem hiding this comment.
@ken0x0a indeed, the condition should probably be !(s.starts_with('(') && s.ends_with(')'))
|
The most important thing I must confess is, If this doesn't fix it, could anyone let me know how to fix it... |
CodSpeed Performance ReportMerging this PR will not alter performanceComparing Summary
Footnotes
|
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| /// so we need to add parentheses when generating prisma schema. | ||
| /// See <https://github.com/prisma/prisma/issues/29064> | ||
| fn wrap_in_parentheses(s: &str) -> Cow<'_, str> { | ||
| if !s.starts_with('(') && s.ends_with(')') { |
There was a problem hiding this comment.
I think this is meant to be
!(s.starts_with('(') && s.ends_with(')'))
There was a problem hiding this comment.
No, it's not.
We need to wrap with parentheses as PRAGMA table_info removes parentheses from default values.
There was a problem hiding this comment.
I think your condition is wrong though, it checks whether the expxression DOES NOT start with ( and DOES end with ). I think the intended condition is whether it DOES NOT start with ( and DOES NOT end with ).
There was a problem hiding this comment.
Oops,
I was wrong.
Sorry.
But I'm worried about some special case like CURRENT_TIMESTAMP.
If there is other special case except for CURRENT_TIMESTAMP,
!(s.starts_with('(') && s.ends_with(')')) might break behavior.
If there is no such case, I should replace that condition as you suggest.
Thank you for your comments!
This PR is intended to fix:
prisma migrate devredefine table endlessly prisma#29064