summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2017-11-11 19:17:20 -0500
committerSimon Charette <charette.s@gmail.com>2017-11-14 22:06:30 -0500
commita35ab95ed4eec5c62fa19bdc69ecfe0eff3e1fca (patch)
treede4cba97ae2ee5cbf65d5669d0f06a7b3f481fbb /django
parentafcde50497983ec48020600345367e161f6ff9c3 (diff)
[1.11.x] Fixed #28792 -- Fixed index name truncation of namespaced tables.
Refs #27458, #27843. Thanks Tim and Mariusz for the review. Backport of ee85ef8315db839e5723dea19d8b971420a2ebb4 from master
Diffstat (limited to 'django')
-rw-r--r--django/db/backends/base/schema.py4
-rw-r--r--django/db/backends/utils.py34
2 files changed, 26 insertions, 12 deletions
diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py
index f4b8b02049..56102ff27b 100644
--- a/django/db/backends/base/schema.py
+++ b/django/db/backends/base/schema.py
@@ -2,7 +2,7 @@ import hashlib
import logging
from datetime import datetime
-from django.db.backends.utils import strip_quotes
+from django.db.backends.utils import split_identifier
from django.db.models import Index
from django.db.transaction import TransactionManagementError, atomic
from django.utils import six, timezone
@@ -852,7 +852,7 @@ class BaseDatabaseSchemaEditor(object):
The name is divided into 3 parts: the table name, the column names,
and a unique digest and suffix.
"""
- table_name = strip_quotes(model._meta.db_table)
+ _, table_name = split_identifier(model._meta.db_table)
hash_data = [table_name] + list(column_names)
hash_suffix_part = '%s%s' % (self._digest(*hash_data), suffix)
max_length = self.connection.ops.max_name_length() or 200
diff --git a/django/db/backends/utils.py b/django/db/backends/utils.py
index ad87eb82e7..e7f55d2972 100644
--- a/django/db/backends/utils.py
+++ b/django/db/backends/utils.py
@@ -4,7 +4,6 @@ import datetime
import decimal
import hashlib
import logging
-import re
from time import time
from django.conf import settings
@@ -180,20 +179,35 @@ def rev_typecast_decimal(d):
return str(d)
-def truncate_name(name, length=None, hash_len=4):
+def split_identifier(identifier):
"""
- Shorten a string to a repeatable mangled version with the given length.
- If a quote stripped name contains a username, e.g. USERNAME"."TABLE,
+ Split a SQL identifier into a two element tuple of (namespace, name).
+
+ The identifier could be a table, column, or sequence name might be prefixed
+ by a namespace.
+ """
+ try:
+ namespace, name = identifier.split('"."')
+ except ValueError:
+ namespace, name = '', identifier
+ return namespace.strip('"'), name.strip('"')
+
+
+def truncate_name(identifier, length=None, hash_len=4):
+ """
+ Shorten a SQL identifier to a repeatable mangled version with the given
+ length.
+
+ If a quote stripped name contains a namespace, e.g. USERNAME"."TABLE,
truncate the table portion only.
"""
- match = re.match(r'([^"]+)"\."([^"]+)', name)
- table_name = match.group(2) if match else name
+ namespace, name = split_identifier(identifier)
- if length is None or len(table_name) <= length:
- return name
+ if length is None or len(name) <= length:
+ return identifier
- hsh = hashlib.md5(force_bytes(table_name)).hexdigest()[:hash_len]
- return '%s%s%s' % (match.group(1) + '"."' if match else '', table_name[:length - hash_len], hsh)
+ digest = hashlib.md5(force_bytes(name)).hexdigest()[:hash_len]
+ return '%s%s%s' % ('%s"."' % namespace if namespace else '', name[:length - hash_len], digest)
def format_number(value, max_digits, decimal_places):