From ce4450080460aef42aec4f18026805642ba9c046 Mon Sep 17 00:00:00 2001 From: bibi samina Date: Thu, 27 Aug 2026 13:54:54 +0530 Subject: [PATCH] fix(django-spanner): backslash-escape string literals in quote_value --- .../django-google-spanner/django_spanner/schema.py | 5 ++++- .../tests/unit/django_spanner/test_schema.py | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/django-google-spanner/django_spanner/schema.py b/packages/django-google-spanner/django_spanner/schema.py index da57122bb73d..905e5843fe51 100644 --- a/packages/django-google-spanner/django_spanner/schema.py +++ b/packages/django-google-spanner/django_spanner/schema.py @@ -450,7 +450,10 @@ def add_index(self, model, index): def quote_value(self, value): # A more complete implementation isn't currently required. if isinstance(value, str): - return "'%s'" % value.replace("'", "''") + # GoogleSQL string literals use backslash escaping; '' quote + # doubling is not recognized, so escape the backslash first and + # then the quote (matching the db_default/generated inlining above). + return "'%s'" % value.replace("\\", "\\\\").replace("'", "\\'") if isinstance(value, bool): return "TRUE" if value else "FALSE" return str(value) diff --git a/packages/django-google-spanner/tests/unit/django_spanner/test_schema.py b/packages/django-google-spanner/tests/unit/django_spanner/test_schema.py index b7ef7cec39ec..0ce848f9afe3 100644 --- a/packages/django-google-spanner/tests/unit/django_spanner/test_schema.py +++ b/packages/django-google-spanner/tests/unit/django_spanner/test_schema.py @@ -40,6 +40,19 @@ def test_quote_value(self): schema_editor = DatabaseSchemaEditor(self.connection) self.assertEqual(schema_editor.quote_value(value=1.1), "1.1") + def test_quote_value_escapes_string(self): + """ + String literals must be backslash-escaped for GoogleSQL. A quote or + backslash in the value must not be able to terminate the literal. + """ + schema_editor = DatabaseSchemaEditor(self.connection) + self.assertEqual(schema_editor.quote_value(value="o'brien"), "'o\\'brien'") + self.assertEqual(schema_editor.quote_value(value="a\\b"), "'a\\\\b'") + self.assertEqual( + schema_editor.quote_value(value="\\'; DROP TABLE t; --"), + "'\\\\\\'; DROP TABLE t; --'", + ) + def test_skip_default(self): """ Tries skipping default as Cloud spanner doesn't support it.