📄 parse_expr.c
字号:
{ /* 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->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 *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m){ MinMaxExpr *newm = makeNode(MinMaxExpr); List *newargs = NIL; List *newcoercedargs = NIL; List *typeids = NIL; ListCell *args; newm->op = m->op; foreach(args, m->args) { Node *e = (Node *) lfirst(args); Node *newe; newe = transformExpr(pstate, e); newargs = lappend(newargs, newe); typeids = lappend_oid(typeids, exprType(newe)); } newm->minmaxtype = select_common_type(typeids, "GREATEST/LEAST"); /* Convert arguments if necessary */ foreach(args, newargs) { Node *e = (Node *) lfirst(args); Node *newe; newe = coerce_to_common_type(pstate, e, newm->minmaxtype, "GREATEST/LEAST"); newcoercedargs = lappend(newcoercedargs, newe); } newm->args = newcoercedargs; return (Node *) newm;}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.*". * * A whole-row reference is a Var with varno set to the correct range * table entry, and varattno == 0 to signal that it references the whole * tuple. (Use of zero here is unclean, since it could easily be confused * with error cases, but it's not worth changing now.) The vartype indicates * a rowtype; either a named composite type, or RECORD. */static Node *transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname){ Node *result; RangeTblEntry *rte; int vnum; int sublevels_up; Oid toid; /* Look up the referenced RTE, creating it if needed */ rte = refnameRangeTblEntry(pstate, schemaname, relname, &sublevels_up); if (rte == NULL) rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname)); vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); /* Build the appropriate referencing node */ switch (rte->rtekind) { case RTE_RELATION: /* relation: the rowtype is a named composite type */ toid = get_rel_type_id(rte->relid); if (!OidIsValid(toid)) elog(ERROR, "could not find type OID for relation %u", rte->relid); result = (Node *) makeVar(vnum, InvalidAttrNumber, toid, -1, sublevels_up); break; case RTE_FUNCTION: toid = exprType(rte->funcexpr); if (toid == RECORDOID || get_typtype(toid) == 'c') { /* func returns composite; same as relation case */ result = (Node *) makeVar(vnum, InvalidAttrNumber, toid, -1, sublevels_up); } else { /* * func returns scalar; instead of making a whole-row Var, * just reference the function's scalar output. (XXX this * seems a tad inconsistent, especially if "f.*" was * explicitly written ...) */ result = (Node *) makeVar(vnum, 1, toid, -1, sublevels_up); } break; default: /* * RTE is a join or subselect. We represent this as a whole-row * Var of RECORD type. (Note that in most cases the Var will be * expanded to a RowExpr during planning, but that is not our * concern here.) */ result = (Node *) makeVar(vnum, InvalidAttrNumber, RECORDOID, -1, sublevels_up); break; } return result;}/* * exprType - * returns the Oid of the type of the expression. (Used for typechecking.) */OidexprType(Node *expr){ Oid type; if (!expr) return InvalidOid; switch (nodeTag(expr)) { case T_Var: type = ((Var *) expr)->vartype; break; case T_Const: type = ((Const *) expr)->consttype; break; case T_Param: type = ((Param *) expr)->paramtype; break; case T_Aggref: type = ((Aggref *) expr)->aggtype; break; case T_ArrayRef: type = ((ArrayRef *) expr)->refrestype; break; case T_FuncExpr: type = ((FuncExpr *) expr)->funcresulttype; break; case T_OpExpr: type = ((OpExpr *) expr)->opresulttype; break; case T_DistinctExpr: type = ((DistinctExpr *) expr)->opresulttype; break; case T_ScalarArrayOpExpr: type = BOOLOID; break; case T_BoolExpr: type = BOOLOID; break; case T_SubLink: { SubLink *sublink = (SubLink *) expr; if (sublink->subLinkType == EXPR_SUBLINK || sublink->subLinkType == ARRAY_SUBLINK) { /* get the type of the subselect's first target column */ Query *qtree = (Query *) sublink->subselect; TargetEntry *tent; if (!qtree || !IsA(qtree, Query)) elog(ERROR, "cannot get type for untransformed sublink"); tent = (TargetEntry *) linitial(qtree->targetList); Assert(IsA(tent, TargetEntry)); Assert(!tent->resjunk); type = exprType((Node *) tent->expr); if (sublink->subLinkType == ARRAY_SUBLINK) { type = get_array_type(type); if (!OidIsValid(type)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(exprType((Node *) tent->expr))))); } } else { /* for all other sublink types, result is boolean */ type = BOOLOID; } } break; case T_SubPlan: { /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -