*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.338 2008/08/25 22:42:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.339 2008/08/28 23:09:45 tgl Exp $
*
*
* INTERFACE ROUTINES
expr = coerce_to_target_type(pstate, expr, type_id,
atttypid, atttypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
* Copyright (c) 2002-2008, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.90 2008/08/25 22:42:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.91 2008/08/28 23:09:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
expr = coerce_to_target_type(pstate, expr, given_type_id,
expected_type_id, -1,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (expr == NULL)
ereport(ERROR,
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.263 2008/08/25 22:42:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.264 2008/08/28 23:09:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
typeOid,
typmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (defval == NULL) /* should not happen */
elog(ERROR, "failed to coerce base type to domain");
}
transform, exprType(transform),
targettype, targettypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (transform == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
defaultexpr, exprType(defaultexpr),
targettype, targettypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (defaultexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.122 2008/07/31 16:27:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.123 2008/08/28 23:09:45 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
domVal = makeNode(CoerceToDomainValue);
domVal->typeId = baseTypeOid;
domVal->typeMod = typMod;
+ domVal->location = -1; /* will be set when/if used */
pstate->p_value_substitute = (Node *) domVal;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.401 2008/08/22 00:16:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.402 2008/08/28 23:09:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
memcpy(newnode->fldname, from->fldname, _size); \
} while (0)
+/* Copy a parse location field (for Copy, this is same as scalar case) */
+#define COPY_LOCATION_FIELD(fldname) \
+ (newnode->fldname = from->fldname)
+
/* ****************************************************************
* plannodes.h copy functions
COPY_SCALAR_FIELD(varlevelsup);
COPY_SCALAR_FIELD(varnoold);
COPY_SCALAR_FIELD(varoattno);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(constisnull);
COPY_SCALAR_FIELD(constbyval);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(paramid);
COPY_SCALAR_FIELD(paramtype);
COPY_SCALAR_FIELD(paramtypmod);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(agglevelsup);
COPY_SCALAR_FIELD(aggstar);
COPY_SCALAR_FIELD(aggdistinct);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(funcretset);
COPY_SCALAR_FIELD(funcformat);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(opresulttype);
COPY_SCALAR_FIELD(opretset);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(opresulttype);
COPY_SCALAR_FIELD(opretset);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(opfuncid);
COPY_SCALAR_FIELD(useOr);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(boolop);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_NODE_FIELD(testexpr);
COPY_NODE_FIELD(operName);
COPY_NODE_FIELD(subselect);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(resulttype);
COPY_SCALAR_FIELD(resulttypmod);
COPY_SCALAR_FIELD(relabelformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_NODE_FIELD(arg);
COPY_SCALAR_FIELD(resulttype);
COPY_SCALAR_FIELD(coerceformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(resulttypmod);
COPY_SCALAR_FIELD(isExplicit);
COPY_SCALAR_FIELD(coerceformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_NODE_FIELD(arg);
COPY_SCALAR_FIELD(resulttype);
COPY_SCALAR_FIELD(convertformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_NODE_FIELD(arg);
COPY_NODE_FIELD(args);
COPY_NODE_FIELD(defresult);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_NODE_FIELD(expr);
COPY_NODE_FIELD(result);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(element_typeid);
COPY_NODE_FIELD(elements);
COPY_SCALAR_FIELD(multidims);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(row_typeid);
COPY_SCALAR_FIELD(row_format);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(coalescetype);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(minmaxtype);
COPY_SCALAR_FIELD(op);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(xmloption);
COPY_SCALAR_FIELD(type);
COPY_SCALAR_FIELD(typmod);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(opresulttype);
COPY_SCALAR_FIELD(opretset);
COPY_NODE_FIELD(args);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(resulttype);
COPY_SCALAR_FIELD(resulttypmod);
COPY_SCALAR_FIELD(coercionformat);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(typeId);
COPY_SCALAR_FIELD(typeMod);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(typeId);
COPY_SCALAR_FIELD(typeMod);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_NODE_FIELD(name);
COPY_NODE_FIELD(lexpr);
COPY_NODE_FIELD(rexpr);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
ColumnRef *newnode = makeNode(ColumnRef);
COPY_NODE_FIELD(fields);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
ParamRef *newnode = makeNode(ParamRef);
COPY_SCALAR_FIELD(number);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
break;
}
+ COPY_LOCATION_FIELD(location);
+
return newnode;
}
COPY_SCALAR_FIELD(agg_star);
COPY_SCALAR_FIELD(agg_distinct);
COPY_SCALAR_FIELD(func_variadic);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
A_ArrayExpr *newnode = makeNode(A_ArrayExpr);
COPY_NODE_FIELD(elements);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_STRING_FIELD(name);
COPY_NODE_FIELD(indirection);
COPY_NODE_FIELD(val);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_NODE_FIELD(typmods);
COPY_SCALAR_FIELD(typemod);
COPY_NODE_FIELD(arrayBounds);
- COPY_SCALAR_FIELD(location);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_NODE_FIELD(arg);
COPY_NODE_FIELD(typename);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
COPY_SCALAR_FIELD(xmloption);
COPY_NODE_FIELD(expr);
COPY_NODE_FIELD(typename);
+ COPY_LOCATION_FIELD(location);
return newnode;
}
* Currently, in fact, equal() doesn't know how to compare Plan trees
* either. This might need to be fixed someday.
*
+ * NOTE: it is intentional that parse location fields (in nodes that have
+ * one) are not compared. This is because we want, for example, a variable
+ * "x" to be considered equal() to another reference to "x" in the query.
+ *
*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.328 2008/08/22 00:16:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.329 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return false; \
} while (0)
+/* Compare a parse location field (this is a no-op, per note above) */
+#define COMPARE_LOCATION_FIELD(fldname) \
+ ((void) 0)
+
/*
* Stuff from primnodes.h
COMPARE_SCALAR_FIELD(varlevelsup);
COMPARE_SCALAR_FIELD(varnoold);
COMPARE_SCALAR_FIELD(varoattno);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(constlen);
COMPARE_SCALAR_FIELD(constisnull);
COMPARE_SCALAR_FIELD(constbyval);
+ COMPARE_LOCATION_FIELD(location);
/*
* We treat all NULL constants of the same type as equal. Someday this
COMPARE_SCALAR_FIELD(paramid);
COMPARE_SCALAR_FIELD(paramtype);
COMPARE_SCALAR_FIELD(paramtypmod);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(agglevelsup);
COMPARE_SCALAR_FIELD(aggstar);
COMPARE_SCALAR_FIELD(aggdistinct);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
return false;
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(opresulttype);
COMPARE_SCALAR_FIELD(opretset);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(opresulttype);
COMPARE_SCALAR_FIELD(opretset);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(useOr);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
{
COMPARE_SCALAR_FIELD(boolop);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_NODE_FIELD(testexpr);
COMPARE_NODE_FIELD(operName);
COMPARE_NODE_FIELD(subselect);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
b->relabelformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
b->coerceformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
b->coerceformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
b->convertformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
COMPARE_NODE_FIELD(arg);
COMPARE_NODE_FIELD(args);
COMPARE_NODE_FIELD(defresult);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
{
COMPARE_NODE_FIELD(expr);
COMPARE_NODE_FIELD(result);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(element_typeid);
COMPARE_NODE_FIELD(elements);
COMPARE_SCALAR_FIELD(multidims);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
b->row_format != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
{
COMPARE_SCALAR_FIELD(coalescetype);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(minmaxtype);
COMPARE_SCALAR_FIELD(op);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(xmloption);
COMPARE_SCALAR_FIELD(type);
COMPARE_SCALAR_FIELD(typmod);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(opresulttype);
COMPARE_SCALAR_FIELD(opretset);
COMPARE_NODE_FIELD(args);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
b->coercionformat != COERCE_DONTCARE)
return false;
+ COMPARE_LOCATION_FIELD(location);
+
return true;
}
{
COMPARE_SCALAR_FIELD(typeId);
COMPARE_SCALAR_FIELD(typeMod);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
{
COMPARE_SCALAR_FIELD(typeId);
COMPARE_SCALAR_FIELD(typeMod);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_NODE_FIELD(name);
COMPARE_NODE_FIELD(lexpr);
COMPARE_NODE_FIELD(rexpr);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
_equalColumnRef(ColumnRef *a, ColumnRef *b)
{
COMPARE_NODE_FIELD(fields);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
_equalParamRef(ParamRef *a, ParamRef *b)
{
COMPARE_SCALAR_FIELD(number);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
{
if (!equal(&a->val, &b->val)) /* hack for in-line Value field */
return false;
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(agg_star);
COMPARE_SCALAR_FIELD(agg_distinct);
COMPARE_SCALAR_FIELD(func_variadic);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
_equalA_ArrayExpr(A_ArrayExpr *a, A_ArrayExpr *b)
{
COMPARE_NODE_FIELD(elements);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(indirection);
COMPARE_NODE_FIELD(val);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_NODE_FIELD(typmods);
COMPARE_SCALAR_FIELD(typemod);
COMPARE_NODE_FIELD(arrayBounds);
- COMPARE_SCALAR_FIELD(location);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
{
COMPARE_NODE_FIELD(arg);
COMPARE_NODE_FIELD(typename);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
COMPARE_SCALAR_FIELD(xmloption);
COMPARE_NODE_FIELD(expr);
COMPARE_NODE_FIELD(typename);
+ COMPARE_LOCATION_FIELD(location);
return true;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.58 2008/01/01 19:45:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.59 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
var->varnoold = varno;
var->varoattno = varattno;
+ /* Likewise, we just set location to "unknown" here */
+ var->location = -1;
+
return var;
}
cnst->constvalue = constvalue;
cnst->constisnull = constisnull;
cnst->constbyval = constbyval;
+ cnst->location = -1; /* "unknown" */
return cnst;
}
* creates a BoolExpr node
*/
Expr *
-makeBoolExpr(BoolExprType boolop, List *args)
+makeBoolExpr(BoolExprType boolop, List *args, int location)
{
BoolExpr *b = makeNode(BoolExpr);
b->boolop = boolop;
b->args = args;
+ b->location = location;
return (Expr *) b;
}
r->resulttype = rtype;
r->resulttypmod = rtypmod;
r->relabelformat = rformat;
+ r->location = -1;
return r;
}
funcexpr->funcretset = false; /* only allowed case here */
funcexpr->funcformat = fformat;
funcexpr->args = args;
+ funcexpr->location = -1;
return funcexpr;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.30 2008/08/25 22:42:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.31 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static bool expression_returns_set_walker(Node *node, void *context);
+static int leftmostLoc(int loc1, int loc2);
/*
/*
+ * exprLocation -
+ * returns the parse location of an expression tree, for error reports
+ *
+ * -1 is returned if the location can't be determined.
+ *
+ * For expressions larger than a single token, the intent here is to
+ * return the location of the expression's leftmost token, not necessarily
+ * the topmost Node's location field. For example, an OpExpr's location
+ * field will point at the operator name, but if it is not a prefix operator
+ * then we should return the location of the left-hand operand instead.
+ * The reason is that we want to reference the entire expression not just
+ * that operator, and pointing to its start seems to be the most natural way.
+ *
+ * The location is not perfect --- for example, since the grammar doesn't
+ * explicitly represent parentheses in the parsetree, given something that
+ * had been written "(a + b) * c" we are going to point at "a" not "(".
+ * But it should be plenty good enough for error reporting purposes.
+ *
+ * You might think that this code is overly general, for instance why check
+ * the operands of a FuncExpr node, when the function name can be expected
+ * to be to the left of them? There are a couple of reasons. The grammar
+ * sometimes builds expressions that aren't quite what the user wrote;
+ * for instance x IS NOT BETWEEN ... becomes a NOT-expression whose keyword
+ * pointer is to the right of its leftmost argument. Also, nodes that were
+ * inserted implicitly by parse analysis (such as FuncExprs for implicit
+ * coercions) will have location -1, and so we can have odd combinations of
+ * known and unknown locations in a tree.
+ */
+int
+exprLocation(Node *expr)
+{
+ int loc;
+
+ if (expr == NULL)
+ return -1;
+ switch (nodeTag(expr))
+ {
+ case T_Var:
+ loc = ((Var *) expr)->location;
+ break;
+ case T_Const:
+ loc = ((Const *) expr)->location;
+ break;
+ case T_Param:
+ loc = ((Param *) expr)->location;
+ break;
+ case T_Aggref:
+ /* function name should always be the first thing */
+ loc = ((Aggref *) expr)->location;
+ break;
+ case T_ArrayRef:
+ /* just use array argument's location */
+ loc = exprLocation((Node *) ((ArrayRef *) expr)->refexpr);
+ break;
+ case T_FuncExpr:
+ {
+ FuncExpr *fexpr = (FuncExpr *) expr;
+
+ /* consider both function name and leftmost arg */
+ loc = leftmostLoc(fexpr->location,
+ exprLocation((Node *) fexpr->args));
+ }
+ break;
+ case T_OpExpr:
+ case T_DistinctExpr: /* struct-equivalent to OpExpr */
+ case T_NullIfExpr: /* struct-equivalent to OpExpr */
+ {
+ OpExpr *opexpr = (OpExpr *) expr;
+
+ /* consider both operator name and leftmost arg */
+ loc = leftmostLoc(opexpr->location,
+ exprLocation((Node *) opexpr->args));
+ }
+ break;
+ case T_ScalarArrayOpExpr:
+ {
+ ScalarArrayOpExpr *saopexpr = (ScalarArrayOpExpr *) expr;
+
+ /* consider both operator name and leftmost arg */
+ loc = leftmostLoc(saopexpr->location,
+ exprLocation((Node *) saopexpr->args));
+ }
+ break;
+ case T_BoolExpr:
+ {
+ BoolExpr *bexpr = (BoolExpr *) expr;
+
+ /*
+ * Same as above, to handle either NOT or AND/OR. We can't
+ * special-case NOT because of the way that it's used for
+ * things like IS NOT BETWEEN.
+ */
+ loc = leftmostLoc(bexpr->location,
+ exprLocation((Node *) bexpr->args));
+ }
+ break;
+ case T_SubLink:
+ {
+ SubLink *sublink = (SubLink *) expr;
+
+ /* check the testexpr, if any, and the operator/keyword */
+ loc = leftmostLoc(exprLocation(sublink->testexpr),
+ sublink->location);
+ }
+ break;
+ case T_FieldSelect:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((FieldSelect *) expr)->arg);
+ break;
+ case T_FieldStore:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((FieldStore *) expr)->arg);
+ break;
+ case T_RelabelType:
+ {
+ RelabelType *rexpr = (RelabelType *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(rexpr->location,
+ exprLocation((Node *) rexpr->arg));
+ }
+ break;
+ case T_CoerceViaIO:
+ {
+ CoerceViaIO *cexpr = (CoerceViaIO *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(cexpr->location,
+ exprLocation((Node *) cexpr->arg));
+ }
+ break;
+ case T_ArrayCoerceExpr:
+ {
+ ArrayCoerceExpr *cexpr = (ArrayCoerceExpr *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(cexpr->location,
+ exprLocation((Node *) cexpr->arg));
+ }
+ break;
+ case T_ConvertRowtypeExpr:
+ {
+ ConvertRowtypeExpr *cexpr = (ConvertRowtypeExpr *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(cexpr->location,
+ exprLocation((Node *) cexpr->arg));
+ }
+ break;
+ case T_CaseExpr:
+ /* CASE keyword should always be the first thing */
+ loc = ((CaseExpr *) expr)->location;
+ break;
+ case T_CaseWhen:
+ /* WHEN keyword should always be the first thing */
+ loc = ((CaseWhen *) expr)->location;
+ break;
+ case T_ArrayExpr:
+ /* the location points at ARRAY or [, which must be leftmost */
+ loc = ((ArrayExpr *) expr)->location;
+ break;
+ case T_RowExpr:
+ /* the location points at ROW or (, which must be leftmost */
+ loc = ((RowExpr *) expr)->location;
+ break;
+ case T_RowCompareExpr:
+ /* just use leftmost argument's location */
+ loc = exprLocation((Node *) ((RowCompareExpr *) expr)->largs);
+ break;
+ case T_CoalesceExpr:
+ /* COALESCE keyword should always be the first thing */
+ loc = ((CoalesceExpr *) expr)->location;
+ break;
+ case T_MinMaxExpr:
+ /* GREATEST/LEAST keyword should always be the first thing */
+ loc = ((MinMaxExpr *) expr)->location;
+ break;
+ case T_XmlExpr:
+ {
+ XmlExpr *xexpr = (XmlExpr *) expr;
+
+ /* consider both function name and leftmost arg */
+ loc = leftmostLoc(xexpr->location,
+ exprLocation((Node *) xexpr->args));
+ }
+ break;
+ case T_NullTest:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((NullTest *) expr)->arg);
+ break;
+ case T_BooleanTest:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((BooleanTest *) expr)->arg);
+ break;
+ case T_CoerceToDomain:
+ {
+ CoerceToDomain *cexpr = (CoerceToDomain *) expr;
+
+ /* Much as above */
+ loc = leftmostLoc(cexpr->location,
+ exprLocation((Node *) cexpr->arg));
+ }
+ break;
+ case T_CoerceToDomainValue:
+ loc = ((CoerceToDomainValue *) expr)->location;
+ break;
+ case T_SetToDefault:
+ loc = ((SetToDefault *) expr)->location;
+ break;
+ case T_TargetEntry:
+ /* just use argument's location */
+ loc = exprLocation((Node *) ((TargetEntry *) expr)->expr);
+ break;
+ case T_List:
+ {
+ /* report location of first list member that has a location */
+ ListCell *lc;
+
+ loc = -1; /* just to suppress compiler warning */
+ foreach(lc, (List *) expr)
+ {
+ loc = exprLocation((Node *) lfirst(lc));
+ if (loc >= 0)
+ break;
+ }
+ }
+ break;
+ case T_A_Expr:
+ {
+ A_Expr *aexpr = (A_Expr *) expr;
+
+ /* use leftmost of operator or left operand (if any) */
+ /* we assume right operand can't be to left of operator */
+ loc = leftmostLoc(aexpr->location,
+ exprLocation(aexpr->lexpr));
+ }
+ break;
+ case T_ColumnRef:
+ loc = ((ColumnRef *) expr)->location;
+ break;
+ case T_ParamRef:
+ loc = ((ParamRef *) expr)->location;
+ break;
+ case T_A_Const:
+ loc = ((A_Const *) expr)->location;
+ break;
+ case T_FuncCall:
+ {
+ FuncCall *fc = (FuncCall *) expr;
+
+ /* consider both function name and leftmost arg */
+ loc = leftmostLoc(fc->location,
+ exprLocation((Node *) fc->args));
+ }
+ break;
+ case T_A_ArrayExpr:
+ /* the location points at ARRAY or [, which must be leftmost */
+ loc = ((A_ArrayExpr *) expr)->location;
+ break;
+ case T_ResTarget:
+ /* we need not examine the contained expression (if any) */
+ loc = ((ResTarget *) expr)->location;
+ break;
+ case T_TypeCast:
+ {
+ TypeCast *tc = (TypeCast *) expr;
+
+ /*
+ * This could represent CAST(), ::, or TypeName 'literal',
+ * so any of the components might be leftmost.
+ */
+ loc = exprLocation(tc->arg);
+ loc = leftmostLoc(loc, tc->typename->location);
+ loc = leftmostLoc(loc, tc->location);
+ }
+ break;
+ case T_TypeName:
+ loc = ((TypeName *) expr)->location;
+ break;
+ case T_XmlSerialize:
+ /* XMLSERIALIZE keyword should always be the first thing */
+ loc = ((XmlSerialize *) expr)->location;
+ break;
+ default:
+ /* for any other node type it's just unknown... */
+ loc = -1;
+ break;
+ }
+ return loc;
+}
+
+/*
+ * leftmostLoc - support for exprLocation
+ *
+ * Take the minimum of two parse location values, but ignore unknowns
+ */
+static int
+leftmostLoc(int loc1, int loc2)
+{
+ if (loc1 < 0)
+ return loc2;
+ else if (loc2 < 0)
+ return loc1;
+ else
+ return Min(loc1, loc2);
+}
+
+
+/*
* Standard expression-tree walking support
*
* We used to have near-duplicate code in many different routines that
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.335 2008/08/22 00:16:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.336 2008/08/28 23:09:46 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
_outToken(str, node->fldname))
+/* Write a parse location field (actually same as INT case) */
+#define WRITE_LOCATION_FIELD(fldname) \
+ appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname)
+
/* Write a Node field */
#define WRITE_NODE_FIELD(fldname) \
(appendStringInfo(str, " :" CppAsString(fldname) " "), \
WRITE_UINT_FIELD(varlevelsup);
WRITE_UINT_FIELD(varnoold);
WRITE_INT_FIELD(varoattno);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_INT_FIELD(constlen);
WRITE_BOOL_FIELD(constbyval);
WRITE_BOOL_FIELD(constisnull);
+ WRITE_LOCATION_FIELD(location);
appendStringInfo(str, " :constvalue ");
if (node->constisnull)
WRITE_INT_FIELD(paramid);
WRITE_OID_FIELD(paramtype);
WRITE_INT_FIELD(paramtypmod);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_UINT_FIELD(agglevelsup);
WRITE_BOOL_FIELD(aggstar);
WRITE_BOOL_FIELD(aggdistinct);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_BOOL_FIELD(funcretset);
WRITE_ENUM_FIELD(funcformat, CoercionForm);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(opresulttype);
WRITE_BOOL_FIELD(opretset);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(opresulttype);
WRITE_BOOL_FIELD(opretset);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(opfuncid);
WRITE_BOOL_FIELD(useOr);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
_outToken(str, opstr);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_FIELD(testexpr);
WRITE_NODE_FIELD(operName);
WRITE_NODE_FIELD(subselect);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(resulttype);
WRITE_INT_FIELD(resulttypmod);
WRITE_ENUM_FIELD(relabelformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_FIELD(arg);
WRITE_OID_FIELD(resulttype);
WRITE_ENUM_FIELD(coerceformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_INT_FIELD(resulttypmod);
WRITE_BOOL_FIELD(isExplicit);
WRITE_ENUM_FIELD(coerceformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_FIELD(arg);
WRITE_OID_FIELD(resulttype);
WRITE_ENUM_FIELD(convertformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_FIELD(arg);
WRITE_NODE_FIELD(args);
WRITE_NODE_FIELD(defresult);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_FIELD(expr);
WRITE_NODE_FIELD(result);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(element_typeid);
WRITE_NODE_FIELD(elements);
WRITE_BOOL_FIELD(multidims);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_FIELD(args);
WRITE_OID_FIELD(row_typeid);
WRITE_ENUM_FIELD(row_format, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(coalescetype);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(minmaxtype);
WRITE_ENUM_FIELD(op, MinMaxOp);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_ENUM_FIELD(xmloption, XmlOptionType);
WRITE_OID_FIELD(type);
WRITE_INT_FIELD(typmod);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(opresulttype);
WRITE_BOOL_FIELD(opretset);
WRITE_NODE_FIELD(args);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(resulttype);
WRITE_INT_FIELD(resulttypmod);
WRITE_ENUM_FIELD(coercionformat, CoercionForm);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(typeId);
WRITE_INT_FIELD(typeMod);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_OID_FIELD(typeId);
WRITE_INT_FIELD(typeMod);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_BOOL_FIELD(agg_star);
WRITE_BOOL_FIELD(agg_distinct);
WRITE_BOOL_FIELD(func_variadic);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_ENUM_FIELD(xmloption, XmlOptionType);
WRITE_NODE_FIELD(expr);
WRITE_NODE_FIELD(typename);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_FIELD(typmods);
WRITE_INT_FIELD(typemod);
WRITE_NODE_FIELD(arrayBounds);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_FIELD(arg);
WRITE_NODE_FIELD(typename);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_FIELD(lexpr);
WRITE_NODE_FIELD(rexpr);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_TYPE("COLUMNREF");
WRITE_NODE_FIELD(fields);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_TYPE("PARAMREF");
WRITE_INT_FIELD(number);
+ WRITE_LOCATION_FIELD(location);
}
static void
appendStringInfo(str, " :val ");
_outValue(str, &(node->val));
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_NODE_TYPE("A_ARRAYEXPR");
WRITE_NODE_FIELD(elements);
+ WRITE_LOCATION_FIELD(location);
}
static void
WRITE_STRING_FIELD(name);
WRITE_NODE_FIELD(indirection);
WRITE_NODE_FIELD(val);
- WRITE_INT_FIELD(location);
+ WRITE_LOCATION_FIELD(location);
}
static void
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.212 2008/08/07 01:11:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.213 2008/08/28 23:09:46 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
* claimed to read them, but it was broken as well as unused.) We
* never read executor state trees, either.
*
+ * Parse location fields are written out by outfuncs.c, but only for
+ * possible debugging use. When reading a location field, we discard
+ * the stored value and set the location field to -1 (ie, "unknown").
+ * This is because nodes coming from a stored rule should not be thought
+ * to have a known location in the current query's text.
+ *
*-------------------------------------------------------------------------
*/
#include "postgres.h"
token = pg_strtok(&length); /* get field value */ \
local_node->fldname = nullable_string(token, length)
+/* Read a parse location field (and throw away the value, per notes above) */
+#define READ_LOCATION_FIELD(fldname) \
+ token = pg_strtok(&length); /* skip :fldname */ \
+ token = pg_strtok(&length); /* get field value */ \
+ local_node->fldname = -1 /* set field to "unknown" */
+
/* Read a Node field */
#define READ_NODE_FIELD(fldname) \
token = pg_strtok(&length); /* skip :fldname */ \
READ_UINT_FIELD(varlevelsup);
READ_UINT_FIELD(varnoold);
READ_INT_FIELD(varoattno);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_INT_FIELD(constlen);
READ_BOOL_FIELD(constbyval);
READ_BOOL_FIELD(constisnull);
+ READ_LOCATION_FIELD(location);
token = pg_strtok(&length); /* skip :constvalue */
if (local_node->constisnull)
READ_INT_FIELD(paramid);
READ_OID_FIELD(paramtype);
READ_INT_FIELD(paramtypmod);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_UINT_FIELD(agglevelsup);
READ_BOOL_FIELD(aggstar);
READ_BOOL_FIELD(aggdistinct);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_BOOL_FIELD(funcretset);
READ_ENUM_FIELD(funcformat, CoercionForm);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(opresulttype);
READ_BOOL_FIELD(opretset);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(opresulttype);
READ_BOOL_FIELD(opretset);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_BOOL_FIELD(useOr);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
elog(ERROR, "unrecognized boolop \"%.*s\"", length, token);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_NODE_FIELD(testexpr);
READ_NODE_FIELD(operName);
READ_NODE_FIELD(subselect);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(resulttype);
READ_INT_FIELD(resulttypmod);
READ_ENUM_FIELD(relabelformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_NODE_FIELD(arg);
READ_OID_FIELD(resulttype);
READ_ENUM_FIELD(coerceformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_INT_FIELD(resulttypmod);
READ_BOOL_FIELD(isExplicit);
READ_ENUM_FIELD(coerceformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_NODE_FIELD(arg);
READ_OID_FIELD(resulttype);
READ_ENUM_FIELD(convertformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_NODE_FIELD(arg);
READ_NODE_FIELD(args);
READ_NODE_FIELD(defresult);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_NODE_FIELD(expr);
READ_NODE_FIELD(result);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(element_typeid);
READ_NODE_FIELD(elements);
READ_BOOL_FIELD(multidims);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_NODE_FIELD(args);
READ_OID_FIELD(row_typeid);
READ_ENUM_FIELD(row_format, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(coalescetype);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(minmaxtype);
READ_ENUM_FIELD(op, MinMaxOp);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_ENUM_FIELD(xmloption, XmlOptionType);
READ_OID_FIELD(type);
READ_INT_FIELD(typmod);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(opresulttype);
READ_BOOL_FIELD(opretset);
READ_NODE_FIELD(args);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(resulttype);
READ_INT_FIELD(resulttypmod);
READ_ENUM_FIELD(coercionformat, CoercionForm);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(typeId);
READ_INT_FIELD(typeMod);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
READ_OID_FIELD(typeId);
READ_INT_FIELD(typeMod);
+ READ_LOCATION_FIELD(location);
READ_DONE();
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.246 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.247 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
temp->opresulttype = clause->opresulttype;
temp->opretset = clause->opretset;
temp->args = list_copy(clause->args);
+ temp->location = clause->location;
/* Commute it --- note this modifies the temp node in-place. */
CommuteOpExpr(temp);
t_list = lappend(t_list, temp);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.139 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.140 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
retval->paramid = i;
retval->paramtype = var->vartype;
retval->paramtypmod = var->vartypmod;
+ retval->location = -1;
return retval;
}
retval->paramid = i;
retval->paramtype = agg->aggtype;
retval->paramtypmod = -1;
+ retval->location = -1;
return retval;
}
retval->paramid = list_length(root->glob->paramlist);
retval->paramtype = paramtype;
retval->paramtypmod = paramtypmod;
+ retval->location = -1;
pitem = makeNode(PlannerParamItem);
pitem->item = (Node *) retval;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.58 2008/01/01 19:45:50 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.59 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
newopexpr->opresulttype = opexpr->opresulttype;
newopexpr->opretset = opexpr->opretset;
newopexpr->args = opexpr->args;
+ newopexpr->location = opexpr->location;
return (Expr *) newopexpr;
}
else
newopexpr->opfuncid = InvalidOid;
newopexpr->useOr = !saopexpr->useOr;
newopexpr->args = saopexpr->args;
+ newopexpr->location = saopexpr->location;
return (Expr *) newopexpr;
}
else
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.90 2008/06/19 00:46:04 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.91 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
InvalidOid, -1,
atttype,
COERCE_IMPLICIT_CAST,
+ -1,
false,
false);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.154 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.155 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
r->arg = (Expr *) var;
r->resulttype = context->parent_reltype;
r->convertformat = COERCE_IMPLICIT_CAST;
+ r->location = -1;
/* Make sure the Var node has the right type ID, too */
var->vartype = context->child_reltype;
return (Node *) r;
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ rowexpr->location = -1;
+
return (Node *) rowexpr;
}
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.265 2008/08/26 02:16:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.266 2008/08/28 23:09:46 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
expr->args = list_make2(leftop, rightop);
else
expr->args = list_make1(leftop);
+ expr->location = -1;
return (Expr *) expr;
}
expr->boolop = NOT_EXPR;
expr->args = list_make1(notclause);
+ expr->location = -1;
return (Expr *) expr;
}
expr->boolop = OR_EXPR;
expr->args = orclauses;
+ expr->location = -1;
return (Expr *) expr;
}
expr->boolop = AND_EXPR;
expr->args = andclauses;
+ expr->location = -1;
return (Expr *) expr;
}
newexpr->funcretset = expr->funcretset;
newexpr->funcformat = expr->funcformat;
newexpr->args = args;
+ newexpr->location = expr->location;
return (Node *) newexpr;
}
if (IsA(node, OpExpr))
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->args = args;
+ newexpr->location = expr->location;
return (Node *) newexpr;
}
if (IsA(node, DistinctExpr))
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
newexpr->args = args;
+ newexpr->location = expr->location;
return (Node *) newexpr;
}
if (IsA(node, BoolExpr))
newrelabel->resulttype = relabel->resulttype;
newrelabel->resulttypmod = relabel->resulttypmod;
newrelabel->relabelformat = relabel->relabelformat;
+ newrelabel->location = relabel->location;
return (Node *) newrelabel;
}
}
newexpr->arg = arg;
newexpr->resulttype = expr->resulttype;
newexpr->coerceformat = expr->coerceformat;
+ newexpr->location = expr->location;
return (Node *) newexpr;
}
if (IsA(node, ArrayCoerceExpr))
newexpr->resulttypmod = expr->resulttypmod;
newexpr->isExplicit = expr->isExplicit;
newexpr->coerceformat = expr->coerceformat;
+ newexpr->location = expr->location;
/*
* If constant argument and it's a binary-coercible or immutable
newcasewhen->expr = (Expr *) casecond;
newcasewhen->result = (Expr *) caseresult;
+ newcasewhen->location = oldcasewhen->location;
newargs = lappend(newargs, newcasewhen);
continue;
}
newcase->arg = (Expr *) newarg;
newcase->args = newargs;
newcase->defresult = (Expr *) defresult;
+ newcase->location = caseexpr->location;
return (Node *) newcase;
}
if (IsA(node, CaseTestExpr))
newarray->element_typeid = arrayexpr->element_typeid;
newarray->elements = newelems;
newarray->multidims = arrayexpr->multidims;
+ newarray->location = arrayexpr->location;
if (all_const)
return (Node *) evaluate_expr((Expr *) newarray,
newcoalesce = makeNode(CoalesceExpr);
newcoalesce->coalescetype = coalesceexpr->coalescetype;
newcoalesce->args = newargs;
+ newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
}
if (IsA(node, FieldSelect))
newexpr->funcretset = false;
newexpr->funcformat = COERCE_DONTCARE; /* doesn't matter */
newexpr->args = args;
+ newexpr->location = -1;
return evaluate_expr((Expr *) newexpr, result_type, result_typmod);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.77 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.78 2008/08/28 23:09:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ rowexpr->location = -1;
return (Node *) rowexpr;
}
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.377 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.378 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
static Query *transformValuesClause(ParseState *pstate, SelectStmt *stmt);
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
-static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
-static void getSetColTypes(ParseState *pstate, Node *node,
- List **colTypes, List **colTypmods);
+static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
+ List **colInfo);
static void applyColumnNames(List *dst, List *src);
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
static List *transformReturningList(ParseState *pstate, List *returningList);
{
Query *qry = makeNode(Query);
List *exprsLists = NIL;
- List **coltype_lists = NULL;
+ List **colexprs = NULL;
Oid *coltypes = NULL;
int sublist_length = -1;
List *newExprsLists;
{
/* Remember post-transformation length of first sublist */
sublist_length = list_length(sublist);
- /* and allocate arrays for column-type info */
- coltype_lists = (List **) palloc0(sublist_length * sizeof(List *));
+ /* and allocate arrays for per-column info */
+ colexprs = (List **) palloc0(sublist_length * sizeof(List *));
coltypes = (Oid *) palloc0(sublist_length * sizeof(Oid));
}
else if (sublist_length != list_length(sublist))
exprsLists = lappend(exprsLists, sublist);
+ /* Check for DEFAULT and build per-column expression lists */
i = 0;
foreach(lc2, sublist)
{
if (IsA(col, SetToDefault))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("DEFAULT can only appear in a VALUES list within INSERT")));
- coltype_lists[i] = lappend_oid(coltype_lists[i], exprType(col));
+ errmsg("DEFAULT can only appear in a VALUES list within INSERT"),
+ parser_errposition(pstate, exprLocation(col))));
+ colexprs[i] = lappend(colexprs[i], col);
i++;
}
}
*/
for (i = 0; i < sublist_length; i++)
{
- coltypes[i] = select_common_type(coltype_lists[i], "VALUES");
+ coltypes[i] = select_common_type(pstate, colexprs[i], "VALUES", NULL);
}
newExprsLists = NIL;
int leftmostRTI;
Query *leftmostQuery;
SetOperationStmt *sostmt;
+ List *socolinfo;
List *intoColNames = NIL;
List *sortClause;
Node *limitOffset;
/*
* Recursively transform the components of the tree.
*/
- sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt);
+ sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt,
+ &socolinfo);
Assert(sostmt && IsA(sostmt, SetOperationStmt));
qry->setOperations = (Node *) sostmt;
/*
* transformSetOperationTree
* Recursively transform leaves and internal nodes of a set-op tree
+ *
+ * In addition to returning the transformed node, we return a list of
+ * expression nodes showing the type, typmod, and location (for error messages)
+ * of each output column of the set-op node. This is used only during the
+ * internal recursion of this function. We use SetToDefault nodes for
+ * this purpose, since they carry exactly the fields needed, but any other
+ * expression node type would do as well.
*/
static Node *
-transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
+transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
+ List **colInfo)
{
bool isLeaf;
char selectName[32];
RangeTblEntry *rte;
RangeTblRef *rtr;
+ ListCell *tl;
/*
* Transform SelectStmt into a Query.
}
/*
+ * Extract information about the result columns.
+ */
+ *colInfo = NIL;
+ foreach(tl, selectQuery->targetList)
+ {
+ TargetEntry *tle = (TargetEntry *) lfirst(tl);
+ SetToDefault *cinfo;
+
+ if (tle->resjunk)
+ continue;
+ cinfo = makeNode(SetToDefault);
+ cinfo->typeId = exprType((Node *) tle->expr);
+ cinfo->typeMod = exprTypmod((Node *) tle->expr);
+ cinfo->location = exprLocation((Node *) tle->expr);
+ *colInfo = lappend(*colInfo, cinfo);
+ }
+
+ /*
* Make the leaf query be a subquery in the top-level rangetable.
*/
snprintf(selectName, sizeof(selectName), "*SELECT* %d",
{
/* Process an internal node (set operation node) */
SetOperationStmt *op = makeNode(SetOperationStmt);
- List *lcoltypes;
- List *rcoltypes;
- List *lcoltypmods;
- List *rcoltypmods;
- ListCell *lct;
- ListCell *rct;
- ListCell *lcm;
- ListCell *rcm;
+ List *lcolinfo;
+ List *rcolinfo;
+ ListCell *lci;
+ ListCell *rci;
const char *context;
context = (stmt->op == SETOP_UNION ? "UNION" :
/*
* Recursively transform the child nodes.
*/
- op->larg = transformSetOperationTree(pstate, stmt->larg);
- op->rarg = transformSetOperationTree(pstate, stmt->rarg);
+ op->larg = transformSetOperationTree(pstate, stmt->larg,
+ &lcolinfo);
+ op->rarg = transformSetOperationTree(pstate, stmt->rarg,
+ &rcolinfo);
/*
* Verify that the two children have the same number of non-junk
* columns, and determine the types of the merged output columns.
*/
- getSetColTypes(pstate, op->larg, &lcoltypes, &lcoltypmods);
- getSetColTypes(pstate, op->rarg, &rcoltypes, &rcoltypmods);
- if (list_length(lcoltypes) != list_length(rcoltypes))
+ if (list_length(lcolinfo) != list_length(rcolinfo))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("each %s query must have the same number of columns",
- context)));
- Assert(list_length(lcoltypes) == list_length(lcoltypmods));
- Assert(list_length(rcoltypes) == list_length(rcoltypmods));
+ context),
+ parser_errposition(pstate,
+ exprLocation((Node *) rcolinfo))));
+ *colInfo = NIL;
op->colTypes = NIL;
op->colTypmods = NIL;
op->groupClauses = NIL;
- /* don't have a "foreach4", so chase two of the lists by hand */
- lcm = list_head(lcoltypmods);
- rcm = list_head(rcoltypmods);
- forboth(lct, lcoltypes, rct, rcoltypes)
+ forboth(lci, lcolinfo, rci, rcolinfo)
{
- Oid lcoltype = lfirst_oid(lct);
- Oid rcoltype = lfirst_oid(rct);
- int32 lcoltypmod = lfirst_int(lcm);
- int32 rcoltypmod = lfirst_int(rcm);
+ SetToDefault *lcolinfo = (SetToDefault *) lfirst(lci);
+ SetToDefault *rcolinfo = (SetToDefault *) lfirst(rci);
+ Oid lcoltype = lcolinfo->typeId;
+ Oid rcoltype = rcolinfo->typeId;
+ int32 lcoltypmod = lcolinfo->typeMod;
+ int32 rcoltypmod = rcolinfo->typeMod;
+ Node *bestexpr;
+ SetToDefault *rescolinfo;
Oid rescoltype;
int32 rescoltypmod;
/* select common type, same as CASE et al */
- rescoltype = select_common_type(list_make2_oid(lcoltype, rcoltype),
- context);
+ rescoltype = select_common_type(pstate,
+ list_make2(lcolinfo, rcolinfo),
+ context,
+ &bestexpr);
/* if same type and same typmod, use typmod; else default */
if (lcoltype == rcoltype && lcoltypmod == rcoltypmod)
rescoltypmod = lcoltypmod;
else
rescoltypmod = -1;
+
+ /* verify the coercions are actually possible */
+ if (lcoltype != UNKNOWNOID)
+ (void) coerce_to_common_type(pstate, (Node *) lcolinfo,
+ rescoltype, context);
+ if (rcoltype != UNKNOWNOID)
+ (void) coerce_to_common_type(pstate, (Node *) rcolinfo,
+ rescoltype, context);
+
+ /* emit results */
+ rescolinfo = makeNode(SetToDefault);
+ rescolinfo->typeId = rescoltype;
+ rescolinfo->typeMod = rescoltypmod;
+ rescolinfo->location = ((SetToDefault *) bestexpr)->location;
+ *colInfo = lappend(*colInfo, rescolinfo);
+
op->colTypes = lappend_oid(op->colTypes, rescoltype);
op->colTypmods = lappend_int(op->colTypmods, rescoltypmod);
op->groupClauses = lappend(op->groupClauses, grpcl);
}
-
- lcm = lnext(lcm);
- rcm = lnext(rcm);
}
return (Node *) op;
}
/*
- * getSetColTypes
- * Get output column types/typmods of an (already transformed) set-op node
- */
-static void
-getSetColTypes(ParseState *pstate, Node *node,
- List **colTypes, List **colTypmods)
-{
- *colTypes = NIL;
- *colTypmods = NIL;
- if (IsA(node, RangeTblRef))
- {
- RangeTblRef *rtr = (RangeTblRef *) node;
- RangeTblEntry *rte = rt_fetch(rtr->rtindex, pstate->p_rtable);
- Query *selectQuery = rte->subquery;
- ListCell *tl;
-
- Assert(selectQuery != NULL);
- /* Get types of non-junk columns */
- foreach(tl, selectQuery->targetList)
- {
- TargetEntry *tle = (TargetEntry *) lfirst(tl);
-
- if (tle->resjunk)
- continue;
- *colTypes = lappend_oid(*colTypes,
- exprType((Node *) tle->expr));
- *colTypmods = lappend_int(*colTypmods,
- exprTypmod((Node *) tle->expr));
- }
- }
- else if (IsA(node, SetOperationStmt))
- {
- SetOperationStmt *op = (SetOperationStmt *) node;
-
- /* Result already computed during transformation of node */
- Assert(op->colTypes != NIL);
- *colTypes = op->colTypes;
- *colTypmods = op->colTypmods;
- }
- else
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
-}
-
-/*
* Attach column names from a ColumnDef list to a TargetEntry list
* (for CREATE TABLE AS)
*/
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.618 2008/07/18 03:32:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.619 2008/08/28 23:09:47 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
/*#define __YYSCLASS*/
static Node *makeColumnRef(char *relname, List *indirection, int location);
-static Node *makeTypeCast(Node *arg, TypeName *typename);
-static Node *makeStringConst(char *str);
-static Node *makeStringConstCast(char *str, TypeName *typename);
-static Node *makeIntConst(int val);
-static Node *makeFloatConst(char *str);
-static Node *makeBitStringConst(char *str);
-static Node *makeNullAConst(void);
-static Node *makeAConst(Value *v);
-static Node *makeBoolAConst(bool state);
+static Node *makeTypeCast(Node *arg, TypeName *typename, int location);
+static Node *makeStringConst(char *str, int location);
+static Node *makeStringConstCast(char *str, int location, TypeName *typename);
+static Node *makeIntConst(int val, int location);
+static Node *makeFloatConst(char *str, int location);
+static Node *makeBitStringConst(char *str, int location);
+static Node *makeNullAConst(int location);
+static Node *makeAConst(Value *v, int location);
+static Node *makeBoolAConst(bool state, int location);
static FuncCall *makeOverlaps(List *largs, List *rargs, int location);
static void check_qualified_name(List *names);
static List *check_func_name(List *names);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n, int location);
static void doNegateFloat(Value *v);
-static Node *makeAArrayExpr(List *elements);
-static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args);
+static Node *makeAArrayExpr(List *elements, int location);
+static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
+ List *args, int location);
static List *mergeTableFuncParameters(List *func_args, List *columns);
static TypeName *TableFuncTypeName(List *columns);
n->kind = VAR_SET_VALUE;
n->name = "client_encoding";
if ($2 != NULL)
- n->args = list_make1(makeStringConst($2));
+ n->args = list_make1(makeStringConst($2, @2));
else
n->kind = VAR_SET_DEFAULT;
$$ = n;
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "role";
- n->args = list_make1(makeStringConst($2));
+ n->args = list_make1(makeStringConst($2, @2));
$$ = n;
}
| SESSION AUTHORIZATION ColId_or_Sconst
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "session_authorization";
- n->args = list_make1(makeStringConst($3));
+ n->args = list_make1(makeStringConst($3, @3));
$$ = n;
}
| SESSION AUTHORIZATION DEFAULT
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "xmloption";
- n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT"));
+ n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3));
$$ = n;
}
;
;
var_value: opt_boolean
- { $$ = makeStringConst($1); }
+ { $$ = makeStringConst($1, @1); }
| ColId_or_Sconst
- { $$ = makeStringConst($1); }
+ { $$ = makeStringConst($1, @1); }
| NumericOnly
- { $$ = makeAConst($1); }
+ { $$ = makeAConst($1, @1); }
;
iso_level: READ UNCOMMITTED { $$ = "read uncommitted"; }
zone_value:
Sconst
{
- $$ = makeStringConst($1);
+ $$ = makeStringConst($1, @1);
}
| IDENT
{
- $$ = makeStringConst($1);
+ $$ = makeStringConst($1, @1);
}
| ConstInterval Sconst opt_interval
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
- t->typmods = list_make1(makeIntConst($3));
+ t->typmods = list_make1(makeIntConst($3, @3));
}
- $$ = makeStringConstCast($2, t);
+ $$ = makeStringConstCast($2, @2, t);
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
- t->typmods = list_make2(makeIntConst($6),
- makeIntConst($3));
- $$ = makeStringConstCast($5, t);
+ t->typmods = list_make2(makeIntConst($6, @6),
+ makeIntConst($3, @3));
+ $$ = makeStringConstCast($5, @5, t);
}
- | NumericOnly { $$ = makeAConst($1); }
+ | NumericOnly { $$ = makeAConst($1, @1); }
| DEFAULT { $$ = NULL; }
| LOCAL { $$ = NULL; }
;
transaction_mode_item:
ISOLATION LEVEL iso_level
{ $$ = makeDefElem("transaction_isolation",
- makeStringConst($3)); }
+ makeStringConst($3, @3)); }
| READ ONLY
{ $$ = makeDefElem("transaction_read_only",
- makeIntConst(TRUE)); }
+ makeIntConst(TRUE, @1)); }
| READ WRITE
{ $$ = makeDefElem("transaction_read_only",
- makeIntConst(FALSE)); }
+ makeIntConst(FALSE, @1)); }
;
/* Syntax with commas is SQL-spec, without commas is Postgres historical */
| ALL
{
/* LIMIT ALL is represented as a NULL constant */
- $$ = makeNullAConst();
+ $$ = makeNullAConst(@1);
}
;
{
$$ = $1;
if ($2 != INTERVAL_FULL_RANGE)
- $$->typmods = list_make1(makeIntConst($2));
+ $$->typmods = list_make1(makeIntConst($2, @2));
}
| ConstInterval '(' Iconst ')' opt_interval
{
$$ = $1;
- $$->typmods = list_make2(makeIntConst($5),
- makeIntConst($3));
+ $$->typmods = list_make2(makeIntConst($5, @5),
+ makeIntConst($3, @3));
}
;
else
{
$$ = SystemTypeName("bit");
- $$->typmods = list_make1(makeIntConst(1));
+ $$->typmods = list_make1(makeIntConst(1, -1));
}
$$->location = @1;
}
}
$$ = SystemTypeName($1);
- $$->typmods = list_make1(makeIntConst($3));
+ $$->typmods = list_make1(makeIntConst($3, @3));
$$->location = @1;
}
;
/* char defaults to char(1), varchar to no limit */
if (strcmp($1, "bpchar") == 0)
- $$->typmods = list_make1(makeIntConst(1));
+ $$->typmods = list_make1(makeIntConst(1, -1));
$$->location = @1;
}
$$ = SystemTypeName("timestamptz");
else
$$ = SystemTypeName("timestamp");
- $$->typmods = list_make1(makeIntConst($3));
+ $$->typmods = list_make1(makeIntConst($3, @3));
$$->location = @1;
}
| TIMESTAMP opt_timezone
$$ = SystemTypeName("timetz");
else
$$ = SystemTypeName("time");
- $$->typmods = list_make1(makeIntConst($3));
+ $$->typmods = list_make1(makeIntConst($3, @3));
$$->location = @1;
}
| TIME opt_timezone
*/
a_expr: c_expr { $$ = $1; }
| a_expr TYPECAST Typename
- { $$ = makeTypeCast($1, $3); }
+ { $$ = makeTypeCast($1, $3, @2); }
| a_expr AT TIME ZONE a_expr
{
FuncCall *n = makeNode(FuncCall);
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("similar_escape");
- n->args = list_make2($4, makeNullAConst());
+ n->args = list_make2($4, makeNullAConst(-1));
n->agg_star = FALSE;
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("similar_escape");
- n->args = list_make2($5, makeNullAConst());
+ n->args = list_make2($5, makeNullAConst(-1));
n->agg_star = FALSE;
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->subLinkType = ANY_SUBLINK;
n->testexpr = $1;
n->operName = list_make1(makeString("="));
+ n->location = @2;
$$ = (Node *)n;
}
else
n->subLinkType = ANY_SUBLINK;
n->testexpr = $1;
n->operName = list_make1(makeString("="));
+ n->location = @3;
/* Stick a NOT on top */
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2);
}
n->testexpr = $1;
n->operName = $2;
n->subselect = $4;
+ n->location = @2;
$$ = (Node *)n;
}
| a_expr subquery_Op sub_type '(' a_expr ')' %prec Op
}
| a_expr IS DOCUMENT_P %prec IS
{
- $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1));
+ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2);
}
| a_expr IS NOT DOCUMENT_P %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
- makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)),
+ makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2),
@2);
}
;
b_expr: c_expr
{ $$ = $1; }
| b_expr TYPECAST Typename
- { $$ = makeTypeCast($1, $3); }
+ { $$ = makeTypeCast($1, $3, @2); }
| '+' b_expr %prec UMINUS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
| '-' b_expr %prec UMINUS
}
| b_expr IS DOCUMENT_P %prec IS
{
- $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1));
+ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2);
}
| b_expr IS NOT DOCUMENT_P %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
- makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)),
+ makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+ list_make1($1), @2),
@2);
}
;
{
ParamRef *p = makeNode(ParamRef);
p->number = $1;
+ p->location = @1;
if ($2)
{
A_Indirection *n = makeNode(A_Indirection);
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $1;
+ n->location = @1;
$$ = (Node *)n;
}
| EXISTS select_with_parens
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
+ n->location = @1;
$$ = (Node *)n;
}
| ARRAY select_with_parens
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
+ n->location = @1;
$$ = (Node *)n;
}
| ARRAY array_expr
- { $$ = $2; }
+ {
+ A_ArrayExpr *n = (A_ArrayExpr *) $2;
+ Assert(IsA(n, A_ArrayExpr));
+ /* point outermost A_ArrayExpr to the ARRAY keyword */
+ n->location = @1;
+ $$ = (Node *)n;
+ }
| row
{
RowExpr *r = makeNode(RowExpr);
r->args = $1;
r->row_typeid = InvalidOid; /* not analyzed yet */
+ r->location = @1;
$$ = (Node *)r;
}
;
* to rely on it.)
*/
Node *n;
- n = makeStringConstCast("now", SystemTypeName("text"));
- $$ = makeTypeCast(n, SystemTypeName("date"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ $$ = makeTypeCast(n, SystemTypeName("date"), -1);
}
| CURRENT_TIME
{
* See comments for CURRENT_DATE.
*/
Node *n;
- n = makeStringConstCast("now", SystemTypeName("text"));
- $$ = makeTypeCast(n, SystemTypeName("timetz"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ $$ = makeTypeCast(n, SystemTypeName("timetz"), -1);
}
| CURRENT_TIME '(' Iconst ')'
{
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", SystemTypeName("text"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("timetz");
- d->typmods = list_make1(makeIntConst($3));
- $$ = makeTypeCast(n, d);
+ d->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeTypeCast(n, d, -1);
}
| CURRENT_TIMESTAMP
{
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", SystemTypeName("text"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("timestamptz");
- d->typmods = list_make1(makeIntConst($3));
- $$ = makeTypeCast(n, d);
+ d->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeTypeCast(n, d, -1);
}
| LOCALTIME
{
* See comments for CURRENT_DATE.
*/
Node *n;
- n = makeStringConstCast("now", SystemTypeName("text"));
- $$ = makeTypeCast((Node *)n, SystemTypeName("time"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ $$ = makeTypeCast((Node *)n, SystemTypeName("time"), -1);
}
| LOCALTIME '(' Iconst ')'
{
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", SystemTypeName("text"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("time");
- d->typmods = list_make1(makeIntConst($3));
- $$ = makeTypeCast((Node *)n, d);
+ d->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeTypeCast((Node *)n, d, -1);
}
| LOCALTIMESTAMP
{
* See comments for CURRENT_DATE.
*/
Node *n;
- n = makeStringConstCast("now", SystemTypeName("text"));
- $$ = makeTypeCast(n, SystemTypeName("timestamp"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ $$ = makeTypeCast(n, SystemTypeName("timestamp"), -1);
}
| LOCALTIMESTAMP '(' Iconst ')'
{
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", SystemTypeName("text"));
+ n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("timestamp");
- d->typmods = list_make1(makeIntConst($3));
- $$ = makeTypeCast(n, d);
+ d->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeTypeCast(n, d, -1);
}
| CURRENT_ROLE
{
$$ = (Node *)n;
}
| CAST '(' a_expr AS Typename ')'
- { $$ = makeTypeCast($3, $5); }
+ { $$ = makeTypeCast($3, $5, @1); }
| EXTRACT '(' extract_list ')'
{
FuncCall *n = makeNode(FuncCall);
{
CoalesceExpr *c = makeNode(CoalesceExpr);
c->args = $3;
+ c->location = @1;
$$ = (Node *)c;
}
| GREATEST '(' expr_list ')'
MinMaxExpr *v = makeNode(MinMaxExpr);
v->args = $3;
v->op = IS_GREATEST;
+ v->location = @1;
$$ = (Node *)v;
}
| LEAST '(' expr_list ')'
MinMaxExpr *v = makeNode(MinMaxExpr);
v->args = $3;
v->op = IS_LEAST;
+ v->location = @1;
$$ = (Node *)v;
}
| XMLCONCAT '(' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3);
+ $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
}
| XMLFOREST '(' xml_attribute_list ')'
{
- $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL);
+ $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
}
| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
{
- XmlExpr *x = (XmlExpr *) makeXmlExpr(IS_XMLPARSE, NULL, NIL,
- list_make2($4,
- makeBoolAConst($5)));
+ XmlExpr *x = (XmlExpr *)
+ makeXmlExpr(IS_XMLPARSE, NULL, NIL,
+ list_make2($4, makeBoolAConst($5, -1)),
+ @1);
x->xmloption = $3;
$$ = (Node *)x;
}
| XMLPI '(' NAME_P ColLabel ')'
{
- $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL);
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1);
}
| XMLPI '(' NAME_P ColLabel ',' a_expr ')'
{
- $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6));
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1);
}
| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
{
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
- list_make3($3, $5, $6));
+ list_make3($3, $5, $6), @1);
}
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
{
n->xmloption = $3;
n->expr = $4;
n->typename = $6;
+ n->location = @1;
$$ = (Node *)n;
}
;
xml_root_version: VERSION_P a_expr
{ $$ = $2; }
| VERSION_P NO VALUE_P
- { $$ = makeNullAConst(); }
+ { $$ = makeNullAConst(-1); }
;
opt_xml_root_standalone: ',' STANDALONE_P YES_P
- { $$ = makeIntConst(XML_STANDALONE_YES); }
+ { $$ = makeIntConst(XML_STANDALONE_YES, -1); }
| ',' STANDALONE_P NO
- { $$ = makeIntConst(XML_STANDALONE_NO); }
+ { $$ = makeIntConst(XML_STANDALONE_NO, -1); }
| ',' STANDALONE_P NO VALUE_P
- { $$ = makeIntConst(XML_STANDALONE_NO_VALUE); }
+ { $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1); }
| /*EMPTY*/
- { $$ = makeIntConst(XML_STANDALONE_OMITTED); }
+ { $$ = makeIntConst(XML_STANDALONE_OMITTED, -1); }
;
xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
array_expr: '[' expr_list ']'
{
- $$ = makeAArrayExpr($2);
+ $$ = makeAArrayExpr($2, @1);
}
| '[' array_expr_list ']'
{
- $$ = makeAArrayExpr($2);
+ $$ = makeAArrayExpr($2, @1);
}
| '[' ']'
{
- $$ = makeAArrayExpr(NIL);
+ $$ = makeAArrayExpr(NIL, @1);
}
;
extract_list:
extract_arg FROM a_expr
{
- $$ = list_make2(makeStringConst($1), $3);
+ $$ = list_make2(makeStringConst($1, @1), $3);
}
| /*EMPTY*/ { $$ = NIL; }
;
* which it is likely to do if the second argument
* is unknown or doesn't have an implicit cast to int4.
*/
- $$ = list_make3($1, makeIntConst(1),
- makeTypeCast($2, SystemTypeName("int4")));
+ $$ = list_make3($1, makeIntConst(1, -1),
+ makeTypeCast($2,
+ SystemTypeName("int4"), -1));
}
| expr_list
{
c->arg = (Expr *) $2;
c->args = $3;
c->defresult = (Expr *) $4;
+ c->location = @1;
$$ = (Node *)c;
}
;
CaseWhen *w = makeNode(CaseWhen);
w->expr = (Expr *) $2;
w->result = (Expr *) $4;
+ w->location = @1;
$$ = (Node *)w;
}
;
ctext_expr:
a_expr { $$ = (Node *) $1; }
- | DEFAULT { $$ = (Node *) makeNode(SetToDefault); }
+ | DEFAULT
+ {
+ SetToDefault *n = makeNode(SetToDefault);
+ n->location = @1;
+ $$ = (Node *) n;
+ }
;
ctext_expr_list:
*/
AexprConst: Iconst
{
- $$ = makeIntConst($1);
+ $$ = makeIntConst($1, @1);
}
| FCONST
{
- $$ = makeFloatConst($1);
+ $$ = makeFloatConst($1, @1);
}
| Sconst
{
- $$ = makeStringConst($1);
+ $$ = makeStringConst($1, @1);
}
| BCONST
{
- $$ = makeBitStringConst($1);
+ $$ = makeBitStringConst($1, @1);
}
| XCONST
{
* a <general literal> shall not be a
* <bit string literal> or a <hex string literal>.
*/
- $$ = makeBitStringConst($1);
+ $$ = makeBitStringConst($1, @1);
}
| func_name Sconst
{
/* generic type 'literal' syntax */
TypeName *t = makeTypeNameFromNameList($1);
t->location = @1;
- $$ = makeStringConstCast($2, t);
+ $$ = makeStringConstCast($2, @2, t);
}
| func_name '(' expr_list ')' Sconst
{
TypeName *t = makeTypeNameFromNameList($1);
t->typmods = $3;
t->location = @1;
- $$ = makeStringConstCast($5, t);
+ $$ = makeStringConstCast($5, @5, t);
}
| ConstTypename Sconst
{
- $$ = makeStringConstCast($2, $1);
+ $$ = makeStringConstCast($2, @2, $1);
}
| ConstInterval Sconst opt_interval
{
TypeName *t = $1;
/* precision is not specified, but fields may be... */
if ($3 != INTERVAL_FULL_RANGE)
- t->typmods = list_make1(makeIntConst($3));
- $$ = makeStringConstCast($2, t);
+ t->typmods = list_make1(makeIntConst($3, @3));
+ $$ = makeStringConstCast($2, @2, t);
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
{
TypeName *t = $1;
- t->typmods = list_make2(makeIntConst($6),
- makeIntConst($3));
- $$ = makeStringConstCast($5, t);
+ t->typmods = list_make2(makeIntConst($6, @6),
+ makeIntConst($3, @3));
+ $$ = makeStringConstCast($5, @5, t);
}
| TRUE_P
{
- $$ = makeBoolAConst(TRUE);
+ $$ = makeBoolAConst(TRUE, @1);
}
| FALSE_P
{
- $$ = makeBoolAConst(FALSE);
+ $$ = makeBoolAConst(FALSE, @1);
}
| NULL_P
{
- $$ = makeNullAConst();
+ $$ = makeNullAConst(@1);
}
;
}
static Node *
-makeTypeCast(Node *arg, TypeName *typename)
+makeTypeCast(Node *arg, TypeName *typename, int location)
{
TypeCast *n = makeNode(TypeCast);
n->arg = arg;
n->typename = typename;
+ n->location = location;
return (Node *) n;
}
static Node *
-makeStringConst(char *str)
+makeStringConst(char *str, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = str;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeStringConstCast(char *str, TypeName *typename)
+makeStringConstCast(char *str, int location, TypeName *typename)
{
- Node *s = makeStringConst(str);
+ Node *s = makeStringConst(str, location);
- return makeTypeCast(s, typename);
+ return makeTypeCast(s, typename, -1);
}
static Node *
-makeIntConst(int val)
+makeIntConst(int val, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Integer;
n->val.val.ival = val;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeFloatConst(char *str)
+makeFloatConst(char *str, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Float;
n->val.val.str = str;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeBitStringConst(char *str)
+makeBitStringConst(char *str, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_BitString;
n->val.val.str = str;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeNullAConst(void)
+makeNullAConst(int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
+ n->location = location;
return (Node *)n;
}
static Node *
-makeAConst(Value *v)
+makeAConst(Value *v, int location)
{
Node *n;
switch (v->type)
{
case T_Float:
- n = makeFloatConst(v->val.str);
+ n = makeFloatConst(v->val.str, location);
break;
case T_Integer:
- n = makeIntConst(v->val.ival);
+ n = makeIntConst(v->val.ival, location);
break;
case T_String:
default:
- n = makeStringConst(v->val.str);
+ n = makeStringConst(v->val.str, location);
break;
}
* Create an A_Const string node and put it inside a boolean cast.
*/
static Node *
-makeBoolAConst(bool state)
+makeBoolAConst(bool state, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = (state ? "t" : "f");
+ n->location = location;
- return makeTypeCast((Node *)n, SystemTypeName("bool"));
+ return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
}
/* makeOverlaps()
* Build a properly-qualified reference to a built-in type.
*
* typmod is defaulted, but may be changed afterwards by caller.
+ * Likewise for the location.
*/
TypeName *
SystemTypeName(char *name)
{
A_Const *con = (A_Const *)n;
+ /* report the constant's location as that of the '-' sign */
+ con->location = location;
+
if (con->val.type == T_Integer)
{
con->val.val.ival = -con->val.val.ival;
}
static Node *
-makeAArrayExpr(List *elements)
+makeAArrayExpr(List *elements, int location)
{
A_ArrayExpr *n = makeNode(A_ArrayExpr);
n->elements = elements;
+ n->location = location;
return (Node *) n;
}
static Node *
-makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
+makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
+ int location)
{
XmlExpr *x = makeNode(XmlExpr);
x->named_args = named_args;
x->arg_names = NIL;
x->args = args;
+ /* xmloption, if relevant, must be filled in by caller */
+ /* type and typmod will be filled in during parse analysis */
+ x->location = location;
return (Node *) x;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.81 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.82 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
argp->paramid = -1;
argp->paramtype = agg_state_type;
argp->paramtypmod = -1;
+ argp->location = -1;
args = list_make1(argp);
argp->paramid = -1;
argp->paramtype = agg_input_types[i];
argp->paramtypmod = -1;
+ argp->location = -1;
args = lappend(args, argp);
}
argp->paramid = -1;
argp->paramtype = agg_state_type;
argp->paramtypmod = -1;
+ argp->location = -1;
args = list_make1(argp);
*finalfnexpr = (Expr *) makeFuncExpr(finalfn_oid,
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.176 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.177 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
outcoltypmod = l_colvar->vartypmod;
if (outcoltype != r_colvar->vartype)
{
- outcoltype = select_common_type(list_make2_oid(l_colvar->vartype,
- r_colvar->vartype),
- "JOIN/USING");
+ outcoltype = select_common_type(pstate,
+ list_make2(l_colvar, r_colvar),
+ "JOIN/USING",
+ NULL);
outcoltypmod = -1; /* ie, unknown */
}
else if (outcoltypmod != r_colvar->vartypmod)
if (l_colvar->vartype != outcoltype)
l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,
outcoltype, outcoltypmod,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
else if (l_colvar->vartypmod != outcoltypmod)
l_node = (Node *) makeRelabelType((Expr *) l_colvar,
outcoltype, outcoltypmod,
if (r_colvar->vartype != outcoltype)
r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,
outcoltype, outcoltypmod,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
else if (r_colvar->vartypmod != outcoltypmod)
r_node = (Node *) makeRelabelType((Expr *) r_colvar,
outcoltype, outcoltypmod,
c->coalescetype = outcoltype;
c->args = list_make2(l_node, r_node);
+ c->location = -1;
res_node = (Node *) c;
break;
}
if (IsA(node, A_Const))
{
Value *val = &((A_Const *) node)->val;
+ int location = ((A_Const *) node)->location;
int targetlist_pos = 0;
int target_pos;
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: %s is name of a SQL construct, eg ORDER BY */
errmsg("non-integer constant in %s",
- clauseText[clause])));
+ clauseText[clause]),
+ parser_errposition(pstate, location)));
+
target_pos = intVal(val);
foreach(tl, *tlist)
{
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
/* translator: %s is name of a SQL construct, eg ORDER BY */
errmsg("%s position %d is not in select list",
- clauseText[clause], target_pos)));
+ clauseText[clause], target_pos),
+ parser_errposition(pstate, location)));
}
/*
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
restype = TEXTOID;
}
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
restype = TEXTOID;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.164 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.165 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static Node *coerce_type_typmod(Node *node,
Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat, bool isExplicit,
- bool hideInputCoercion);
+ CoercionForm cformat, int location,
+ bool isExplicit, bool hideInputCoercion);
static void hide_coercion_node(Node *node);
static Node *build_coercion_expression(Node *node,
CoercionPathType pathtype,
Oid funcId,
Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat, bool isExplicit);
+ CoercionForm cformat, int location,
+ bool isExplicit);
static Node *coerce_record_to_complex(ParseState *pstate, Node *node,
Oid targetTypeId,
CoercionContext ccontext,
- CoercionForm cformat);
+ CoercionForm cformat,
+ int location);
/*
* targettype - desired result type
* targettypmod - desired result typmod
* ccontext, cformat - context indicators to control coercions
+ * location - parse location of the coercion request, or -1 if unknown/implicit
*/
Node *
coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
Oid targettype, int32 targettypmod,
CoercionContext ccontext,
- CoercionForm cformat)
+ CoercionForm cformat,
+ int location)
{
Node *result;
result = coerce_type(pstate, expr, exprtype,
targettype, targettypmod,
- ccontext, cformat);
+ ccontext, cformat, location);
/*
* If the target is a fixed-length type, it may need a length coercion as
*/
result = coerce_type_typmod(result,
targettype, targettypmod,
- cformat,
+ cformat, location,
(cformat != COERCE_IMPLICIT_CAST),
(result != expr && !IsA(result, Const)));
Node *
coerce_type(ParseState *pstate, Node *node,
Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
- CoercionContext ccontext, CoercionForm cformat)
+ CoercionContext ccontext, CoercionForm cformat, int location)
{
Node *result;
CoercionPathType pathtype;
newcon->constlen = typeLen(targetType);
newcon->constbyval = typeByVal(targetType);
newcon->constisnull = con->constisnull;
+ /* Use the leftmost of the constant's and coercion's locations */
+ if (location < 0)
+ newcon->location = con->location;
+ else if (con->location >= 0 && con->location < location)
+ newcon->location = con->location;
+ else
+ newcon->location = location;
/*
* We pass typmod -1 to the input routine, primarily because existing
result = coerce_to_domain(result,
baseTypeId, baseTypeMod,
targetTypeId,
- cformat, false, false);
+ cformat, location, false, false);
ReleaseSysCache(targetType);
*/
param->paramtypmod = -1;
+ /* Use the leftmost of the param's and coercion's locations */
+ if (location >= 0 &&
+ (param->location < 0 || location < param->location))
+ param->location = location;
+
return (Node *) param;
}
pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
result = build_coercion_expression(node, pathtype, funcId,
baseTypeId, baseTypeMod,
- cformat,
+ cformat, location,
(cformat != COERCE_IMPLICIT_CAST));
/*
if (targetTypeId != baseTypeId)
result = coerce_to_domain(result, baseTypeId, baseTypeMod,
targetTypeId,
- cformat, true,
+ cformat, location, true,
exprIsLengthCoercion(result,
NULL));
}
* then we won't need a RelabelType node.
*/
result = coerce_to_domain(node, InvalidOid, -1, targetTypeId,
- cformat, false, false);
+ cformat, location, false, false);
if (result == node)
{
/*
* later? Would work if both types have same interpretation of
* typmod, which is likely but not certain.
*/
- result = (Node *) makeRelabelType((Expr *) result,
- targetTypeId, -1,
- cformat);
+ RelabelType *r = makeRelabelType((Expr *) result,
+ targetTypeId, -1,
+ cformat);
+
+ r->location = location;
+ result = (Node *) r;
}
}
return result;
{
/* Coerce a RECORD to a specific complex type */
return coerce_record_to_complex(pstate, node, targetTypeId,
- ccontext, cformat);
+ ccontext, cformat, location);
}
if (targetTypeId == RECORDOID &&
ISCOMPLEX(inputTypeId))
r->arg = (Expr *) node;
r->resulttype = targetTypeId;
r->convertformat = cformat;
+ r->location = location;
return (Node *) r;
}
/* If we get here, caller blew it */
* has not bothered to look this up)
* 'typeId': target type to coerce to
* 'cformat': coercion format
+ * 'location': coercion request location
* 'hideInputCoercion': if true, hide the input coercion under this one.
* 'lengthCoercionDone': if true, caller already accounted for length,
* ie the input is already of baseTypMod as well as baseTypeId.
*/
Node *
coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
- CoercionForm cformat, bool hideInputCoercion,
+ CoercionForm cformat, int location,
+ bool hideInputCoercion,
bool lengthCoercionDone)
{
CoerceToDomain *result;
{
if (baseTypeMod >= 0)
arg = coerce_type_typmod(arg, baseTypeId, baseTypeMod,
- COERCE_IMPLICIT_CAST,
+ COERCE_IMPLICIT_CAST, location,
(cformat != COERCE_IMPLICIT_CAST),
false);
}
result->resulttype = typeId;
result->resulttypmod = -1; /* currently, always -1 for domains */
result->coercionformat = cformat;
+ result->location = location;
return (Node *) result;
}
*/
static Node *
coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat, bool isExplicit,
- bool hideInputCoercion)
+ CoercionForm cformat, int location,
+ bool isExplicit, bool hideInputCoercion)
{
CoercionPathType pathtype;
Oid funcId;
node = build_coercion_expression(node, pathtype, funcId,
targetTypeId, targetTypMod,
- cformat, isExplicit);
+ cformat, location,
+ isExplicit);
}
return node;
CoercionPathType pathtype,
Oid funcId,
Oid targetTypeId, int32 targetTypMod,
- CoercionForm cformat, bool isExplicit)
+ CoercionForm cformat, int location,
+ bool isExplicit)
{
int nargs = 0;
if (pathtype == COERCION_PATH_FUNC)
{
/* We build an ordinary FuncExpr with special arguments */
+ FuncExpr *fexpr;
List *args;
Const *cons;
args = lappend(args, cons);
}
- return (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat);
+ fexpr = makeFuncExpr(funcId, targetTypeId, args, cformat);
+ fexpr->location = location;
+ return (Node *) fexpr;
}
else if (pathtype == COERCION_PATH_ARRAYCOERCE)
{
acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1;
acoerce->isExplicit = isExplicit;
acoerce->coerceformat = cformat;
+ acoerce->location = location;
return (Node *) acoerce;
}
iocoerce->arg = (Expr *) node;
iocoerce->resulttype = targetTypeId;
iocoerce->coerceformat = cformat;
+ iocoerce->location = location;
return (Node *) iocoerce;
}
coerce_record_to_complex(ParseState *pstate, Node *node,
Oid targetTypeId,
CoercionContext ccontext,
- CoercionForm cformat)
+ CoercionForm cformat,
+ int location)
{
RowExpr *rowexpr;
TupleDesc tupdesc;
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
format_type_be(RECORDOID),
- format_type_be(targetTypeId))));
+ format_type_be(targetTypeId)),
+ parser_coercion_errposition(pstate, location, node)));
tupdesc = lookup_rowtype_tupdesc(targetTypeId, -1);
newargs = NIL;
for (i = 0; i < tupdesc->natts; i++)
{
Node *expr;
+ Node *cexpr;
Oid exprtype;
/* Fill in NULLs for dropped columns in rowtype */
errmsg("cannot cast type %s to %s",
format_type_be(RECORDOID),
format_type_be(targetTypeId)),
- errdetail("Input has too few columns.")));
+ errdetail("Input has too few columns."),
+ parser_coercion_errposition(pstate, location, node)));
expr = (Node *) lfirst(arg);
exprtype = exprType(expr);
- expr = coerce_to_target_type(pstate,
- expr, exprtype,
- tupdesc->attrs[i]->atttypid,
- tupdesc->attrs[i]->atttypmod,
- ccontext,
- COERCE_IMPLICIT_CAST);
- if (expr == NULL)
+ cexpr = coerce_to_target_type(pstate,
+ expr, exprtype,
+ tupdesc->attrs[i]->atttypid,
+ tupdesc->attrs[i]->atttypmod,
+ ccontext,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (cexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
errdetail("Cannot cast type %s to %s in column %d.",
format_type_be(exprtype),
format_type_be(tupdesc->attrs[i]->atttypid),
- ucolno)));
- newargs = lappend(newargs, expr);
+ ucolno),
+ parser_coercion_errposition(pstate, location, expr)));
+ newargs = lappend(newargs, cexpr);
ucolno++;
arg = lnext(arg);
}
errmsg("cannot cast type %s to %s",
format_type_be(RECORDOID),
format_type_be(targetTypeId)),
- errdetail("Input has too many columns.")));
+ errdetail("Input has too many columns."),
+ parser_coercion_errposition(pstate, location, node)));
ReleaseTupleDesc(tupdesc);
rowexpr->args = newargs;
rowexpr->row_typeid = targetTypeId;
rowexpr->row_format = cformat;
+ rowexpr->location = location;
return (Node *) rowexpr;
}
if (inputTypeId != BOOLOID)
{
- node = coerce_to_target_type(pstate, node, inputTypeId,
- BOOLOID, -1,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
- if (node == NULL)
+ Node *newnode;
+
+ newnode = coerce_to_target_type(pstate, node, inputTypeId,
+ BOOLOID, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (newnode == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: first %s is name of a SQL construct, eg WHERE */
- errmsg("argument of %s must be type boolean, not type %s",
- constructName, format_type_be(inputTypeId))));
+ errmsg("argument of %s must be type boolean, not type %s",
+ constructName, format_type_be(inputTypeId)),
+ parser_errposition(pstate, exprLocation(node))));
+ node = newnode;
}
if (expression_returns_set(node))
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: %s is name of a SQL construct, eg WHERE */
errmsg("argument of %s must not return a set",
- constructName)));
+ constructName),
+ parser_errposition(pstate, exprLocation(node))));
return node;
}
if (inputTypeId != targetTypeId)
{
- node = coerce_to_target_type(pstate, node, inputTypeId,
- targetTypeId, -1,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
- if (node == NULL)
+ Node *newnode;
+
+ newnode = coerce_to_target_type(pstate, node, inputTypeId,
+ targetTypeId, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (newnode == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: first %s is name of a SQL construct, eg LIMIT */
errmsg("argument of %s must be type %s, not type %s",
constructName,
format_type_be(targetTypeId),
- format_type_be(inputTypeId))));
+ format_type_be(inputTypeId)),
+ parser_errposition(pstate, exprLocation(node))));
+ node = newnode;
}
if (expression_returns_set(node))
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: %s is name of a SQL construct, eg LIMIT */
errmsg("argument of %s must not return a set",
- constructName)));
+ constructName),
+ parser_errposition(pstate, exprLocation(node))));
return node;
}
-/* select_common_type()
- * Determine the common supertype of a list of input expression types.
+/*
+ * parser_coercion_errposition - report coercion error location, if possible
+ *
+ * We prefer to point at the coercion request (CAST, ::, etc) if possible;
+ * but there may be no such location in the case of an implicit coercion.
+ * In that case point at the input expression.
+ *
+ * XXX possibly this is more generally useful than coercion errors;
+ * if so, should rename and place with parser_errposition.
+ */
+int
+parser_coercion_errposition(ParseState *pstate,
+ int coerce_location,
+ Node *input_expr)
+{
+ if (coerce_location >= 0)
+ return parser_errposition(pstate, coerce_location);
+ else
+ return parser_errposition(pstate, exprLocation(input_expr));
+}
+
+
+/*
+ * select_common_type()
+ * Determine the common supertype of a list of input expressions.
* This is used for determining the output type of CASE and UNION
* constructs.
*
- * 'typeids' is a nonempty list of type OIDs. Note that earlier items
+ * 'exprs' is a *nonempty* list of expressions. Note that earlier items
* in the list will be preferred if there is doubt.
* 'context' is a phrase to use in the error message if we fail to select
* a usable type.
+ * 'which_expr': if not NULL, receives a pointer to the particular input
+ * expression from which the result type was taken.
*/
Oid
-select_common_type(List *typeids, const char *context)
+select_common_type(ParseState *pstate, List *exprs, const char *context,
+ Node **which_expr)
{
+ Node *pexpr;
Oid ptype;
TYPCATEGORY pcategory;
bool pispreferred;
- ListCell *type_item;
+ ListCell *lc;
- Assert(typeids != NIL);
- ptype = linitial_oid(typeids);
+ Assert(exprs != NIL);
+ pexpr = (Node *) linitial(exprs);
+ lc = lnext(list_head(exprs));
+ ptype = exprType(pexpr);
/*
* If all input types are valid and exactly the same, just pick that type.
*/
if (ptype != UNKNOWNOID)
{
- for_each_cell(type_item, lnext(list_head(typeids)))
+ for_each_cell(lc, lc)
{
- Oid ntype = lfirst_oid(type_item);
+ Node *nexpr = (Node *) lfirst(lc);
+ Oid ntype = exprType(nexpr);
if (ntype != ptype)
break;
}
- if (type_item == NULL) /* got to the end of the list? */
+ if (lc == NULL) /* got to the end of the list? */
+ {
+ if (which_expr)
+ *which_expr = pexpr;
return ptype;
+ }
}
- /* Nope, so set up for the full algorithm */
+ /*
+ * Nope, so set up for the full algorithm. Note that at this point,
+ * lc points to the first list item with type different from pexpr's;
+ * we need not re-examine any items the previous loop advanced over.
+ */
ptype = getBaseType(ptype);
get_type_category_preferred(ptype, &pcategory, &pispreferred);
- for_each_cell(type_item, lnext(list_head(typeids)))
+ for_each_cell(lc, lc)
{
- Oid ntype = getBaseType(lfirst_oid(type_item));
+ Node *nexpr = (Node *) lfirst(lc);
+ Oid ntype = getBaseType(exprType(nexpr));
/* move on to next one if no new information... */
if (ntype != UNKNOWNOID && ntype != ptype)
if (ptype == UNKNOWNOID)
{
/* so far, only unknowns so take anything... */
+ pexpr = nexpr;
ptype = ntype;
pcategory = ncategory;
pispreferred = nispreferred;
*/
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
-
/*------
translator: first %s is name of a SQL construct, eg CASE */
errmsg("%s types %s and %s cannot be matched",
context,
format_type_be(ptype),
- format_type_be(ntype))));
+ format_type_be(ntype)),
+ parser_errposition(pstate, exprLocation(nexpr))));
}
else if (!pispreferred &&
can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
* take new type if can coerce to it implicitly but not the
* other way; but if we have a preferred type, stay on it.
*/
+ pexpr = nexpr;
ptype = ntype;
pcategory = ncategory;
pispreferred = nispreferred;
if (ptype == UNKNOWNOID)
ptype = TEXTOID;
+ if (which_expr)
+ *which_expr = pexpr;
return ptype;
}
-/* coerce_to_common_type()
+/*
+ * coerce_to_common_type()
* Coerce an expression to the given type.
*
* This is used following select_common_type() to coerce the individual
return node; /* no work */
if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
else
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("%s could not convert type %s to %s",
context,
format_type_be(inputTypeId),
- format_type_be(targetTypeId))));
+ format_type_be(targetTypeId)),
+ parser_errposition(pstate, exprLocation(node))));
return node;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.231 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.232 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
char *relname, int location);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection);
-static Node *typecast_expression(ParseState *pstate, Node *expr,
- TypeName *typename);
+static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
List *largs, List *rargs, int location);
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
A_Const *con = (A_Const *) expr;
Value *val = &con->val;
- result = (Node *) make_const(val);
+ result = (Node *) make_const(val, con->location);
break;
}
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
- Node *arg;
/*
* If the subject of the typecast is an ARRAY[] construct
*/
}
- arg = transformExpr(pstate, tc->arg);
- result = typecast_expression(pstate, arg, tc->typename);
+ result = transformTypeCast(pstate, tc);
break;
}
strcmp(name, "value") == 0)
{
node = (Node *) copyObject(pstate->p_value_substitute);
+
+ /*
+ * Try to propagate location knowledge. This should
+ * be extended if p_value_substitute can ever take on
+ * other node types.
+ */
+ if (IsA(node, CoerceToDomainValue))
+ ((CoerceToDomainValue *) node)->location = cref->location;
break;
}
param->paramid = paramno;
param->paramtype = *pptype;
param->paramtypmod = -1;
+ param->location = pref->location;
return (Node *) param;
}
s->subLinkType = ROWCOMPARE_SUBLINK;
s->testexpr = lexpr;
s->operName = a->name;
+ s->location = a->location;
result = transformExpr(pstate, (Node *) s);
}
else if (lexpr && IsA(lexpr, RowExpr) &&
rexpr = coerce_to_boolean(pstate, rexpr, "AND");
return (Node *) makeBoolExpr(AND_EXPR,
- list_make2(lexpr, rexpr));
+ list_make2(lexpr, rexpr),
+ a->location);
}
static Node *
rexpr = coerce_to_boolean(pstate, rexpr, "OR");
return (Node *) makeBoolExpr(OR_EXPR,
- list_make2(lexpr, rexpr));
+ list_make2(lexpr, rexpr),
+ a->location);
}
static Node *
rexpr = coerce_to_boolean(pstate, rexpr, "NOT");
return (Node *) makeBoolExpr(NOT_EXPR,
- list_make1(rexpr));
+ list_make1(rexpr),
+ a->location);
}
static Node *
* in a boolean constant node.
*/
Node *lexpr = transformExpr(pstate, a->lexpr);
+ Const *result;
ListCell *telem;
Oid ltype,
rtype;
if (strcmp(strVal(linitial(a->name)), "<>") == 0)
matched = (!matched);
- return makeBoolConst(matched, false);
+ result = (Const *) makeBoolConst(matched, false);
+
+ /* Make the result have the original input's parse location */
+ result->location = exprLocation((Node *) a);
+
+ return (Node *) result;
}
static Node *
{
Node *lexpr;
List *rexprs;
- List *typeids;
bool useOr;
bool haveRowExpr;
Node *result;
*/
lexpr = transformExpr(pstate, a->lexpr);
haveRowExpr = (lexpr && IsA(lexpr, RowExpr));
- typeids = list_make1_oid(exprType(lexpr));
rexprs = NIL;
foreach(l, (List *) a->rexpr)
{
haveRowExpr |= (rexpr && IsA(rexpr, RowExpr));
rexprs = lappend(rexprs, rexpr);
- typeids = lappend_oid(typeids, exprType(rexpr));
}
/*
*/
if (!haveRowExpr && list_length(rexprs) != 1)
{
+ List *allexprs;
Oid scalar_type;
Oid array_type;
* Select a common type for the array elements. Note that since the
* LHS' type is first in the list, it will be preferred when there is
* doubt (eg, when all the RHS items are unknown literals).
+ *
+ * Note: use list_concat here not lcons, to avoid damaging rexprs.
*/
- scalar_type = select_common_type(typeids, "IN");
+ allexprs = list_concat(list_make1(lexpr), rexprs);
+ scalar_type = select_common_type(pstate, allexprs, "IN", NULL);
/* Do we have an array type to use? */
array_type = get_array_type(scalar_type);
newa->element_typeid = scalar_type;
newa->elements = aexprs;
newa->multidims = false;
+ newa->location = -1;
return (Node *) make_scalar_array_op(pstate,
a->name,
result = cmp;
else
result = (Node *) makeBoolExpr(useOr ? OR_EXPR : AND_EXPR,
- list_make2(result, cmp));
+ list_make2(result, cmp),
+ a->location);
}
return result;
Node *arg;
CaseTestExpr *placeholder;
List *newargs;
- List *typeids;
+ List *resultexprs;
ListCell *l;
Node *defresult;
Oid ptype;
/* transform the list of arguments */
newargs = NIL;
- typeids = NIL;
+ resultexprs = NIL;
foreach(l, c->args)
{
CaseWhen *w = (CaseWhen *) lfirst(l);
warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
(Node *) placeholder,
warg,
- -1);
+ w->location);
}
neww->expr = (Expr *) transformExpr(pstate, warg);
warg = (Node *) w->result;
neww->result = (Expr *) transformExpr(pstate, warg);
+ neww->location = w->location;
newargs = lappend(newargs, neww);
- typeids = lappend_oid(typeids, exprType((Node *) neww->result));
+ resultexprs = lappend(resultexprs, neww->result);
}
newc->args = newargs;
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
+ n->location = -1;
defresult = (Node *) n;
}
newc->defresult = (Expr *) transformExpr(pstate, defresult);
* determining preferred type. This is how the code worked before, but it
* seems a little bogus to me --- tgl
*/
- typeids = lcons_oid(exprType((Node *) newc->defresult), typeids);
+ resultexprs = lcons(newc->defresult, resultexprs);
- ptype = select_common_type(typeids, "CASE");
+ ptype = select_common_type(pstate, resultexprs, "CASE", NULL);
Assert(OidIsValid(ptype));
newc->casetype = ptype;
"CASE/WHEN");
}
+ newc->location = c->location;
+
return (Node *) newc;
}
((TargetEntry *) lfirst(tlist_item))->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery must return a column")));
+ errmsg("subquery must return a column"),
+ parser_errposition(pstate, sublink->location)));
while ((tlist_item = lnext(tlist_item)) != NULL)
{
if (!((TargetEntry *) lfirst(tlist_item))->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery must return only one column")));
+ errmsg("subquery must return only one column"),
+ parser_errposition(pstate, sublink->location)));
}
/*
param->paramid = tent->resno;
param->paramtype = exprType((Node *) tent->expr);
param->paramtypmod = exprTypmod((Node *) tent->expr);
+ param->location = -1;
right_list = lappend(right_list, param);
}
if (list_length(left_list) < list_length(right_list))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery has too many columns")));
+ errmsg("subquery has too many columns"),
+ parser_errposition(pstate, sublink->location)));
if (list_length(left_list) > list_length(right_list))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery has too few columns")));
+ errmsg("subquery has too few columns"),
+ parser_errposition(pstate, sublink->location)));
/*
* Identify the combining operator(s) and generate a suitable
sublink->operName,
left_list,
right_list,
- -1);
+ sublink->location);
}
return result;
ArrayExpr *newa = makeNode(ArrayExpr);
List *newelems = NIL;
List *newcoercedelems = NIL;
- List *typeids = NIL;
ListCell *element;
Oid coerce_type;
bool coerce_hard;
{
Node *e = (Node *) lfirst(element);
Node *newe;
- Oid newe_type;
/*
* If an element is itself an A_ArrayExpr, recurse directly so that
array_type,
element_type,
typmod);
- newe_type = exprType(newe);
/* we certainly have an array here */
- Assert(array_type == InvalidOid || array_type == newe_type);
+ Assert(array_type == InvalidOid || array_type == exprType(newe));
newa->multidims = true;
}
else
{
newe = transformExpr(pstate, e);
- newe_type = exprType(newe);
/*
* Check for sub-array expressions, if we haven't already
* found one.
*/
- if (!newa->multidims && type_is_array(newe_type))
+ if (!newa->multidims && type_is_array(exprType(newe)))
newa->multidims = true;
}
newelems = lappend(newelems, newe);
- typeids = lappend_oid(typeids, newe_type);
}
/*
else
{
/* Can't handle an empty array without a target type */
- if (typeids == NIL)
+ if (newelems == NIL)
ereport(ERROR,
(errcode(ERRCODE_INDETERMINATE_DATATYPE),
errmsg("cannot determine type of empty array"),
errhint("Explicitly cast to the desired type, "
- "for example ARRAY[]::integer[].")));
+ "for example ARRAY[]::integer[]."),
+ parser_errposition(pstate, a->location)));
/* Select a common type for the elements */
- coerce_type = select_common_type(typeids, "ARRAY");
+ coerce_type = select_common_type(pstate, newelems, "ARRAY", NULL);
if (newa->multidims)
{
coerce_type,
typmod,
COERCION_EXPLICIT,
- COERCE_EXPLICIT_CAST);
+ COERCE_EXPLICIT_CAST,
+ -1);
if (newe == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
format_type_be(exprType(e)),
- format_type_be(coerce_type))));
+ format_type_be(coerce_type)),
+ parser_errposition(pstate, exprLocation(e))));
}
else
newe = coerce_to_common_type(pstate, e,
newa->array_typeid = array_type;
newa->element_typeid = element_type;
newa->elements = newcoercedelems;
+ newa->location = a->location;
return (Node *) newa;
}
/* Barring later casting, we consider the type RECORD */
newr->row_typeid = RECORDOID;
newr->row_format = COERCE_IMPLICIT_CAST;
+ newr->location = r->location;
return (Node *) newr;
}
CoalesceExpr *newc = makeNode(CoalesceExpr);
List *newargs = NIL;
List *newcoercedargs = NIL;
- List *typeids = NIL;
ListCell *args;
foreach(args, c->args)
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
- typeids = lappend_oid(typeids, exprType(newe));
}
- newc->coalescetype = select_common_type(typeids, "COALESCE");
+ newc->coalescetype = select_common_type(pstate, newargs, "COALESCE", NULL);
/* Convert arguments if necessary */
foreach(args, newargs)
}
newc->args = newcoercedargs;
+ newc->location = c->location;
return (Node *) newc;
}
MinMaxExpr *newm = makeNode(MinMaxExpr);
List *newargs = NIL;
List *newcoercedargs = NIL;
- List *typeids = NIL;
+ const char *funcname = (m->op == IS_GREATEST) ? "GREATEST" : "LEAST";
ListCell *args;
newm->op = m->op;
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
- typeids = lappend_oid(typeids, exprType(newe));
}
- newm->minmaxtype = select_common_type(typeids, "GREATEST/LEAST");
+ newm->minmaxtype = select_common_type(pstate, newargs, funcname, NULL);
/* Convert arguments if necessary */
foreach(args, newargs)
newe = coerce_to_common_type(pstate, e,
newm->minmaxtype,
- "GREATEST/LEAST");
+ funcname);
newcoercedargs = lappend(newcoercedargs, newe);
}
newm->args = newcoercedargs;
+ newm->location = m->location;
return (Node *) newm;
}
newx->name = map_sql_identifier_to_xml_name(x->name, false, false);
else
newx->name = NULL;
+ newx->xmloption = x->xmloption;
+ newx->location = x->location;
/*
* gram.y built the named args as a list of ResTarget. Transform each,
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
x->op == IS_XMLELEMENT
- ? errmsg("unnamed XML attribute value must be a column reference")
- : errmsg("unnamed XML element value must be a column reference")));
+ ? errmsg("unnamed XML attribute value must be a column reference")
+ : errmsg("unnamed XML element value must be a column reference"),
+ parser_errposition(pstate, r->location)));
argname = NULL; /* keep compiler quiet */
}
- newx->named_args = lappend(newx->named_args, expr);
- newx->arg_names = lappend(newx->arg_names, makeString(argname));
- }
-
- newx->xmloption = x->xmloption;
-
- if (x->op == IS_XMLELEMENT)
- {
- foreach(lc, newx->arg_names)
+ /* reject duplicate argnames in XMLELEMENT only */
+ if (x->op == IS_XMLELEMENT)
{
ListCell *lc2;
- for_each_cell(lc2, lnext(lc))
+ foreach(lc2, newx->arg_names)
{
- if (strcmp(strVal(lfirst(lc)), strVal(lfirst(lc2))) == 0)
+ if (strcmp(argname, strVal(lfirst(lc2))) == 0)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("XML attribute name \"%s\" appears more than once", strVal(lfirst(lc)))));
+ errmsg("XML attribute name \"%s\" appears more than once",
+ argname),
+ parser_errposition(pstate, r->location)));
}
}
+
+ newx->named_args = lappend(newx->named_args, expr);
+ newx->arg_names = lappend(newx->arg_names, makeString(argname));
}
/* The other arguments are of varying types depending on the function */
break;
case IS_XMLSERIALIZE:
/* not handled here */
+ Assert(false);
break;
case IS_DOCUMENT:
newe = coerce_to_specific_type(pstate, newe, XMLOID,
static Node *
transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
{
+ Node *result;
+ XmlExpr *xexpr;
Oid targetType;
int32 targetTypmod;
- XmlExpr *xexpr;
xexpr = makeNode(XmlExpr);
xexpr->op = IS_XMLSERIALIZE;
targetType = typenameTypeId(pstate, xs->typename, &targetTypmod);
xexpr->xmloption = xs->xmloption;
+ xexpr->location = xs->location;
/* We actually only need these to be able to parse back the expression. */
xexpr->type = targetType;
xexpr->typmod = targetTypmod;
* from text. This way, user-defined text-like data types automatically
* fit in.
*/
- return (Node *) coerce_to_target_type(pstate, (Node *) xexpr, TEXTOID, targetType, targetTypmod,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+ result = coerce_to_target_type(pstate, (Node *) xexpr,
+ TEXTOID, targetType, targetTypmod,
+ COERCION_IMPLICIT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (result == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_CANNOT_COERCE),
+ errmsg("cannot cast XMLSERIALIZE result to %s",
+ format_type_be(targetType)),
+ parser_errposition(pstate, xexpr->location)));
+ return result;
}
static Node *
transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
int location)
{
- Node *result;
+ Var *result;
RangeTblEntry *rte;
int vnum;
int sublevels_up;
if (!OidIsValid(toid))
elog(ERROR, "could not find type OID for relation %u",
rte->relid);
- result = (Node *) makeVar(vnum,
- InvalidAttrNumber,
- toid,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ InvalidAttrNumber,
+ toid,
+ -1,
+ sublevels_up);
break;
case RTE_FUNCTION:
toid = exprType(rte->funcexpr);
if (type_is_rowtype(toid))
{
/* func returns composite; same as relation case */
- result = (Node *) makeVar(vnum,
- InvalidAttrNumber,
- toid,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ InvalidAttrNumber,
+ toid,
+ -1,
+ sublevels_up);
}
else
{
* seems a tad inconsistent, especially if "f.*" was
* explicitly written ...)
*/
- result = (Node *) makeVar(vnum,
- 1,
- toid,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ 1,
+ toid,
+ -1,
+ sublevels_up);
}
break;
case RTE_VALUES:
toid = RECORDOID;
/* returns composite; same as relation case */
- result = (Node *) makeVar(vnum,
- InvalidAttrNumber,
- toid,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ InvalidAttrNumber,
+ toid,
+ -1,
+ sublevels_up);
break;
default:
* expanded to a RowExpr during planning, but that is not our
* concern here.)
*/
- result = (Node *) makeVar(vnum,
- InvalidAttrNumber,
- RECORDOID,
- -1,
- sublevels_up);
+ result = makeVar(vnum,
+ InvalidAttrNumber,
+ RECORDOID,
+ -1,
+ sublevels_up);
break;
}
- return result;
+ /* location is not filled in by makeVar */
+ result->location = location;
+
+ return (Node *) result;
}
/*
* Handle an explicit CAST construct.
*
- * The given expr has already been transformed, but we need to lookup
- * the type name and then apply any necessary coercion function(s).
+ * Transform the argument, then look up the type name and apply any necessary
+ * coercion function(s).
*/
static Node *
-typecast_expression(ParseState *pstate, Node *expr, TypeName *typename)
+transformTypeCast(ParseState *pstate, TypeCast *tc)
{
+ Node *result;
+ Node *expr = transformExpr(pstate, tc->arg);
Oid inputType = exprType(expr);
Oid targetType;
int32 targetTypmod;
+ int location;
- targetType = typenameTypeId(pstate, typename, &targetTypmod);
+ targetType = typenameTypeId(pstate, tc->typename, &targetTypmod);
if (inputType == InvalidOid)
return expr; /* do nothing if NULL input */
- expr = coerce_to_target_type(pstate, expr, inputType,
- targetType, targetTypmod,
- COERCION_EXPLICIT,
- COERCE_EXPLICIT_CAST);
- if (expr == NULL)
+ /*
+ * Location of the coercion is preferentially the location of the :: or
+ * CAST symbol, but if there is none then use the location of the type
+ * name (this can happen in TypeName 'string' syntax, for instance).
+ */
+ location = tc->location;
+ if (location < 0)
+ location = tc->typename->location;
+
+ result = coerce_to_target_type(pstate, expr, inputType,
+ targetType, targetTypmod,
+ COERCION_EXPLICIT,
+ COERCE_EXPLICIT_CAST,
+ location);
+ if (result == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
format_type_be(inputType),
format_type_be(targetType)),
- parser_errposition(pstate, typename->location)));
+ parser_coercion_errposition(pstate, location, expr)));
- return expr;
+ return result;
}
/*
* the system thinks BoolExpr is N-argument anyway.
*/
if (rctype == ROWCOMPARE_EQ)
- return (Node *) makeBoolExpr(AND_EXPR, opexprs);
+ return (Node *) makeBoolExpr(AND_EXPR, opexprs, location);
if (rctype == ROWCOMPARE_NE)
- return (Node *) makeBoolExpr(OR_EXPR, opexprs);
+ return (Node *) makeBoolExpr(OR_EXPR, opexprs, location);
/*
* Otherwise we need to choose exactly which opfamily to associate with
result = cmp;
else
result = (Node *) makeBoolExpr(OR_EXPR,
- list_make2(result, cmp));
+ list_make2(result, cmp),
+ location);
}
if (result == NULL)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.205 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.206 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
return coerce_type(pstate, linitial(fargs),
actual_arg_types[0], rettype, -1,
- COERCION_EXPLICIT, COERCE_EXPLICIT_CALL);
+ COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
}
else if (fdresult == FUNCDETAIL_NORMAL)
{
errmsg("could not find array type for data type %s",
format_type_be(newa->element_typeid))));
newa->multidims = false;
+ newa->location = exprLocation((Node *) vargs);
fargs = lappend(fargs, newa);
}
funcexpr->funcretset = retset;
funcexpr->funcformat = COERCE_EXPLICIT_CALL;
funcexpr->args = fargs;
+ funcexpr->location = location;
retval = (Node *) funcexpr;
}
aggref->args = fargs;
aggref->aggstar = agg_star;
aggref->aggdistinct = agg_distinct;
+ aggref->location = location;
/*
* Reject attempt to call a parameterless aggregate without (*)
actual_arg_types[i],
declared_arg_types[i], -1,
COERCION_IMPLICIT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
}
i++;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.101 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.102 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* Build a Var node for an attribute identified by RTE and attrno
*/
Var *
-make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
+make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
{
+ Var *result;
int vnum,
sublevels_up;
Oid vartypeid;
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod);
- return makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
+ result = makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
+ result->location = location;
+ return result;
}
/*
subexpr, exprType(subexpr),
INT4OID, -1,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (subexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("array subscript must have type integer")));
+ errmsg("array subscript must have type integer"),
+ parser_errposition(pstate, exprLocation(ai->lidx))));
}
else
{
subexpr, exprType(subexpr),
INT4OID, -1,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (subexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("array subscript must have type integer")));
+ errmsg("array subscript must have type integer"),
+ parser_errposition(pstate, exprLocation(ai->uidx))));
upperIndexpr = lappend(upperIndexpr, subexpr);
}
{
Oid typesource = exprType(assignFrom);
Oid typeneeded = isSlice ? arrayType : elementType;
+ Node *newFrom;
- assignFrom = coerce_to_target_type(pstate,
- assignFrom, typesource,
- typeneeded, elementTypMod,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
- if (assignFrom == NULL)
+ newFrom = coerce_to_target_type(pstate,
+ assignFrom, typesource,
+ typeneeded, elementTypMod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST,
+ -1);
+ if (newFrom == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array assignment requires type %s"
" but expression is of type %s",
format_type_be(typeneeded),
format_type_be(typesource)),
- errhint("You will need to rewrite or cast the expression.")));
+ errhint("You will need to rewrite or cast the expression."),
+ parser_errposition(pstate, exprLocation(assignFrom))));
+ assignFrom = newFrom;
}
/*
* too many examples that fail if we try.
*/
Const *
-make_const(Value *value)
+make_const(Value *value, int location)
{
Datum val;
int64 val64;
(Datum) 0,
true,
false);
+ con->location = location;
return con;
default:
val,
false,
typebyval);
+ con->location = location;
return con;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.104 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.105 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
result->opresulttype = rettype;
result->opretset = get_func_retset(opform->oprcode);
result->args = args;
+ result->location = location;
ReleaseSysCache(tup);
result->opfuncid = opform->oprcode;
result->useOr = useOr;
result->args = args;
+ result->location = location;
ReleaseSysCache(tup);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.133 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.134 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
errmsg("column reference \"%s\" is ambiguous",
colname),
parser_errposition(pstate, location)));
- result = (Node *) make_var(pstate, rte, attnum);
+ result = (Node *) make_var(pstate, rte, attnum, location);
/* Require read access */
rte->requiredPerms |= ACL_SELECT;
}
Int16GetDatum(attnum),
0, 0))
{
- result = (Node *) make_var(pstate, rte, attnum);
+ result = (Node *) make_var(pstate, rte, attnum, location);
/* Require read access */
rte->requiredPerms |= ACL_SELECT;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.161 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.162 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* colname target column name (ie, name of attribute to be assigned to)
* attrno target attribute number
* indirection subscripts/field names for target column, if any
- * location error cursor position, or -1
+ * location error cursor position for the target column, or -1
*
* Returns the modified expression.
*/
*/
colVar = (Node *) make_var(pstate,
pstate->p_target_rangetblentry,
- attrno);
+ attrno,
+ location);
}
expr = (Expr *)
(Node *) expr, type_id,
attrtype, attrtypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
rhs, exprType(rhs),
targetTypeId, targetTypMod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (result == NULL)
{
if (targetIsArray)
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.15 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.16 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
snamenode = makeNode(A_Const);
snamenode->val.type = T_String;
snamenode->val.val.str = qstring;
+ snamenode->location = -1;
castnode = makeNode(TypeCast);
castnode->typename = SystemTypeName("regclass");
castnode->arg = (Node *) snamenode;
+ castnode->location = -1;
funccallnode = makeNode(FuncCall);
funccallnode->funcname = SystemFuncName("nextval");
funccallnode->args = list_make1(castnode);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.178 2008/08/25 22:42:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.179 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
InvalidOid, -1,
att_tup->atttypid,
COERCE_IMPLICIT_CAST,
+ -1,
false,
false);
}
expr, exprtype,
atttype, atttypmod,
COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
+ COERCE_IMPLICIT_CAST,
+ -1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
InvalidOid, -1,
att_tup->atttypid,
COERCE_IMPLICIT_CAST,
+ -1,
false,
false);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.111 2008/08/25 22:42:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.112 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
InvalidOid, -1,
var->vartype,
COERCE_IMPLICIT_CAST,
+ -1,
false,
false);
}
rowexpr->args = fields;
rowexpr->row_typeid = var->vartype;
rowexpr->row_format = COERCE_IMPLICIT_CAST;
+ rowexpr->location = -1;
return (Node *) rowexpr;
}
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.480 2008/08/25 11:18:43 mha Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.481 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200808251
+#define CATALOG_VERSION_NO 200808281
#endif
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.61 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.62 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Node *makeBoolConst(bool value, bool isnull);
-extern Expr *makeBoolExpr(BoolExprType boolop, List *args);
+extern Expr *makeBoolExpr(BoolExprType boolop, List *args, int location);
extern Alias *makeAlias(const char *aliasname, List *colnames);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodeFuncs.h,v 1.27 2008/08/25 22:42:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodeFuncs.h,v 1.28 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
extern bool expression_returns_set(Node *clause);
+extern int exprLocation(Node *expr);
+
extern bool expression_tree_walker(Node *node, bool (*walker) (),
void *context);
extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (),
* parsenodes.h
* definitions for parse tree nodes
*
+ * Many of the node types used in parsetrees include a "location" field.
+ * This is a byte (not character) offset in the original source text, to be
+ * used for positioning an error cursor when there is an error related to
+ * the node. Access to the original source text is needed to make use of
+ * the location.
+ *
*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.371 2008/08/07 01:11:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.372 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* Most of these node types appear in raw parsetrees output by the grammar,
* and get transformed to something else by the analyzer. A few of them
* are used as-is in transformed querytrees.
- *
- * Many of the node types used in raw parsetrees include a "location" field.
- * This is a byte (not character) offset in the original source text, to be
- * used for positioning an error cursor when there is an analysis-time
- * error related to the node.
****************************************************************************/
/*
{
NodeTag type;
int number; /* the number of the parameter */
+ int location; /* token location, or -1 if unknown */
} ParamRef;
/*
{
NodeTag type;
Value val; /* value (includes type info, see value.h) */
+ int location; /* token location, or -1 if unknown */
} A_Const;
/*
NodeTag type;
Node *arg; /* the expression being casted */
TypeName *typename; /* the target type */
+ int location; /* token location, or -1 if unknown */
} TypeCast;
/*
{
NodeTag type;
List *elements; /* array element expressions */
+ int location; /* token location, or -1 if unknown */
} A_ArrayExpr;
/*
} LockingClause;
/*
- * XMLSERIALIZE
+ * XMLSERIALIZE (in raw parse tree only)
*/
typedef struct XmlSerialize
{
NodeTag type;
- XmlOptionType xmloption;
+ XmlOptionType xmloption; /* DOCUMENT or CONTENT */
Node *expr;
TypeName *typename;
+ int location; /* token location, or -1 if unknown */
} XmlSerialize;
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.139 2008/08/22 00:16:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.140 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* all */
Oid vartype; /* pg_type OID for the type of this var */
int32 vartypmod; /* pg_attribute typmod value */
- Index varlevelsup;
-
- /*
- * for subquery variables referencing outer relations; 0 in a normal var,
- * >0 means N levels up
- */
+ Index varlevelsup; /* for subquery variables referencing outer
+ * relations; 0 in a normal var, >0 means N
+ * levels up */
Index varnoold; /* original value of varno, for debugging */
AttrNumber varoattno; /* original value of varattno */
+ int location; /* token location, or -1 if unknown */
} Var;
/*
* If true, then all the information is stored
* in the Datum. If false, then the Datum
* contains a pointer to the information. */
+ int location; /* token location, or -1 if unknown */
} Const;
/* ----------------
int paramid; /* numeric ID for parameter */
Oid paramtype; /* pg_type OID of parameter's datatype */
int32 paramtypmod; /* typmod value, if known */
+ int location; /* token location, or -1 if unknown */
} Param;
/*
Index agglevelsup; /* > 0 if agg belongs to outer query */
bool aggstar; /* TRUE if argument list was really '*' */
bool aggdistinct; /* TRUE if it's agg(DISTINCT ...) */
+ int location; /* token location, or -1 if unknown */
} Aggref;
/* ----------------
bool funcretset; /* true if function returns set */
CoercionForm funcformat; /* how to display this function call */
List *args; /* arguments to the function */
+ int location; /* token location, or -1 if unknown */
} FuncExpr;
/*
Oid opresulttype; /* PG_TYPE OID of result value */
bool opretset; /* true if operator returns set */
List *args; /* arguments to the operator (1 or 2) */
+ int location; /* token location, or -1 if unknown */
} OpExpr;
/*
Oid opfuncid; /* PG_PROC OID of underlying function */
bool useOr; /* true for ANY, false for ALL */
List *args; /* the scalar and array operands */
+ int location; /* token location, or -1 if unknown */
} ScalarArrayOpExpr;
/*
*
* Notice the arguments are given as a List. For NOT, of course the list
* must always have exactly one element. For AND and OR, the executor can
- * handle any number of arguments. The parser treats AND and OR as binary
- * and so it only produces two-element lists, but the optimizer will flatten
- * trees of AND and OR nodes to produce longer lists when possible.
+ * handle any number of arguments. The parser generally treats AND and OR
+ * as binary and so it typically only produces two-element lists, but the
+ * optimizer will flatten trees of AND and OR nodes to produce longer lists
+ * when possible. There are also a few special cases where more arguments
+ * can appear before optimization.
*/
typedef enum BoolExprType
{
Expr xpr;
BoolExprType boolop;
List *args; /* arguments to this expression */
+ int location; /* token location, or -1 if unknown */
} BoolExpr;
/*
Node *testexpr; /* outer-query test for ALL/ANY/ROWCOMPARE */
List *operName; /* originally specified operator name */
Node *subselect; /* subselect as Query* or parsetree */
+ int location; /* token location, or -1 if unknown */
} SubLink;
/*
Oid resulttype; /* output type of coercion expression */
int32 resulttypmod; /* output typmod (usually -1) */
CoercionForm relabelformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} RelabelType;
/* ----------------
Oid resulttype; /* output type of coercion */
/* output typmod is not stored, but is presumed -1 */
CoercionForm coerceformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} CoerceViaIO;
/* ----------------
int32 resulttypmod; /* output typmod (also element typmod) */
bool isExplicit; /* conversion semantics flag to pass to func */
CoercionForm coerceformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} ArrayCoerceExpr;
/* ----------------
Oid resulttype; /* output type (always a composite type) */
/* result typmod is not stored, but must be -1; see RowExpr comments */
CoercionForm convertformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} ConvertRowtypeExpr;
/*----------
Expr *arg; /* implicit equality comparison argument */
List *args; /* the arguments (list of WHEN clauses) */
Expr *defresult; /* the default result (ELSE clause) */
+ int location; /* token location, or -1 if unknown */
} CaseExpr;
/*
Expr xpr;
Expr *expr; /* condition expression */
Expr *result; /* substitution result */
+ int location; /* token location, or -1 if unknown */
} CaseWhen;
/*
Oid element_typeid; /* common type of array elements */
List *elements; /* the array elements or sub-arrays */
bool multidims; /* true if elements are sub-arrays */
+ int location; /* token location, or -1 if unknown */
} ArrayExpr;
/*
* parsetrees. We must assume typmod -1 for a RowExpr node.
*/
CoercionForm row_format; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} RowExpr;
/*
Expr xpr;
Oid coalescetype; /* type of expression result */
List *args; /* the arguments */
+ int location; /* token location, or -1 if unknown */
} CoalesceExpr;
/*
Oid minmaxtype; /* common type of arguments and result */
MinMaxOp op; /* function to execute */
List *args; /* the arguments */
+ int location; /* token location, or -1 if unknown */
} MinMaxExpr;
/*
XmlOptionType xmloption; /* DOCUMENT or CONTENT */
Oid type; /* target type for XMLSERIALIZE */
int32 typmod;
+ int location; /* token location, or -1 if unknown */
} XmlExpr;
/*
Oid resulttype; /* domain type ID (result type) */
int32 resulttypmod; /* output typmod (currently always -1) */
CoercionForm coercionformat; /* how to display this node */
+ int location; /* token location, or -1 if unknown */
} CoerceToDomain;
/*
Expr xpr;
Oid typeId; /* type for substituted value */
int32 typeMod; /* typemod for substituted value */
+ int location; /* token location, or -1 if unknown */
} CoerceToDomainValue;
/*
Expr xpr;
Oid typeId; /* type for substituted value */
int32 typeMod; /* typemod for substituted value */
+ int location; /* token location, or -1 if unknown */
} SetToDefault;
/*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.76 2008/07/30 17:05:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.77 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Node *expr, Oid exprtype,
Oid targettype, int32 targettypmod,
CoercionContext ccontext,
- CoercionForm cformat);
+ CoercionForm cformat,
+ int location);
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
CoercionContext ccontext);
extern Node *coerce_type(ParseState *pstate, Node *node,
Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
- CoercionContext ccontext, CoercionForm cformat);
+ CoercionContext ccontext, CoercionForm cformat, int location);
extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod,
Oid typeId,
- CoercionForm cformat, bool hideInputCoercion,
+ CoercionForm cformat, int location,
+ bool hideInputCoercion,
bool lengthCoercionDone);
extern Node *coerce_to_boolean(ParseState *pstate, Node *node,
Oid targetTypeId,
const char *constructName);
-extern Oid select_common_type(List *typeids, const char *context);
+extern int parser_coercion_errposition(ParseState *pstate,
+ int coerce_location,
+ Node *input_expr);
+
+extern Oid select_common_type(ParseState *pstate, List *exprs,
+ const char *context, Node **which_expr);
extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
Oid targetTypeId,
const char *context);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.54 2008/06/19 00:46:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.55 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern void free_parsestate(ParseState *pstate);
extern int parser_errposition(ParseState *pstate, int location);
-extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);
+extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno,
+ int location);
extern Oid transformArrayType(Oid arrayType);
extern ArrayRef *transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
int32 elementTypMod,
List *indirection,
Node *assignFrom);
-extern Const *make_const(Value *value);
+extern Const *make_const(Value *value, int location);
#endif /* PARSE_NODE_H */
ERROR: malformed array literal: "{ }}"
select array[];
ERROR: cannot determine type of empty array
+LINE 1: select array[];
+ ^
HINT: Explicitly cast to the desired type, for example ARRAY[]::integer[].
-- none of the above should be accepted
-- all of the following should be accepted
-- failure expected
SELECT c, count(*) FROM test_missing_target GROUP BY 3;
ERROR: GROUP BY position 3 is not in select list
+LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3;
+ ^
-- group w/o existing GROUP BY and ORDER BY target under ambiguous condition
-- failure expected
SELECT count(*) FROM test_missing_target x, test_missing_target y
-- failure expected
SELECT c, count(*) FROM test_missing_target GROUP BY 3;
ERROR: GROUP BY position 3 is not in select list
+LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3;
+ ^
-- group w/o existing GROUP BY and ORDER BY target under ambiguous condition
-- failure expected
SELECT count(*) FROM test_missing_target x, test_missing_target y
-- failure expected
SELECT c, count(*) FROM test_missing_target GROUP BY 3;
ERROR: GROUP BY position 3 is not in select list
+LINE 1: SELECT c, count(*) FROM test_missing_target GROUP BY 3;
+ ^
-- group w/o existing GROUP BY and ORDER BY target under ambiguous condition
-- failure expected
SELECT count(*) FROM test_missing_target x, test_missing_target y
SELECT xmlconcat(1, 2);
ERROR: argument of XMLCONCAT must be type xml, not type integer
+LINE 1: SELECT xmlconcat(1, 2);
+ ^
SELECT xmlconcat('bad', '<syntax');
ERROR: invalid XML content
DETAIL: Entity: line 1: parser error : Couldn't find end of Start Tag syntax line 1
SELECT xmlelement(name element,
xmlattributes ('unnamed and wrong'));
ERROR: unnamed XML attribute value must be a column reference
+LINE 2: xmlattributes ('unnamed and wrong'));
+ ^
SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
xmlelement
-------------------------------------------
SELECT xmlelement(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
ERROR: XML attribute name "a" appears more than once
+LINE 1: ...ment(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
+ ^
SELECT xmlelement(name num, 37);
xmlelement
---------------
HINT: You need to rebuild PostgreSQL using --with-libxml.
SELECT xmlconcat(1, 2);
ERROR: argument of XMLCONCAT must be type xml, not type integer
+LINE 1: SELECT xmlconcat(1, 2);
+ ^
SELECT xmlconcat('bad', '<syntax');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.