Planner wasn't correctly handling adjustment of tuple_fraction for the
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 1 Apr 2001 22:37:19 +0000 (22:37 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 1 Apr 2001 22:37:19 +0000 (22:37 +0000)
case of LIMIT in a sub-select.

src/backend/optimizer/plan/planner.c

index c5bd439587ea688ea4e7b23ff067faf8a3b30053..199d27973bcf241a3a655dc45f04cf8a92ea2fd4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.102 2001/03/22 03:59:37 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.103 2001/04/01 22:37:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -874,9 +874,9 @@ grouping_planner(Query *parse, double tuple_fraction)
 
        /*
         * Figure out whether we expect to retrieve all the tuples that
-        * the plan can generate, or to stop early due to a LIMIT or other
-        * factors.  If the caller passed a value >= 0, believe that
-        * value, else do our own examination of the query context.
+        * the plan can generate, or to stop early due to outside factors
+        * such as a cursor.  If the caller passed a value >= 0, believe
+        * that value, else do our own examination of the query context.
         */
        if (tuple_fraction < 0.0)
        {
@@ -884,74 +884,118 @@ grouping_planner(Query *parse, double tuple_fraction)
            tuple_fraction = 0.0;
 
            /*
-            * Check for a LIMIT clause.
+            * Check for retrieve-into-portal, ie DECLARE CURSOR.
+            *
+            * We have no real idea how many tuples the user will ultimately
+            * FETCH from a cursor, but it seems a good bet that he
+            * doesn't want 'em all.  Optimize for 10% retrieval (you
+            * gotta better number?  Should this be a SETtable parameter?)
+            */
+           if (parse->isPortal)
+               tuple_fraction = 0.10;
+       }
+
+       /*
+        * Adjust tuple_fraction if we see that we are going to apply
+        * limiting/grouping/aggregation/etc.  This is not overridable by
+        * the caller, since it reflects plan actions that this routine
+        * will certainly take, not assumptions about context.
+        */
+       if (parse->limitCount != NULL)
+       {
+           /*
+            * A LIMIT clause limits the absolute number of tuples returned.
+            * However, if it's not a constant LIMIT then we have to punt;
+            * for lack of a better idea, assume 10% of the plan's result
+            * is wanted.
             */
-           if (parse->limitCount != NULL)
+           double  limit_fraction = 0.0;
+
+           if (IsA(parse->limitCount, Const))
            {
-               if (IsA(parse->limitCount, Const))
+               Const      *limitc = (Const *) parse->limitCount;
+               int32       count = DatumGetInt32(limitc->constvalue);
+
+               /*
+                * A NULL-constant LIMIT represents "LIMIT ALL", which
+                * we treat the same as no limit (ie, expect to
+                * retrieve all the tuples).
+                */
+               if (!limitc->constisnull && count > 0)
                {
-                   Const      *limitc = (Const *) parse->limitCount;
-                   int32       count = DatumGetInt32(limitc->constvalue);
-
-                   /*
-                    * A NULL-constant LIMIT represents "LIMIT ALL", which
-                    * we treat the same as no limit (ie, expect to
-                    * retrieve all the tuples).
-                    */
-                   if (!limitc->constisnull && count > 0)
+                   limit_fraction = (double) count;
+                   /* We must also consider the OFFSET, if present */
+                   if (parse->limitOffset != NULL)
                    {
-                       tuple_fraction = (double) count;
-                       /* We must also consider the OFFSET, if present */
-                       if (parse->limitOffset != NULL)
+                       if (IsA(parse->limitOffset, Const))
+                       {
+                           int32       offset;
+
+                           limitc = (Const *) parse->limitOffset;
+                           offset = DatumGetInt32(limitc->constvalue);
+                           if (!limitc->constisnull && offset > 0)
+                               limit_fraction += (double) offset;
+                       }
+                       else
                        {
-                           if (IsA(parse->limitOffset, Const))
-                           {
-                               int32       offset;
-
-                               limitc = (Const *) parse->limitOffset;
-                               offset = DatumGetInt32(limitc->constvalue);
-                               if (!limitc->constisnull && offset > 0)
-                                   tuple_fraction += (double) offset;
-                           }
-                           else
-                           {
-                               /* It's an expression ... punt ... */
-                               tuple_fraction = 0.10;
-                           }
+                           /* OFFSET is an expression ... punt ... */
+                           limit_fraction = 0.10;
                        }
                    }
                }
+           }
+           else
+           {
+               /* LIMIT is an expression ... punt ... */
+               limit_fraction = 0.10;
+           }
+
+           if (limit_fraction > 0.0)
+           {
+               /*
+                * If we have absolute limits from both caller and LIMIT,
+                * use the smaller value; if one is fractional and the other
+                * absolute, treat the fraction as a fraction of the absolute
+                * value; else we can multiply the two fractions together.
+                */
+               if (tuple_fraction >= 1.0)
+               {
+                   if (limit_fraction >= 1.0)
+                   {
+                       /* both absolute */
+                       tuple_fraction = Min(tuple_fraction, limit_fraction);
+                   }
+                   else
+                   {
+                       /* caller absolute, limit fractional */
+                       tuple_fraction *= limit_fraction;
+                       if (tuple_fraction < 1.0)
+                           tuple_fraction = 1.0;
+                   }
+               }
+               else if (tuple_fraction > 0.0)
+               {
+                   if (limit_fraction >= 1.0)
+                   {
+                       /* caller fractional, limit absolute */
+                       tuple_fraction *= limit_fraction;
+                       if (tuple_fraction < 1.0)
+                           tuple_fraction = 1.0;
+                   }
+                   else
+                   {
+                       /* both fractional */
+                       tuple_fraction *= limit_fraction;
+                   }
+               }
                else
                {
-
-                   /*
-                    * COUNT is an expression ... don't know exactly what
-                    * the limit will be, but for lack of a better idea
-                    * assume 10% of the plan's result is wanted.
-                    */
-                   tuple_fraction = 0.10;
+                   /* no info from caller, just use limit */
+                   tuple_fraction = limit_fraction;
                }
            }
-
-           /*
-            * If no LIMIT, check for retrieve-into-portal, ie DECLARE
-            * CURSOR.
-            *
-            * We have no real idea how many tuples the user will ultimately
-            * FETCH from a cursor, but it seems a good bet that he
-            * doesn't want 'em all.  Optimize for 10% retrieval (you
-            * gotta better number?)
-            */
-           else if (parse->isPortal)
-               tuple_fraction = 0.10;
        }
 
-       /*
-        * Adjust tuple_fraction if we see that we are going to apply
-        * grouping/aggregation/etc.  This is not overridable by the
-        * caller, since it reflects plan actions that this routine will
-        * certainly take, not assumptions about context.
-        */
        if (parse->groupClause)
        {