From: Andrew Gierth <andrew@tao11.riddles.org.uk>
To: pgsql-hackers@postgresql.org
Subject: Fix for FETCH FIRST syntax problems
Date: Sat, 19 May 2018 23:33:22 +0100
Message-ID: <877enz476l.fsf@news-spur.riddles.org.uk> (raw)
Per bug #15200, our support for sql2008 FETCH FIRST syntax is incomplete
to the extent that it should be regarded as a bug; the spec quite
clearly allows parameters/host variables in addition to constants, but
we don't.
Attached is a draft patch for fixing that, which additionally fixes the
ugly wart that OFFSET <x> ROW/ROWS and FETCH FIRST [<x>] ROW/ROWS ONLY
had very different productions for <x>; both now accept c_expr there.
Shift/reduce conflict is avoided by taking advantage of the fact that
ONLY is a fully reserved word.
I've checked that this change would not make it any harder to add
(post-2008 features) WITH TIES or PERCENT in the event that someone
wants to do that.
I think a case can be made that this should be backpatched; thoughts?
(While I can't find any visible change for existing working queries, one
change that does occur is that FETCH FIRST -1 ROWS ONLY now returns a
different error message; but that was already inconsistent with the
error from OFFSET -1 ROWS.)
--
Andrew (irc:RhodiumToad)
Attachments:ff.patch (text/x-patch, 3.7K) downloaddiff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgmlindex b5d3d3a071..330adb8c37 100644--- a/doc/src/sgml/ref/select.sgml+++ b/doc/src/sgml/ref/select.sgml@@ -1399,10 +1399,11 @@ OFFSET <replaceable class="parameter">start</replaceable>
OFFSET <replaceable class="parameter">start</replaceable> { ROW | ROWS }
FETCH { FIRST | NEXT } [ <replaceable class="parameter">count</replaceable> ] { ROW | ROWS } ONLY
</synopsis>
- In this syntax, to write anything except a simple integer constant for+ In this syntax, to write anything except a simple integer constant,+ parameter, or variable name for
<replaceable class="parameter">start</replaceable> or <replaceable
- class="parameter">count</replaceable>, you must write parentheses- around it.+ class="parameter">count</replaceable>, you should write parentheses+ around it (this is a <productname>PostgreSQL</productname> extension).
If <replaceable class="parameter">count</replaceable> is
omitted in a <literal>FETCH</literal> clause, it defaults to 1.
<literal>ROW</literal>
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.yindex babb62dae1..e441c555a4 100644--- a/src/backend/parser/gram.y+++ b/src/backend/parser/gram.y@@ -451,7 +451,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <node> fetch_args limit_clause select_limit_value
offset_clause select_offset_value
- select_offset_value2 opt_select_fetch_first_value+ select_fetch_first_value
%type <ival> row_or_rows first_or_next
%type <list> OptSeqOptList SeqOptList OptParenthesizedSeqOptList
@@ -11570,15 +11570,23 @@ limit_clause:
parser_errposition(@1)));
}
/* SQL:2008 syntax */
- | FETCH first_or_next opt_select_fetch_first_value row_or_rows ONLY+ /* to avoid shift/reduce conflicts, handle the optional value with+ * a separate production rather than an opt_ expression. The fact+ * that ONLY is fully reserved means that this way, we defer any+ * decision about what rule reduces ROW or ROWS to the point where+ * we can see the ONLY token in the lookahead slot.+ */+ | FETCH first_or_next select_fetch_first_value row_or_rows ONLY
{ $$ = $3; }
+ | FETCH first_or_next row_or_rows ONLY+ { $$ = makeIntConst(1, -1); }
;
offset_clause:
OFFSET select_offset_value
{ $$ = $2; }
/* SQL:2008 syntax */
- | OFFSET select_offset_value2 row_or_rows+ | OFFSET select_fetch_first_value row_or_rows
{ $$ = $2; }
;
@@ -11597,21 +11605,16 @@ select_offset_value:
/*
* Allowing full expressions without parentheses causes various parsing
- * problems with the trailing ROW/ROWS key words. SQL only calls for- * constants, so we allow the rest only with parentheses. If omitted,- * default to 1.- */-opt_select_fetch_first_value:- SignedIconst { $$ = makeIntConst($1, @1); }- | '(' a_expr ')' { $$ = $2; }- | /*EMPTY*/ { $$ = makeIntConst(1, -1); }- ;--/*- * Again, the trailing ROW/ROWS in this case prevent the full expression- * syntax. c_expr is the best we can do.+ * problems with the trailing ROW/ROWS key words. SQL spec only calls for+ * <simple value specification>, which is either a literal or a parameter (but+ * an <SQL parameter reference> could be an identifier, bringing up conflicts+ * with ROW/ROWS). We solve this by leveraging the presense of ONLY (see above)+ * to determine whether the expression is missing rather than trying to make it+ * optional in this rule.+ *+ * c_expr covers all the spec-required cases (and more).
*/
-select_offset_value2:+select_fetch_first_value:
c_expr { $$ = $1; }
;
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: andrew@tao11.riddles.org.uk
Subject: Re: Fix for FETCH FIRST syntax problems
In-Reply-To: <877enz476l.fsf@news-spur.riddles.org.uk>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox