diff options
Diffstat (limited to 'src/backend')
27 files changed, 551 insertions, 1024 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index e1d5101ae1..6b58af6522 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.65 2007/03/27 23:21:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.66 2007/06/05 21:31:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1315,6 +1315,14 @@ find_expr_references_walker(Node *node, add_object_address(OCLASS_TYPE, relab->resulttype, 0, context->addrs); } + if (IsA(node, CoerceViaIO)) + { + CoerceViaIO *iocoerce = (CoerceViaIO *) node; + + /* since there is no exposed function, need to depend on type */ + add_object_address(OCLASS_TYPE, iocoerce->resulttype, 0, + context->addrs); + } if (IsA(node, ArrayCoerceExpr)) { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 50ab3ada23..fd54b89f0a 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.217 2007/04/06 04:21:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.218 2007/06/05 21:31:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -145,6 +145,9 @@ static Datum ExecEvalFieldStore(FieldStoreState *fstate, static Datum ExecEvalRelabelType(GenericExprState *exprstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); +static Datum ExecEvalCoerceViaIO(CoerceViaIOState *iostate, + ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); @@ -3505,6 +3508,40 @@ ExecEvalRelabelType(GenericExprState *exprstate, } /* ---------------------------------------------------------------- + * ExecEvalCoerceViaIO + * + * Evaluate a CoerceViaIO node. + * ---------------------------------------------------------------- + */ +static Datum +ExecEvalCoerceViaIO(CoerceViaIOState *iostate, + ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone) +{ + Datum result; + Datum inputval; + char *string; + + inputval = ExecEvalExpr(iostate->arg, econtext, isNull, isDone); + + if (isDone && *isDone == ExprEndResult) + return inputval; /* nothing to do */ + + if (*isNull) + string = NULL; /* output functions are not called on nulls */ + else + string = OutputFunctionCall(&iostate->outfunc, inputval); + + result = InputFunctionCall(&iostate->infunc, + string, + iostate->intypioparam, + -1); + + /* The input function cannot change the null/not-null status */ + return result; +} + +/* ---------------------------------------------------------------- * ExecEvalArrayCoerceExpr * * Evaluate an ArrayCoerceExpr node. @@ -3850,6 +3887,26 @@ ExecInitExpr(Expr *node, PlanState *parent) state = (ExprState *) gstate; } break; + case T_CoerceViaIO: + { + CoerceViaIO *iocoerce = (CoerceViaIO *) node; + CoerceViaIOState *iostate = makeNode(CoerceViaIOState); + Oid iofunc; + bool typisvarlena; + + iostate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalCoerceViaIO; + iostate->arg = ExecInitExpr(iocoerce->arg, parent); + /* lookup the result type's input function */ + getTypeInputInfo(iocoerce->resulttype, &iofunc, + &iostate->intypioparam); + fmgr_info(iofunc, &iostate->infunc); + /* lookup the input type's output function */ + getTypeOutputInfo(exprType((Node *) iocoerce->arg), + &iofunc, &typisvarlena); + fmgr_info(iofunc, &iostate->outfunc); + state = (ExprState *) iostate; + } + break; case T_ArrayCoerceExpr: { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 34ef2808fb..39027b1dbc 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.376 2007/05/22 23:23:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.377 2007/06/05 21:31:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1022,6 +1022,21 @@ _copyRelabelType(RelabelType *from) } /* + * _copyCoerceViaIO + */ +static CoerceViaIO * +_copyCoerceViaIO(CoerceViaIO *from) +{ + CoerceViaIO *newnode = makeNode(CoerceViaIO); + + COPY_NODE_FIELD(arg); + COPY_SCALAR_FIELD(resulttype); + COPY_SCALAR_FIELD(coerceformat); + + return newnode; +} + +/* * _copyArrayCoerceExpr */ static ArrayCoerceExpr * @@ -3108,6 +3123,9 @@ copyObject(void *from) case T_RelabelType: retval = _copyRelabelType(from); break; + case T_CoerceViaIO: + retval = _copyCoerceViaIO(from); + break; case T_ArrayCoerceExpr: retval = _copyArrayCoerceExpr(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index bd237cd6f4..8a0957c117 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.307 2007/05/22 23:23:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.308 2007/06/05 21:31:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -360,6 +360,24 @@ _equalRelabelType(RelabelType *a, RelabelType *b) } static bool +_equalCoerceViaIO(CoerceViaIO *a, CoerceViaIO *b) +{ + COMPARE_NODE_FIELD(arg); + COMPARE_SCALAR_FIELD(resulttype); + + /* + * Special-case COERCE_DONTCARE, so that planner can build coercion nodes + * that are equal() to both explicit and implicit coercions. + */ + if (a->coerceformat != b->coerceformat && + a->coerceformat != COERCE_DONTCARE && + b->coerceformat != COERCE_DONTCARE) + return false; + + return true; +} + +static bool _equalArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b) { COMPARE_NODE_FIELD(arg); @@ -2052,6 +2070,9 @@ equal(void *a, void *b) case T_RelabelType: retval = _equalRelabelType(a, b); break; + case T_CoerceViaIO: + retval = _equalCoerceViaIO(a, b); + break; case T_ArrayCoerceExpr: retval = _equalArrayCoerceExpr(a, b); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 4bf6764c18..5de540642f 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.308 2007/05/22 23:23:56 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.309 2007/06/05 21:31:04 tgl Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -871,6 +871,16 @@ _outRelabelType(StringInfo str, RelabelType *node) } static void +_outCoerceViaIO(StringInfo str, CoerceViaIO *node) +{ + WRITE_NODE_TYPE("COERCEVIAIO"); + + WRITE_NODE_FIELD(arg); + WRITE_OID_FIELD(resulttype); + WRITE_ENUM_FIELD(coerceformat, CoercionForm); +} + +static void _outArrayCoerceExpr(StringInfo str, ArrayCoerceExpr *node) { WRITE_NODE_TYPE("ARRAYCOERCEEXPR"); @@ -2165,6 +2175,9 @@ _outNode(StringInfo str, void *obj) case T_RelabelType: _outRelabelType(str, obj); break; + case T_CoerceViaIO: + _outCoerceViaIO(str, obj); + break; case T_ArrayCoerceExpr: _outArrayCoerceExpr(str, obj); break; diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index be450e94c0..86c9e911a7 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.206 2007/04/27 22:05:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.207 2007/06/05 21:31:04 tgl Exp $ * * NOTES * Path and Plan nodes do not have any readfuncs support, because we @@ -585,6 +585,21 @@ _readRelabelType(void) } /* + * _readCoerceViaIO + */ +static CoerceViaIO * +_readCoerceViaIO(void) +{ + READ_LOCALS(CoerceViaIO); + + READ_NODE_FIELD(arg); + READ_OID_FIELD(resulttype); + READ_ENUM_FIELD(coerceformat, CoercionForm); + + READ_DONE(); +} + +/* * _readArrayCoerceExpr */ static ArrayCoerceExpr * @@ -1042,6 +1057,8 @@ parseNodeString(void) return_value = _readFieldStore(); else if (MATCH("RELABELTYPE", 11)) return_value = _readRelabelType(); + else if (MATCH("COERCEVIAIO", 11)) + return_value = _readCoerceViaIO(); else if (MATCH("ARRAYCOERCEEXPR", 15)) return_value = _readArrayCoerceExpr(); else if (MATCH("CONVERTROWTYPEEXPR", 18)) diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 55c7648b9e..a4d03e9f8f 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -54,7 +54,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.183 2007/05/21 17:57:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.184 2007/06/05 21:31:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -70,6 +70,7 @@ #include "optimizer/pathnode.h" #include "optimizer/planmain.h" #include "parser/parsetree.h" +#include "parser/parse_expr.h" #include "utils/lsyscache.h" #include "utils/selfuncs.h" #include "utils/tuplesort.h" @@ -1951,6 +1952,22 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context) context->total.per_tuple += get_func_cost(saop->opfuncid) * cpu_operator_cost * estimate_array_length(arraynode) * 0.5; } + else if (IsA(node, CoerceViaIO)) + { + CoerceViaIO *iocoerce = (CoerceViaIO *) node; + Oid iofunc; + Oid typioparam; + bool typisvarlena; + + /* check the result type's input function */ + getTypeInputInfo(iocoerce->resulttype, + &iofunc, &typioparam); + context->total.per_tuple += get_func_cost(iofunc) * cpu_operator_cost; + /* check the input type's output function */ + getTypeOutputInfo(exprType((Node *) iocoerce->arg), + &iofunc, &typisvarlena); + context->total.per_tuple += get_func_cost(iofunc) * cpu_operator_cost; + } else if (IsA(node, ArrayCoerceExpr)) { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 5233a338e6..00f5f6e2c8 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.244 2007/05/01 18:53:51 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.245 2007/06/05 21:31:05 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -734,6 +734,25 @@ contain_mutable_functions_walker(Node *node, void *context) return true; /* else fall through to check args */ } + else if (IsA(node, CoerceViaIO)) + { + CoerceViaIO *expr = (CoerceViaIO *) node; + Oid iofunc; + Oid typioparam; + bool typisvarlena; + + /* check the result type's input function */ + getTypeInputInfo(expr->resulttype, + &iofunc, &typioparam); + if (func_volatile(iofunc) != PROVOLATILE_IMMUTABLE) + return true; + /* check the input type's output function */ + getTypeOutputInfo(exprType((Node *) expr->arg), + &iofunc, &typisvarlena); + if (func_volatile(iofunc) != PROVOLATILE_IMMUTABLE) + return true; + /* else fall through to check args */ + } else if (IsA(node, ArrayCoerceExpr)) { ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; @@ -826,6 +845,25 @@ contain_volatile_functions_walker(Node *node, void *context) return true; /* else fall through to check args */ } + else if (IsA(node, CoerceViaIO)) + { + CoerceViaIO *expr = (CoerceViaIO *) node; + Oid iofunc; + Oid typioparam; + bool typisvarlena; + + /* check the result type's input function */ + getTypeInputInfo(expr->resulttype, + &iofunc, &typioparam); + if (func_volatile(iofunc) == PROVOLATILE_VOLATILE) + return true; + /* check the input type's output function */ + getTypeOutputInfo(exprType((Node *) expr->arg), + &iofunc, &typisvarlena); + if (func_volatile(iofunc) == PROVOLATILE_VOLATILE) + return true; + /* else fall through to check args */ + } else if (IsA(node, ArrayCoerceExpr)) { ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; @@ -1124,6 +1162,13 @@ find_nonnullable_rels_walker(Node *node, bool top_level) result = find_nonnullable_rels_walker((Node *) expr->arg, top_level); } + else if (IsA(node, CoerceViaIO)) + { + /* not clear this is useful, but it can't hurt */ + CoerceViaIO *expr = (CoerceViaIO *) node; + + result = find_nonnullable_rels_walker((Node *) expr->arg, top_level); + } else if (IsA(node, ArrayCoerceExpr)) { /* ArrayCoerceExpr is strict at the array level */ @@ -1486,6 +1531,13 @@ strip_implicit_coercions(Node *node) if (r->relabelformat == COERCE_IMPLICIT_CAST) return strip_implicit_coercions((Node *) r->arg); } + else if (IsA(node, CoerceViaIO)) + { + CoerceViaIO *c = (CoerceViaIO *) node; + + if (c->coerceformat == COERCE_IMPLICIT_CAST) + return strip_implicit_coercions((Node *) c->arg); + } else if (IsA(node, ArrayCoerceExpr)) { ArrayCoerceExpr *c = (ArrayCoerceExpr *) node; @@ -1537,6 +1589,8 @@ set_coercionform_dontcare_walker(Node *node, void *context) ((FuncExpr *) node)->funcformat = COERCE_DONTCARE; else if (IsA(node, RelabelType)) ((RelabelType *) node)->relabelformat = COERCE_DONTCARE; + else if (IsA(node, CoerceViaIO)) + ((CoerceViaIO *) node)->coerceformat = COERCE_DONTCARE; else if (IsA(node, ArrayCoerceExpr)) ((ArrayCoerceExpr *) node)->coerceformat = COERCE_DONTCARE; else if (IsA(node, ConvertRowtypeExpr)) @@ -3471,6 +3525,8 @@ expression_tree_walker(Node *node, break; case T_RelabelType: return walker(((RelabelType *) node)->arg, context); + case T_CoerceViaIO: + return walker(((CoerceViaIO *) node)->arg, context); case T_ArrayCoerceExpr: return walker(((ArrayCoerceExpr *) node)->arg, context); case T_ConvertRowtypeExpr: @@ -3959,6 +4015,16 @@ expression_tree_mutator(Node *node, return (Node *) newnode; } break; + case T_CoerceViaIO: + { + CoerceViaIO *iocoerce = (CoerceViaIO *) node; + CoerceViaIO *newnode; + + FLATCOPY(newnode, iocoerce, CoerceViaIO); + MUTATE(newnode->arg, iocoerce->arg, Expr *); + return (Node *) newnode; + } + break; case T_ArrayCoerceExpr: { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index c232dee4a5..98cc669112 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.153 2007/04/02 03:49:38 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.154 2007/06/05 21:31:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,9 +37,10 @@ static Node *coerce_type_typmod(Node *node, bool hideInputCoercion); static void hide_coercion_node(Node *node); static Node *build_coercion_expression(Node *node, - Oid funcId, bool arrayCoerce, - Oid targetTypeId, int32 targetTypMod, - CoercionForm cformat, bool isExplicit); + CoercionPathType pathtype, + Oid funcId, + Oid targetTypeId, int32 targetTypMod, + CoercionForm cformat, bool isExplicit); static Node *coerce_record_to_complex(ParseState *pstate, Node *node, Oid targetTypeId, CoercionContext ccontext, @@ -121,8 +122,8 @@ coerce_type(ParseState *pstate, Node *node, CoercionContext ccontext, CoercionForm cformat) { Node *result; + CoercionPathType pathtype; Oid funcId; - bool arrayCoerce; if (targetTypeId == inputTypeId || node == NULL) @@ -280,10 +281,11 @@ coerce_type(ParseState *pstate, Node *node, return (Node *) param; } - if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext, - &funcId, &arrayCoerce)) + pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext, + &funcId); + if (pathtype != COERCION_PATH_NONE) { - if (OidIsValid(funcId) || arrayCoerce) + if (pathtype != COERCION_PATH_RELABELTYPE) { /* * Generate an expression tree representing run-time application @@ -298,7 +300,7 @@ coerce_type(ParseState *pstate, Node *node, baseTypeMod = targetTypeMod; baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod); - result = build_coercion_expression(node, funcId, arrayCoerce, + result = build_coercion_expression(node, pathtype, funcId, baseTypeId, baseTypeMod, cformat, (cformat != COERCE_IMPLICIT_CAST)); @@ -397,8 +399,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, { Oid inputTypeId = input_typeids[i]; Oid targetTypeId = target_typeids[i]; + CoercionPathType pathtype; Oid funcId; - bool arrayCoerce; /* no problem if same type */ if (inputTypeId == targetTypeId) @@ -426,8 +428,9 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, * If pg_cast shows that we can coerce, accept. This test now covers * both binary-compatible and coercion-function cases. */ - if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext, - &funcId, &arrayCoerce)) + pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext, + &funcId); + if (pathtype != COERCION_PATH_NONE) continue; /* @@ -567,8 +570,8 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, bool isExplicit, bool hideInputCoercion) { + CoercionPathType pathtype; Oid funcId; - bool arrayCoerce; /* * A negative typmod is assumed to mean that no coercion is wanted. Also, @@ -577,14 +580,15 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, if (targetTypMod < 0 || targetTypMod == exprTypmod(node)) return node; - if (find_typmod_coercion_function(targetTypeId, - &funcId, &arrayCoerce)) + pathtype = find_typmod_coercion_function(targetTypeId, &funcId); + + if (pathtype != COERCION_PATH_NONE) { /* Suppress display of nested coercion steps */ if (hideInputCoercion) hide_coercion_node(node); - node = build_coercion_expression(node, funcId, arrayCoerce, + node = build_coercion_expression(node, pathtype, funcId, targetTypeId, targetTypMod, cformat, isExplicit); } @@ -609,6 +613,8 @@ hide_coercion_node(Node *node) ((FuncExpr *) node)->funcformat = COERCE_IMPLICIT_CAST; else if (IsA(node, RelabelType)) ((RelabelType *) node)->relabelformat = COERCE_IMPLICIT_CAST; + else if (IsA(node, CoerceViaIO)) + ((CoerceViaIO *) node)->coerceformat = COERCE_IMPLICIT_CAST; else if (IsA(node, ArrayCoerceExpr)) ((ArrayCoerceExpr *) node)->coerceformat = COERCE_IMPLICIT_CAST; else if (IsA(node, ConvertRowtypeExpr)) @@ -630,7 +636,8 @@ hide_coercion_node(Node *node) */ static Node * build_coercion_expression(Node *node, - Oid funcId, bool arrayCoerce, + CoercionPathType pathtype, + Oid funcId, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, bool isExplicit) { @@ -651,7 +658,7 @@ build_coercion_expression(Node *node, /* * These Asserts essentially check that function is a legal coercion * function. We can't make the seemingly obvious tests on prorettype - * and proargtypes[0], even in the non-arrayCoerce case, because of + * and proargtypes[0], even in the COERCION_PATH_FUNC case, because of * various binary-compatibility cases. */ /* Assert(targetTypeId == procstruct->prorettype); */ @@ -666,26 +673,7 @@ build_coercion_expression(Node *node, ReleaseSysCache(tp); } - if (arrayCoerce) - { - /* We need to build an ArrayCoerceExpr */ - ArrayCoerceExpr *acoerce = makeNode(ArrayCoerceExpr); - - acoerce->arg = (Expr *) node; - acoerce->elemfuncid = funcId; - acoerce->resulttype = targetTypeId; - /* - * Label the output as having a particular typmod only if we are - * really invoking a length-coercion function, ie one with more - * than one argument. - */ - acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1; - acoerce->isExplicit = isExplicit; - acoerce->coerceformat = cformat; - - return (Node *) acoerce; - } - else + if (pathtype == COERCION_PATH_FUNC) { /* We build an ordinary FuncExpr with special arguments */ List *args; @@ -723,6 +711,44 @@ build_coercion_expression(Node *node, return (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat); } + else if (pathtype == COERCION_PATH_ARRAYCOERCE) + { + /* We need to build an ArrayCoerceExpr */ + ArrayCoerceExpr *acoerce = makeNode(ArrayCoerceExpr); + + acoerce->arg = (Expr *) node; + acoerce->elemfuncid = funcId; + acoerce->resulttype = targetTypeId; + /* + * Label the output as having a particular typmod only if we are + * really invoking a length-coercion function, ie one with more + * than one argument. + */ + acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1; + acoerce->isExplicit = isExplicit; + acoerce->coerceformat = cformat; + + return (Node *) acoerce; + } + else if (pathtype == COERCION_PATH_COERCEVIAIO) + { + /* We need to build a CoerceViaIO node */ + CoerceViaIO *iocoerce = makeNode(CoerceViaIO); + + Assert(!OidIsValid(funcId)); + + iocoerce->arg = (Expr *) node; + iocoerce->resulttype = targetTypeId; + iocoerce->coerceformat = cformat; + + return (Node *) iocoerce; + } + else + { + elog(ERROR, "unsupported pathtype %d in build_coercion_expression", + (int) pathtype); + return NULL; /* keep compiler quiet */ + } } @@ -1711,29 +1737,38 @@ IsBinaryCoercible(Oid srctype, Oid targettype) * find_coercion_pathway * Look for a coercion pathway between two types. * + * Currently, this deals only with scalar-type cases; it does not consider + * polymorphic types nor casts between composite types. (Perhaps fold + * those in someday?) + * * ccontext determines the set of available casts. * - * If we find a suitable entry in pg_cast, return TRUE, and set *funcid - * to the castfunc value, which may be InvalidOid for a binary-compatible - * coercion. Also, arrayCoerce is set to indicate whether this is a plain - * or array coercion (if true, funcid actually shows how to coerce the - * array elements). + * The possible result codes are: + * COERCION_PATH_NONE: failed to find any coercion pathway + * *funcid is set to InvalidOid + * COERCION_PATH_FUNC: apply the coercion function returned in *funcid + * COERCION_PATH_RELABELTYPE: binary-compatible cast, no function needed + * *funcid is set to InvalidOid + * COERCION_PATH_ARRAYCOERCE: need an ArrayCoerceExpr node + * *funcid is set to the element cast function, or InvalidOid + * if the array elements are binary-compatible + * COERCION_PATH_COERCEVIAIO: need a CoerceViaIO node + * *funcid is set to InvalidOid * - * NOTE: *funcid == InvalidOid does not necessarily mean that no work is + * Note: COERCION_PATH_RELABELTYPE does not necessarily mean that no work is * needed to do the coercion; if the target is a domain then we may need to * apply domain constraint checking. If you want to check for a zero-effort * conversion then use IsBinaryCoercible(). */ -bool +CoercionPathType find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, CoercionContext ccontext, - Oid *funcid, bool *arrayCoerce) + Oid *funcid) { - bool result = false; + CoercionPathType result = COERCION_PATH_NONE; HeapTuple tuple; *funcid = InvalidOid; - *arrayCoerce = false; /* Perhaps the types are domains; if so, look at their base types */ if (OidIsValid(sourceTypeId)) @@ -1743,7 +1778,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, /* Domains are always coercible to and from their base type */ if (sourceTypeId == targetTypeId) - return true; + return COERCION_PATH_RELABELTYPE; /* Look in pg_cast */ tuple = SearchSysCache(CASTSOURCETARGET, @@ -1779,7 +1814,10 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, if (ccontext >= castcontext) { *funcid = castForm->castfunc; - result = true; + if (OidIsValid(*funcid)) + result = COERCION_PATH_FUNC; + else + result = COERCION_PATH_RELABELTYPE; } ReleaseSysCache(tuple); @@ -1789,7 +1827,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, /* * If there's no pg_cast entry, perhaps we are dealing with a pair of * array types. If so, and if the element types have a suitable cast, - * report that with arrayCoerce = true. + * report that we can coerce with an ArrayCoerceExpr. * * Hack: disallow coercions to oidvector and int2vector, which * otherwise tend to capture coercions that should go to "real" array @@ -1798,25 +1836,30 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, * guaranteed to produce an output that meets the restrictions of * these datatypes, such as being 1-dimensional.) */ - Oid targetElemType; - Oid sourceElemType; - Oid elemfuncid; - bool elemarraycoerce; - - if (targetTypeId == OIDVECTOROID || targetTypeId == INT2VECTOROID) - return false; - - if ((targetElemType = get_element_type(targetTypeId)) != InvalidOid && - (sourceElemType = get_element_type(sourceTypeId)) != InvalidOid) + if (targetTypeId != OIDVECTOROID && targetTypeId != INT2VECTOROID) { - if (find_coercion_pathway(targetElemType, sourceElemType, - ccontext, - &elemfuncid, &elemarraycoerce) && - !elemarraycoerce) + Oid targetElem; + Oid sourceElem; + + if ((targetElem = get_element_type(targetTypeId)) != InvalidOid && + (sourceElem = get_element_type(sourceTypeId)) != InvalidOid) { - *funcid = elemfuncid; - *arrayCoerce = true; - result = true; + CoercionPathType elempathtype; + Oid elemfuncid; + + elempathtype = find_coercion_pathway(targetElem, + sourceElem, + ccontext, + &elemfuncid); + if (elempathtype != COERCION_PATH_NONE && + elempathtype != COERCION_PATH_ARRAYCOERCE) + { + *funcid = elemfuncid; + if (elempathtype == COERCION_PATH_COERCEVIAIO) + result = COERCION_PATH_COERCEVIAIO; + else + result = COERCION_PATH_ARRAYCOERCE; + } } } @@ -1826,14 +1869,39 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, * mistakenly conclude that ANYENUM-to-some-enum-type is a * trivial cast. */ - if (!result) + if (result == COERCION_PATH_NONE) { if (type_is_enum(sourceTypeId)) result = find_coercion_pathway(targetTypeId, ANYENUMOID, - ccontext, funcid, arrayCoerce); + ccontext, funcid); else if (sourceTypeId != ANYENUMOID && type_is_enum(targetTypeId)) result = find_coercion_pathway(ANYENUMOID, sourceTypeId, - ccontext, funcid, arrayCoerce); + ccontext, funcid); + } + + /* + * If we still haven't found a possibility, consider automatic casting + * using I/O functions. We allow assignment casts to textual types + * and explicit casts from textual types to be handled this way. + * (The CoerceViaIO mechanism is a lot more general than that, but + * this is all we want to allow in the absence of a pg_cast entry.) + * It would probably be better to insist on explicit casts in both + * directions, but this is a compromise to preserve something of the + * pre-8.3 behavior that many types had implicit (yipes!) casts to + * text. + */ + if (result == COERCION_PATH_NONE) + { + if (ccontext >= COERCION_ASSIGNMENT && + (targetTypeId == TEXTOID || + targetTypeId == VARCHAROID || + targetTypeId == BPCHAROID)) + result = COERCION_PATH_COERCEVIAIO; + else if (ccontext >= COERCION_EXPLICIT && + (sourceTypeId == TEXTOID || + sourceTypeId == VARCHAROID || + sourceTypeId == BPCHAROID)) + result = COERCION_PATH_COERCEVIAIO; } } @@ -1851,19 +1919,26 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, * * If the given type is a varlena array type, we do not look for a coercion * function associated directly with the array type, but instead look for - * one associated with the element type. If one exists, we report it with - * *arrayCoerce set to true. + * one associated with the element type. An ArrayCoerceExpr node must be + * used to apply such a function. + * + * We use the same result enum as find_coercion_pathway, but the only possible + * result codes are: + * COERCION_PATH_NONE: no length coercion needed + * COERCION_PATH_FUNC: apply the function returned in *funcid + * COERCION_PATH_ARRAYCOERCE: apply the function using ArrayCoerceExpr */ -bool +CoercionPathType find_typmod_coercion_function(Oid typeId, - Oid *funcid, bool *arrayCoerce) + Oid *funcid) { + CoercionPathType result; Type targetType; Form_pg_type typeForm; HeapTuple tuple; *funcid = InvalidOid; - *arrayCoerce = false; + result = COERCION_PATH_FUNC; targetType = typeidType(typeId); typeForm = (Form_pg_type) GETSTRUCT(targetType); @@ -1875,7 +1950,7 @@ find_typmod_coercion_function(Oid typeId, { /* Yes, switch our attention to the element type */ typeId = typeForm->typelem; - *arrayCoerce = true; + result = COERCION_PATH_ARRAYCOERCE; } ReleaseSysCache(targetType); @@ -1893,5 +1968,8 @@ find_typmod_coercion_function(Oid typeId, ReleaseSysCache(tuple); } - return OidIsValid(*funcid); + if (!OidIsValid(*funcid)) + result = COERCION_PATH_NONE; + + return result; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index a0f92f66a6..45107e43ac 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.217 2007/04/27 22:05:48 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.218 2007/06/05 21:31:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -265,6 +265,7 @@ transformExpr(ParseState *pstate, Node *expr) case T_FieldSelect: case T_FieldStore: case T_RelabelType: + case T_CoerceViaIO: case T_ArrayCoerceExpr: case T_ConvertRowtypeExpr: case T_CaseTestExpr: @@ -1806,6 +1807,9 @@ exprType(Node *expr) case T_RelabelType: type = ((RelabelType *) expr)->resulttype; break; + case T_CoerceViaIO: + type = ((CoerceViaIO *) expr)->resulttype; + break; case T_ArrayCoerceExpr: type = ((ArrayCoerceExpr *) expr)->resulttype; break; diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 01593317b1..5e7a1cccff 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.195 2007/03/27 23:21:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.196 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -160,7 +160,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, if (fdresult == FUNCDETAIL_COERCION) { /* - * We can do it as a trivial coercion. coerce_type can handle these + * We interpreted it as a type coercion. coerce_type can handle these * cases, so why duplicate code... */ return coerce_type(pstate, linitial(fargs), @@ -669,7 +669,7 @@ func_select_candidate(int nargs, * (exact match) is as quick as possible. * * If an exact match isn't found: - * 1) check for possible interpretation as a trivial type coercion + * 1) check for possible interpretation as a type coercion request * 2) get a vector of all possible input arg type arrays constructed * from the superclasses of the original input arg types * 3) get a list of all possible argument type arrays to the function @@ -720,29 +720,35 @@ func_get_detail(List *funcname, * If we didn't find an exact match, next consider the possibility * that this is really a type-coercion request: a single-argument * function call where the function name is a type name. If so, and - * if we can do the coercion trivially (no run-time function call - * needed), then go ahead and treat the "function call" as a coercion. + * if the coercion path is RELABELTYPE or COERCEVIAIO, then go ahead + * and treat the "function call" as a coercion. + * * This interpretation needs to be given higher priority than * interpretations involving a type coercion followed by a function * call, otherwise we can produce surprising results. For example, we - * want "text(varchar)" to be interpreted as a trivial coercion, not + * want "text(varchar)" to be interpreted as a simple coercion, not * as "text(name(varchar))" which the code below this point is * entirely capable of selecting. * - * "Trivial" coercions are ones that involve binary-compatible types - * and ones that are coercing a previously-unknown-type literal - * constant to a specific type. + * We also treat a coercion of a previously-unknown-type literal + * constant to a specific type this way. + * + * The reason we reject COERCION_PATH_FUNC here is that we expect the + * cast implementation function to be named after the target type. + * Thus the function will be found by normal lookup if appropriate. * - * The reason we can restrict our check to binary-compatible coercions - * here is that we expect non-binary-compatible coercions to have an - * implementation function named after the target type. That function - * will be found by normal lookup if appropriate. + * The reason we reject COERCION_PATH_ARRAYCOERCE is mainly that + * you can't write "foo[] (something)" as a function call. In theory + * someone might want to invoke it as "_foo (something)" but we have + * never supported that historically, so we can insist that people + * write it as a normal cast instead. Lack of historical support is + * also the reason for not considering composite-type casts here. * - * NB: it's important that this code stays in sync with what - * coerce_type can do, because the caller will try to apply - * coerce_type if we return FUNCDETAIL_COERCION. If we return that - * result for something coerce_type can't handle, we'll cause infinite - * recursion between this module and coerce_type! + * NB: it's important that this code does not exceed what coerce_type + * can do, because the caller will try to apply coerce_type if we + * return FUNCDETAIL_COERCION. If we return that result for something + * coerce_type can't handle, we'll cause infinite recursion between + * this module and coerce_type! */ if (nargs == 1 && fargs != NIL) { @@ -755,16 +761,28 @@ func_get_detail(List *funcname, { Oid sourceType = argtypes[0]; Node *arg1 = linitial(fargs); - Oid cfuncid; - bool arrayCoerce; - - if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) || - (find_coercion_pathway(targetType, sourceType, - COERCION_EXPLICIT, - &cfuncid, &arrayCoerce) && - cfuncid == InvalidOid && !arrayCoerce)) + bool iscoercion; + + if (sourceType == UNKNOWNOID && IsA(arg1, Const)) + { + /* always treat typename('literal') as coercion */ + iscoercion = true; + } + else + { + CoercionPathType cpathtype; + Oid cfuncid; + + cpathtype = find_coercion_pathway(targetType, sourceType, + COERCION_EXPLICIT, + &cfuncid); + iscoercion = (cpathtype == COERCION_PATH_RELABELTYPE || + cpathtype == COERCION_PATH_COERCEVIAIO); + } + + if (iscoercion) { - /* Yup, it's a trivial type coercion */ + /* Treat it as a type coercion */ *funcid = InvalidOid; *rettype = targetType; *retset = false; diff --git a/src/backend/utils/Gen_fmgrtab.sh b/src/backend/utils/Gen_fmgrtab.sh index ccd2da3d63..5543da5a61 100644 --- a/src/backend/utils/Gen_fmgrtab.sh +++ b/src/backend/utils/Gen_fmgrtab.sh @@ -9,7 +9,7 @@ # # # IDENTIFICATION -# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.35 2007/01/22 01:35:21 tgl Exp $ +# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.36 2007/06/05 21:31:06 tgl Exp $ # #------------------------------------------------------------------------- @@ -127,7 +127,7 @@ cat > "$$-$OIDSFILE" <<FuNkYfMgRsTuFf * NOTE: macros are named after the prosrc value, ie the actual C name * of the implementing function, not the proname which may be overloaded. * For example, we want to be able to assign different macro names to both - * char_text() and int4_text() even though these both appear with proname + * char_text() and name_text() even though these both appear with proname * 'text'. If the same C function appears in more than one pg_proc entry, * its equivalent macro will be defined with the lowest OID among those * entries. diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c index e238e131be..1e44bc1cb5 100644 --- a/src/backend/utils/adt/bool.c +++ b/src/backend/utils/adt/bool.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/bool.c,v 1.39 2007/06/01 23:40:18 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/bool.c,v 1.40 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -143,21 +143,10 @@ boolsend(PG_FUNCTION_ARGS) } /* - * textbool - cast function for text => bool - */ -Datum -textbool(PG_FUNCTION_ARGS) -{ - Datum in_text = PG_GETARG_DATUM(0); - char *str; - - str = DatumGetCString(DirectFunctionCall1(textout, in_text)); - - PG_RETURN_DATUM(DirectFunctionCall1(boolin, CStringGetDatum(str))); -} - -/* * booltext - cast function for bool => text + * + * We need this because it's different from the behavior of boolout(); + * this function follows the SQL-spec result (except for producing lower case) */ Datum booltext(PG_FUNCTION_ARGS) diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c index 7e4b461f8f..4914736116 100644 --- a/src/backend/utils/adt/date.c +++ b/src/backend/utils/adt/date.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.131 2007/06/02 16:41:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/date.c,v 1.132 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -873,65 +873,6 @@ abstime_date(PG_FUNCTION_ARGS) } -/* date_text() - * Convert date to text data type. - */ -Datum -date_text(PG_FUNCTION_ARGS) -{ - /* Input is a Date, but may as well leave it in Datum form */ - Datum date = PG_GETARG_DATUM(0); - text *result; - char *str; - int len; - - str = DatumGetCString(DirectFunctionCall1(date_out, date)); - - len = strlen(str) + VARHDRSZ; - - result = palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, (len - VARHDRSZ)); - - pfree(str); - - PG_RETURN_TEXT_P(result); -} - - -/* text_date() - * Convert text string to date. - * Text type is not null terminated, so use temporary string - * then call the standard input routine. - */ -Datum -text_date(PG_FUNCTION_ARGS) -{ - text *str = PG_GETARG_TEXT_P(0); - int i; - char *sp, - *dp, - dstr[MAXDATELEN + 1]; - - if (VARSIZE(str) - VARHDRSZ > MAXDATELEN) - ereport(ERROR, - (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("invalid input syntax for type date: \"%s\"", - DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(str)))))); - - sp = VARDATA(str); - dp = dstr; - for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) - *dp++ = *sp++; - *dp = '\0'; - - return DirectFunctionCall1(date_in, - CStringGetDatum(dstr)); -} - - /***************************************************************************** * Time ADT *****************************************************************************/ @@ -1617,62 +1558,6 @@ time_mi_interval(PG_FUNCTION_ARGS) } -/* time_text() - * Convert time to text data type. - */ -Datum -time_text(PG_FUNCTION_ARGS) -{ - /* Input is a Time, but may as well leave it in Datum form */ - Datum time = PG_GETARG_DATUM(0); - text *result; - char *str; - int len; - - str = DatumGetCString(DirectFunctionCall1(time_out, time)); - - len = strlen(str) + VARHDRSZ; - - result = palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, len - VARHDRSZ); - - pfree(str); - - PG_RETURN_TEXT_P(result); -} - - -/* text_time() - * Convert text string to time. - * Text type is not null terminated, so use temporary string - * then call the standard input routine. - */ -Datum -text_time(PG_FUNCTION_ARGS) -{ - text *str = PG_GETARG_TEXT_P(0); - char dstr[MAXDATELEN + 1]; - size_t len; - - if (VARSIZE(str) - VARHDRSZ > MAXDATELEN) - ereport(ERROR, - (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("invalid input syntax for type time: \"%s\"", - DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(str)))))); - - len = VARSIZE(str) - VARHDRSZ; - memcpy(dstr, VARDATA(str), len); - dstr[len] = '\0'; - - return DirectFunctionCall3(time_in, - CStringGetDatum(dstr), - ObjectIdGetDatum(InvalidOid), - Int32GetDatum(-1)); -} - /* time_part() * Extract specified field from time type. */ @@ -2400,66 +2285,6 @@ datetimetz_timestamptz(PG_FUNCTION_ARGS) } -/* timetz_text() - * Convert timetz to text data type. - */ -Datum -timetz_text(PG_FUNCTION_ARGS) -{ - /* Input is a Timetz, but may as well leave it in Datum form */ - Datum timetz = PG_GETARG_DATUM(0); - text *result; - char *str; - int len; - - str = DatumGetCString(DirectFunctionCall1(timetz_out, timetz)); - - len = strlen(str) + VARHDRSZ; - - result = palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, (len - VARHDRSZ)); - - pfree(str); - - PG_RETURN_TEXT_P(result); -} - - -/* text_timetz() - * Convert text string to timetz. - * Text type is not null terminated, so use temporary string - * then call the standard input routine. - */ -Datum -text_timetz(PG_FUNCTION_ARGS) -{ - text *str = PG_GETARG_TEXT_P(0); - int i; - char *sp, - *dp, - dstr[MAXDATELEN + 1]; - - if (VARSIZE(str) - VARHDRSZ > MAXDATELEN) - ereport(ERROR, - (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("invalid input syntax for type time with time zone: \"%s\"", - DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(str)))))); - - sp = VARDATA(str); - dp = dstr; - for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) - *dp++ = *sp++; - *dp = '\0'; - - return DirectFunctionCall3(timetz_in, - CStringGetDatum(dstr), - ObjectIdGetDatum(InvalidOid), - Int32GetDatum(-1)); -} - /* timetz_part() * Extract specified field from time type. */ diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c index 635d232912..a5506a0c1b 100644 --- a/src/backend/utils/adt/enum.c +++ b/src/backend/utils/adt/enum.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/enum.c,v 1.2 2007/04/02 22:14:17 adunstan Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/enum.c,v 1.3 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,8 +21,6 @@ #include "utils/syscache.h" -static Oid cstring_enum(char *name, Oid enumtypoid); -static char *enum_cstring(Oid enumval); static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper); static int enum_elem_cmp(const void *left, const void *right); @@ -32,75 +30,60 @@ static int enum_elem_cmp(const void *left, const void *right); Datum enum_in(PG_FUNCTION_ARGS) { - char *name = PG_GETARG_CSTRING(0); - Oid enumtypoid = PG_GETARG_OID(1); - - PG_RETURN_OID(cstring_enum(name, enumtypoid)); -} - -/* guts of enum_in and text-to-enum */ -static Oid -cstring_enum(char *name, Oid enumtypoid) -{ - HeapTuple tup; + char *name = PG_GETARG_CSTRING(0); + Oid enumtypoid = PG_GETARG_OID(1); Oid enumoid; + HeapTuple tup; /* must check length to prevent Assert failure within SearchSysCache */ - if (strlen(name) >= NAMEDATALEN) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input value for enum %s: \"%s\"", + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input value for enum %s: \"%s\"", format_type_be(enumtypoid), - name))); + name))); tup = SearchSysCache(ENUMTYPOIDNAME, ObjectIdGetDatum(enumtypoid), CStringGetDatum(name), 0, 0); - if (tup == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input value for enum %s: \"%s\"", + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input value for enum %s: \"%s\"", format_type_be(enumtypoid), - name))); + name))); enumoid = HeapTupleGetOid(tup); ReleaseSysCache(tup); - return enumoid; + + PG_RETURN_OID(enumoid); } Datum enum_out(PG_FUNCTION_ARGS) { - Oid enumoid = PG_GETARG_OID(0); - - PG_RETURN_CSTRING(enum_cstring(enumoid)); -} - -/* guts of enum_out and enum-to-text */ -static char * -enum_cstring(Oid enumval) -{ + Oid enumval = PG_GETARG_OID(0); + char *result; HeapTuple tup; Form_pg_enum en; - char *label; tup = SearchSysCache(ENUMOID, ObjectIdGetDatum(enumval), 0, 0, 0); - if (tup == NULL) - ereport(ERROR, - (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), - errmsg("invalid internal value for enum: %u", - enumval))); + if (!HeapTupleIsValid(tup)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid internal value for enum: %u", + enumval))); en = (Form_pg_enum) GETSTRUCT(tup); - label = pstrdup(NameStr(en->enumlabel)); + result = pstrdup(NameStr(en->enumlabel)); ReleaseSysCache(tup); - return label; + + PG_RETURN_CSTRING(result); } /* Comparison functions and related */ @@ -191,47 +174,6 @@ enum_cmp(PG_FUNCTION_ARGS) PG_RETURN_INT32(-1); } -/* Casts between text and enum */ - -Datum -enum_text(PG_FUNCTION_ARGS) -{ - Oid enumval = PG_GETARG_OID(0); - text *result; - char *cstr; - int len; - - cstr = enum_cstring(enumval); - len = strlen(cstr); - result = (text *) palloc(VARHDRSZ + len); - SET_VARSIZE(result, VARHDRSZ + len); - memcpy(VARDATA(result), cstr, len); - pfree(cstr); - PG_RETURN_TEXT_P(result); -} - -Datum -text_enum(PG_FUNCTION_ARGS) -{ - text *textval = PG_GETARG_TEXT_P(0); - Oid enumtypoid; - char *str; - - /* - * We rely on being able to get the specific enum type from the calling - * expression tree. - */ - enumtypoid = get_fn_expr_rettype(fcinfo->flinfo); - if (enumtypoid == InvalidOid) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("could not determine actual enum type"))); - - str = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(textval))); - PG_RETURN_OID(cstring_enum(str, enumtypoid)); -} - /* Enum programming support functions */ Datum @@ -266,7 +208,7 @@ enum_first(PG_FUNCTION_ARGS) ReleaseCatCacheList(list); - if (!OidIsValid(min)) /* should not happen */ + if (!OidIsValid(min)) /* should not happen */ elog(ERROR, "no values found for enum %s", format_type_be(enumtypoid)); @@ -276,10 +218,10 @@ enum_first(PG_FUNCTION_ARGS) Datum enum_last(PG_FUNCTION_ARGS) { - Oid enumtypoid; - Oid max = InvalidOid; - CatCList *list; - int num, i; + Oid enumtypoid; + Oid max = InvalidOid; + CatCList *list; + int num, i; /* * We rely on being able to get the specific enum type from the calling @@ -292,24 +234,24 @@ enum_last(PG_FUNCTION_ARGS) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("could not determine actual enum type"))); - list = SearchSysCacheList(ENUMTYPOIDNAME, 1, - ObjectIdGetDatum(enumtypoid), + list = SearchSysCacheList(ENUMTYPOIDNAME, 1, + ObjectIdGetDatum(enumtypoid), 0, 0, 0); - num = list->n_members; - for (i = 0; i < num; i++) - { + num = list->n_members; + for (i = 0; i < num; i++) + { Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data); - if(!OidIsValid(max) || valoid > max) - max = valoid; - } + if (!OidIsValid(max) || valoid > max) + max = valoid; + } ReleaseCatCacheList(list); - if (!OidIsValid(max)) /* should not happen */ + if (!OidIsValid(max)) /* should not happen */ elog(ERROR, "no values found for enum %s", format_type_be(enumtypoid)); - PG_RETURN_OID(max); + PG_RETURN_OID(max); } /* 2-argument variant of enum_range */ @@ -368,26 +310,26 @@ static ArrayType * enum_range_internal(Oid enumtypoid, Oid lower, Oid upper) { ArrayType *result; - CatCList *list; - int total, i, j; - Datum *elems; + CatCList *list; + int total, i, j; + Datum *elems; list = SearchSysCacheList(ENUMTYPOIDNAME, 1, - ObjectIdGetDatum(enumtypoid), + ObjectIdGetDatum(enumtypoid), 0, 0, 0); total = list->n_members; elems = (Datum *) palloc(total * sizeof(Datum)); j = 0; - for (i = 0; i < total; i++) - { + for (i = 0; i < total; i++) + { Oid val = HeapTupleGetOid(&(list->members[i]->tuple)); if ((!OidIsValid(lower) || lower <= val) && (!OidIsValid(upper) || val <= upper)) - elems[j++] = ObjectIdGetDatum(val); - } + elems[j++] = ObjectIdGetDatum(val); + } /* shouldn't need the cache anymore */ ReleaseCatCacheList(list); diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index f2c2293756..7a66bd4c56 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.149 2007/02/27 23:48:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.150 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1197,108 +1197,6 @@ i2tof(PG_FUNCTION_ARGS) /* - * float8_text - converts a float8 number to a text string - */ -Datum -float8_text(PG_FUNCTION_ARGS) -{ - float8 num = PG_GETARG_FLOAT8(0); - text *result; - int len; - char *str; - - str = DatumGetCString(DirectFunctionCall1(float8out, - Float8GetDatum(num))); - - len = strlen(str) + VARHDRSZ; - - result = (text *) palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, (len - VARHDRSZ)); - - pfree(str); - - PG_RETURN_TEXT_P(result); -} - - -/* - * text_float8 - converts a text string to a float8 number - */ -Datum -text_float8(PG_FUNCTION_ARGS) -{ - text *string = PG_GETARG_TEXT_P(0); - Datum result; - int len; - char *str; - - len = (VARSIZE(string) - VARHDRSZ); - str = palloc(len + 1); - memcpy(str, VARDATA(string), len); - *(str + len) = '\0'; - - result = DirectFunctionCall1(float8in, CStringGetDatum(str)); - - pfree(str); - - PG_RETURN_DATUM(result); -} - - -/* - * float4_text - converts a float4 number to a text string - */ -Datum -float4_text(PG_FUNCTION_ARGS) -{ - float4 num = PG_GETARG_FLOAT4(0); - text *result; - int len; - char *str; - - str = DatumGetCString(DirectFunctionCall1(float4out, - Float4GetDatum(num))); - - len = strlen(str) + VARHDRSZ; - - result = (text *) palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, (len - VARHDRSZ)); - - pfree(str); - - PG_RETURN_TEXT_P(result); -} - - -/* - * text_float4 - converts a text string to a float4 number - */ -Datum -text_float4(PG_FUNCTION_ARGS) -{ - text *string = PG_GETARG_TEXT_P(0); - Datum result; - int len; - char *str; - - len = (VARSIZE(string) - VARHDRSZ); - str = palloc(len + 1); - memcpy(str, VARDATA(string), len); - *(str + len) = '\0'; - - result = DirectFunctionCall1(float4in, CStringGetDatum(str)); - - pfree(str); - - PG_RETURN_DATUM(result); -} - - -/* * ======================= * RANDOM FLOAT8 OPERATORS * ======================= diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index d6d5902207..405b16ecef 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.79 2007/02/27 23:48:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.80 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,8 +18,6 @@ * int2in, int2out, int2recv, int2send * int4in, int4out, int4recv, int4send * int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend - * Conversion routines: - * itoi, int2_text, int4_text * Boolean operators: * inteq, intne, intlt, intle, intgt, intge * Arithmetic operators: @@ -343,68 +341,6 @@ i4toi2(PG_FUNCTION_ARGS) PG_RETURN_INT16((int16) arg1); } -Datum -int2_text(PG_FUNCTION_ARGS) -{ - int16 arg1 = PG_GETARG_INT16(0); - text *result = (text *) palloc(7 + VARHDRSZ); /* sign,5 digits, '\0' */ - - pg_itoa(arg1, VARDATA(result)); - SET_VARSIZE(result, strlen(VARDATA(result)) + VARHDRSZ); - PG_RETURN_TEXT_P(result); -} - -Datum -text_int2(PG_FUNCTION_ARGS) -{ - text *string = PG_GETARG_TEXT_P(0); - Datum result; - int len; - char *str; - - len = VARSIZE(string) - VARHDRSZ; - - str = palloc(len + 1); - memcpy(str, VARDATA(string), len); - *(str + len) = '\0'; - - result = DirectFunctionCall1(int2in, CStringGetDatum(str)); - pfree(str); - - return result; -} - -Datum -int4_text(PG_FUNCTION_ARGS) -{ - int32 arg1 = PG_GETARG_INT32(0); - text *result = (text *) palloc(12 + VARHDRSZ); /* sign,10 digits,'\0' */ - - pg_ltoa(arg1, VARDATA(result)); - SET_VARSIZE(result, strlen(VARDATA(result)) + VARHDRSZ); - PG_RETURN_TEXT_P(result); -} - -Datum -text_int4(PG_FUNCTION_ARGS) -{ - text *string = PG_GETARG_TEXT_P(0); - Datum result; - int len; - char *str; - - len = VARSIZE(string) - VARHDRSZ; - - str = palloc(len + 1); - memcpy(str, VARDATA(string), len); - *(str + len) = '\0'; - - result = DirectFunctionCall1(int4in, CStringGetDatum(str)); - pfree(str); - - return result; -} - /* Cast int4 -> bool */ Datum int4_bool(PG_FUNCTION_ARGS) diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 25672b680f..3a88a0591c 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.65 2007/02/27 23:48:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.66 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1137,48 +1137,6 @@ oidtoi8(PG_FUNCTION_ARGS) PG_RETURN_INT64((int64) arg); } -Datum -text_int8(PG_FUNCTION_ARGS) -{ - text *str = PG_GETARG_TEXT_P(0); - int len; - char *s; - Datum result; - - len = (VARSIZE(str) - VARHDRSZ); - s = palloc(len + 1); - memcpy(s, VARDATA(str), len); - *(s + len) = '\0'; - - result = DirectFunctionCall1(int8in, CStringGetDatum(s)); - - pfree(s); - - return result; -} - -Datum -int8_text(PG_FUNCTION_ARGS) -{ - /* arg is int64, but easier to leave it as Datum */ - Datum arg = PG_GETARG_DATUM(0); - char *s; - int len; - text *result; - - s = DatumGetCString(DirectFunctionCall1(int8out, arg)); - len = strlen(s); - - result = (text *) palloc(VARHDRSZ + len); - - SET_VARSIZE(result, VARHDRSZ + len); - memcpy(VARDATA(result), s, len); - - pfree(s); - - PG_RETURN_TEXT_P(result); -} - /* * non-persistent numeric series generator */ diff --git a/src/backend/utils/adt/mac.c b/src/backend/utils/adt/mac.c index fa13abe461..aa13589b8a 100644 --- a/src/backend/utils/adt/mac.c +++ b/src/backend/utils/adt/mac.c @@ -1,7 +1,7 @@ /* * PostgreSQL type definitions for MAC addresses. * - * $PostgreSQL: pgsql/src/backend/utils/adt/mac.c,v 1.37 2007/02/27 23:48:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/mac.c,v 1.38 2007/06/05 21:31:06 tgl Exp $ */ #include "postgres.h" @@ -145,59 +145,6 @@ macaddr_send(PG_FUNCTION_ARGS) /* - * Convert macaddr to text data type. - */ - -Datum -macaddr_text(PG_FUNCTION_ARGS) -{ - /* Input is a macaddr, but may as well leave it in Datum form */ - Datum addr = PG_GETARG_DATUM(0); - text *result; - char *str; - int len; - - str = DatumGetCString(DirectFunctionCall1(macaddr_out, addr)); - - len = (strlen(str) + VARHDRSZ); - - result = palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, (len - VARHDRSZ)); - - pfree(str); - - PG_RETURN_TEXT_P(result); -} - -/* - * Convert text to macaddr data type. - */ - -Datum -text_macaddr(PG_FUNCTION_ARGS) -{ - text *addr = PG_GETARG_TEXT_P(0); - Datum result; - char str[100]; - int len; - - len = (VARSIZE(addr) - VARHDRSZ); - if (len >= sizeof(str)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("text too long to convert to MAC address"))); - - memcpy(str, VARDATA(addr), len); - *(str + len) = '\0'; - - result = DirectFunctionCall1(macaddr_in, CStringGetDatum(str)); - - return result; -} - -/* * Comparison function for sorting: */ diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 7a190719b8..10c1285bd6 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -1,7 +1,7 @@ /* * PostgreSQL type definitions for the INET and CIDR types. * - * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.70 2007/05/17 23:31:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.71 2007/06/05 21:31:06 tgl Exp $ * * Jon Postel RIP 16 Oct 1998 */ @@ -22,7 +22,6 @@ #include "utils/inet.h" -static inet *text_network(text *src, bool is_cidr); static int32 network_cmp_internal(inet *a1, inet *a2); static int bitncmp(void *l, void *r, int n); static bool addressOK(unsigned char *a, int bits, int family); @@ -314,35 +313,6 @@ cidr_send(PG_FUNCTION_ARGS) } -static inet * -text_network(text *src, bool is_cidr) -{ - int len = VARSIZE(src) - VARHDRSZ; - char *str = palloc(len + 1); - - memcpy(str, VARDATA(src), len); - str[len] = '\0'; - - return network_in(str, is_cidr); -} - -Datum -text_inet(PG_FUNCTION_ARGS) -{ - text *src = PG_GETARG_TEXT_P(0); - - PG_RETURN_INET_P(text_network(src, false)); -} - -Datum -text_cidr(PG_FUNCTION_ARGS) -{ - text *src = PG_GETARG_TEXT_P(0); - - PG_RETURN_INET_P(text_network(src, true)); -} - - Datum inet_to_cidr(PG_FUNCTION_ARGS) { @@ -655,6 +625,11 @@ network_host(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(ret); } +/* + * network_show implements the inet and cidr casts to text. This is not + * quite the same behavior as network_out, hence we can't drop it in favor + * of CoerceViaIO. + */ Datum network_show(PG_FUNCTION_ARGS) { diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 6a6f3d44af..aa585f4267 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -14,7 +14,7 @@ * Copyright (c) 1998-2007, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.102 2007/05/08 18:56:47 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.103 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2146,50 +2146,6 @@ numeric_float4(PG_FUNCTION_ARGS) } -Datum -text_numeric(PG_FUNCTION_ARGS) -{ - text *str = PG_GETARG_TEXT_P(0); - int len; - char *s; - Datum result; - - len = (VARSIZE(str) - VARHDRSZ); - s = palloc(len + 1); - memcpy(s, VARDATA(str), len); - *(s + len) = '\0'; - - result = DirectFunctionCall3(numeric_in, CStringGetDatum(s), - ObjectIdGetDatum(0), Int32GetDatum(-1)); - - pfree(s); - - return result; -} - -Datum -numeric_text(PG_FUNCTION_ARGS) -{ - /* val is numeric, but easier to leave it as Datum */ - Datum val = PG_GETARG_DATUM(0); - char *s; - int len; - text *result; - - s = DatumGetCString(DirectFunctionCall1(numeric_out, val)); - len = strlen(s); - - result = (text *) palloc(VARHDRSZ + len); - - SET_VARSIZE(result, VARHDRSZ + len); - memcpy(VARDATA(result), s, len); - - pfree(s); - - PG_RETURN_TEXT_P(result); -} - - /* ---------------------------------------------------------------------- * * Aggregate functions diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c index 8a9f971a22..fc37b18434 100644 --- a/src/backend/utils/adt/oid.c +++ b/src/backend/utils/adt/oid.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.71 2007/02/27 23:48:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.72 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,7 +31,7 @@ *****************************************************************************/ static Oid -oidin_subr(const char *funcname, const char *s, char **endloc) +oidin_subr(const char *s, char **endloc) { unsigned long cvt; char *endptr; @@ -116,7 +116,7 @@ oidin(PG_FUNCTION_ARGS) char *s = PG_GETARG_CSTRING(0); Oid result; - result = oidin_subr("oidin", s, NULL); + result = oidin_subr(s, NULL); PG_RETURN_OID(result); } @@ -202,7 +202,7 @@ oidvectorin(PG_FUNCTION_ARGS) oidString++; if (*oidString == '\0') break; - result->values[n] = oidin_subr("oidvectorin", oidString, &oidString); + result->values[n] = oidin_subr(oidString, &oidString); } while (*oidString && isspace((unsigned char) *oidString)) oidString++; @@ -419,45 +419,3 @@ oidvectorgt(PG_FUNCTION_ARGS) PG_RETURN_BOOL(cmp > 0); } - -Datum -oid_text(PG_FUNCTION_ARGS) -{ - Oid oid = PG_GETARG_OID(0); - text *result; - int len; - char *str; - - str = DatumGetCString(DirectFunctionCall1(oidout, - ObjectIdGetDatum(oid))); - len = strlen(str) + VARHDRSZ; - - result = (text *) palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, (len - VARHDRSZ)); - pfree(str); - - PG_RETURN_TEXT_P(result); -} - -Datum -text_oid(PG_FUNCTION_ARGS) -{ - text *string = PG_GETARG_TEXT_P(0); - Oid result; - int len; - char *str; - - len = (VARSIZE(string) - VARHDRSZ); - - str = palloc(len + 1); - memcpy(str, VARDATA(string), len); - *(str + len) = '\0'; - - result = oidin_subr("text_oid", str, NULL); - - pfree(str); - - PG_RETURN_OID(result); -} diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index bf4bcc365e..88b0c1d266 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.100 2007/01/05 22:19:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.101 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1070,6 +1070,10 @@ regtypesend(PG_FUNCTION_ARGS) /* * text_regclass: convert text to regclass + * + * This could be replaced by CoerceViaIO, except that we need to treat + * text-to-regclass as an implicit cast to support legacy forms of nextval() + * and related functions. */ Datum text_regclass(PG_FUNCTION_ARGS) diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index b9a026c7ea..3f257f375f 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -15,7 +15,7 @@ * * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.94 2007/03/27 23:21:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.95 2007/06/05 21:31:06 tgl Exp $ * * ---------- */ @@ -3871,7 +3871,7 @@ ri_HashCompareOp(Oid eq_opr, Oid typeid) Oid lefttype, righttype, castfunc; - bool arrayCoerce; + CoercionPathType pathtype; /* We always need to know how to call the equality operator */ fmgr_info_cxt(get_opcode(eq_opr), &entry->eq_opr_finfo, @@ -3885,20 +3885,28 @@ ri_HashCompareOp(Oid eq_opr, Oid typeid) * here and in ri_AttributesEqual(). At the moment there is no * point because cases involving nonidentical array types will * be rejected at constraint creation time. + * + * XXX perhaps also consider supporting CoerceViaIO? No need at the + * moment since that will never be generated for implicit coercions. */ op_input_types(eq_opr, &lefttype, &righttype); Assert(lefttype == righttype); if (typeid == lefttype) castfunc = InvalidOid; /* simplest case */ - else if (!find_coercion_pathway(lefttype, typeid, COERCION_IMPLICIT, - &castfunc, &arrayCoerce) - || arrayCoerce) /* XXX fixme */ + else { - /* If target is ANYARRAY, assume it's OK, else punt. */ - if (lefttype != ANYARRAYOID) - elog(ERROR, "no conversion function from %s to %s", - format_type_be(typeid), - format_type_be(lefttype)); + pathtype = find_coercion_pathway(lefttype, typeid, + COERCION_IMPLICIT, + &castfunc); + if (pathtype != COERCION_PATH_FUNC && + pathtype != COERCION_PATH_RELABELTYPE) + { + /* If target is ANYARRAY, assume it's OK, else punt. */ + if (lefttype != ANYARRAYOID) + elog(ERROR, "no conversion function from %s to %s", + format_type_be(typeid), + format_type_be(lefttype)); + } } if (OidIsValid(castfunc)) fmgr_info_cxt(castfunc, &entry->cast_func_finfo, diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index d5de627df1..78be35ef36 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.258 2007/05/24 18:58:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.259 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3127,6 +3127,9 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags) case T_RelabelType: return isSimpleNode((Node *) ((RelabelType *) node)->arg, node, prettyFlags); + case T_CoerceViaIO: + return isSimpleNode((Node *) ((CoerceViaIO *) node)->arg, + node, prettyFlags); case T_ArrayCoerceExpr: return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg, node, prettyFlags); @@ -3595,6 +3598,27 @@ get_rule_expr(Node *node, deparse_context *context, } break; + case T_CoerceViaIO: + { + CoerceViaIO *iocoerce = (CoerceViaIO *) node; + Node *arg = (Node *) iocoerce->arg; + + if (iocoerce->coerceformat == COERCE_IMPLICIT_CAST && + !showimplicit) + { + /* don't show the implicit cast */ + get_rule_expr_paren(arg, context, false, node); + } + else + { + get_coercion_expr(arg, context, + iocoerce->resulttype, + -1, + node); + } + } + break; + case T_ArrayCoerceExpr: { ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c index f9fb9ef582..f7c385ad46 100644 --- a/src/backend/utils/adt/timestamp.c +++ b/src/backend/utils/adt/timestamp.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.176 2007/04/30 21:01:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.177 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3229,187 +3229,6 @@ timestamptz_age(PG_FUNCTION_ARGS) *---------------------------------------------------------*/ -/* timestamp_text() - * Convert timestamp to text data type. - */ -Datum -timestamp_text(PG_FUNCTION_ARGS) -{ - /* Input is a Timestamp, but may as well leave it in Datum form */ - Datum timestamp = PG_GETARG_DATUM(0); - text *result; - char *str; - int len; - - str = DatumGetCString(DirectFunctionCall1(timestamp_out, timestamp)); - - len = (strlen(str) + VARHDRSZ); - - result = palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, len - VARHDRSZ); - - pfree(str); - - PG_RETURN_TEXT_P(result); -} - - -/* text_timestamp() - * Convert text string to timestamp. - * Text type is not null terminated, so use temporary string - * then call the standard input routine. - */ -Datum -text_timestamp(PG_FUNCTION_ARGS) -{ - text *str = PG_GETARG_TEXT_P(0); - int i; - char *sp, - *dp, - dstr[MAXDATELEN + 1]; - - if (VARSIZE(str) - VARHDRSZ > MAXDATELEN) - ereport(ERROR, - (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("invalid input syntax for type timestamp: \"%s\"", - DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(str)))))); - - sp = VARDATA(str); - dp = dstr; - for (i = 0; i < VARSIZE(str) - VARHDRSZ; i++) - *dp++ = *sp++; - *dp = '\0'; - - return DirectFunctionCall3(timestamp_in, - CStringGetDatum(dstr), - ObjectIdGetDatum(InvalidOid), - Int32GetDatum(-1)); -} - - -/* timestamptz_text() - * Convert timestamp with time zone to text data type. - */ -Datum -timestamptz_text(PG_FUNCTION_ARGS) -{ - /* Input is a Timestamp, but may as well leave it in Datum form */ - Datum timestamp = PG_GETARG_DATUM(0); - text *result; - char *str; - int len; - - str = DatumGetCString(DirectFunctionCall1(timestamptz_out, timestamp)); - - len = strlen(str) + VARHDRSZ; - - result = palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, len - VARHDRSZ); - - pfree(str); - - PG_RETURN_TEXT_P(result); -} - -/* text_timestamptz() - * Convert text string to timestamp with time zone. - * Text type is not null terminated, so use temporary string - * then call the standard input routine. - */ -Datum -text_timestamptz(PG_FUNCTION_ARGS) -{ - text *str = PG_GETARG_TEXT_P(0); - int i; - char *sp, - *dp, - dstr[MAXDATELEN + 1]; - - if (VARSIZE(str) - VARHDRSZ > MAXDATELEN) - ereport(ERROR, - (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("invalid input syntax for type timestamp with time zone: \"%s\"", - DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(str)))))); - - sp = VARDATA(str); - dp = dstr; - for (i = 0; i < VARSIZE(str) - VARHDRSZ; i++) - *dp++ = *sp++; - *dp = '\0'; - - return DirectFunctionCall3(timestamptz_in, - CStringGetDatum(dstr), - ObjectIdGetDatum(InvalidOid), - Int32GetDatum(-1)); -} - - -/* interval_text() - * Convert interval to text data type. - */ -Datum -interval_text(PG_FUNCTION_ARGS) -{ - Interval *interval = PG_GETARG_INTERVAL_P(0); - text *result; - char *str; - int len; - - str = DatumGetCString(DirectFunctionCall1(interval_out, - IntervalPGetDatum(interval))); - - len = strlen(str) + VARHDRSZ; - - result = palloc(len); - - SET_VARSIZE(result, len); - memcpy(VARDATA(result), str, len - VARHDRSZ); - - pfree(str); - - PG_RETURN_TEXT_P(result); -} - - -/* text_interval() - * Convert text string to interval. - * Text type may not be null terminated, so copy to temporary string - * then call the standard input routine. - */ -Datum -text_interval(PG_FUNCTION_ARGS) -{ - text *str = PG_GETARG_TEXT_P(0); - int i; - char *sp, - *dp, - dstr[MAXDATELEN + 1]; - - if (VARSIZE(str) - VARHDRSZ > MAXDATELEN) - ereport(ERROR, - (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("invalid input syntax for type interval: \"%s\"", - DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(str)))))); - - sp = VARDATA(str); - dp = dstr; - for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++) - *dp++ = *sp++; - *dp = '\0'; - - return DirectFunctionCall3(interval_in, - CStringGetDatum(dstr), - ObjectIdGetDatum(InvalidOid), - Int32GetDatum(-1)); -} - /* timestamp_trunc() * Truncate timestamp to specified units. */ diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c index d01fef4b57..24b05f3426 100644 --- a/src/backend/utils/adt/uuid.c +++ b/src/backend/utils/adt/uuid.c @@ -6,7 +6,7 @@ * Copyright (c) 2007, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.3 2007/01/31 19:33:54 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/uuid.c,v 1.4 2007/06/05 21:31:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -238,32 +238,3 @@ uuid_hash(PG_FUNCTION_ARGS) pg_uuid_t *key = PG_GETARG_UUID_P(0); return hash_any(key->data, UUID_LEN); } - -/* cast text to uuid */ -Datum -text_uuid(PG_FUNCTION_ARGS) -{ - text *input = PG_GETARG_TEXT_P(0); - int length; - char *str; - Datum result; - - length = VARSIZE(input) - VARHDRSZ; - str = palloc(length + 1); - memcpy(str, VARDATA(input), length); - *(str + length) = '\0'; - - result = DirectFunctionCall1(uuid_in, CStringGetDatum(str)); - pfree(str); - PG_RETURN_DATUM(result); -} - -/* cast uuid to text */ -Datum -uuid_text(PG_FUNCTION_ARGS) -{ - pg_uuid_t *uuid = PG_GETARG_UUID_P(0); - Datum uuid_str = DirectFunctionCall1(uuid_out, UUIDPGetDatum(uuid)); - - PG_RETURN_DATUM(DirectFunctionCall1(textin, uuid_str)); -} |
