@ -127,6 +127,14 @@ typedef struct ImportQual
List *table_names;
} ImportQual;
/* Private struct for the result of opt_select_limit production */
typedef struct SelectLimit
{
Node *limitOffset;
Node *limitCount;
LimitOption limitOption;
} SelectLimit;
/* ConstraintAttributeSpec yields an integer bitmask of these flags: */
#define CAS_NOT_DEFERRABLE 0x01
#define CAS_DEFERRABLE 0x02
@ -164,7 +172,7 @@ static List *makeOrderedSetArgs(List *directargs, List *orderedargs,
core_yyscan_t yyscanner);
static void insertSelectOptions(SelectStmt *stmt,
List *sortClause, List *lockingClause,
Node *limitOffset, Node *limitCount ,
SelectLimit *limitClause ,
WithClause *withClause,
core_yyscan_t yyscanner);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
@ -242,6 +250,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
PartitionSpec *partspec;
PartitionBoundSpec *partboundspec;
RoleSpec *rolespec;
struct SelectLimit *selectlimit;
}
%type <node> stmt schema_stmt
@ -374,6 +383,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> import_qualification_type
%type <importqual> import_qualification
%type <node> vacuum_relation
%type <selectlimit> opt_select_limit select_limit limit_clause
%type <list> stmtblock stmtmulti
OptTableElementList TableElementList OptInherit definition
@ -394,8 +404,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
target_list opt_target_list insert_column_list set_target_list
set_clause_list set_clause
def_list operator_def_list indirection opt_indirection
reloption_list group_clause TriggerFuncArgs select_limit
opt_select_limit opclass_item_list opclass_drop_list
reloption_list group_clause TriggerFuncArgs opclass_item_list opclass_drop_list
opclass_purpose opt_opfamily transaction_mode_list_or_empty
OptTableFuncElementList TableFuncElementList opt_type_modifiers
prep_type_clause
@ -458,7 +467,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
comment_type_any_name comment_type_name
security_label_type_any_name security_label_type_name
%type <node> fetch_args limit_clause select_limit_value
%type <node> fetch_args select_limit_value
offset_clause select_offset_value
select_fetch_first_value I_or_F_const
%type <ival> row_or_rows first_or_next
@ -11378,14 +11387,14 @@ select_no_parens:
| select_clause sort_clause
{
insertSelectOptions((SelectStmt *) $1, $2, NIL,
NULL, NULL, NULL,
NULL, NULL,
yyscanner);
$$ = $1;
}
| select_clause opt_sort_clause for_locking_clause opt_select_limit
{
insertSelectOptions((SelectStmt *) $1, $2, $3,
list_nth( $4, 0), list_nth($4, 1) ,
$4,
NULL,
yyscanner);
$$ = $1;
@ -11393,7 +11402,7 @@ select_no_parens:
| select_clause opt_sort_clause select_limit opt_for_locking_clause
{
insertSelectOptions((SelectStmt *) $1, $2, $4,
list_nth( $3, 0), list_nth($3, 1) ,
$3,
NULL,
yyscanner);
$$ = $1;
@ -11401,7 +11410,7 @@ select_no_parens:
| with_clause select_clause
{
insertSelectOptions((SelectStmt *) $2, NULL, NIL,
NULL, NULL,
NULL,
$1,
yyscanner);
$$ = $2;
@ -11409,7 +11418,7 @@ select_no_parens:
| with_clause select_clause sort_clause
{
insertSelectOptions((SelectStmt *) $2, $3, NIL,
NULL, NULL,
NULL,
$1,
yyscanner);
$$ = $2;
@ -11417,7 +11426,7 @@ select_no_parens:
| with_clause select_clause opt_sort_clause for_locking_clause opt_select_limit
{
insertSelectOptions((SelectStmt *) $2, $3, $4,
list_nth( $5, 0), list_nth($5, 1) ,
$5,
$1,
yyscanner);
$$ = $2;
@ -11425,7 +11434,7 @@ select_no_parens:
| with_clause select_clause opt_sort_clause select_limit opt_for_locking_clause
{
insertSelectOptions((SelectStmt *) $2, $3, $5,
list_nth( $4, 0), list_nth($4, 1) ,
$4,
$1,
yyscanner);
$$ = $2;
@ -11719,20 +11728,44 @@ sortby: a_expr USING qual_all_Op opt_nulls_order
select_limit:
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); }
limit_clause offset_clause
{
$$ = $1;
($$)->limitOffset = $2;
}
| offset_clause limit_clause
{
$$ = $2;
($$)->limitOffset = $1;
}
| limit_clause
{
$$ = $1;
}
| offset_clause
{
SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
n->limitOffset = $1;
n->limitCount = NULL;
n->limitOption = LIMIT_OPTION_COUNT;
$$ = n;
}
;
opt_select_limit:
select_limit { $$ = $1; }
| /* EMPTY */ { $$ = list_make2(NULL,NULL); }
| /* EMPTY */ { $$ = NULL; }
;
limit_clause:
LIMIT select_limit_value
{ $$ = $2; }
{
SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
n->limitOffset = NULL;
n->limitCount = $2;
n->limitOption = LIMIT_OPTION_COUNT;
$$ = n;
}
| LIMIT select_limit_value ',' select_offset_value
{
/* Disabled because it was too confusing, bjm 2002-02-18 */
@ -11750,9 +11783,29 @@ limit_clause:
* we can see the ONLY token in the lookahead slot.
*/
| FETCH first_or_next select_fetch_first_value row_or_rows ONLY
{ $$ = $3; }
{
SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
n->limitOffset = NULL;
n->limitCount = $3;
n->limitOption = LIMIT_OPTION_COUNT;
$$ = n;
}
| FETCH first_or_next select_fetch_first_value row_or_rows WITH TIES
{
SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
n->limitOffset = NULL;
n->limitCount = $3;
n->limitOption = LIMIT_OPTION_WITH_TIES;
$$ = n;
}
| FETCH first_or_next row_or_rows ONLY
{ $$ = makeIntConst(1, -1); }
{
SelectLimit *n = (SelectLimit *) palloc(sizeof(SelectLimit));
n->limitOffset = NULL;
n->limitCount = makeIntConst(1, -1);
n->limitOption = LIMIT_OPTION_COUNT;
$$ = n;
}
;
offset_clause:
@ -16047,7 +16100,7 @@ makeOrderedSetArgs(List *directargs, List *orderedargs,
static void
insertSelectOptions(SelectStmt *stmt,
List *sortClause, List *lockingClause,
Node *limitOffset, Node *limitCount ,
SelectLimit *limitClause ,
WithClause *withClause,
core_yyscan_t yyscanner)
{
@ -16068,23 +16121,35 @@ insertSelectOptions(SelectStmt *stmt,
}
/* We can handle multiple locking clauses, though */
stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause);
if (limitOffset)
if (limitClause && limitClause->limit Offset)
{
if (stmt->limitOffset)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple OFFSET clauses not allowed"),
parser_errposition(exprLocation(limitOffset))));
stmt->limitOffset = limitOffset;
parser_errposition(exprLocation(limitClause->limit Offset))));
stmt->limitOffset = limitClause->limit Offset;
}
if (limitCount)
if (limitClause && limitClause->limitC ount)
{
if (stmt->limitCount)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple LIMIT clauses not allowed"),
parser_errposition(exprLocation(limitCount))));
stmt->limitCount = limitCount;
parser_errposition(exprLocation(limitClause->limitCount))));
stmt->limitCount = limitClause->limitCount;
}
if (limitClause && limitClause->limitOption != LIMIT_OPTION_DEFAULT)
{
if (stmt->limitOption)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple limit options not allowed")));
if (!stmt->sortClause && limitClause->limitOption == LIMIT_OPTION_WITH_TIES)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("WITH TIES options can not be specified without ORDER BY clause")));
stmt->limitOption = limitClause->limitOption;
}
if (withClause)
{