📄 parse_expr.c
字号:
* Although the parser does not ever deal with already-planned * expression trees, we support SubPlan nodes in this routine * for the convenience of ruleutils.c. */ SubPlan *subplan = (SubPlan *) expr; if (subplan->subLinkType == EXPR_SUBLINK || subplan->subLinkType == ARRAY_SUBLINK) { /* get the type of the subselect's first target column */ TargetEntry *tent; tent = (TargetEntry *) linitial(subplan->plan->targetlist); Assert(IsA(tent, TargetEntry)); Assert(!tent->resjunk); type = exprType((Node *) tent->expr); if (subplan->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 subplan types, result is boolean */ type = BOOLOID; } } break; case T_FieldSelect: type = ((FieldSelect *) expr)->resulttype; break; case T_FieldStore: type = ((FieldStore *) expr)->resulttype; break; case T_RelabelType: type = ((RelabelType *) expr)->resulttype; break; case T_ConvertRowtypeExpr: type = ((ConvertRowtypeExpr *) expr)->resulttype; break; case T_CaseExpr: type = ((CaseExpr *) expr)->casetype; break; case T_CaseWhen: type = exprType((Node *) ((CaseWhen *) expr)->result); break; case T_CaseTestExpr: type = ((CaseTestExpr *) expr)->typeId; break; case T_ArrayExpr: type = ((ArrayExpr *) expr)->array_typeid; break; case T_RowExpr: type = ((RowExpr *) expr)->row_typeid; break; case T_CoalesceExpr: type = ((CoalesceExpr *) expr)->coalescetype; break; case T_MinMaxExpr: type = ((MinMaxExpr *) expr)->minmaxtype; break; case T_NullIfExpr: type = exprType((Node *) linitial(((NullIfExpr *) expr)->args)); break; case T_NullTest: type = BOOLOID; break; case T_BooleanTest: type = BOOLOID; break; case T_CoerceToDomain: type = ((CoerceToDomain *) expr)->resulttype; break; case T_CoerceToDomainValue: type = ((CoerceToDomainValue *) expr)->typeId; break; case T_SetToDefault: type = ((SetToDefault *) expr)->typeId; break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); type = InvalidOid; /* keep compiler quiet */ break; } return type;}/* * exprTypmod - * returns the type-specific attrmod of the expression, if it can be * determined. In most cases, it can't and we return -1. */int32exprTypmod(Node *expr){ if (!expr) return -1; switch (nodeTag(expr)) { case T_Var: return ((Var *) expr)->vartypmod; case T_Const: { /* Be smart about string constants... */ Const *con = (Const *) expr; switch (con->consttype) { case BPCHAROID: if (!con->constisnull) { int32 len = VARSIZE(DatumGetPointer(con->constvalue)) - VARHDRSZ; /* if multi-byte, take len and find # characters */ if (pg_database_encoding_max_length() > 1) len = pg_mbstrlen_with_len(VARDATA(DatumGetPointer(con->constvalue)), len); return len + VARHDRSZ; } break; default: break; } } break; case T_FuncExpr: { int32 coercedTypmod; /* Be smart about length-coercion functions... */ if (exprIsLengthCoercion(expr, &coercedTypmod)) return coercedTypmod; } break; case T_FieldSelect: return ((FieldSelect *) expr)->resulttypmod; case T_RelabelType: return ((RelabelType *) expr)->resulttypmod; case T_CaseExpr: { /* * If all the alternatives agree on type/typmod, return that * typmod, else use -1 */ CaseExpr *cexpr = (CaseExpr *) expr; Oid casetype = cexpr->casetype; int32 typmod; ListCell *arg; if (!cexpr->defresult) return -1; if (exprType((Node *) cexpr->defresult) != casetype) return -1; typmod = exprTypmod((Node *) cexpr->defresult); if (typmod < 0) return -1; /* no point in trying harder */ foreach(arg, cexpr->args) { CaseWhen *w = (CaseWhen *) lfirst(arg); Assert(IsA(w, CaseWhen)); if (exprType((Node *) w->result) != casetype) return -1; if (exprTypmod((Node *) w->result) != typmod) return -1; } return typmod; } break; case T_CaseTestExpr: return ((CaseTestExpr *) expr)->typeMod; case T_CoalesceExpr: { /* * If all the alternatives agree on type/typmod, return that * typmod, else use -1 */ CoalesceExpr *cexpr = (CoalesceExpr *) expr; Oid coalescetype = cexpr->coalescetype; int32 typmod; ListCell *arg; if (exprType((Node *) linitial(cexpr->args)) != coalescetype) return -1; typmod = exprTypmod((Node *) linitial(cexpr->args)); if (typmod < 0) return -1; /* no point in trying harder */ for_each_cell(arg, lnext(list_head(cexpr->args))) { Node *e = (Node *) lfirst(arg); if (exprType(e) != coalescetype) return -1; if (exprTypmod(e) != typmod) return -1; } return typmod; } break; case T_MinMaxExpr: { /* * If all the alternatives agree on type/typmod, return that * typmod, else use -1 */ MinMaxExpr *mexpr = (MinMaxExpr *) expr; Oid minmaxtype = mexpr->minmaxtype; int32 typmod; ListCell *arg; if (exprType((Node *) linitial(mexpr->args)) != minmaxtype) return -1; typmod = exprTypmod((Node *) linitial(mexpr->args)); if (typmod < 0) return -1; /* no point in trying harder */ for_each_cell(arg, lnext(list_head(mexpr->args))) { Node *e = (Node *) lfirst(arg); if (exprType(e) != minmaxtype) return -1; if (exprTypmod(e) != typmod) return -1; } return typmod; } break; case T_NullIfExpr: { NullIfExpr *nexpr = (NullIfExpr *) expr; return exprTypmod((Node *) linitial(nexpr->args)); } break; case T_CoerceToDomain: return ((CoerceToDomain *) expr)->resulttypmod; case T_CoerceToDomainValue: return ((CoerceToDomainValue *) expr)->typeMod; case T_SetToDefault: return ((SetToDefault *) expr)->typeMod; default: break; } return -1;}/* * exprIsLengthCoercion * Detect whether an expression tree is an application of a datatype's * typmod-coercion function. Optionally extract the result's typmod. * * If coercedTypmod is not NULL, the typmod is stored there if the expression * is a length-coercion function, else -1 is stored there. * * Note that a combined type-and-length coercion will be treated as a * length coercion by this routine. */boolexprIsLengthCoercion(Node *expr, int32 *coercedTypmod){ FuncExpr *func; int nargs; Const *second_arg; if (coercedTypmod != NULL) *coercedTypmod = -1; /* default result on failure */ /* Is it a function-call at all? */ if (expr == NULL || !IsA(expr, FuncExpr)) return false; func = (FuncExpr *) expr; /* * If it didn't come from a coercion context, reject. */ if (func->funcformat != COERCE_EXPLICIT_CAST && func->funcformat != COERCE_IMPLICIT_CAST) return false; /* * If it's not a two-argument or three-argument function with the second * argument being an int4 constant, it can't have been created from a * length coercion (it must be a type coercion, instead). */ nargs = list_length(func->args); if (nargs < 2 || nargs > 3) return false; second_arg = (Const *) lsecond(func->args); if (!IsA(second_arg, Const) || second_arg->consttype != INT4OID || second_arg->constisnull) return false; /* * OK, it is indeed a length-coercion function. */ if (coercedTypmod != NULL) *coercedTypmod = DatumGetInt32(second_arg->constvalue); return true;}/* * Handle an explicit CAST construct. * * The given expr has already been transformed, but we need to lookup * the type name and then apply any necessary coercion function(s). */static Node *typecast_expression(ParseState *pstate, Node *expr, TypeName *typename){ Oid inputType = exprType(expr); Oid targetType; targetType = typenameTypeId(typename); if (inputType == InvalidOid) return expr; /* do nothing if NULL input */ expr = coerce_to_target_type(pstate, expr, inputType, targetType, typename->typmod, COERCION_EXPLICIT, COERCE_EXPLICIT_CAST); if (expr == NULL) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), errmsg("cannot cast type %s to %s", format_type_be(inputType), format_type_be(targetType)))); return expr;}/* * Transform a "row op row" construct */static Node *make_row_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree){ Node *result = NULL; RowExpr *lrow, *rrow; List *largs, *rargs; ListCell *l, *r; char *oprname; BoolExprType boolop; /* Inputs are untransformed RowExprs */ lrow = (RowExpr *) transformExpr(pstate, ltree); rrow = (RowExpr *) transformExpr(pstate, rtree); Assert(IsA(lrow, RowExpr)); Assert(IsA(rrow, RowExpr)); largs = lrow->args; rargs = rrow->args; if (list_length(largs) != list_length(rargs)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unequal number of entries in row expression"))); /* * XXX it's really wrong to generate a simple AND combination for < <= > * >=. We probably need to invent a new runtime node type to handle those * correctly. For the moment, though, keep on doing this ... */ oprname = strVal(llast(opname)); if ((strcmp(oprname, "=") == 0) || (strcmp(oprname, "<") == 0) || (strcmp(oprname, "<=") == 0) || (strcmp(oprname, ">") == 0) || (strcmp(oprname, ">=") == 0)) boolop = AND_EXPR; else if (strcmp(oprname, "<>") == 0) boolop = OR_EXPR; else { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("operator %s is not supported for row expressions", oprname))); boolop = 0; /* keep compiler quiet */ } forboth(l, largs, r, rargs) { Node *larg = (Node *) lfirst(l); Node *rarg = (Node *) lfirst(r); Node *cmp; cmp = (Node *) make_op(pstate, opname, larg, rarg); cmp = coerce_to_boolean(pstate, cmp, "row comparison"); if (result == NULL) result = cmp; else result = (Node *) makeBoolExpr(boolop, list_make2(result, cmp)); } if (result == NULL) { /* zero-length rows? Generate constant TRUE or FALSE */ if (boolop == AND_EXPR) result = makeBoolConst(true, false); else result = makeBoolConst(false, false); } return result;}/* * Transform a "row IS DISTINCT FROM row" construct */static Node *make_row_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree){ Node *result = NULL; RowExpr *lrow, *rrow; List *largs, *rargs; ListCell *l, *r; /* Inputs are untransformed RowExprs */ lrow = (RowExpr *) transformExpr(pstate, ltree); rrow = (RowExpr *) transformExpr(pstate, rtree); Assert(IsA(lrow, RowExpr)); Assert(IsA(rrow, RowExpr)); largs = lrow->args; rargs = rrow->args; if (list_length(largs) != list_length(rargs)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unequal number of entries in row expression"))); forboth(l, largs, r, rargs) { Node *larg = (Node *) lfirst(l); Node *rarg = (Node *) lfirst(r); Node *cmp; cmp = (Node *) make_distinct_op(pstate, opname, larg, rarg); if (result == NULL) result = cmp; else result = (Node *) makeBoolExpr(OR_EXPR, list_make2(result, cmp)); } if (result == NULL) { /* zero-length rows? Generate constant FALSE */ result = makeBoolConst(false, false); } return result;}/* * make the node for an IS DISTINCT FROM operator */static Expr *make_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree){ Expr *result; result = make_op(pstate, opname, ltree, rtree); if (((OpExpr *) result)->opresulttype != BOOLOID) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("IS DISTINCT FROM requires = operator to yield boolean"))); /* * We rely on DistinctExpr and OpExpr being same struct */ NodeSetTag(result, T_DistinctExpr); return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -