From 6a456830ca33eb5edaa634a9b0febe5d71bea2be Mon Sep 17 00:00:00 2001 From: ikatyal2110 <134458944+ikatyal2110@users.noreply.github.com> Date: Sat, 25 Jul 2026 23:52:04 -0500 Subject: [PATCH] Fix _decode_default_value to unescape doubled single quotes in string defaults (#811) * Fix _decode_default_value to unescape doubled single quotes in string defaults SQLite stores string defaults with single quotes doubled (e.g. DEFAULT 'O''Brien' is stored as the literal "'O''Brien'" in sqlite_master). The previous code stripped the outer quotes with value[1:-1] but never converted '' back to ', so default_values returned the raw escaped form instead of the true string value. * Test for doubled single quotes in string defaults --- sqlite_utils/db.py | 4 ++-- tests/test_introspect.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index 9a00123..713b110 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -5108,8 +5108,8 @@ def resolve_extracts( def _decode_default_value(value: str) -> object: if value.startswith("'") and value.endswith("'"): - # It's a string - return value[1:-1] + # It's a string; unescape doubled single quotes + return value[1:-1].replace("''", "'") if value.isdigit(): # It's an integer return int(value) diff --git a/tests/test_introspect.py b/tests/test_introspect.py index 385c052..b7e8fc2 100644 --- a/tests/test_introspect.py +++ b/tests/test_introspect.py @@ -312,6 +312,7 @@ def test_table_strict(fresh_db, create_table, expected_strict): 1, 1.3, "foo", + "O'Brien", True, b"binary", ), @@ -324,6 +325,16 @@ def test_table_default_values(fresh_db, value): assert default_values == {"value": value} +def test_table_default_values_escaped_quotes(fresh_db): + # SQLite stores string defaults with single quotes doubled, so + # introspection needs to unescape them again + fresh_db.execute( + "create table t (id integer primary key, name text default 'O''Brien')" + ) + assert "default 'O''Brien'" in fresh_db["t"].schema + assert fresh_db["t"].default_values == {"name": "O'Brien"} + + def test_pks_use_primary_key_declaration_order(fresh_db): # PRIMARY KEY (a, b) declared against columns stored in order (b, a) - # pks must follow the declaration order, which is what SQLite uses to