From 87775b64cdda97567a33c7bad65ad42853048525 Mon Sep 17 00:00:00 2001
From: Mariusz Felisiak <felisiak.mariusz@gmail.com>
Date: Wed, 15 Feb 2017 12:22:34 +0100
Subject: [PATCH] [1.11.x] Fixed #27843 -- Fixed truncate_name() when the name
 contains a username.

Backport of b9351905721771fb49ea0020c751ae4280754c43 from master
---
 django/db/backends/utils.py  | 15 +++++++++++----
 tests/backends/test_utils.py |  4 ++++
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/django/db/backends/utils.py b/django/db/backends/utils.py
index e4ee025077..ce5e274649 100644
--- a/django/db/backends/utils.py
+++ b/django/db/backends/utils.py
@@ -4,6 +4,7 @@ import datetime
 import decimal
 import hashlib
 import logging
+import re
 from time import time
 
 from django.conf import settings
@@ -180,13 +181,19 @@ def rev_typecast_decimal(d):
 
 
 def truncate_name(name, length=None, hash_len=4):
-    """Shortens a string to a repeatable mangled version with the given length.
     """
-    if length is None or len(name) <= length:
+    Shorten a string to a repeatable mangled version with the given length.
+    If a quote stripped name contains a username, e.g. USERNAME"."TABLE,
+    truncate the table portion only.
+    """
+    match = re.match('([^"]+)"\."([^"]+)', name)
+    table_name = match.group(2) if match else name
+
+    if length is None or len(table_name) <= length:
         return name
 
-    hsh = hashlib.md5(force_bytes(name)).hexdigest()[:hash_len]
-    return '%s%s' % (name[:length - hash_len], hsh)
+    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)
 
 
 def format_number(value, max_digits, decimal_places):
diff --git a/tests/backends/test_utils.py b/tests/backends/test_utils.py
index ac7f9ab848..47720f7c92 100644
--- a/tests/backends/test_utils.py
+++ b/tests/backends/test_utils.py
@@ -21,3 +21,7 @@ class TestLoadBackend(SimpleTestCase):
         self.assertEqual(truncate_name('some_long_table', 10), 'some_la38a')
         self.assertEqual(truncate_name('some_long_table', 10, 3), 'some_loa38')
         self.assertEqual(truncate_name('some_long_table'), 'some_long_table')
+        # "user"."table" syntax
+        self.assertEqual(truncate_name('username"."some_table', 10), 'username"."some_table')
+        self.assertEqual(truncate_name('username"."some_long_table', 10), 'username"."some_la38a')
+        self.assertEqual(truncate_name('username"."some_long_table', 10, 3), 'username"."some_loa38')