Thread: explain doesn't work with execute using

explain doesn't work with execute using

From
"Pavel Stehule"
Date:
Hello

I found following bug - using explain in stored procedures like:

CREATE OR REPLACE FUNCTION test(int)
RETURNS void AS $$
DECLARE s varchar;
BEGIN FOR s IN EXECUTE 'EXPLAIN SELECT * FROM o WHERE a = $1+1' USING $1 LOOP   RAISE NOTICE '%', s; END LOOP;
END; $$
LANGUAGE plpgsql;

produce wrong result. Real plan is correct, etc variables are
substituted. Bud this explain show variables. Reason is in difference
in pflags. Planner works with PARAM_FLAG_CONST's variables, but
explain (proc ExplainQuery) get variables from Portal, where flag
PARAM_FLAG_CONST is lost.

Portal
SPI_cursor_open_with_args(const char *name,                                                 const char *src,
                                    int nargs, Oid *argtypes,                                                 Datum
*Values,const
 
char *Nulls,                                                 bool read_only, int
cursorOptions)
{  ...       paramLI = _SPI_convert_params(nargs, argtypes,
   Values, Nulls,
 

PARAM_FLAG_CONST);
      // variables are correct

but      result = SPI_cursor_open(name, &plan, Values, Nulls, read_only);      // result->portalParams lost flags

Portal
SPI_cursor_open(const char *name, SPIPlanPtr plan,                               Datum *Values, const char *Nulls,
                        bool read_only)
 
{       CachedPlanSource *plansource;       CachedPlan *cplan;       List       *stmt_list;       char
*query_string;      ParamListInfo paramLI;....       if (plan->nargs > 0)       {               /*
sizeof(ParamListInfoData)includes the first array
 
element */               paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +

(plan->nargs - 1) *sizeof(ParamExternData));               paramLI->numParams = plan->nargs;
               for (k = 0; k < plan->nargs; k++)               {                       ParamExternData *prm =
¶mLI->params[k];
                       prm->ptype = plan->argtypes[k];

/***************************************************/                       prm->pflags = 0; // correct flags is
overwritten
/***************************************************/                       prm->isnull = (Nulls && Nulls[k] == 'n');
                   if (prm->isnull)                       {                               /* nulls just copy */
                     prm->value = Values[k];                       }
 

so this is strange bug - EXECUTE USING use well plan, but isn't
possible verify it.

Regards
Pavel Stehule


Re: explain doesn't work with execute using

From
Tom Lane
Date:
"Pavel Stehule" <pavel.stehule@gmail.com> writes:
> I found following bug - using explain in stored procedures like:
> ...
> produce wrong result. Real plan is correct, etc variables are
> substituted. Bud this explain show variables.

This seems to be correctable with a one-line patch: make SPI_cursor_open
set the CONST flag on parameters it puts into the portal (attached).
I'm not entirely sure if it's a good idea or not --- comments?
        regards, tom lane

Index: src/backend/executor/spi.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/executor/spi.c,v
retrieving revision 1.195
diff -c -r1.195 spi.c
*** src/backend/executor/spi.c    12 May 2008 20:02:00 -0000    1.195
--- src/backend/executor/spi.c    1 Jun 2008 15:33:13 -0000
***************
*** 997,1003 ****             ParamExternData *prm = ¶mLI->params[k];              prm->ptype = plan->argtypes[k];
!             prm->pflags = 0;             prm->isnull = (Nulls && Nulls[k] == 'n');             if (prm->isnull)
     {
 
--- 997,1010 ----             ParamExternData *prm = ¶mLI->params[k];              prm->ptype = plan->argtypes[k];
!             /*
!              * We mark the parameters as const.  This has no effect for simple
!              * execution of a plan, but if more planning happens within the
!              * portal (eg via EXPLAIN), the effect will be to treat the
!              * parameters as constants.  This is good and correct as long as
!              * no plan generated inside the portal is used outside it.
!              */
!             prm->pflags = PARAM_FLAG_CONST;             prm->isnull = (Nulls && Nulls[k] == 'n');             if
(prm->isnull)            {
 


Re: explain doesn't work with execute using

From
"Pavel Stehule"
Date:
hello

2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
> "Pavel Stehule" <pavel.stehule@gmail.com> writes:
>> I found following bug - using explain in stored procedures like:
>> ...
>> produce wrong result. Real plan is correct, etc variables are
>> substituted. Bud this explain show variables.
>
> This seems to be correctable with a one-line patch: make SPI_cursor_open
> set the CONST flag on parameters it puts into the portal (attached).
> I'm not entirely sure if it's a good idea or not --- comments?

We can do less invasive patch - it's much more ugly, but don't change
any other behave. I am afraid, so one-line patch can change behave of
explain statements in some cases where using variables is correct.

Regards
Pavel Stehule

>
>                        regards, tom lane
>
> Index: src/backend/executor/spi.c
> ===================================================================
> RCS file: /cvsroot/pgsql/src/backend/executor/spi.c,v
> retrieving revision 1.195
> diff -c -r1.195 spi.c
> *** src/backend/executor/spi.c  12 May 2008 20:02:00 -0000      1.195
> --- src/backend/executor/spi.c  1 Jun 2008 15:33:13 -0000
> ***************
> *** 997,1003 ****
>                        ParamExternData *prm = ¶mLI->params[k];
>
>                        prm->ptype = plan->argtypes[k];
> !                       prm->pflags = 0;
>                        prm->isnull = (Nulls && Nulls[k] == 'n');
>                        if (prm->isnull)
>                        {
> --- 997,1010 ----
>                        ParamExternData *prm = ¶mLI->params[k];
>
>                        prm->ptype = plan->argtypes[k];
> !                       /*
> !                        * We mark the parameters as const.  This has no effect for simple
> !                        * execution of a plan, but if more planning happens within the
> !                        * portal (eg via EXPLAIN), the effect will be to treat the
> !                        * parameters as constants.  This is good and correct as long as
> !                        * no plan generated inside the portal is used outside it.
> !                        */
> !                       prm->pflags = PARAM_FLAG_CONST;
>                        prm->isnull = (Nulls && Nulls[k] == 'n');
>                        if (prm->isnull)
>                        {
>

Attachment

Re: explain doesn't work with execute using

From
Tom Lane
Date:
"Pavel Stehule" <pavel.stehule@gmail.com> writes:
> 2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
>> This seems to be correctable with a one-line patch: make SPI_cursor_open
>> set the CONST flag on parameters it puts into the portal (attached).
>> I'm not entirely sure if it's a good idea or not --- comments?

> We can do less invasive patch - it's much more ugly, but don't change
> any other behave. I am afraid, so one-line patch can change behave of
> explain statements in some cases where using variables is correct.

If you can name a case where that is correct, then I'll worry about
this, but offhand I don't see one.

What do you think a "less invasive" patch would be, anyway?  I don't
buy that, say, having SPI_cursor_open_with_args set the flag but
SPI_cursor_open not do so is any safer.  There is no difference between
the two as to what might get executed, so if there's a problem then
both would be at risk.
        regards, tom lane


Re: explain doesn't work with execute using

From
"Pavel Stehule"
Date:
2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
> "Pavel Stehule" <pavel.stehule@gmail.com> writes:
>> 2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
>>> This seems to be correctable with a one-line patch: make SPI_cursor_open
>>> set the CONST flag on parameters it puts into the portal (attached).
>>> I'm not entirely sure if it's a good idea or not --- comments?
>
>> We can do less invasive patch - it's much more ugly, but don't change
>> any other behave. I am afraid, so one-line patch can change behave of
>> explain statements in some cases where using variables is correct.
>
> If you can name a case where that is correct, then I'll worry about
> this, but offhand I don't see one.

this case - there variables are correct

postgres=# create or replace function foo(_a integer) returns void as
$$declare s varchar; begin for s in explain select * from o where a =
_a loop raise notice '%', s; end loop; end; $$ language plpgsql;
CREATE FUNCTION
Time: 43,138 ms
postgres=# select foo(20);
NOTICE:  Index Scan using o_pkey on o  (cost=0.00..8.27 rows=1 width=4)
NOTICE:    Index Cond: (a = 20) -- wrong :(foo
-----

(1 row)


>
> What do you think a "less invasive" patch would be, anyway?  I don't
> buy that, say, having SPI_cursor_open_with_args set the flag but
> SPI_cursor_open not do so is any safer.  There is no difference between
> the two as to what might get executed, so if there's a problem then
> both would be at risk.

SPI_cursor_open_with_args is new function, it's used only in FOR
EXECUTE statement - and in this context variables are really
constants.

Pavel

>
>                        regards, tom lane
>


Re: explain doesn't work with execute using

From
Tom Lane
Date:
"Pavel Stehule" <pavel.stehule@gmail.com> writes:
> 2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
>> What do you think a "less invasive" patch would be, anyway?  I don't
>> buy that, say, having SPI_cursor_open_with_args set the flag but
>> SPI_cursor_open not do so is any safer.  There is no difference between
>> the two as to what might get executed, so if there's a problem then
>> both would be at risk.

> SPI_cursor_open_with_args is new function, it's used only in FOR
> EXECUTE statement - and in this context variables are really
> constants.

This argument seems entirely bogus.  How are they any more constant
than in the other case?  The value isn't going to change for the life
of the portal in either case.

ISTM you're expecting EXPLAIN to behave in some magic way that has
got little to do with "correctness".
        regards, tom lane


Re: explain doesn't work with execute using

From
"Pavel Stehule"
Date:
2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
> "Pavel Stehule" <pavel.stehule@gmail.com> writes:
>> 2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
>>> What do you think a "less invasive" patch would be, anyway?  I don't
>>> buy that, say, having SPI_cursor_open_with_args set the flag but
>>> SPI_cursor_open not do so is any safer.  There is no difference between
>>> the two as to what might get executed, so if there's a problem then
>>> both would be at risk.
>
>> SPI_cursor_open_with_args is new function, it's used only in FOR
>> EXECUTE statement - and in this context variables are really
>> constants.
>
> This argument seems entirely bogus.  How are they any more constant
> than in the other case?  The value isn't going to change for the life
> of the portal in either case.

this is true Tom, but problem is in EXPLAIN. I thing, so my and your
solution are little bit incorect. We solve result, not reason. We have
problem, bacause plan doesn't carry parameter's flags, and with
EXPLAIN planner is called two times with different param's flags.


>
> ISTM you're expecting EXPLAIN to behave in some magic way that has
> got little to do with "correctness".
>

It is first time when I do some with EXPLAIN and I don't understad
well, but I would correct EXPLAIN output. When original plan use
variables I would to see variables in plan and when plan use constant
I would to see constant.


>                        regards, tom lane
>


Re: explain doesn't work with execute using

From
Tom Lane
Date:
"Pavel Stehule" <pavel.stehule@gmail.com> writes:
> 2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
>> This argument seems entirely bogus.  How are they any more constant
>> than in the other case?  The value isn't going to change for the life
>> of the portal in either case.

> this is true Tom, but problem is in EXPLAIN. I thing, so my and your
> solution are little bit incorect. We solve result, not reason. We have
> problem, bacause plan doesn't carry parameter's flags, and with
> EXPLAIN planner is called two times with different param's flags.

[ shrug... ]  Well, I'm willing to change the code as you suggest,
but if you're thinking that this will make EXPLAIN exactly reproduce
the plan that would be generated for a plain SELECT invoked in the
same context, you're still mistaken.  It doesn't account for the
effects of the fast-start-cursor option.  And for what you seem to
want EXPLAIN to do here, it probably shouldn't.  The whole thing
seems pretty unprincipled to me ...
        regards, tom lane


Re: explain doesn't work with execute using

From
"Pavel Stehule"
Date:
2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
> "Pavel Stehule" <pavel.stehule@gmail.com> writes:
>> 2008/6/1 Tom Lane <tgl@sss.pgh.pa.us>:
>>> This argument seems entirely bogus.  How are they any more constant
>>> than in the other case?  The value isn't going to change for the life
>>> of the portal in either case.
>
>> this is true Tom, but problem is in EXPLAIN. I thing, so my and your
>> solution are little bit incorect. We solve result, not reason. We have
>> problem, bacause plan doesn't carry parameter's flags, and with
>> EXPLAIN planner is called two times with different param's flags.
>
> [ shrug... ]  Well, I'm willing to change the code as you suggest,
> but if you're thinking that this will make EXPLAIN exactly reproduce
> the plan that would be generated for a plain SELECT invoked in the
> same context, you're still mistaken.  It doesn't account for the
> effects of the fast-start-cursor option.  And for what you seem to
> want EXPLAIN to do here, it probably shouldn't.  The whole thing
> seems pretty unprincipled to me ...
>

It's not best, and it's surprise for me, so EXPLAIN can be different
then real plan. It's basic tool for identification of plpgsql
procedure's performance problems. So this can be short fix and point
for ToDo?

Regards
Pavel Stehule

>                        regards, tom lane
>