Sitelet https://github.com/googleapis/google-cloud-python/pull/19069
Skip to content

fix(django-google-spanner): harden identifier quoting - #19069

Open
olavloite wants to merge 1 commit into
mainfrom
spanner-django-harden-identifier-quoting
Open

olavloite wants to merge 1 commit into
mainfrom
spanner-django-harden-identifier-quoting

Conversation

@olavloite

Copy link
Copy Markdown
Contributor

Previously, Django's identifier quoting delegated directly to the DB-API driver's name-escaping helper, which is meant for dot-qualified SQL paths and unconditionally quotes all identifiers in newer versions. That caused single identifiers containing dots to be split into separate parts and broke compatibility with existing Django SQL expectations.

This change implements single-identifier quoting directly in the Django backend:

  • Quotes identifiers as a single unit without splitting on dots.
  • Escapes backslashes, backticks (using GoogleSQL hex escapes so both Spanner DDL and downstream SQL comment/statement parsing keep the identifier intact), and ASCII control characters without rejecting identifiers client-side.
  • Preserves already validly quoted single identifiers idempotently while re-escaping malformed inputs and injection payloads.
  • Keeps unreserved regular ASCII identifiers unquoted for now, with a TODO to switch to unconditional quoting in a follow-up change.
  • Expands unit tests to cover dotted identifiers, control characters, malformed quotes, idempotency, and SQL injection payloads.

Previously, Django's identifier quoting delegated directly to the DB-API
driver's name-escaping helper, which is meant for dot-qualified SQL paths
and unconditionally quotes all identifiers in newer versions. That caused
single identifiers containing dots to be split into separate parts and
broke compatibility with existing Django SQL expectations.

This change implements single-identifier quoting directly in the Django
backend:
- Quotes identifiers as a single unit without splitting on dots.
- Escapes backslashes, backticks (using GoogleSQL hex escapes so both
  Spanner DDL and downstream SQL comment/statement parsing keep the
  identifier intact), and ASCII control characters without rejecting
  identifiers client-side.
- Preserves already validly quoted single identifiers idempotently while
  re-escaping malformed inputs and injection payloads.
- Keeps unreserved regular ASCII identifiers unquoted for now, with a
  TODO to switch to unconditional quoting in a follow-up change.
- Expands unit tests to cover dotted identifiers, control characters,
  malformed quotes, idempotency, and SQL injection payloads.
@olavloite
olavloite requested a review from a team as a code owner November 13, 2026 11:57

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request improves the identifier quoting mechanism in django_spanner/operations.py by rewriting quote_name to safely escape and quote table, index, and column names using robust regular expressions and an escape translation table. This prevents SQL injection and ensures compatibility with GoogleSQL. Additionally, a comprehensive set of unit tests has been added in test_operations.py to cover various edge cases, including reserved keywords, special characters, and SQL injection payloads. There are no review comments, and I have no feedback to provide.

This branch has not been deployed

No deployments
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.

1 participant