Re: FETCH FIRST clause PERCENT option

From: Andres Freund <andres(at)anarazel(dot)de>
To: Surafel Temesgen <surafel3000(at)gmail(dot)com>
Cc: Kyotaro HORIGUCHI <horiguchi(dot)kyotaro(at)lab(dot)ntt(dot)co(dot)jp>, Tomas Vondra <tomas(dot)vondra(at)2ndquadrant(dot)com>, vik(dot)fearing(at)2ndquadrant(dot)com, Mark Dilger <hornschnorter(at)gmail(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>, andrew(at)tao11(dot)riddles(dot)org(dot)uk
Subject: Re: FETCH FIRST clause PERCENT option
Date: 2019-03-31 21:34:31
Message-ID: 20190331213431.qrbh3tbj2bcketep@alap3.anarazel.de
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

On 2019-03-29 12:04:50 +0300, Surafel Temesgen wrote:

> + if (node->limitOption == PERCENTAGE)
> + {
> + while (node->position - node->offset < node->count)
> + {
> + slot = MakeSingleTupleTableSlot(tupleDescriptor, &TTSOpsMinimalTuple);
> + if (tuplestore_gettupleslot(node->tupleStore, true, true, slot))

There's several blocks like this - how's this not going to be a resource
leak? As far as I can tell you're just going to create new slots, and
their previous contents aren't going to be cleared? I think there very
rarely are cases where an executor node's *Next function (or its
subsidiaries) creates slots. Normally you ought to create them *once* on
the *Init function.

You might not directly leak memory, because this is probably running in
a short lived context, but you'll leak tuple desc references etc. (Or if
it were a heap buffer slot, buffer pins).

> + /* In PERCENTAGE case the result is already in tuplestore */
> + if (node->limitOption == PERCENTAGE)
> + {
> + slot = MakeSingleTupleTableSlot(tupleDescriptor, &TTSOpsMinimalTuple);
> + if (tuplestore_gettupleslot(node->tupleStore, false, false, slot))
> + {
> + node->subSlot = slot;
> + node->lstate = LIMIT_INWINDOW;
> + }
> + else
> + elog(ERROR, "LIMIT subplan failed to run backwards");
> + }
> + else if (node->limitOption == EXACT_NUMBER)
> + {
> /*
> * Backing up from subplan EOF, so re-fetch previous tuple; there
> * should be one! Note previous tuple must be in window.
> @@ -194,6 +329,7 @@ ExecLimit(PlanState *pstate)
> node->subSlot = slot;
> node->lstate = LIMIT_INWINDOW;
> /* position does not change 'cause we didn't advance it before */
> + }

The indentation here looks wrong...

> break;
>
> case LIMIT_WINDOWEND:
> @@ -278,17 +414,29 @@ recompute_limits(LimitState *node)
> /* Interpret NULL count as no count (LIMIT ALL) */
> if (isNull)
> {
> - node->count = 0;
> + node->count = 1;
> node->noCount = true;

Huh?

> }
> else
> {
> - node->count = DatumGetInt64(val);
> - if (node->count < 0)
> - ereport(ERROR,
> - (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),
> - errmsg("LIMIT must not be negative")));
> - node->noCount = false;
> + if (node->limitOption == PERCENTAGE)
> + {
> + /*
> + * We expect to return at least one row (unless there
> + * are no rows in the subplan), and we'll update this
> + * count later as we go.
> + */
> + node->count = 0;
> + node->percent = DatumGetFloat8(val);
> + }
> + else
> + {
> + node->count = DatumGetInt64(val);
> + if (node->count < 0)
> + ereport(ERROR,
> + (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),
> + errmsg("LIMIT must not be negative")));
> + }

Shouldn't we error out with a negative count, regardless of PERCENT? Or
is that prevented elsewhere?

> }
> }
> else
> @@ -299,8 +447,10 @@ recompute_limits(LimitState *node)
> }
>
> /* Reset position to start-of-scan */
> - node->position = 0;
> + node->position = 0;;

unnecessary

> if (parse->sortClause)
> {
> - current_rel = create_ordered_paths(root,
> - current_rel,
> - final_target,
> - final_target_parallel_safe,
> - have_postponed_srfs ? -1.0 :
> - limit_tuples);
> +
> + /* In PERCENTAGE option there are no bound on the number of output tuples */
> + if (parse->limitOption == PERCENTAGE)
> + current_rel = create_ordered_paths(root,
> + current_rel,
> + final_target,
> + final_target_parallel_safe,
> + have_postponed_srfs ? -1.0 :
> + -1.0);
> + else
> + current_rel = create_ordered_paths(root,
> + current_rel,
> + final_target,
> + final_target_parallel_safe,
> + have_postponed_srfs ? -1.0 :
> + limit_tuples);

I'd rather not duplicate those two calls, and just have the limit_tuples
computation inside an if.

> offset_clause:
> @@ -15435,6 +15442,7 @@ reserved_keyword:
> | ONLY
> | OR
> | ORDER
> + | PERCENT
> | PLACING
> | PRIMARY
> | REFERENCES

Are we really ok with adding a new reserved keyword 'PERCENT' for this?
That seems awfully likely to already exist in columns etc. Is there a
chance we can use a less strong category?

Greetings,

Andres Freund

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Andreas Karlsson 2019-03-31 21:49:51 Re: DWIM mode for psql
Previous Message Corey Huinker 2019-03-31 21:32:23 Re: DWIM mode for psql