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