*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.155 2003/06/16 02:03:37 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.156 2003/07/03 19:07:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define EXPRKIND_QUAL 0
#define EXPRKIND_TARGET 1
#define EXPRKIND_RTFUNC 2
-#define EXPRKIND_ININFO 3
+#define EXPRKIND_LIMIT 3
+#define EXPRKIND_ININFO 4
static Node *preprocess_expression(Query *parse, Node *expr, int kind);
parse->havingQual = preprocess_expression(parse, parse->havingQual,
EXPRKIND_QUAL);
+ parse->limitOffset = preprocess_expression(parse, parse->limitOffset,
+ EXPRKIND_LIMIT);
+ parse->limitCount = preprocess_expression(parse, parse->limitCount,
+ EXPRKIND_LIMIT);
+
parse->in_info_list = (List *)
preprocess_expression(parse, (Node *) parse->in_info_list,
EXPRKIND_ININFO);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.145 2003/07/03 16:33:07 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.146 2003/07/03 19:07:25 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
return true;
if (walker(query->havingQual, context))
return true;
+ if (walker(query->limitOffset, context))
+ return true;
+ if (walker(query->limitCount, context))
+ return true;
if (walker(query->in_info_list, context))
return true;
foreach(rt, query->rtable)
MUTATE(query->jointree, query->jointree, FromExpr *);
MUTATE(query->setOperations, query->setOperations, Node *);
MUTATE(query->havingQual, query->havingQual, Node *);
+ MUTATE(query->limitOffset, query->limitOffset, Node *);
+ MUTATE(query->limitCount, query->limitCount, Node *);
MUTATE(query->in_info_list, query->in_info_list, List *);
FastListInit(&newrt);
foreach(rt, query->rtable)
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.277 2003/06/25 04:19:24 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.278 2003/07/03 19:07:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
qry->distinctClause = NIL;
/* fix where clause */
- qual = transformWhereClause(pstate, stmt->whereClause);
+ qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
/* done building the range table and jointree */
qry->rtable = pstate->p_rtable;
/* no to join list, yes to namespace */
addRTEtoQuery(pstate, rte, false, true);
- stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause,
+ "WHERE");
}
/* take care of any index expressions */
}
/* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause,
+ "WHERE");
if (length(pstate->p_rtable) != 2) /* naughty, naughty... */
elog(ERROR, "Rule WHERE condition may not contain references to other relations");
markTargetListOrigins(pstate, qry->targetList);
/* transform WHERE */
- qual = transformWhereClause(pstate, stmt->whereClause);
+ qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
/*
* Initial processing of HAVING clause is just like WHERE clause.
* Additional work will be done in optimizer/plan/planner.c.
*/
- qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
+ qry->havingQual = transformWhereClause(pstate, stmt->havingClause,
+ "HAVING");
/*
* Transform sorting/grouping stuff. Do ORDER BY first because both
qry->targetList,
&qry->sortClause);
- qry->limitOffset = stmt->limitOffset;
- qry->limitCount = stmt->limitCount;
+ qry->limitOffset = transformLimitClause(pstate, stmt->limitOffset,
+ "OFFSET");
+ qry->limitCount = transformLimitClause(pstate, stmt->limitCount,
+ "LIMIT");
qry->rtable = pstate->p_rtable;
qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
if (tllen != length(qry->targetList))
elog(ERROR, "ORDER BY on a UNION/INTERSECT/EXCEPT result must be on one of the result columns");
- qry->limitOffset = limitOffset;
- qry->limitCount = limitCount;
+ qry->limitOffset = transformLimitClause(pstate, limitOffset,
+ "OFFSET");
+ qry->limitCount = transformLimitClause(pstate, limitCount,
+ "LIMIT");
qry->rtable = pstate->p_rtable;
qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
qry->targetList = transformTargetList(pstate, stmt->targetList);
- qual = transformWhereClause(pstate, stmt->whereClause);
+ qual = transformWhereClause(pstate, stmt->whereClause, "WHERE");
qry->rtable = pstate->p_rtable;
qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.425 2003/07/03 16:33:37 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.426 2003/07/03 19:07:36 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
| OFFSET select_offset_value
{ $$ = makeList2($2, NULL); }
| LIMIT select_limit_value ',' select_offset_value
- /* Disabled because it was too confusing, bjm 2002-02-18 */
- { elog(ERROR,
- "LIMIT #,# syntax not supported.\n\tUse separate LIMIT and OFFSET clauses."); }
+ {
+ /* Disabled because it was too confusing, bjm 2002-02-18 */
+ elog(ERROR,
+ "LIMIT #,# syntax not supported.\n\tUse separate LIMIT and OFFSET clauses.");
+ }
;
-
opt_select_limit:
select_limit { $$ = $1; }
| /* EMPTY */
;
select_limit_value:
- Iconst
- {
- Const *n = makeNode(Const);
-
- if ($1 < 0)
- elog(ERROR, "LIMIT must not be negative");
-
- n->consttype = INT4OID;
- n->constlen = sizeof(int4);
- n->constvalue = Int32GetDatum($1);
- n->constisnull = FALSE;
- n->constbyval = TRUE;
- $$ = (Node *)n;
- }
+ a_expr { $$ = $1; }
| ALL
{
/* LIMIT ALL is represented as a NULL constant */
- Const *n = makeNode(Const);
-
- n->consttype = INT4OID;
- n->constlen = sizeof(int4);
- n->constvalue = (Datum) 0;
- n->constisnull = TRUE;
- n->constbyval = TRUE;
- $$ = (Node *)n;
- }
- | PARAM
- {
- Param *n = makeNode(Param);
-
- n->paramkind = PARAM_NUM;
- n->paramid = $1;
- n->paramtype = INT4OID;
+ A_Const *n = makeNode(A_Const);
+ n->val.type = T_Null;
$$ = (Node *)n;
}
;
select_offset_value:
- Iconst
- {
- Const *n = makeNode(Const);
-
- if ($1 < 0)
- elog(ERROR, "OFFSET must not be negative");
-
- n->consttype = INT4OID;
- n->constlen = sizeof(int4);
- n->constvalue = Int32GetDatum($1);
- n->constisnull = FALSE;
- n->constbyval = TRUE;
- $$ = (Node *)n;
- }
- | PARAM
- {
- Param *n = makeNode(Param);
-
- n->paramkind = PARAM_NUM;
- n->paramid = $1;
- n->paramtype = INT4OID;
- $$ = (Node *)n;
- }
+ a_expr { $$ = $1; }
;
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.116 2003/06/16 02:03:37 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.117 2003/07/03 19:07:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
save_namespace = pstate->p_namespace;
pstate->p_namespace = makeList2(j->larg, j->rarg);
- /* This part is just like transformWhereClause() */
- result = transformExpr(pstate, j->quals);
-
- result = coerce_to_boolean(pstate, result, "JOIN/ON");
+ result = transformWhereClause(pstate, j->quals, "JOIN/ON");
pstate->p_namespace = save_namespace;
/*
* transformWhereClause -
- * transforms the qualification and make sure it is of type Boolean
+ * Transform the qualification and make sure it is of type boolean.
+ * Used for WHERE and allied clauses.
+ *
+ * constructName does not affect the semantics, but is used in error messages
+ */
+Node *
+transformWhereClause(ParseState *pstate, Node *clause,
+ const char *constructName)
+{
+ Node *qual;
+
+ if (clause == NULL)
+ return NULL;
+
+ qual = transformExpr(pstate, clause);
+
+ qual = coerce_to_boolean(pstate, qual, constructName);
+
+ return qual;
+}
+
+
+/*
+ * transformLimitClause -
+ * Transform the expression and make sure it is of type integer.
+ * Used for LIMIT and allied clauses.
+ *
+ * constructName does not affect the semantics, but is used in error messages
*/
Node *
-transformWhereClause(ParseState *pstate, Node *clause)
+transformLimitClause(ParseState *pstate, Node *clause,
+ const char *constructName)
{
Node *qual;
qual = transformExpr(pstate, clause);
- qual = coerce_to_boolean(pstate, qual, "WHERE");
+ qual = coerce_to_integer(pstate, qual, constructName);
+
+ /*
+ * LIMIT can't refer to any vars or aggregates of the current query;
+ * we don't allow subselects either (though that case would at least
+ * be sensible)
+ */
+ if (contain_vars_of_level(qual, 0))
+ {
+ /* translator: %s is name of a SQL construct, eg LIMIT */
+ elog(ERROR, "argument of %s must not contain variables",
+ constructName);
+ }
+ if (checkExprHasAggs(qual))
+ {
+ /* translator: %s is name of a SQL construct, eg LIMIT */
+ elog(ERROR, "argument of %s must not contain aggregates",
+ constructName);
+ }
+ if (contain_subplans(qual))
+ {
+ /* translator: %s is name of a SQL construct, eg LIMIT */
+ elog(ERROR, "argument of %s must not contain subselects",
+ constructName);
+ }
return qual;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.102 2003/07/01 19:10:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.103 2003/07/03 19:07:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (node == NULL)
{
/* translator: first %s is name of a SQL construct, eg WHERE */
- elog(ERROR, "Argument of %s must be type boolean, not type %s",
+ elog(ERROR, "argument of %s must be type boolean, not type %s",
constructName, format_type_be(inputTypeId));
}
}
if (expression_returns_set(node))
{
/* translator: %s is name of a SQL construct, eg WHERE */
- elog(ERROR, "Argument of %s must not be a set function",
+ elog(ERROR, "argument of %s must not be a set function",
+ constructName);
+ }
+
+ return node;
+}
+
+/* coerce_to_integer()
+ * Coerce an argument of a construct that requires integer input
+ * (LIMIT, OFFSET, etc). Also check that input is not a set.
+ *
+ * Returns the possibly-transformed node tree.
+ *
+ * As with coerce_type, pstate may be NULL if no special unknown-Param
+ * processing is wanted.
+ */
+Node *
+coerce_to_integer(ParseState *pstate, Node *node,
+ const char *constructName)
+{
+ Oid inputTypeId = exprType(node);
+
+ if (inputTypeId != INT4OID)
+ {
+ node = coerce_to_target_type(pstate, node, inputTypeId,
+ INT4OID, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST);
+ if (node == NULL)
+ {
+ /* translator: first %s is name of a SQL construct, eg LIMIT */
+ elog(ERROR, "argument of %s must be type integer, not type %s",
+ constructName, format_type_be(inputTypeId));
+ }
+ }
+
+ if (expression_returns_set(node))
+ {
+ /* translator: %s is name of a SQL construct, eg LIMIT */
+ elog(ERROR, "argument of %s must not be a set function",
constructName);
}
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_clause.h,v 1.32 2003/06/16 02:03:38 tgl Exp $
+ * $Id: parse_clause.h,v 1.33 2003/07/03 19:07:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool inh, bool alsoSource);
extern bool interpretInhOption(InhOption inhOpt);
-extern Node *transformWhereClause(ParseState *pstate, Node *where);
+extern Node *transformWhereClause(ParseState *pstate, Node *clause,
+ const char *constructName);
+extern Node *transformLimitClause(ParseState *pstate, Node *clause,
+ const char *constructName);
extern List *transformGroupClause(ParseState *pstate, List *grouplist,
List *targetlist, List *sortClause);
extern List *transformSortClause(ParseState *pstate, List *orderlist,
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_coerce.h,v 1.52 2003/07/01 19:10:53 tgl Exp $
+ * $Id: parse_coerce.h,v 1.53 2003/07/03 19:07:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Node *coerce_to_boolean(ParseState *pstate, Node *node,
const char *constructName);
+extern Node *coerce_to_integer(ParseState *pstate, Node *node,
+ const char *constructName);
extern Oid select_common_type(List *typeids, const char *context);
extern Node *coerce_to_common_type(ParseState *pstate, Node *node,