In Postgres, does the EXISTS
operator have the highest precedence of all? For example:
SELECT 1 + EXISTS (SELECT 1)::int;
It seems to be missing from the manual page. Though the highest one is ::
, meaning EXISTS
would be higher?
In other words, it evaluates it like this:
select (exists (select 1))::int;
And not like this, which, if you try, will error:
select exists ((select 1)::int);
Meaning that the EXISTS
operator has higher precedence than the CAST
operator. Is this correct?
2
Answers
This is not a matter of operator precedence but of how a grammar is parsed, in this case SQL. Let's step back a bit and take a basic arithmetic example for this:
If we ignore operator precedence, there are two valid ways to parse this statement:
And:
Both of these are valid parses. Operator precedence is used when there are multiple valid parses to resolve ambiguity. Notice, however, that the following is not a valid parse:
So before we bring in operator precedence to resolve ambiguities, we must first have a validly parsed expression.
Now we'll return back to the question at hand. We will modify it slightly as well so that the literal used is not castable to an
INT
:In the question, it was assumed that there may be two possible ways to validly parse this statement:
And:
But in fact, the latter parse is invalid, the
<subselect>::INT
will return anINT
(or runtime error), not a sub-select, and so (substituting a placeholder value of1
to make it more clear)SELECT EXISTS 1
is not a valid statement.In other words, you only have one valid parse, and so operator precedence is totally irrelevant.
Here is an example Antlr program that demonstrates this (you can copy-paste it into this site to view, though it doesn't allow you to save-and-share the grammar like most pastebin sites do):
Let's now take a different query that does show operator precedence in action:
Here it can be parsed in two ways:
And:
Here the first approach is used since the
::
operator has higher precedence thanNOT
. In this way, ironically, theEXISTS
is applied before the cast operation, though theNOT
is applied after the cast operation. TheEXISTS
is applied first because there is only one possible grammatical parse, whereas with theNOT
there are two possible parses, and so we use operator precedence to resolve ambiguity.You can view both example queries for the grammar here.
And both parse trees in Antlr if useful:
The elephant in the room:
EXISTS
is not an operator in Postgres, technically speaking.It’s a syntax element. The manual lists it in the chapter "Subquery Expressions". Operator precedence does not apply.
EXISTS
"binds" before any operator. The Postgres source code uses the term "SubLink" for this kind of plan node.Accordingly, you’ll also find no corresponding entry in
pg_operator
.Also accordingly, in your example,
::
ranking number 2 in operator precedence doesn’t make the cut. Your test isn’t ideal, though. Either precedence would result in integer 1:This is unambiguous:
Would error out, if
::int
took precedence – like this does:In case you still want more proof: even the number 1 in the operator precedence ranking, the column separator (
.
), can’t overcome the gravitational pull ofEXISTS
:fiddle
The second
SELECT
would try to append.id
to the boolean valuetrue
, which is a syntax error.