diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 6676ae0a4b..ba3dbcad75 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; - } + result = transformColumnRef(pstate, (ColumnRef *) expr); + break; + case T_ParamRef: - { - ParamRef *pref = (ParamRef *) expr; - int paramno = pref->number; - ParseState *toppstate; - Param *param; + result = transformParamRef(pstate, (ParamRef *) expr); + break; - /* - * 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]; - 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.*". *