parse_expr.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,537 行 · 第 1/3 页
C
1,537 行
rv->relname = name; rv->inhOpt = INH_DEFAULT; node = (Node *) rv; } else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" does not exist", name))); } break; } case 2: { char *name1 = strVal(lfirst(cref->fields)); char *name2 = strVal(lsecond(cref->fields)); /* Whole-row reference? */ if (strcmp(name2, "*") == 0) { rv = makeNode(RangeVar); rv->relname = name1; rv->inhOpt = INH_DEFAULT; node = (Node *) rv; break; } /* Try to identify as a once-qualified column */ node = qualifiedNameToVar(pstate, NULL, name1, name2, true); if (node == NULL) { /* * Not known as a column of any range-table entry, so * try it as a function call. Here, we will create an * implicit RTE for tables not already entered. */ rv = makeNode(RangeVar); rv->relname = name1; rv->inhOpt = INH_DEFAULT; node = ParseFuncOrColumn(pstate, makeList1(makeString(name2)), makeList1(rv), false, false, true); } break; } case 3: { char *name1 = strVal(lfirst(cref->fields)); char *name2 = strVal(lsecond(cref->fields)); char *name3 = strVal(lthird(cref->fields)); /* Whole-row reference? */ if (strcmp(name3, "*") == 0) { rv = makeNode(RangeVar); rv->schemaname = name1; rv->relname = name2; rv->inhOpt = INH_DEFAULT; node = (Node *) rv; break; } /* Try to identify as a twice-qualified column */ node = qualifiedNameToVar(pstate, name1, name2, name3, true); if (node == NULL) { /* Try it as a function call */ rv = makeNode(RangeVar); rv->schemaname = name1; rv->relname = name2; rv->inhOpt = INH_DEFAULT; node = ParseFuncOrColumn(pstate, makeList1(makeString(name3)), makeList1(rv), false, false, true); } break; } case 4: { char *name1 = strVal(lfirst(cref->fields)); char *name2 = strVal(lsecond(cref->fields)); char *name3 = strVal(lthird(cref->fields)); char *name4 = strVal(lfourth(cref->fields)); /* * We check the catalog name and then ignore it. */ if (strcmp(name1, get_database_name(MyDatabaseId)) != 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cross-database references are not implemented"))); /* Whole-row reference? */ if (strcmp(name4, "*") == 0) { rv = makeNode(RangeVar); rv->schemaname = name2; rv->relname = name3; rv->inhOpt = INH_DEFAULT; node = (Node *) rv; break; } /* Try to identify as a twice-qualified column */ node = qualifiedNameToVar(pstate, name2, name3, name4, true); if (node == NULL) { /* Try it as a function call */ rv = makeNode(RangeVar); rv->schemaname = name2; rv->relname = name3; rv->inhOpt = INH_DEFAULT; node = ParseFuncOrColumn(pstate, makeList1(makeString(name4)), makeList1(rv), false, false, true); } break; } default: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("improper qualified name (too many dotted names): %s", NameListToString(cref->fields)))); node = NULL; /* keep compiler quiet */ break; } return transformIndirection(pstate, node, cref->indirection);}/* * 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 *) lfirst(qtree->targetList); Assert(IsA(tent, TargetEntry)); Assert(!tent->resdom->resjunk); if (sublink->subLinkType == EXPR_SUBLINK) type = tent->resdom->restype; else/* ARRAY_SUBLINK */ { type = get_array_type(tent->resdom->restype); if (!OidIsValid(type)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(tent->resdom->restype)))); } } else { /* for all other sublink types, result is boolean */ type = BOOLOID; } } break; case T_SubPlan: { /* * 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 *) lfirst(subplan->plan->targetlist); Assert(IsA(tent, TargetEntry)); Assert(!tent->resdom->resjunk); if (subplan->subLinkType == EXPR_SUBLINK) type = tent->resdom->restype; else/* ARRAY_SUBLINK */ { type = get_array_type(tent->resdom->restype); if (!OidIsValid(type)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for data type %s", format_type_be(tent->resdom->restype)))); } } else { /* for all other subplan types, result is boolean */ type = BOOLOID; } } break; case T_FieldSelect: type = ((FieldSelect *) expr)->resulttype; break; case T_RelabelType: type = ((RelabelType *) expr)->resulttype; break; case T_CaseExpr: type = ((CaseExpr *) expr)->casetype; break; case T_CaseWhen: type = exprType((Node *) ((CaseWhen *) expr)->result); break; case T_ArrayExpr: type = ((ArrayExpr *) expr)->array_typeid; break; case T_CoalesceExpr: type = ((CoalesceExpr *) expr)->coalescetype; break; case T_NullIfExpr: type = exprType((Node *) lfirst(((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; case T_RangeVar: /* * If someone uses a bare relation name in an expression, we * will likely first notice a problem here (see comments in * transformColumnRef()). Issue an appropriate error message. */ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("relation reference \"%s\" cannot be used in an expression", ((RangeVar *) expr)->relname))); type = InvalidOid; /* keep compiler quiet */ 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) return VARSIZE(DatumGetPointer(con->constvalue)); 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; List *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_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; List *arg; typmod = exprTypmod((Node *) lfirst(cexpr->args)); foreach(arg, cexpr->args) { Node *e = (Node *) lfirst(arg); if (exprType(e) != coalescetype) return -1; if (exprTypmod(e) != typmod) return -1; } return typmod; } break; case T_NullIfExpr: { NullIfExpr *nexpr = (NullIfExpr *) expr; return exprTypmod((Node *) lfirst(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. */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 = 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;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?