Skip to content

Comments

fix: prevent breaking default expr in SQLite#5748

Open
ken0x0a wants to merge 3 commits intoprisma:mainfrom
ken0x0a:fix/sql-default-expr
Open

fix: prevent breaking default expr in SQLite#5748
ken0x0a wants to merge 3 commits intoprisma:mainfrom
ken0x0a:fix/sql-default-expr

Conversation

@ken0x0a
Copy link

@ken0x0a ken0x0a commented Jan 22, 2026

Copilot AI review requested due to automatic review settings January 22, 2026 18:31
@CLAassistant
Copy link

CLAassistant commented Jan 22, 2026

CLA assistant check
All committers have signed the CLA.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_parentheses function 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),
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
ColumnTypeFamily::Binary => DefaultValue::db_generated(default_string),
ColumnTypeFamily::Binary => DefaultValue::db_generated(wrap_in_parentheses(&default_string)),

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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..] == *")" {
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
if s[0..1] != *"(" && s[s.len() - 1..] == *")" {
if !(s.starts_with('(') && s.ends_with(')')) {

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ken0x0a indeed, the condition should probably be !(s.starts_with('(') && s.ends_with(')'))

@ken0x0a
Copy link
Author

ken0x0a commented Jan 22, 2026

The most important thing I must confess is,
I'm not sure if this PR fixes the above ISSUE (prisma/prisma#29064) ...

If this doesn't fix it, could anyone let me know how to fix it...

@codspeed-hq
Copy link

codspeed-hq bot commented Feb 5, 2026

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing ken0x0a:fix/sql-default-expr (3088ecd) with main (9d6ad21)

Summary

✅ 11 untouched benchmarks
⏩ 11 skipped benchmarks1

Footnotes

  1. 11 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

ken0x0a and others added 2 commits February 10, 2026 19:26
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(')') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is meant to be
!(s.starts_with('(') && s.ends_with(')'))

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not.

We need to wrap with parentheses as PRAGMA table_info removes parentheses from default values.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants