aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorNeil Conway <neilc@samurai.com>2005-01-19 23:45:24 +0000
committerNeil Conway <neilc@samurai.com>2005-01-19 23:45:24 +0000
commita341a96c01c08669918df4398950c519db159380 (patch)
tree8bbf157ffe5b4ccbdff521c0de3776bdc7b06646 /src/backend/parser/parse_expr.c
parenta73198ac176a5db1910547d3418ea4ae6b059ca4 (diff)
downloadpostgresql-a341a96c01c08669918df4398950c519db159380.tar.gz
postgresql-a341a96c01c08669918df4398950c519db159380.zip
Refactor transformExpr() by creating separate functions for most of the
expression types.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r--src/backend/parser/parse_expr.c1588
1 files changed, 827 insertions, 761 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 6676ae0a4bd..ba3dbcad75b 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.179 2005/01/12 17:32:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.180 2005/01/19 23:45:24 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,9 +37,27 @@
bool Transform_null_equals = false;
+static Node *transformParamRef(ParseState *pstate, ParamRef *pref);
+static Node *transformAExprOp(ParseState *pstate, A_Expr *a);
+static Node *transformAExprAnd(ParseState *pstate, A_Expr *a);
+static Node *transformAExprOr(ParseState *pstate, A_Expr *a);
+static Node *transformAExprNot(ParseState *pstate, A_Expr *a);
+static Node *transformAExprOpAny(ParseState *pstate, A_Expr *a);
+static Node *transformAExprOpAll(ParseState *pstate, A_Expr *a);
+static Node *transformAExprDistinct(ParseState *pstate, A_Expr *a);
+static Node *transformAExprNullIf(ParseState *pstate, A_Expr *a);
+static Node *transformAExprOf(ParseState *pstate, A_Expr *a);
+static Node *transformFuncCall(ParseState *pstate, FuncCall *fn);
+static Node *transformCaseExpr(ParseState *pstate, CaseExpr *c);
+static Node *transformSubLink(ParseState *pstate, SubLink *sublink);
+static Node *transformArrayExpr(ParseState *pstate, ArrayExpr *a);
+static Node *transformRowExpr(ParseState *pstate, RowExpr *r);
+static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
+static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
char *relname);
+static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection);
static Node *typecast_expression(ParseState *pstate, Node *expr,
@@ -90,65 +108,13 @@ transformExpr(ParseState *pstate, Node *expr)
switch (nodeTag(expr))
{
case T_ColumnRef:
- {
- result = transformColumnRef(pstate, (ColumnRef *) expr);
- break;
- }
- case T_ParamRef:
- {
- ParamRef *pref = (ParamRef *) expr;
- int paramno = pref->number;
- ParseState *toppstate;
- Param *param;
-
- /*
- * Find topmost ParseState, which is where paramtype info
- * lives.
- */
- toppstate = pstate;
- while (toppstate->parentParseState != NULL)
- toppstate = toppstate->parentParseState;
+ result = transformColumnRef(pstate, (ColumnRef *) expr);
+ break;
- /* Check parameter number is in range */
- if (paramno <= 0) /* probably can't happen? */
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_PARAMETER),
- errmsg("there is no parameter $%d", paramno)));
- if (paramno > toppstate->p_numparams)
- {
- if (!toppstate->p_variableparams)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_PARAMETER),
- errmsg("there is no parameter $%d",
- paramno)));
- /* Okay to enlarge param array */
- if (toppstate->p_paramtypes)
- toppstate->p_paramtypes =
- (Oid *) repalloc(toppstate->p_paramtypes,
- paramno * sizeof(Oid));
- else
- toppstate->p_paramtypes =
- (Oid *) palloc(paramno * sizeof(Oid));
- /* Zero out the previously-unreferenced slots */
- MemSet(toppstate->p_paramtypes + toppstate->p_numparams,
- 0,
- (paramno - toppstate->p_numparams) * sizeof(Oid));
- toppstate->p_numparams = paramno;
- }
- if (toppstate->p_variableparams)
- {
- /* If not seen before, initialize to UNKNOWN type */
- if (toppstate->p_paramtypes[paramno - 1] == InvalidOid)
- toppstate->p_paramtypes[paramno - 1] = UNKNOWNOID;
- }
+ case T_ParamRef:
+ result = transformParamRef(pstate, (ParamRef *) expr);
+ break;
- param = makeNode(Param);
- param->paramkind = PARAM_NUM;
- param->paramid = (AttrNumber) paramno;
- param->paramtype = toppstate->p_paramtypes[paramno - 1];
- result = (Node *) param;
- break;
- }
case T_A_Const:
{
A_Const *con = (A_Const *) expr;
@@ -160,6 +126,7 @@ transformExpr(ParseState *pstate, Node *expr)
con->typename);
break;
}
+
case T_A_Indirection:
{
A_Indirection *ind = (A_Indirection *) expr;
@@ -169,6 +136,7 @@ transformExpr(ParseState *pstate, Node *expr)
ind->indirection);
break;
}
+
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
@@ -177,6 +145,7 @@ transformExpr(ParseState *pstate, Node *expr)
result = typecast_expression(pstate, arg, tc->typename);
break;
}
+
case T_A_Expr:
{
A_Expr *a = (A_Expr *) expr;
@@ -184,701 +153,61 @@ transformExpr(ParseState *pstate, Node *expr)
switch (a->kind)
{
case AEXPR_OP:
- {
- Node *lexpr = a->lexpr;
- Node *rexpr = a->rexpr;
-
- /*
- * Special-case "foo = NULL" and "NULL = foo"
- * for compatibility with standards-broken
- * products (like Microsoft's). Turn these
- * into IS NULL exprs.
- */
- if (Transform_null_equals &&
- list_length(a->name) == 1 &&
- strcmp(strVal(linitial(a->name)), "=") == 0 &&
- (exprIsNullConstant(lexpr) ||
- exprIsNullConstant(rexpr)))
- {
- NullTest *n = makeNode(NullTest);
-
- n->nulltesttype = IS_NULL;
-
- if (exprIsNullConstant(lexpr))
- n->arg = (Expr *) rexpr;
- else
- n->arg = (Expr *) lexpr;
-
- result = transformExpr(pstate,
- (Node *) n);
- }
- else if (lexpr && IsA(lexpr, RowExpr) &&
- rexpr && IsA(rexpr, SubLink) &&
- ((SubLink *) rexpr)->subLinkType == EXPR_SUBLINK)
- {
- /*
- * Convert "row op subselect" into a
- * MULTIEXPR sublink. Formerly the
- * grammar did this, but now that a row
- * construct is allowed anywhere in
- * expressions, it's easier to do it here.
- */
- SubLink *s = (SubLink *) rexpr;
-
- s->subLinkType = MULTIEXPR_SUBLINK;
- s->lefthand = ((RowExpr *) lexpr)->args;
- s->operName = a->name;
- result = transformExpr(pstate, (Node *) s);
- }
- else if (lexpr && IsA(lexpr, RowExpr) &&
- rexpr && IsA(rexpr, RowExpr))
- {
- /* "row op row" */
- result = make_row_op(pstate, a->name,
- lexpr, rexpr);
- }
- else
- {
- /* Ordinary scalar operator */
- lexpr = transformExpr(pstate, lexpr);
- rexpr = transformExpr(pstate, rexpr);
-
- result = (Node *) make_op(pstate,
- a->name,
- lexpr,
- rexpr);
- }
- }
+ result = transformAExprOp(pstate, a);
break;
case AEXPR_AND:
- {
- Node *lexpr = transformExpr(pstate,
- a->lexpr);
- Node *rexpr = transformExpr(pstate,
- a->rexpr);
-
- lexpr = coerce_to_boolean(pstate, lexpr, "AND");
- rexpr = coerce_to_boolean(pstate, rexpr, "AND");
-
- result = (Node *) makeBoolExpr(AND_EXPR,
- list_make2(lexpr,
- rexpr));
- }
+ result = transformAExprAnd(pstate, a);
break;
case AEXPR_OR:
- {
- Node *lexpr = transformExpr(pstate,
- a->lexpr);
- Node *rexpr = transformExpr(pstate,
- a->rexpr);
-
- lexpr = coerce_to_boolean(pstate, lexpr, "OR");
- rexpr = coerce_to_boolean(pstate, rexpr, "OR");
-
- result = (Node *) makeBoolExpr(OR_EXPR,
- list_make2(lexpr,
- rexpr));
- }
+ result = transformAExprOr(pstate, a);
break;
case AEXPR_NOT:
- {
- Node *rexpr = transformExpr(pstate,
- a->rexpr);
-
- rexpr = coerce_to_boolean(pstate, rexpr, "NOT");
-
- result = (Node *) makeBoolExpr(NOT_EXPR,
- list_make1(rexpr));
- }
+ result = transformAExprNot(pstate, a);
break;
case AEXPR_OP_ANY:
- {
- Node *lexpr = transformExpr(pstate,
- a->lexpr);
- Node *rexpr = transformExpr(pstate,
- a->rexpr);
-
- result = (Node *) make_scalar_array_op(pstate,
- a->name,
- true,
- lexpr,
- rexpr);
- }
+ result = transformAExprOpAny(pstate, a);
break;
case AEXPR_OP_ALL:
- {
- Node *lexpr = transformExpr(pstate,
- a->lexpr);
- Node *rexpr = transformExpr(pstate,
- a->rexpr);
-
- result = (Node *) make_scalar_array_op(pstate,
- a->name,
- false,
- lexpr,
- rexpr);
- }
+ result = transformAExprOpAll(pstate, a);
break;
case AEXPR_DISTINCT:
- {
- Node *lexpr = a->lexpr;
- Node *rexpr = a->rexpr;
-
- if (lexpr && IsA(lexpr, RowExpr) &&
- rexpr && IsA(rexpr, RowExpr))
- {
- /* "row op row" */
- result = make_row_distinct_op(pstate, a->name,
- lexpr, rexpr);
- }
- else
- {
- /* Ordinary scalar operator */
- lexpr = transformExpr(pstate, lexpr);
- rexpr = transformExpr(pstate, rexpr);
-
- result = (Node *) make_distinct_op(pstate,
- a->name,
- lexpr,
- rexpr);
- }
- }
+ result = transformAExprDistinct(pstate, a);
break;
case AEXPR_NULLIF:
- {
- Node *lexpr = transformExpr(pstate,
- a->lexpr);
- Node *rexpr = transformExpr(pstate,
- a->rexpr);
-
- result = (Node *) make_op(pstate,
- a->name,
- lexpr,
- rexpr);
- if (((OpExpr *) result)->opresulttype != BOOLOID)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("NULLIF requires = operator to yield boolean")));
-
- /*
- * We rely on NullIfExpr and OpExpr being same
- * struct
- */
- NodeSetTag(result, T_NullIfExpr);
- }
+ result = transformAExprNullIf(pstate, a);
break;
case AEXPR_OF:
- {
- /*
- * Checking an expression for match to type.
- * Will result in a boolean constant node.
- */
- ListCell *telem;
- A_Const *n;
- Oid ltype,
- rtype;
- bool matched = FALSE;
- Node *lexpr = transformExpr(pstate,
- a->lexpr);
-
- ltype = exprType(lexpr);
- foreach(telem, (List *) a->rexpr)
- {
- rtype = LookupTypeName(lfirst(telem));
- matched = (rtype == ltype);
- if (matched)
- break;
- }
-
- /*
- * Expect two forms: equals or not equals.
- * Flip the sense of the result for not
- * equals.
- */
- if (strcmp(strVal(linitial(a->name)), "!=") == 0)
- matched = (!matched);
-
- n = makeNode(A_Const);
- n->val.type = T_String;
- n->val.val.str = (matched ? "t" : "f");
- n->typename = SystemTypeName("bool");
-
- result = transformExpr(pstate, (Node *) n);
- }
+ result = transformAExprOf(pstate, a);
break;
+ default:
+ elog(ERROR, "unrecognized A_Expr kind: %d", a->kind);
}
break;
}
+
case T_FuncCall:
- {
- FuncCall *fn = (FuncCall *) expr;
- List *targs;
- ListCell *args;
+ result = transformFuncCall(pstate, (FuncCall *) expr);
+ break;
- /*
- * Transform the list of arguments. We use a shallow list
- * copy and then transform-in-place to avoid O(N^2)
- * behavior from repeated lappend's.
- *
- * XXX: repeated lappend() would no longer result in O(n^2)
- * behavior; worth reconsidering this design?
- */
- targs = list_copy(fn->args);
- foreach(args, targs)
- {
- lfirst(args) = transformExpr(pstate,
- (Node *) lfirst(args));
- }
- result = ParseFuncOrColumn(pstate,
- fn->funcname,
- targs,
- fn->agg_star,
- fn->agg_distinct,
- false);
- break;
- }
case T_SubLink:
- {
- SubLink *sublink = (SubLink *) expr;
- List *qtrees;
- Query *qtree;
-
- /* If we already transformed this node, do nothing */
- if (IsA(sublink->subselect, Query))
- {
- result = expr;
- break;
- }
- pstate->p_hasSubLinks = true;
- qtrees = parse_sub_analyze(sublink->subselect, pstate);
- if (list_length(qtrees) != 1)
- elog(ERROR, "bad query in sub-select");
- qtree = (Query *) linitial(qtrees);
- if (qtree->commandType != CMD_SELECT ||
- qtree->resultRelation != 0)
- elog(ERROR, "bad query in sub-select");
- sublink->subselect = (Node *) qtree;
-
- if (sublink->subLinkType == EXISTS_SUBLINK)
- {
- /*
- * EXISTS needs no lefthand or combining operator.
- * These fields should be NIL already, but make sure.
- */
- sublink->lefthand = NIL;
- sublink->operName = NIL;
- sublink->operOids = NIL;
- sublink->useOr = FALSE;
- }
- else if (sublink->subLinkType == EXPR_SUBLINK ||
- sublink->subLinkType == ARRAY_SUBLINK)
- {
- ListCell *tlist_item = list_head(qtree->targetList);
-
- /*
- * Make sure the subselect delivers a single column
- * (ignoring resjunk targets).
- */
- if (tlist_item == NULL ||
- ((TargetEntry *) lfirst(tlist_item))->resdom->resjunk)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery must return a column")));
- while ((tlist_item = lnext(tlist_item)) != NULL)
- {
- if (!((TargetEntry *) lfirst(tlist_item))->resdom->resjunk)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery must return only one column")));
- }
-
- /*
- * EXPR and ARRAY need no lefthand or combining
- * operator. These fields should be NIL already, but
- * make sure.
- */
- sublink->lefthand = NIL;
- sublink->operName = NIL;
- sublink->operOids = NIL;
- sublink->useOr = FALSE;
- }
- else
- {
- /* ALL, ANY, or MULTIEXPR: generate operator list */
- List *left_list = sublink->lefthand;
- List *right_list = qtree->targetList;
- int row_length = list_length(left_list);
- bool needNot = false;
- List *op = sublink->operName;
- char *opname = strVal(llast(op));
- ListCell *l;
- ListCell *ll_item;
-
- /* transform lefthand expressions */
- foreach(l, left_list)
- lfirst(l) = transformExpr(pstate, lfirst(l));
-
- /*
- * If the expression is "<> ALL" (with unqualified
- * opname) then convert it to "NOT IN". This is a
- * hack to improve efficiency of expressions output by
- * pre-7.4 Postgres.
- */
- if (sublink->subLinkType == ALL_SUBLINK &&
- list_length(op) == 1 && strcmp(opname, "<>") == 0)
- {
- sublink->subLinkType = ANY_SUBLINK;
- opname = pstrdup("=");
- op = list_make1(makeString(opname));
- sublink->operName = op;
- needNot = true;
- }
-
- /* Set useOr if op is "<>" (possibly qualified) */
- if (strcmp(opname, "<>") == 0)
- sublink->useOr = TRUE;
- else
- sublink->useOr = FALSE;
-
- /* Combining operators other than =/<> is dubious... */
- if (row_length != 1 &&
- strcmp(opname, "=") != 0 &&
- strcmp(opname, "<>") != 0)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("row comparison cannot use operator %s",
- opname)));
-
- /*
- * To build the list of combining operator OIDs, we
- * must scan subquery's targetlist to find values that
- * will be matched against lefthand values. We need
- * to ignore resjunk targets, so doing the outer
- * iteration over right_list is easier than doing it
- * over left_list.
- */
- sublink->operOids = NIL;
-
- ll_item = list_head(left_list);
- foreach(l, right_list)
- {
- TargetEntry *tent = (TargetEntry *) lfirst(l);
- Node *lexpr;
- Operator optup;
- Form_pg_operator opform;
-
- if (tent->resdom->resjunk)
- continue;
-
- if (ll_item == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery has too many columns")));
- lexpr = lfirst(ll_item);
- ll_item = lnext(ll_item);
-
- /*
- * It's OK to use oper() not compatible_oper()
- * here, because make_subplan() will insert type
- * coercion calls if needed.
- */
- optup = oper(op,
- exprType(lexpr),
- exprType((Node *) tent->expr),
- false);
- opform = (Form_pg_operator) GETSTRUCT(optup);
-
- if (opform->oprresult != BOOLOID)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("operator %s must return type boolean, not type %s",
- opname,
- format_type_be(opform->oprresult)),
- errhint("The operator of a quantified predicate subquery must return type boolean.")));
-
- if (get_func_retset(opform->oprcode))
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("operator %s must not return a set",
- opname),
- errhint("The operator of a quantified predicate subquery must return type boolean.")));
-
- sublink->operOids = lappend_oid(sublink->operOids,
- oprid(optup));
-
- ReleaseSysCache(optup);
- }
- if (ll_item != NULL)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery has too few columns")));
-
- if (needNot)
- {
- expr = coerce_to_boolean(pstate, expr, "NOT");
- expr = (Node *) makeBoolExpr(NOT_EXPR,
- list_make1(expr));
- }
- }
- result = (Node *) expr;
- break;
- }
+ result = transformSubLink(pstate, (SubLink *) expr);
+ break;
case T_CaseExpr:
- {
- CaseExpr *c = (CaseExpr *) expr;
- CaseExpr *newc;
- Node *arg;
- CaseTestExpr *placeholder;
- List *newargs;
- List *typeids;
- ListCell *l;
- Node *defresult;
- Oid ptype;
-
- /* If we already transformed this node, do nothing */
- if (OidIsValid(c->casetype))
- {
- result = expr;
- break;
- }
- newc = makeNode(CaseExpr);
-
- /* transform the test expression, if any */
- arg = transformExpr(pstate, (Node *) c->arg);
-
- /* generate placeholder for test expression */
- if (arg)
- {
- /*
- * If test expression is an untyped literal, force it to
- * text. We have to do something now because we won't be
- * able to do this coercion on the placeholder. This is
- * not as flexible as what was done in 7.4 and before,
- * but it's good enough to handle the sort of silly
- * coding commonly seen.
- */
- if (exprType(arg) == UNKNOWNOID)
- arg = coerce_to_common_type(pstate, arg,
- TEXTOID, "CASE");
- placeholder = makeNode(CaseTestExpr);
- placeholder->typeId = exprType(arg);
- placeholder->typeMod = exprTypmod(arg);
- }
- else
- placeholder = NULL;
-
- newc->arg = (Expr *) arg;
-
- /* transform the list of arguments */
- newargs = NIL;
- typeids = NIL;
- foreach(l, c->args)
- {
- CaseWhen *w = (CaseWhen *) lfirst(l);
- CaseWhen *neww = makeNode(CaseWhen);
- Node *warg;
-
- Assert(IsA(w, CaseWhen));
-
- warg = (Node *) w->expr;
- if (placeholder)
- {
- /* shorthand form was specified, so expand... */
- warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
- (Node *) placeholder,
- warg);
- }
- neww->expr = (Expr *) transformExpr(pstate, warg);
-
- neww->expr = (Expr *) coerce_to_boolean(pstate,
- (Node *) neww->expr,
- "CASE/WHEN");
-
- warg = (Node *) w->result;
- neww->result = (Expr *) transformExpr(pstate, warg);
-
- newargs = lappend(newargs, neww);
- typeids = lappend_oid(typeids, exprType((Node *) neww->result));
- }
-
- newc->args = newargs;
-
- /* transform the default clause */
- defresult = (Node *) c->defresult;
- if (defresult == NULL)
- {
- A_Const *n = makeNode(A_Const);
-
- n->val.type = T_Null;
- defresult = (Node *) n;
- }
- newc->defresult = (Expr *) transformExpr(pstate, defresult);
-
- /*
- * Note: default result is considered the most significant
- * type in 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);
-
- ptype = select_common_type(typeids, "CASE");
- Assert(OidIsValid(ptype));
- newc->casetype = ptype;
-
- /* Convert default result clause, if necessary */
- newc->defresult = (Expr *)
- coerce_to_common_type(pstate,
- (Node *) newc->defresult,
- ptype,
- "CASE/ELSE");
-
- /* Convert when-clause results, if necessary */
- foreach(l, newc->args)
- {
- CaseWhen *w = (CaseWhen *) lfirst(l);
-
- w->result = (Expr *)
- coerce_to_common_type(pstate,
- (Node *) w->result,
- ptype,
- "CASE/WHEN");
- }
-
- result = (Node *) newc;
- break;
- }
+ result = transformCaseExpr(pstate, (CaseExpr *) expr);
+ break;
case T_ArrayExpr:
- {
- ArrayExpr *a = (ArrayExpr *) expr;
- ArrayExpr *newa = makeNode(ArrayExpr);
- List *newelems = NIL;
- List *newcoercedelems = NIL;
- List *typeids = NIL;
- ListCell *element;
- Oid array_type;
- Oid element_type;
-
- /* Transform the element expressions */
- foreach(element, a->elements)
- {
- Node *e = (Node *) lfirst(element);
- Node *newe;
-
- newe = transformExpr(pstate, e);
- newelems = lappend(newelems, newe);
- typeids = lappend_oid(typeids, exprType(newe));
- }
-
- /* Select a common type for the elements */
- element_type = select_common_type(typeids, "ARRAY");
-
- /* Coerce arguments to common type if necessary */
- foreach(element, newelems)
- {
- Node *e = (Node *) lfirst(element);
- Node *newe;
-
- newe = coerce_to_common_type(pstate, e,
- element_type,
- "ARRAY");
- newcoercedelems = lappend(newcoercedelems, newe);
- }
-
- /* Do we have an array type to use? */
- array_type = get_array_type(element_type);
- if (array_type != InvalidOid)
- {
- /* Elements are presumably of scalar type */
- newa->multidims = false;
- }
- else
- {
- /* Must be nested array expressions */
- newa->multidims = true;
-
- array_type = element_type;
- element_type = get_element_type(array_type);
- if (!OidIsValid(element_type))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("could not find array type for data type %s",
- format_type_be(array_type))));
- }
-
- newa->array_typeid = array_type;
- newa->element_typeid = element_type;
- newa->elements = newcoercedelems;
-
- result = (Node *) newa;
- break;
- }
+ result = transformArrayExpr(pstate, (ArrayExpr *) expr);
+ break;
case T_RowExpr:
- {
- RowExpr *r = (RowExpr *) expr;
- RowExpr *newr = makeNode(RowExpr);
- List *newargs = NIL;
- ListCell *arg;
-
- /* Transform the field expressions */
- foreach(arg, r->args)
- {
- Node *e = (Node *) lfirst(arg);
- Node *newe;
-
- newe = transformExpr(pstate, e);
- newargs = lappend(newargs, newe);
- }
- newr->args = newargs;
-
- /* Barring later casting, we consider the type RECORD */
- newr->row_typeid = RECORDOID;
- newr->row_format = COERCE_IMPLICIT_CAST;
-
- result = (Node *) newr;
- break;
- }
+ result = transformRowExpr(pstate, (RowExpr *) expr);
+ break;
case T_CoalesceExpr:
- {
- CoalesceExpr *c = (CoalesceExpr *) expr;
- CoalesceExpr *newc = makeNode(CoalesceExpr);
- List *newargs = NIL;
- List *newcoercedargs = NIL;
- List *typeids = NIL;
- ListCell *args;
-
- foreach(args, c->args)
- {
- Node *e = (Node *) lfirst(args);
- Node *newe;
-
- newe = transformExpr(pstate, e);
- newargs = lappend(newargs, newe);
- typeids = lappend_oid(typeids, exprType(newe));
- }
-
- newc->coalescetype = select_common_type(typeids, "COALESCE");
-
- /* Convert arguments if necessary */
- foreach(args, newargs)
- {
- Node *e = (Node *) lfirst(args);
- Node *newe;
-
- newe = coerce_to_common_type(pstate, e,
- newc->coalescetype,
- "COALESCE");
- newcoercedargs = lappend(newcoercedargs, newe);
- }
-
- newc->args = newcoercedargs;
- result = (Node *) newc;
- break;
- }
+ result = transformCoalesceExpr(pstate, (CoalesceExpr *) expr);
+ break;
case T_NullTest:
{
@@ -891,45 +220,8 @@ transformExpr(ParseState *pstate, Node *expr)
}
case T_BooleanTest:
- {
- BooleanTest *b = (BooleanTest *) expr;
- const char *clausename;
-
- switch (b->booltesttype)
- {
- case IS_TRUE:
- clausename = "IS TRUE";
- break;
- case IS_NOT_TRUE:
- clausename = "IS NOT TRUE";
- break;
- case IS_FALSE:
- clausename = "IS FALSE";
- break;
- case IS_NOT_FALSE:
- clausename = "IS NOT FALSE";
- break;
- case IS_UNKNOWN:
- clausename = "IS UNKNOWN";
- break;
- case IS_NOT_UNKNOWN:
- clausename = "IS NOT UNKNOWN";
- break;
- default:
- elog(ERROR, "unrecognized booltesttype: %d",
- (int) b->booltesttype);
- clausename = NULL; /* keep compiler quiet */
- }
-
- b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg);
-
- b->arg = (Expr *) coerce_to_boolean(pstate,
- (Node *) b->arg,
- clausename);
-
- result = expr;
- break;
- }
+ result = transformBooleanTest(pstate, (BooleanTest *) expr);
+ break;
/*********************************************
* Quietly accept node types that may be presented when we are
@@ -1203,6 +495,780 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
return node;
}
+static Node *
+transformParamRef(ParseState *pstate, ParamRef *pref)
+{
+ int paramno = pref->number;
+ ParseState *toppstate;
+ Param *param;
+
+ /*
+ * Find topmost ParseState, which is where paramtype info lives.
+ */
+ toppstate = pstate;
+ while (toppstate->parentParseState != NULL)
+ toppstate = toppstate->parentParseState;
+
+ /* Check parameter number is in range */
+ if (paramno <= 0) /* probably can't happen? */
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_PARAMETER),
+ errmsg("there is no parameter $%d", paramno)));
+ if (paramno > toppstate->p_numparams)
+ {
+ if (!toppstate->p_variableparams)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_PARAMETER),
+ errmsg("there is no parameter $%d",
+ paramno)));
+ /* Okay to enlarge param array */
+ if (toppstate->p_paramtypes)
+ toppstate->p_paramtypes =
+ (Oid *) repalloc(toppstate->p_paramtypes,
+ paramno * sizeof(Oid));
+ else
+ toppstate->p_paramtypes =
+ (Oid *) palloc(paramno * sizeof(Oid));
+ /* Zero out the previously-unreferenced slots */
+ MemSet(toppstate->p_paramtypes + toppstate->p_numparams,
+ 0,
+ (paramno - toppstate->p_numparams) * sizeof(Oid));
+ toppstate->p_numparams = paramno;
+ }
+ if (toppstate->p_variableparams)
+ {
+ /* If not seen before, initialize to UNKNOWN type */
+ if (toppstate->p_paramtypes[paramno - 1] == InvalidOid)
+ toppstate->p_paramtypes[paramno - 1] = UNKNOWNOID;
+ }
+
+ param = makeNode(Param);
+ param->paramkind = PARAM_NUM;
+ param->paramid = (AttrNumber) paramno;
+ param->paramtype = toppstate->p_paramtypes[paramno - 1];
+
+ return (Node *) param;
+}
+
+static Node *
+transformAExprOp(ParseState *pstate, A_Expr *a)
+{
+ Node *lexpr = a->lexpr;
+ Node *rexpr = a->rexpr;
+ Node *result;
+
+ /*
+ * Special-case "foo = NULL" and "NULL = foo" for compatibility
+ * with standards-broken products (like Microsoft's). Turn these
+ * into IS NULL exprs.
+ */
+ if (Transform_null_equals &&
+ list_length(a->name) == 1 &&
+ strcmp(strVal(linitial(a->name)), "=") == 0 &&
+ (exprIsNullConstant(lexpr) || exprIsNullConstant(rexpr)))
+ {
+ NullTest *n = makeNode(NullTest);
+
+ n->nulltesttype = IS_NULL;
+
+ if (exprIsNullConstant(lexpr))
+ n->arg = (Expr *) rexpr;
+ else
+ n->arg = (Expr *) lexpr;
+
+ result = transformExpr(pstate, (Node *) n);
+ }
+ else if (lexpr && IsA(lexpr, RowExpr) &&
+ rexpr && IsA(rexpr, SubLink) &&
+ ((SubLink *) rexpr)->subLinkType == EXPR_SUBLINK)
+ {
+ /*
+ * Convert "row op subselect" into a MULTIEXPR sublink.
+ * Formerly the grammar did this, but now that a row construct
+ * is allowed anywhere in expressions, it's easier to do it
+ * here.
+ */
+ SubLink *s = (SubLink *) rexpr;
+
+ s->subLinkType = MULTIEXPR_SUBLINK;
+ s->lefthand = ((RowExpr *) lexpr)->args;
+ s->operName = a->name;
+ result = transformExpr(pstate, (Node *) s);
+ }
+ else if (lexpr && IsA(lexpr, RowExpr) &&
+ rexpr && IsA(rexpr, RowExpr))
+ {
+ /* "row op row" */
+ result = make_row_op(pstate, a->name, lexpr, rexpr);
+ }
+ else
+ {
+ /* Ordinary scalar operator */
+ lexpr = transformExpr(pstate, lexpr);
+ rexpr = transformExpr(pstate, rexpr);
+
+ result = (Node *) make_op(pstate,
+ a->name,
+ lexpr,
+ rexpr);
+ }
+
+ return result;
+}
+
+static Node *
+transformAExprAnd(ParseState *pstate, A_Expr *a)
+{
+ Node *lexpr = transformExpr(pstate, a->lexpr);
+ Node *rexpr = transformExpr(pstate, a->rexpr);
+
+ lexpr = coerce_to_boolean(pstate, lexpr, "AND");
+ rexpr = coerce_to_boolean(pstate, rexpr, "AND");
+
+ return (Node *) makeBoolExpr(AND_EXPR,
+ list_make2(lexpr, rexpr));
+}
+
+static Node *
+transformAExprOr(ParseState *pstate, A_Expr *a)
+{
+ Node *lexpr = transformExpr(pstate, a->lexpr);
+ Node *rexpr = transformExpr(pstate, a->rexpr);
+
+ lexpr = coerce_to_boolean(pstate, lexpr, "OR");
+ rexpr = coerce_to_boolean(pstate, rexpr, "OR");
+
+ return (Node *) makeBoolExpr(OR_EXPR,
+ list_make2(lexpr, rexpr));
+}
+
+static Node *
+transformAExprNot(ParseState *pstate, A_Expr *a)
+{
+ Node *rexpr = transformExpr(pstate, a->rexpr);
+
+ rexpr = coerce_to_boolean(pstate, rexpr, "NOT");
+
+ return (Node *) makeBoolExpr(NOT_EXPR,
+ list_make1(rexpr));
+}
+
+static Node *
+transformAExprOpAny(ParseState *pstate, A_Expr *a)
+{
+ Node *lexpr = transformExpr(pstate, a->lexpr);
+ Node *rexpr = transformExpr(pstate, a->rexpr);
+
+ return (Node *) make_scalar_array_op(pstate,
+ a->name,
+ true,
+ lexpr,
+ rexpr);
+}
+
+static Node *
+transformAExprOpAll(ParseState *pstate, A_Expr *a)
+{
+ Node *lexpr = transformExpr(pstate, a->lexpr);
+ Node *rexpr = transformExpr(pstate, a->rexpr);
+
+ return (Node *) make_scalar_array_op(pstate,
+ a->name,
+ false,
+ lexpr,
+ rexpr);
+}
+
+static Node *
+transformAExprDistinct(ParseState *pstate, A_Expr *a)
+{
+ Node *lexpr = a->lexpr;
+ Node *rexpr = a->rexpr;
+
+ if (lexpr && IsA(lexpr, RowExpr) &&
+ rexpr && IsA(rexpr, RowExpr))
+ {
+ /* "row op row" */
+ return make_row_distinct_op(pstate, a->name,
+ lexpr, rexpr);
+ }
+ else
+ {
+ /* Ordinary scalar operator */
+ lexpr = transformExpr(pstate, lexpr);
+ rexpr = transformExpr(pstate, rexpr);
+
+ return (Node *) make_distinct_op(pstate,
+ a->name,
+ lexpr,
+ rexpr);
+ }
+}
+
+static Node *
+transformAExprNullIf(ParseState *pstate, A_Expr *a)
+{
+ Node *lexpr = transformExpr(pstate, a->lexpr);
+ Node *rexpr = transformExpr(pstate, a->rexpr);
+ Node *result;
+
+ result = (Node *) make_op(pstate,
+ a->name,
+ lexpr,
+ rexpr);
+ if (((OpExpr *) result)->opresulttype != BOOLOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("NULLIF requires = operator to yield boolean")));
+
+ /*
+ * We rely on NullIfExpr and OpExpr being the same struct
+ */
+ NodeSetTag(result, T_NullIfExpr);
+
+ return result;
+}
+
+static Node *
+transformAExprOf(ParseState *pstate, A_Expr *a)
+{
+ /*
+ * Checking an expression for match to type. Will result in a
+ * boolean constant node.
+ */
+ ListCell *telem;
+ A_Const *n;
+ Oid ltype,
+ rtype;
+ bool matched = false;
+ Node *lexpr = transformExpr(pstate, a->lexpr);
+
+ ltype = exprType(lexpr);
+ foreach(telem, (List *) a->rexpr)
+ {
+ rtype = LookupTypeName(lfirst(telem));
+ matched = (rtype == ltype);
+ if (matched)
+ break;
+ }
+
+ /*
+ * Expect two forms: equals or not equals. Flip the sense of the
+ * result for not equals.
+ */
+ if (strcmp(strVal(linitial(a->name)), "!=") == 0)
+ matched = (!matched);
+
+ n = makeNode(A_Const);
+ n->val.type = T_String;
+ n->val.val.str = (matched ? "t" : "f");
+ n->typename = SystemTypeName("bool");
+
+ return transformExpr(pstate, (Node *) n);
+}
+
+static Node *
+transformFuncCall(ParseState *pstate, FuncCall *fn)
+{
+ List *targs;
+ ListCell *args;
+
+ /*
+ * Transform the list of arguments. We use a shallow list copy
+ * and then transform-in-place to avoid O(N^2) behavior from
+ * repeated lappend's.
+ *
+ * XXX: repeated lappend() would no longer result in O(n^2)
+ * behavior; worth reconsidering this design?
+ */
+ targs = list_copy(fn->args);
+ foreach(args, targs)
+ {
+ lfirst(args) = transformExpr(pstate,
+ (Node *) lfirst(args));
+ }
+
+ return ParseFuncOrColumn(pstate,
+ fn->funcname,
+ targs,
+ fn->agg_star,
+ fn->agg_distinct,
+ false);
+}
+
+static Node *
+transformCaseExpr(ParseState *pstate, CaseExpr *c)
+{
+ CaseExpr *newc;
+ Node *arg;
+ CaseTestExpr *placeholder;
+ List *newargs;
+ List *typeids;
+ ListCell *l;
+ Node *defresult;
+ Oid ptype;
+
+ /* If we already transformed this node, do nothing */
+ if (OidIsValid(c->casetype))
+ return (Node *) c;
+
+ newc = makeNode(CaseExpr);
+
+ /* transform the test expression, if any */
+ arg = transformExpr(pstate, (Node *) c->arg);
+
+ /* generate placeholder for test expression */
+ if (arg)
+ {
+ /*
+ * If test expression is an untyped literal, force it to text.
+ * We have to do something now because we won't be able to do
+ * this coercion on the placeholder. This is not as flexible
+ * as what was done in 7.4 and before, but it's good enough to
+ * handle the sort of silly coding commonly seen.
+ */
+ if (exprType(arg) == UNKNOWNOID)
+ arg = coerce_to_common_type(pstate, arg, TEXTOID, "CASE");
+
+ placeholder = makeNode(CaseTestExpr);
+ placeholder->typeId = exprType(arg);
+ placeholder->typeMod = exprTypmod(arg);
+ }
+ else
+ placeholder = NULL;
+
+ newc->arg = (Expr *) arg;
+
+ /* transform the list of arguments */
+ newargs = NIL;
+ typeids = NIL;
+ foreach(l, c->args)
+ {
+ CaseWhen *w = (CaseWhen *) lfirst(l);
+ CaseWhen *neww = makeNode(CaseWhen);
+ Node *warg;
+
+ Assert(IsA(w, CaseWhen));
+
+ warg = (Node *) w->expr;
+ if (placeholder)
+ {
+ /* shorthand form was specified, so expand... */
+ warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
+ (Node *) placeholder,
+ warg);
+ }
+ neww->expr = (Expr *) transformExpr(pstate, warg);
+
+ neww->expr = (Expr *) coerce_to_boolean(pstate,
+ (Node *) neww->expr,
+ "CASE/WHEN");
+
+ warg = (Node *) w->result;
+ neww->result = (Expr *) transformExpr(pstate, warg);
+
+ newargs = lappend(newargs, neww);
+ typeids = lappend_oid(typeids, exprType((Node *) neww->result));
+ }
+
+ newc->args = newargs;
+
+ /* transform the default clause */
+ defresult = (Node *) c->defresult;
+ if (defresult == NULL)
+ {
+ A_Const *n = makeNode(A_Const);
+
+ n->val.type = T_Null;
+ defresult = (Node *) n;
+ }
+ newc->defresult = (Expr *) transformExpr(pstate, defresult);
+
+ /*
+ * Note: default result is considered the most significant type in
+ * 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);
+
+ ptype = select_common_type(typeids, "CASE");
+ Assert(OidIsValid(ptype));
+ newc->casetype = ptype;
+
+ /* Convert default result clause, if necessary */
+ newc->defresult = (Expr *)
+ coerce_to_common_type(pstate,
+ (Node *) newc->defresult,
+ ptype,
+ "CASE/ELSE");
+
+ /* Convert when-clause results, if necessary */
+ foreach(l, newc->args)
+ {
+ CaseWhen *w = (CaseWhen *) lfirst(l);
+
+ w->result = (Expr *)
+ coerce_to_common_type(pstate,
+ (Node *) w->result,
+ ptype,
+ "CASE/WHEN");
+ }
+
+ return (Node *) newc;
+}
+
+static Node *
+transformSubLink(ParseState *pstate, SubLink *sublink)
+{
+ List *qtrees;
+ Query *qtree;
+ Node *result = (Node *) sublink;
+
+ /* If we already transformed this node, do nothing */
+ if (IsA(sublink->subselect, Query))
+ return result;
+
+ pstate->p_hasSubLinks = true;
+ qtrees = parse_sub_analyze(sublink->subselect, pstate);
+ if (list_length(qtrees) != 1)
+ elog(ERROR, "bad query in sub-select");
+ qtree = (Query *) linitial(qtrees);
+ if (qtree->commandType != CMD_SELECT ||
+ qtree->resultRelation != 0)
+ elog(ERROR, "bad query in sub-select");
+ sublink->subselect = (Node *) qtree;
+
+ if (sublink->subLinkType == EXISTS_SUBLINK)
+ {
+ /*
+ * EXISTS needs no lefthand or combining operator. These
+ * fields should be NIL already, but make sure.
+ */
+ sublink->lefthand = NIL;
+ sublink->operName = NIL;
+ sublink->operOids = NIL;
+ sublink->useOr = FALSE;
+ }
+ else if (sublink->subLinkType == EXPR_SUBLINK ||
+ sublink->subLinkType == ARRAY_SUBLINK)
+ {
+ ListCell *tlist_item = list_head(qtree->targetList);
+
+ /*
+ * Make sure the subselect delivers a single column (ignoring
+ * resjunk targets).
+ */
+ if (tlist_item == NULL ||
+ ((TargetEntry *) lfirst(tlist_item))->resdom->resjunk)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("subquery must return a column")));
+ while ((tlist_item = lnext(tlist_item)) != NULL)
+ {
+ if (!((TargetEntry *) lfirst(tlist_item))->resdom->resjunk)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("subquery must return only one column")));
+ }
+
+ /*
+ * EXPR and ARRAY need no lefthand or combining
+ * operator. These fields should be NIL already, but make
+ * sure.
+ */
+ sublink->lefthand = NIL;
+ sublink->operName = NIL;
+ sublink->operOids = NIL;
+ sublink->useOr = FALSE;
+ }
+ else
+ {
+ /* ALL, ANY, or MULTIEXPR: generate operator list */
+ List *left_list = sublink->lefthand;
+ List *right_list = qtree->targetList;
+ int row_length = list_length(left_list);
+ bool needNot = false;
+ List *op = sublink->operName;
+ char *opname = strVal(llast(op));
+ ListCell *l;
+ ListCell *ll_item;
+
+ /* transform lefthand expressions */
+ foreach(l, left_list)
+ lfirst(l) = transformExpr(pstate, lfirst(l));
+
+ /*
+ * If the expression is "<> ALL" (with unqualified opname)
+ * then convert it to "NOT IN". This is a hack to improve
+ * efficiency of expressions output by pre-7.4 Postgres.
+ */
+ if (sublink->subLinkType == ALL_SUBLINK &&
+ list_length(op) == 1 && strcmp(opname, "<>") == 0)
+ {
+ sublink->subLinkType = ANY_SUBLINK;
+ opname = pstrdup("=");
+ op = list_make1(makeString(opname));
+ sublink->operName = op;
+ needNot = true;
+ }
+
+ /* Set useOr if op is "<>" (possibly qualified) */
+ if (strcmp(opname, "<>") == 0)
+ sublink->useOr = TRUE;
+ else
+ sublink->useOr = FALSE;
+
+ /* Combining operators other than =/<> is dubious... */
+ if (row_length != 1 &&
+ strcmp(opname, "=") != 0 &&
+ strcmp(opname, "<>") != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("row comparison cannot use operator %s",
+ opname)));
+
+ /*
+ * To build the list of combining operator OIDs, we must scan
+ * subquery's targetlist to find values that will be matched
+ * against lefthand values. We need to ignore resjunk
+ * targets, so doing the outer iteration over right_list is
+ * easier than doing it over left_list.
+ */
+ sublink->operOids = NIL;
+
+ ll_item = list_head(left_list);
+ foreach(l, right_list)
+ {
+ TargetEntry *tent = (TargetEntry *) lfirst(l);
+ Node *lexpr;
+ Operator optup;
+ Form_pg_operator opform;
+
+ if (tent->resdom->resjunk)
+ continue;
+
+ if (ll_item == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("subquery has too many columns")));
+ lexpr = lfirst(ll_item);
+ ll_item = lnext(ll_item);
+
+ /*
+ * It's OK to use oper() not compatible_oper() here,
+ * because make_subplan() will insert type coercion calls
+ * if needed.
+ */
+ optup = oper(op,
+ exprType(lexpr),
+ exprType((Node *) tent->expr),
+ false);
+ opform = (Form_pg_operator) GETSTRUCT(optup);
+
+ if (opform->oprresult != BOOLOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("operator %s must return type boolean, not type %s",
+ opname,
+ format_type_be(opform->oprresult)),
+ errhint("The operator of a quantified predicate subquery must return type boolean.")));
+
+ if (get_func_retset(opform->oprcode))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("operator %s must not return a set",
+ opname),
+ errhint("The operator of a quantified predicate subquery must return type boolean.")));
+
+ sublink->operOids = lappend_oid(sublink->operOids,
+ oprid(optup));
+
+ ReleaseSysCache(optup);
+ }
+ if (ll_item != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("subquery has too few columns")));
+
+ if (needNot)
+ {
+ result = coerce_to_boolean(pstate, result, "NOT");
+ result = (Node *) makeBoolExpr(NOT_EXPR,
+ list_make1(result));
+ }
+ }
+
+ return result;
+}
+
+static Node *
+transformArrayExpr(ParseState *pstate, ArrayExpr *a)
+{
+ ArrayExpr *newa = makeNode(ArrayExpr);
+ List *newelems = NIL;
+ List *newcoercedelems = NIL;
+ List *typeids = NIL;
+ ListCell *element;
+ Oid array_type;
+ Oid element_type;
+
+ /* Transform the element expressions */
+ foreach(element, a->elements)
+ {
+ Node *e = (Node *) lfirst(element);
+ Node *newe;
+
+ newe = transformExpr(pstate, e);
+ newelems = lappend(newelems, newe);
+ typeids = lappend_oid(typeids, exprType(newe));
+ }
+
+ /* Select a common type for the elements */
+ element_type = select_common_type(typeids, "ARRAY");
+
+ /* Coerce arguments to common type if necessary */
+ foreach(element, newelems)
+ {
+ Node *e = (Node *) lfirst(element);
+ Node *newe;
+
+ newe = coerce_to_common_type(pstate, e,
+ element_type,
+ "ARRAY");
+ newcoercedelems = lappend(newcoercedelems, newe);
+ }
+
+ /* Do we have an array type to use? */
+ array_type = get_array_type(element_type);
+ if (array_type != InvalidOid)
+ {
+ /* Elements are presumably of scalar type */
+ newa->multidims = false;
+ }
+ else
+ {
+ /* Must be nested array expressions */
+ newa->multidims = true;
+
+ array_type = element_type;
+ element_type = get_element_type(array_type);
+ if (!OidIsValid(element_type))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find array type for data type %s",
+ format_type_be(array_type))));
+ }
+
+ newa->array_typeid = array_type;
+ newa->element_typeid = element_type;
+ newa->elements = newcoercedelems;
+
+ return (Node *) newa;
+}
+
+static Node *
+transformRowExpr(ParseState *pstate, RowExpr *r)
+{
+ RowExpr *newr = makeNode(RowExpr);
+ List *newargs = NIL;
+ ListCell *arg;
+
+ /* Transform the field expressions */
+ foreach(arg, r->args)
+ {
+ Node *e = (Node *) lfirst(arg);
+ Node *newe;
+
+ newe = transformExpr(pstate, e);
+ newargs = lappend(newargs, newe);
+ }
+ newr->args = newargs;
+
+ /* Barring later casting, we consider the type RECORD */
+ newr->row_typeid = RECORDOID;
+ newr->row_format = COERCE_IMPLICIT_CAST;
+
+ return (Node *) newr;
+}
+
+static Node *
+transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
+{
+ CoalesceExpr *newc = makeNode(CoalesceExpr);
+ List *newargs = NIL;
+ List *newcoercedargs = NIL;
+ List *typeids = NIL;
+ ListCell *args;
+
+ foreach(args, c->args)
+ {
+ Node *e = (Node *) lfirst(args);
+ Node *newe;
+
+ newe = transformExpr(pstate, e);
+ newargs = lappend(newargs, newe);
+ typeids = lappend_oid(typeids, exprType(newe));
+ }
+
+ newc->coalescetype = select_common_type(typeids, "COALESCE");
+
+ /* Convert arguments if necessary */
+ foreach(args, newargs)
+ {
+ Node *e = (Node *) lfirst(args);
+ Node *newe;
+
+ newe = coerce_to_common_type(pstate, e,
+ newc->coalescetype,
+ "COALESCE");
+ newcoercedargs = lappend(newcoercedargs, newe);
+ }
+
+ newc->args = newcoercedargs;
+ return (Node *) newc;
+}
+
+static Node *
+transformBooleanTest(ParseState *pstate, BooleanTest *b)
+{
+ const char *clausename;
+
+ switch (b->booltesttype)
+ {
+ case IS_TRUE:
+ clausename = "IS TRUE";
+ break;
+ case IS_NOT_TRUE:
+ clausename = "IS NOT TRUE";
+ break;
+ case IS_FALSE:
+ clausename = "IS FALSE";
+ break;
+ case IS_NOT_FALSE:
+ clausename = "IS NOT FALSE";
+ break;
+ case IS_UNKNOWN:
+ clausename = "IS UNKNOWN";
+ break;
+ case IS_NOT_UNKNOWN:
+ clausename = "IS NOT UNKNOWN";
+ break;
+ default:
+ elog(ERROR, "unrecognized booltesttype: %d",
+ (int) b->booltesttype);
+ clausename = NULL; /* keep compiler quiet */
+ }
+
+ b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg);
+
+ b->arg = (Expr *) coerce_to_boolean(pstate,
+ (Node *) b->arg,
+ clausename);
+
+ return (Node *) b;
+}
+
/*
* Construct a whole-row reference to represent the notation "relation.*".
*