1
0
mirror of https://github.com/django/django.git synced 2025-06-21 11:29:12 +00:00

Fixed #36152 -- Deprecated use of "%" in column aliases.

Unintentional support existed only on SQLite and Oracle.
This commit is contained in:
Jacob Walls 2025-02-17 19:27:21 -05:00 committed by Sarah Boyce
parent 56f468681a
commit 8ede411a81
4 changed files with 49 additions and 0 deletions

View File

@ -10,7 +10,9 @@ all about the internals of models in order to get the information it needs.
import copy import copy
import difflib import difflib
import functools import functools
import inspect
import sys import sys
import warnings
from collections import Counter, namedtuple from collections import Counter, namedtuple
from collections.abc import Iterator, Mapping from collections.abc import Iterator, Mapping
from itertools import chain, count, product from itertools import chain, count, product
@ -42,12 +44,17 @@ from django.db.models.query_utils import (
from django.db.models.sql.constants import INNER, LOUTER, ORDER_DIR, SINGLE from django.db.models.sql.constants import INNER, LOUTER, ORDER_DIR, SINGLE
from django.db.models.sql.datastructures import BaseTable, Empty, Join, MultiJoin from django.db.models.sql.datastructures import BaseTable, Empty, Join, MultiJoin
from django.db.models.sql.where import AND, OR, ExtraWhere, NothingNode, WhereNode from django.db.models.sql.where import AND, OR, ExtraWhere, NothingNode, WhereNode
from django.utils.deprecation import RemovedInDjango70Warning
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.regex_helper import _lazy_re_compile from django.utils.regex_helper import _lazy_re_compile
from django.utils.tree import Node from django.utils.tree import Node
__all__ = ["Query", "RawQuery"] __all__ = ["Query", "RawQuery"]
# RemovedInDjango70Warning: When the deprecation ends, replace with:
# Quotation marks ('"`[]), whitespace characters, semicolons, percent signs
# or inline SQL comments are forbidden in column aliases.
# FORBIDDEN_ALIAS_PATTERN = _lazy_re_compile(r"['`\"\]\[;\s]|%|--|/\*|\*/")
# Quotation marks ('"`[]), whitespace characters, semicolons, or inline # Quotation marks ('"`[]), whitespace characters, semicolons, or inline
# SQL comments are forbidden in column aliases. # SQL comments are forbidden in column aliases.
FORBIDDEN_ALIAS_PATTERN = _lazy_re_compile(r"['`\"\]\[;\s]|--|/\*|\*/") FORBIDDEN_ALIAS_PATTERN = _lazy_re_compile(r"['`\"\]\[;\s]|--|/\*|\*/")
@ -1206,9 +1213,23 @@ class Query(BaseExpression):
return alias or seen[None] return alias or seen[None]
def check_alias(self, alias): def check_alias(self, alias):
# RemovedInDjango70Warning: When the deprecation ends, remove.
if "%" in alias:
if "aggregate" in {frame.function for frame in inspect.stack()}:
stacklevel = 5
else:
# annotate() and alias().
stacklevel = 6
warnings.warn(
"Using percent signs in a column alias is deprecated.",
stacklevel=stacklevel,
category=RemovedInDjango70Warning,
)
if FORBIDDEN_ALIAS_PATTERN.search(alias): if FORBIDDEN_ALIAS_PATTERN.search(alias):
raise ValueError( raise ValueError(
"Column aliases cannot contain whitespace characters, quotation marks, " "Column aliases cannot contain whitespace characters, quotation marks, "
# RemovedInDjango70Warning: When the deprecation ends, replace with:
# "semicolons, percent signs, or SQL comments."
"semicolons, or SQL comments." "semicolons, or SQL comments."
) )

View File

@ -28,6 +28,9 @@ details on these changes.
* The ``URLIZE_ASSUME_HTTPS`` transitional setting will be removed. * The ``URLIZE_ASSUME_HTTPS`` transitional setting will be removed.
* Using a percent sign in a column alias or annotation will raise
``ValueError``.
* Support for setting the ``ADMINS`` or ``MANAGERS`` settings to a list of * Support for setting the ``ADMINS`` or ``MANAGERS`` settings to a list of
(name, address) tuples will be removed. (name, address) tuples will be removed.

View File

@ -375,6 +375,8 @@ Miscellaneous
``per_page`` argument of :class:`django.core.paginator.Paginator` and ``per_page`` argument of :class:`django.core.paginator.Paginator` and
:class:`django.core.paginator.AsyncPaginator` is deprecated. :class:`django.core.paginator.AsyncPaginator` is deprecated.
* Using a percent sign in a column alias or annotation is deprecated.
Features removed in 6.0 Features removed in 6.0
======================= =======================

View File

@ -39,6 +39,7 @@ from django.db.models.functions import (
from django.db.models.sql.query import get_field_names_from_opts from django.db.models.sql.query import get_field_names_from_opts
from django.test import TestCase, skipUnlessDBFeature from django.test import TestCase, skipUnlessDBFeature
from django.test.utils import register_lookup from django.test.utils import register_lookup
from django.utils.deprecation import RemovedInDjango70Warning
from .models import ( from .models import (
Author, Author,
@ -1157,6 +1158,11 @@ class NonAggregateAnnotationTestCase(TestCase):
def test_alias_sql_injection(self): def test_alias_sql_injection(self):
crafted_alias = """injected_name" from "annotations_book"; --""" crafted_alias = """injected_name" from "annotations_book"; --"""
# RemovedInDjango70Warning: When the deprecation ends, replace with:
# msg = (
# "Column aliases cannot contain whitespace characters, quotation marks, "
# "semicolons, percent signs, or SQL comments."
# )
msg = ( msg = (
"Column aliases cannot contain whitespace characters, quotation marks, " "Column aliases cannot contain whitespace characters, quotation marks, "
"semicolons, or SQL comments." "semicolons, or SQL comments."
@ -1176,10 +1182,17 @@ class NonAggregateAnnotationTestCase(TestCase):
"ali/*as", "ali/*as",
"alias*/", "alias*/",
"alias;", "alias;",
# RemovedInDjango70Warning: When the deprecation ends, add this case.
# "alias%",
# [] are used by MSSQL. # [] are used by MSSQL.
"alias[", "alias[",
"alias]", "alias]",
] ]
# RemovedInDjango70Warning: When the deprecation ends, replace with:
# msg = (
# "Column aliases cannot contain whitespace characters, quotation marks, "
# "semicolons, percent signs, or SQL comments."
# )
msg = ( msg = (
"Column aliases cannot contain whitespace characters, quotation marks, " "Column aliases cannot contain whitespace characters, quotation marks, "
"semicolons, or SQL comments." "semicolons, or SQL comments."
@ -1189,6 +1202,11 @@ class NonAggregateAnnotationTestCase(TestCase):
with self.assertRaisesMessage(ValueError, msg): with self.assertRaisesMessage(ValueError, msg):
Book.objects.annotate(**{crafted_alias: Value(1)}) Book.objects.annotate(**{crafted_alias: Value(1)})
def test_alias_containing_percent_sign_deprecation(self):
msg = "Using percent signs in a column alias is deprecated."
with self.assertRaisesMessage(RemovedInDjango70Warning, msg):
Book.objects.annotate(**{"alias%": Value(1)})
@skipUnless(connection.vendor == "postgresql", "PostgreSQL tests") @skipUnless(connection.vendor == "postgresql", "PostgreSQL tests")
@skipUnlessDBFeature("supports_json_field") @skipUnlessDBFeature("supports_json_field")
def test_set_returning_functions(self): def test_set_returning_functions(self):
@ -1476,6 +1494,11 @@ class AliasTests(TestCase):
def test_alias_sql_injection(self): def test_alias_sql_injection(self):
crafted_alias = """injected_name" from "annotations_book"; --""" crafted_alias = """injected_name" from "annotations_book"; --"""
# RemovedInDjango70Warning: When the deprecation ends, replace with:
# msg = (
# "Column aliases cannot contain whitespace characters, quotation marks, "
# "semicolons, percent signs, or SQL comments."
# )
msg = ( msg = (
"Column aliases cannot contain whitespace characters, quotation marks, " "Column aliases cannot contain whitespace characters, quotation marks, "
"semicolons, or SQL comments." "semicolons, or SQL comments."