diff options
Diffstat (limited to 'src/backend/parser/parse_coerce.c')
-rw-r--r-- | src/backend/parser/parse_coerce.c | 121 |
1 files changed, 120 insertions, 1 deletions
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index a5bff31c89f..c7a8c3c83bb 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.114 2004/03/15 01:13:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.115 2004/05/10 22:44:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,19 +19,26 @@ #include "nodes/makefuncs.h" #include "nodes/params.h" #include "optimizer/clauses.h" +#include "parser/parsetree.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" #include "parser/parse_func.h" +#include "parser/parse_relation.h" #include "parser/parse_type.h" #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/syscache.h" +#include "utils/typcache.h" static Node *coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, bool isExplicit); +static Node *coerce_record_to_complex(ParseState *pstate, Node *node, + Oid targetTypeId, + CoercionContext ccontext, + CoercionForm cformat); /* @@ -279,6 +286,13 @@ coerce_type(ParseState *pstate, Node *node, } return result; } + if (inputTypeId == RECORDOID && + ISCOMPLEX(targetTypeId)) + { + /* Coerce a RECORD to a specific complex type */ + return coerce_record_to_complex(pstate, node, targetTypeId, + ccontext, cformat); + } if (typeInheritsFrom(inputTypeId, targetTypeId)) { /* @@ -360,6 +374,14 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, continue; /* + * If input is RECORD and target is a composite type, assume + * we can coerce (may need tighter checking here) + */ + if (inputTypeId == RECORDOID && + ISCOMPLEX(targetTypeId)) + continue; + + /* * If input is a class type that inherits from target, accept */ if (typeInheritsFrom(inputTypeId, targetTypeId)) @@ -506,6 +528,103 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, return node; } +/* + * coerce_record_to_complex + * Coerce a RECORD to a specific composite type. + * + * Currently we only support this for inputs that are RowExprs or whole-row + * Vars. + */ +static Node * +coerce_record_to_complex(ParseState *pstate, Node *node, + Oid targetTypeId, + CoercionContext ccontext, + CoercionForm cformat) +{ + RowExpr *rowexpr; + TupleDesc tupdesc; + List *args = NIL; + List *newargs; + int i; + List *arg; + + if (node && IsA(node, RowExpr)) + { + args = ((RowExpr *) node)->args; + } + else if (node && IsA(node, Var) && + ((Var *) node)->varattno == InvalidAttrNumber) + { + RangeTblEntry *rte; + AttrNumber nfields; + AttrNumber nf; + + rte = GetRTEByRangeTablePosn(pstate, + ((Var *) node)->varno, + ((Var *) node)->varlevelsup); + nfields = length(rte->eref->colnames); + for (nf = 1; nf <= nfields; nf++) + { + Oid vartype; + int32 vartypmod; + + get_rte_attribute_type(rte, nf, &vartype, &vartypmod); + args = lappend(args, + makeVar(((Var *) node)->varno, + nf, + vartype, + vartypmod, + ((Var *) node)->varlevelsup)); + } + } + else + ereport(ERROR, + (errcode(ERRCODE_CANNOT_COERCE), + errmsg("cannot cast type %s to %s", + format_type_be(RECORDOID), + format_type_be(targetTypeId)))); + + tupdesc = lookup_rowtype_tupdesc(targetTypeId, -1); + if (length(args) != tupdesc->natts) + ereport(ERROR, + (errcode(ERRCODE_CANNOT_COERCE), + errmsg("cannot cast type %s to %s", + format_type_be(RECORDOID), + format_type_be(targetTypeId)), + errdetail("Input has wrong number of columns."))); + newargs = NIL; + i = 0; + foreach(arg, args) + { + Node *expr = (Node *) lfirst(arg); + Oid exprtype = exprType(expr); + + expr = coerce_to_target_type(pstate, + expr, exprtype, + tupdesc->attrs[i]->atttypid, + tupdesc->attrs[i]->atttypmod, + ccontext, + COERCE_IMPLICIT_CAST); + if (expr == NULL) + ereport(ERROR, + (errcode(ERRCODE_CANNOT_COERCE), + errmsg("cannot cast type %s to %s", + format_type_be(RECORDOID), + format_type_be(targetTypeId)), + errdetail("Cannot cast type %s to %s in column %d.", + format_type_be(exprtype), + format_type_be(tupdesc->attrs[i]->atttypid), + i + 1))); + newargs = lappend(newargs, expr); + i++; + } + + rowexpr = makeNode(RowExpr); + rowexpr->args = newargs; + rowexpr->row_typeid = targetTypeId; + rowexpr->row_format = cformat; + return (Node *) rowexpr; +} /* coerce_to_boolean() * Coerce an argument of a construct that requires boolean input |