From dd8ed64113947ed066b83e443053e389e8f77ebc Mon Sep 17 00:00:00 2001
From: Mariusz Felisiak <felisiak.mariusz@gmail.com>
Date: Thu, 27 Dec 2018 20:21:57 +0100
Subject: [PATCH] Fixed #29851 -- Fixed crash of annotations with window
 expressions in Subquery.

---
 django/db/models/expressions.py   | 18 +++++++++---------
 tests/expressions_window/tests.py | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index b21a3b7526..1ab9ae11e0 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -1292,14 +1292,14 @@ class WindowFrame(Expression):
     template = '%(frame_type)s BETWEEN %(start)s AND %(end)s'
 
     def __init__(self, start=None, end=None):
-        self.start = start
-        self.end = end
+        self.start = Value(start)
+        self.end = Value(end)
 
     def set_source_expressions(self, exprs):
         self.start, self.end = exprs
 
     def get_source_expressions(self):
-        return [Value(self.start), Value(self.end)]
+        return [self.start, self.end]
 
     def as_sql(self, compiler, connection):
         connection.ops.check_expression_support(self)
@@ -1317,16 +1317,16 @@ class WindowFrame(Expression):
         return []
 
     def __str__(self):
-        if self.start is not None and self.start < 0:
-            start = '%d %s' % (abs(self.start), connection.ops.PRECEDING)
-        elif self.start is not None and self.start == 0:
+        if self.start.value is not None and self.start.value < 0:
+            start = '%d %s' % (abs(self.start.value), connection.ops.PRECEDING)
+        elif self.start.value is not None and self.start.value == 0:
             start = connection.ops.CURRENT_ROW
         else:
             start = connection.ops.UNBOUNDED_PRECEDING
 
-        if self.end is not None and self.end > 0:
-            end = '%d %s' % (self.end, connection.ops.FOLLOWING)
-        elif self.end is not None and self.end == 0:
+        if self.end.value is not None and self.end.value > 0:
+            end = '%d %s' % (self.end.value, connection.ops.FOLLOWING)
+        elif self.end.value is not None and self.end.value == 0:
             end = connection.ops.CURRENT_ROW
         else:
             end = connection.ops.UNBOUNDED_FOLLOWING
diff --git a/tests/expressions_window/tests.py b/tests/expressions_window/tests.py
index ba757dfb94..9759e5cbfa 100644
--- a/tests/expressions_window/tests.py
+++ b/tests/expressions_window/tests.py
@@ -4,7 +4,7 @@ from unittest import skipIf, skipUnless
 from django.core.exceptions import FieldError
 from django.db import NotSupportedError, connection
 from django.db.models import (
-    F, RowRange, Value, ValueRange, Window, WindowFrame,
+    F, OuterRef, RowRange, Subquery, Value, ValueRange, Window, WindowFrame,
 )
 from django.db.models.aggregates import Avg, Max, Min, Sum
 from django.db.models.functions import (
@@ -584,6 +584,35 @@ class WindowFunctionTests(TestCase):
             ('Brown', 'Sales', 53000, datetime.date(2009, 9, 1), 148000)
         ], transform=lambda row: (row.name, row.department, row.salary, row.hire_date, row.sum))
 
+    def test_subquery_row_range_rank(self):
+        qs = Employee.objects.annotate(
+            highest_avg_salary_date=Subquery(
+                Employee.objects.filter(
+                    department=OuterRef('department'),
+                ).annotate(
+                    avg_salary=Window(
+                        expression=Avg('salary'),
+                        order_by=[F('hire_date').asc()],
+                        frame=RowRange(start=-1, end=1),
+                    ),
+                ).order_by('-avg_salary', '-hire_date').values('hire_date')[:1],
+            ),
+        ).order_by('department', 'name')
+        self.assertQuerysetEqual(qs, [
+            ('Adams', 'Accounting', datetime.date(2005, 11, 1)),
+            ('Jenson', 'Accounting', datetime.date(2005, 11, 1)),
+            ('Jones', 'Accounting', datetime.date(2005, 11, 1)),
+            ('Williams', 'Accounting', datetime.date(2005, 11, 1)),
+            ('Moore', 'IT', datetime.date(2013, 8, 1)),
+            ('Wilkinson', 'IT', datetime.date(2013, 8, 1)),
+            ('Johnson', 'Management', datetime.date(2005, 7, 1)),
+            ('Miller', 'Management', datetime.date(2005, 7, 1)),
+            ('Johnson', 'Marketing', datetime.date(2012, 3, 1)),
+            ('Smith', 'Marketing', datetime.date(2012, 3, 1)),
+            ('Brown', 'Sales', datetime.date(2009, 9, 1)),
+            ('Smith', 'Sales', datetime.date(2009, 9, 1)),
+        ], transform=lambda row: (row.name, row.department, row.highest_avg_salary_date))
+
     def test_row_range_rank(self):
         """
         A query with ROWS BETWEEN UNBOUNDED PRECEDING AND 3 FOLLOWING.