diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml index 9675adcbf86252632224a4a40a0bcd31aaa17e46..d67d2b4ff764036e3ee8179de7aba6bff0c10cee 100644 --- a/doc/src/sgml/ref/select.sgml +++ b/doc/src/sgml/ref/select.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.122 2009/05/03 20:45:43 tgl Exp $ +$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.123 2009/08/18 23:40:20 tgl Exp $ PostgreSQL documentation --> @@ -1005,14 +1005,15 @@ OFFSET <replaceable class="parameter">start</replaceable> <para> SQL:2008 introduced a different syntax to achieve the same thing, - which PostgreSQL also supports. It is: + which <productname>PostgreSQL</> also supports. It is: <synopsis> OFFSET <replaceable class="parameter">start</replaceable> { ROW | ROWS } FETCH { FIRST | NEXT } [ <replaceable class="parameter">count</replaceable> ] { ROW | ROWS } ONLY </synopsis> - Both clauses are optional, but if present - the <literal>OFFSET</literal> clause must come before - the <literal>FETCH</literal> clause. <literal>ROW</literal> + According to the standard, the <literal>OFFSET</literal> clause must come + before the <literal>FETCH</literal> clause if both are present; but + <productname>PostgreSQL</> is laxer and allows either order. + <literal>ROW</literal> and <literal>ROWS</literal> as well as <literal>FIRST</literal> and <literal>NEXT</literal> are noise words that don't influence the effects of these clauses. In this syntax, when using expressions diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 6e52d3bcbd37ac42ef2ace2b04bd11bc71aabe00..ebf5b5d6455c2f16d5698039704fdf583d5db969 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.676 2009/08/02 22:14:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.677 2009/08/18 23:40:20 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -331,7 +331,8 @@ static TypeName *TableFuncTypeName(List *columns); %type <ival> opt_column event cursor_options opt_hold opt_set_data %type <objtype> reindex_type drop_type comment_type -%type <node> fetch_direction select_limit_value select_offset_value +%type <node> fetch_direction limit_clause select_limit_value + offset_clause select_offset_value select_offset_value2 opt_select_fetch_first_value %type <ival> row_or_rows first_or_next @@ -7228,14 +7229,20 @@ sortby: a_expr USING qual_all_Op opt_nulls_order select_limit: - LIMIT select_limit_value OFFSET select_offset_value - { $$ = list_make2($4, $2); } - | OFFSET select_offset_value LIMIT select_limit_value - { $$ = list_make2($2, $4); } - | LIMIT select_limit_value - { $$ = list_make2(NULL, $2); } - | OFFSET select_offset_value - { $$ = list_make2($2, NULL); } + limit_clause offset_clause { $$ = list_make2($2, $1); } + | offset_clause limit_clause { $$ = list_make2($1, $2); } + | limit_clause { $$ = list_make2(NULL, $1); } + | offset_clause { $$ = list_make2($1, NULL); } + ; + +opt_select_limit: + select_limit { $$ = $1; } + | /* EMPTY */ { $$ = list_make2(NULL,NULL); } + ; + +limit_clause: + LIMIT select_limit_value + { $$ = $2; } | LIMIT select_limit_value ',' select_offset_value { /* Disabled because it was too confusing, bjm 2002-02-18 */ @@ -7245,19 +7252,17 @@ select_limit: errhint("Use separate LIMIT and OFFSET clauses."), parser_errposition(@1))); } - /* SQL:2008 syntax variants */ - | OFFSET select_offset_value2 row_or_rows - { $$ = list_make2($2, NULL); } + /* SQL:2008 syntax */ | FETCH first_or_next opt_select_fetch_first_value row_or_rows ONLY - { $$ = list_make2(NULL, $3); } - | OFFSET select_offset_value2 row_or_rows FETCH first_or_next opt_select_fetch_first_value row_or_rows ONLY - { $$ = list_make2($2, $6); } + { $$ = $3; } ; -opt_select_limit: - select_limit { $$ = $1; } - | /* EMPTY */ - { $$ = list_make2(NULL,NULL); } +offset_clause: + OFFSET select_offset_value + { $$ = $2; } + /* SQL:2008 syntax */ + | OFFSET select_offset_value2 row_or_rows + { $$ = $2; } ; select_limit_value: @@ -7269,19 +7274,20 @@ select_limit_value: } ; +select_offset_value: + a_expr { $$ = $1; } + ; + /* * 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. + * 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); } - ; - -select_offset_value: - a_expr { $$ = $1; } + SignedIconst { $$ = makeIntConst($1, @1); } + | '(' a_expr ')' { $$ = $2; } + | /*EMPTY*/ { $$ = makeIntConst(1, -1); } ; /* @@ -7293,16 +7299,14 @@ select_offset_value2: ; /* noise words */ -row_or_rows: - ROW { $$ = 0; } - | ROWS { $$ = 0; } - ; +row_or_rows: ROW { $$ = 0; } + | ROWS { $$ = 0; } + ; + +first_or_next: FIRST_P { $$ = 0; } + | NEXT { $$ = 0; } + ; -/* noise words */ -first_or_next: - FIRST_P { $$ = 0; } - | NEXT { $$ = 0; } - ; group_clause: GROUP_P BY expr_list { $$ = $3; }