📄 parse_expr.c
字号:
errmsg("improper qualified name (too many dotted names): %s", NameListToString(cref->fields)))); node = NULL; /* keep compiler quiet */ break; } 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))->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))->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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -