diff options
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 485 |
1 files changed, 2 insertions, 483 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 6309525cabf..4257b91a8e9 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.230 2008/08/22 00:16:04 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.231 2008/08/25 22:42:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,13 +17,10 @@ #include "catalog/pg_type.h" #include "commands/dbcommands.h" -#include "mb/pg_wchar.h" #include "miscadmin.h" #include "nodes/makefuncs.h" -#include "nodes/plannodes.h" -#include "optimizer/clauses.h" +#include "nodes/nodeFuncs.h" #include "parser/analyze.h" -#include "parser/gramparse.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" #include "parser/parse_func.h" @@ -1864,484 +1861,6 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, } /* - * exprType - - * returns the Oid of the type of the expression. (Used for typechecking.) - */ -Oid -exprType(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: - { - ArrayRef *arrayref = (ArrayRef *) expr; - - /* slice and/or store operations yield the array type */ - if (arrayref->reflowerindexpr || arrayref->refassgnexpr) - type = arrayref->refarraytype; - else - type = arrayref->refelemtype; - } - 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: - { - /* - * 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 */ - type = subplan->firstColType; - 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(subplan->firstColType)))); - } - } - else - { - /* for all other subplan types, result is boolean */ - type = BOOLOID; - } - } - break; - case T_AlternativeSubPlan: - { - /* As above, supported for the convenience of ruleutils.c */ - AlternativeSubPlan *asplan = (AlternativeSubPlan *) expr; - - /* subplans should all return the same thing */ - type = exprType((Node *) linitial(asplan->subplans)); - } - 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_CoerceViaIO: - type = ((CoerceViaIO *) expr)->resulttype; - break; - case T_ArrayCoerceExpr: - type = ((ArrayCoerceExpr *) expr)->resulttype; - break; - case T_ConvertRowtypeExpr: - type = ((ConvertRowtypeExpr *) expr)->resulttype; - break; - case T_CaseExpr: - type = ((CaseExpr *) expr)->casetype; - 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_RowCompareExpr: - type = BOOLOID; - break; - case T_CoalesceExpr: - type = ((CoalesceExpr *) expr)->coalescetype; - break; - case T_MinMaxExpr: - type = ((MinMaxExpr *) expr)->minmaxtype; - break; - case T_XmlExpr: - if (((XmlExpr *) expr)->op == IS_DOCUMENT) - type = BOOLOID; - else if (((XmlExpr *) expr)->op == IS_XMLSERIALIZE) - type = TEXTOID; - else - type = XMLOID; - 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; - case T_CurrentOfExpr: - type = BOOLOID; - 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. - */ -int32 -exprTypmod(Node *expr) -{ - if (!expr) - return -1; - - switch (nodeTag(expr)) - { - case T_Var: - return ((Var *) expr)->vartypmod; - case T_Const: - return ((Const *) expr)->consttypmod; - case T_Param: - return ((Param *) expr)->paramtypmod; - case T_ArrayRef: - /* typmod is the same for array or element */ - return ((ArrayRef *) expr)->reftypmod; - case T_FuncExpr: - { - int32 coercedTypmod; - - /* Be smart about length-coercion functions... */ - if (exprIsLengthCoercion(expr, &coercedTypmod)) - return coercedTypmod; - } - break; - case T_SubLink: - { - SubLink *sublink = (SubLink *) expr; - - if (sublink->subLinkType == EXPR_SUBLINK || - sublink->subLinkType == ARRAY_SUBLINK) - { - /* get the typmod 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); - return exprTypmod((Node *) tent->expr); - /* note we don't need to care if it's an array */ - } - } - break; - case T_FieldSelect: - return ((FieldSelect *) expr)->resulttypmod; - case T_RelabelType: - return ((RelabelType *) expr)->resulttypmod; - case T_ArrayCoerceExpr: - return ((ArrayCoerceExpr *) 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_ArrayExpr: - { - /* - * If all the elements agree on type/typmod, return that - * typmod, else use -1 - */ - ArrayExpr *arrayexpr = (ArrayExpr *) expr; - Oid commontype; - int32 typmod; - ListCell *elem; - - if (arrayexpr->elements == NIL) - return -1; - typmod = exprTypmod((Node *) linitial(arrayexpr->elements)); - if (typmod < 0) - return -1; /* no point in trying harder */ - if (arrayexpr->multidims) - commontype = arrayexpr->array_typeid; - else - commontype = arrayexpr->element_typeid; - foreach(elem, arrayexpr->elements) - { - Node *e = (Node *) lfirst(elem); - - if (exprType(e) != commontype) - return -1; - if (exprTypmod(e) != 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; - 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. - */ -bool -exprIsLengthCoercion(Node *expr, int32 *coercedTypmod) -{ - if (coercedTypmod != NULL) - *coercedTypmod = -1; /* default result on failure */ - - /* - * Scalar-type length coercions are FuncExprs, array-type length coercions - * are ArrayCoerceExprs - */ - if (expr && IsA(expr, FuncExpr)) - { - FuncExpr *func = (FuncExpr *) expr; - int nargs; - Const *second_arg; - - /* - * 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; - } - - if (expr && IsA(expr, ArrayCoerceExpr)) - { - ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) expr; - - /* It's not a length coercion unless there's a nondefault typmod */ - if (acoerce->resulttypmod < 0) - return false; - - /* - * OK, it is indeed a length-coercion expression. - */ - if (coercedTypmod != NULL) - *coercedTypmod = acoerce->resulttypmod; - - return true; - } - - return false; -} - -/* * Handle an explicit CAST construct. * * The given expr has already been transformed, but we need to lookup |