fix: transform() corrupts expression defaults into string literals - #882
Closed
harsh-thakkar7 wants to merge 1 commit into
Closed
harsh-thakkar7 wants to merge 1 commit into
harsh-thakkar7 wants to merge 1 commit into
Conversation
PRAGMA reports expression defaults without their parentheses (DEFAULT
(1+2) comes back as '1+2'), and transform() fed that fragment straight
back into CREATE TABLE, where it was re-quoted as a string literal.
Every table rebuilt by transform() then silently stored the text '1+2'
instead of the value 3 (and blob/concat defaults like (X'ff') or
('x'||'y') were corrupted too). Re-emit PRAGMA-derived defaults by
re-wrapping non-literal fragments in parentheses and pass blob literals
through unquoted.
Author
|
Closing this — I don't think this change is mature enough to land right now. Thanks for the project! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
transform()silently corrupts expression defaults into string literals. When a column has an expression default:PRAGMA table_inforeports the expression without its parentheses (b→'1+2',c→X'ff',d→'x'||'y').transform()fed that fragment straight back into the rebuiltCREATE TABLE, where it was re-interpreted as a string literal:Every subsequent insert silently stored the text
'1+2'in the INTEGER column instead of the computed value3, and the blob became the string"X'ff'". This is the same class of bug the codebase already fixed for keyword literals (TRUE/FALSE/NULL) intest_transform_preserves_keyword_literal_defaults, but expressions were missed.Fix
Database.transform_default_fragment()classifies a PRAGMA-returned default and re-emits it safely: quoted string literals, blob literals (X'ff'), keywords (TRUE/FALSE/NULL/CURRENT_*) and numeric literals pass through unchanged; anything else was a parenthesized expression (1+2,'x'||'y',lower('ab')+1) and is wrapped in parentheses again, which SQLite requires for expression defaults.transform_sql()uses it when carrying existing defaults across the rebuild.quote_default_value()now passes blob literals through unquoted (they were previously re-quoted as strings) and avoids double-wrapping already-parenthesized expressions.Round-tripped schema:
Tests
Added
test_transform_preserves_expression_defaultstotests/test_transform.py: builds a table with an arithmetic, blob and concatenation default, runstransform(rename=...), asserts the expressions stay unparenthesized-correct in the schema, then inserts a row and asserts the stored values are(3, b"\xff", "xy")— not the literal strings (this test fails before the change; the pre-fix row stored'1+2').Note: plain numeric defaults like
DEFAULT 1still round-trip asDEFAULT '1'— this is existing, documented-by-test behavior (SQLite's type affinity stores the correct integer), and is intentionally left unchanged.📚 Documentation preview 📚: https://sqlite-utils--882.org.readthedocs.build/en/882/