Thread: plpgsql and logical expression evaluation

plpgsql and logical expression evaluation

From
wstrzalka
Date:
One of the annoying things in plpgsql is logical expression
evaluation.

In most (all??) languages I know, logical expression like:

     if ( [A_true_expression] or [B_false_expression] ) then

will stop evaluating when the A expression will be evaluated as a
TRUE.
So the B will be not checked. In plpgsql it's different - all the
expressions are evaluated.


Why I don't like it? One of the samples is trigger procedure called
with body like this:

IF (TG_OP = 'INSERT' OR (TG_OP = 'UPDATE' AND NEW.status <>
OLD.status)) THEN
        -- DO SOMETHING
END IF;

It don't work for insert as the part designed for UPDATE will be
evaluated, while there is no OLD for an insert operation.
So the code looks like that:

IF (TG_OP = 'INSERT') THEN
        -- DO SOMETHING
ELSIF  (TG_OP = 'UPDATE' AND NEW.status <> OLD.status) THEN
        -- DO THE SAME AS ABOVE
END IF;


Is there any reason for that like side effects (please give me any
example?) or it's just not yet done optimization?


Re: plpgsql and logical expression evaluation

From
Martijn van Oosterhout
Date:
On Tue, Apr 22, 2008 at 02:41:50AM -0700, wstrzalka wrote:
> One of the annoying things in plpgsql is logical expression
> evaluation.
>
> In most (all??) languages I know, logical expression like:
>
>      if ( [A_true_expression] or [B_false_expression] ) then
>
> will stop evaluating when the A expression will be evaluated as a
> TRUE.

I guess you should complain to the SQL design comittee, SQL is a
declarative language not a procedural language and the order of the
expressions in AND/OR is not important to the evaluation.

> It don't work for insert as the part designed for UPDATE will be
> evaluated, while there is no OLD for an insert operation.
> So the code looks like that:
>
> IF (TG_OP = 'INSERT') THEN
>         -- DO SOMETHING
> ELSIF  (TG_OP = 'UPDATE' AND NEW.status <> OLD.status) THEN
>         -- DO THE SAME AS ABOVE
> END IF;

You could use a flag variable.

> Is there any reason for that like side effects (please give me any
> example?) or it's just not yet done optimization?

The spec explicitly says it doesn't matter and it removes the
possibility of optimisation (in many queries it is important that the
optimiser can execute conditions in any order it likes).

Have a nice day,
--
Martijn van Oosterhout   <kleptog@svana.org>   http://svana.org/kleptog/
> Please line up in a tree and maintain the heap invariant while
> boarding. Thank you for flying nlogn airlines.

Attachment

Re: plpgsql and logical expression evaluation

From
Alvaro Herrera
Date:
Martijn van Oosterhout escribió:
> On Tue, Apr 22, 2008 at 02:41:50AM -0700, wstrzalka wrote:
> > One of the annoying things in plpgsql is logical expression
> > evaluation.
> >
> > In most (all??) languages I know, logical expression like:
> >
> >      if ( [A_true_expression] or [B_false_expression] ) then
> >
> > will stop evaluating when the A expression will be evaluated as a
> > TRUE.
>
> I guess you should complain to the SQL design comittee, SQL is a
> declarative language not a procedural language and the order of the
> expressions in AND/OR is not important to the evaluation.

While I agree with that in principle, we should by now start getting
used to the idea that PL/pgSQL is a different language from SQL.  For
example, SELECT INTO are totally different in both languages.  So are
BEGIN and END, and then there are loads of procedural constructs not
found on SQL at all.

I think this business of non-shortcircuiting boolean operators is just
an artifact of the fact that PL/pgSQL hands off expression to the SQL
engine for evaluation.

Perhaps SQL/PSM is designed differently (I haven't checked), or PL/SQL
words differently on Oracle.  If either of these cases is true, we will
need to attack the problem sooner or later.

--
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.

Re: plpgsql and logical expression evaluation

From
Tom Lane
Date:
Alvaro Herrera <alvherre@commandprompt.com> writes:
> I think this business of non-shortcircuiting boolean operators is just
> an artifact of the fact that PL/pgSQL hands off expression to the SQL
> engine for evaluation.

The complainant is not actually complaining about non-shortcircuiting
boolean operators --- he thinks he is, but he's 100% mistaken.  The
reason he's got a problem in the given example is that plpgsql has to
provide parameter values for every parameter in the whole expression
before it ships it off to the main engine.  ExecEvalAnd actually *does*
know about short-circuiting, but it doesn't help because control never
gets that far.

Even if we rejiggered things so that supplying parameter values could be
done lazily, there's the little problem that we can't even parse the
expression without knowing the types of the parameters.  The correct
analogy for what the OP tried to do is writing in C

    if (x == 0 || no_such_var == 0)

and expecting the "undefined variable no_such_var" failure not to be
reported if x is zero.  Since it's happening at compile time, that's
not going to happen.

            regards, tom lane

Re: plpgsql and logical expression evaluation

From
wstrzalka
Date:
On 23 Kwi, 16:32, t...@sss.pgh.pa.us (Tom Lane) wrote:
> Alvaro Herrera <alvhe...@commandprompt.com> writes:
> > I think this business of non-shortcircuiting boolean operators is just
> > an artifact of the fact that PL/pgSQL hands off expression to the SQL
> > engine for evaluation.
>
> The complainant is not actually complaining about non-shortcircuiting
> boolean operators --- he thinks he is, but he's 100% mistaken.  The
> reason he's got a problem in the given example is that plpgsql has to
> provide parameter values for every parameter in the whole expression
> before it ships it off to the main engine.  ExecEvalAnd actually *does*
> know about short-circuiting, but it doesn't help because control never
> gets that far.
>
> Even if we rejiggered things so that supplying parameter values could be
> done lazily, there's the little problem that we can't even parse the
> expression without knowing the types of the parameters.  The correct
> analogy for what the OP tried to do is writing in C
>
>         if (x == 0 || no_such_var == 0)
>
> and expecting the "undefined variable no_such_var" failure not to be
> reported if x is zero.  Since it's happening at compile time, that's
> not going to happen.
>
>                         regards, tom lane
>
> --
> Sent via pgsql-general mailing list (pgsql-gene...@postgresql.org)
> To make changes to your subscription:http://www.postgresql.org/mailpref/pgsql-general

Yes. You are right. I didn't realized what my complain was about.
But the 'no_such_var' example is great and explains what I was trying
to do, and why it doesn't work.

So - does it mean that the whole IF-ELSE-ENDIF is not parsed at once -
but lazy-parsed when the control reaches it, while the IF condition is
parsed as a single expression and therefore I get error in this case?



Thanks a lot.

                         regards
                                 wojtek

Re: plpgsql and logical expression evaluation

From
Tom Lane
Date:
wstrzalka <wstrzalka@gmail.com> writes:
> So - does it mean that the whole IF-ELSE-ENDIF is not parsed at once -
> but lazy-parsed when the control reaches it, while the IF condition is
> parsed as a single expression and therefore I get error in this case?

Right, for a suitable definition of "parsed".  There is some trivial
syntax checking that happens early (eg, you'll see complaints for
mismatched parentheses) but actually trying to determine the meaning
of an expression happens when control first gets there.

            regards, tom lane