aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r--src/backend/parser/parse_expr.c485
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