aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/optimizer/plan/planner.c160
1 files changed, 102 insertions, 58 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index c5bd439587e..199d27973bc 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -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)
{