* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.64 2007/02/14 01:58:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.65 2007/03/27 23:21:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
add_object_address(OCLASS_TYPE, relab->resulttype, 0,
context->addrs);
}
+ if (IsA(node, ArrayCoerceExpr))
+ {
+ ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
+
+ if (OidIsValid(acoerce->elemfuncid))
+ add_object_address(OCLASS_PROC, acoerce->elemfuncid, 0,
+ context->addrs);
+ add_object_address(OCLASS_TYPE, acoerce->resulttype, 0,
+ context->addrs);
+ /* fall through to examine arguments */
+ }
if (IsA(node, ConvertRowtypeExpr))
{
ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.215 2007/02/27 23:48:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.216 2007/03/27 23:21:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static Datum ExecEvalRelabelType(GenericExprState *exprstate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone);
/* ----------------------------------------------------------------
return ExecEvalExpr(exprstate->arg, econtext, isNull, isDone);
}
+/* ----------------------------------------------------------------
+ * ExecEvalArrayCoerceExpr
+ *
+ * Evaluate an ArrayCoerceExpr node.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) astate->xprstate.expr;
+ Datum result;
+ ArrayType *array;
+ FunctionCallInfoData locfcinfo;
+
+ result = ExecEvalExpr(astate->arg, econtext, isNull, isDone);
+
+ if (isDone && *isDone == ExprEndResult)
+ return result; /* nothing to do */
+ if (*isNull)
+ return result; /* nothing to do */
+
+ /*
+ * If it's binary-compatible, modify the element type in the array header,
+ * but otherwise leave the array as we received it.
+ */
+ if (!OidIsValid(acoerce->elemfuncid))
+ {
+ /* Detoast input array if necessary, and copy in any case */
+ array = DatumGetArrayTypePCopy(result);
+ ARR_ELEMTYPE(array) = astate->resultelemtype;
+ PG_RETURN_ARRAYTYPE_P(array);
+ }
+
+ /* Detoast input array if necessary, but don't make a useless copy */
+ array = DatumGetArrayTypeP(result);
+
+ /* Initialize function cache if first time through */
+ if (astate->elemfunc.fn_oid == InvalidOid)
+ {
+ AclResult aclresult;
+
+ /* Check permission to call function */
+ aclresult = pg_proc_aclcheck(acoerce->elemfuncid, GetUserId(),
+ ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_PROC,
+ get_func_name(acoerce->elemfuncid));
+
+ /* Set up the primary fmgr lookup information */
+ fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc),
+ econtext->ecxt_per_query_memory);
+
+ /* Initialize additional info */
+ astate->elemfunc.fn_expr = (Node *) acoerce;
+ }
+
+ /*
+ * Use array_map to apply the function to each array element.
+ *
+ * We pass on the desttypmod and isExplicit flags whether or not the
+ * function wants them.
+ */
+ InitFunctionCallInfoData(locfcinfo, &(astate->elemfunc), 3,
+ NULL, NULL);
+ locfcinfo.arg[0] = PointerGetDatum(array);
+ locfcinfo.arg[1] = Int32GetDatum(acoerce->resulttypmod);
+ locfcinfo.arg[2] = BoolGetDatum(acoerce->isExplicit);
+ locfcinfo.argnull[0] = false;
+ locfcinfo.argnull[1] = false;
+ locfcinfo.argnull[2] = false;
+
+ return array_map(&locfcinfo, ARR_ELEMTYPE(array), astate->resultelemtype,
+ astate->amstate);
+}
+
/*
* ExecEvalExprSwitchContext
state = (ExprState *) gstate;
}
break;
+ case T_ArrayCoerceExpr:
+ {
+ ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
+ ArrayCoerceExprState *astate = makeNode(ArrayCoerceExprState);
+
+ astate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalArrayCoerceExpr;
+ astate->arg = ExecInitExpr(acoerce->arg, parent);
+ astate->resultelemtype = get_element_type(acoerce->resulttype);
+ if (astate->resultelemtype == InvalidOid)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("target type is not an array")));
+ /* Arrays over domains aren't supported yet */
+ Assert(getBaseType(astate->resultelemtype) ==
+ astate->resultelemtype);
+ astate->elemfunc.fn_oid = InvalidOid; /* not initialized */
+ astate->amstate = (ArrayMapState *) palloc0(sizeof(ArrayMapState));
+ state = (ExprState *) astate;
+ }
+ break;
case T_ConvertRowtypeExpr:
{
ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.371 2007/03/17 00:11:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.372 2007/03/27 23:21:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return newnode;
}
+/*
+ * _copyArrayCoerceExpr
+ */
+static ArrayCoerceExpr *
+_copyArrayCoerceExpr(ArrayCoerceExpr *from)
+{
+ ArrayCoerceExpr *newnode = makeNode(ArrayCoerceExpr);
+
+ COPY_NODE_FIELD(arg);
+ COPY_SCALAR_FIELD(elemfuncid);
+ COPY_SCALAR_FIELD(resulttype);
+ COPY_SCALAR_FIELD(resulttypmod);
+ COPY_SCALAR_FIELD(isExplicit);
+ COPY_SCALAR_FIELD(coerceformat);
+
+ return newnode;
+}
+
/*
* _copyConvertRowtypeExpr
*/
case T_RelabelType:
retval = _copyRelabelType(from);
break;
+ case T_ArrayCoerceExpr:
+ retval = _copyArrayCoerceExpr(from);
+ break;
case T_ConvertRowtypeExpr:
retval = _copyConvertRowtypeExpr(from);
break;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.302 2007/03/17 00:11:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.303 2007/03/27 23:21:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return true;
}
+static bool
+_equalArrayCoerceExpr(ArrayCoerceExpr *a, ArrayCoerceExpr *b)
+{
+ COMPARE_NODE_FIELD(arg);
+ COMPARE_SCALAR_FIELD(elemfuncid);
+ COMPARE_SCALAR_FIELD(resulttype);
+ COMPARE_SCALAR_FIELD(resulttypmod);
+ COMPARE_SCALAR_FIELD(isExplicit);
+
+ /*
+ * 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
_equalConvertRowtypeExpr(ConvertRowtypeExpr *a, ConvertRowtypeExpr *b)
{
case T_RelabelType:
retval = _equalRelabelType(a, b);
break;
+ case T_ArrayCoerceExpr:
+ retval = _equalArrayCoerceExpr(a, b);
+ break;
case T_ConvertRowtypeExpr:
retval = _equalConvertRowtypeExpr(a, b);
break;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.304 2007/03/17 00:11:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.305 2007/03/27 23:21:09 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
WRITE_ENUM_FIELD(relabelformat, CoercionForm);
}
+static void
+_outArrayCoerceExpr(StringInfo str, ArrayCoerceExpr *node)
+{
+ WRITE_NODE_TYPE("ARRAYCOERCEEXPR");
+
+ WRITE_NODE_FIELD(arg);
+ WRITE_OID_FIELD(elemfuncid);
+ WRITE_OID_FIELD(resulttype);
+ WRITE_INT_FIELD(resulttypmod);
+ WRITE_BOOL_FIELD(isExplicit);
+ WRITE_ENUM_FIELD(coerceformat, CoercionForm);
+}
+
static void
_outConvertRowtypeExpr(StringInfo str, ConvertRowtypeExpr *node)
{
case T_RelabelType:
_outRelabelType(str, obj);
break;
+ case T_ArrayCoerceExpr:
+ _outArrayCoerceExpr(str, obj);
+ break;
case T_ConvertRowtypeExpr:
_outConvertRowtypeExpr(str, obj);
break;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.204 2007/03/17 00:11:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.205 2007/03/27 23:21:09 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
READ_DONE();
}
+/*
+ * _readArrayCoerceExpr
+ */
+static ArrayCoerceExpr *
+_readArrayCoerceExpr(void)
+{
+ READ_LOCALS(ArrayCoerceExpr);
+
+ READ_NODE_FIELD(arg);
+ READ_OID_FIELD(elemfuncid);
+ READ_OID_FIELD(resulttype);
+ READ_INT_FIELD(resulttypmod);
+ READ_BOOL_FIELD(isExplicit);
+ READ_ENUM_FIELD(coerceformat, CoercionForm);
+
+ READ_DONE();
+}
+
/*
* _readConvertRowtypeExpr
*/
return_value = _readFieldStore();
else if (MATCH("RELABELTYPE", 11))
return_value = _readRelabelType();
+ else if (MATCH("ARRAYCOERCEEXPR", 15))
+ return_value = _readArrayCoerceExpr();
else if (MATCH("CONVERTROWTYPEEXPR", 18))
return_value = _readConvertRowtypeExpr();
else if (MATCH("CASE", 4))
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.178 2007/02/22 22:00:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.179 2007/03/27 23:21:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
context->total.per_tuple += get_func_cost(saop->opfuncid) *
cpu_operator_cost * estimate_array_length(arraynode) * 0.5;
}
+ else if (IsA(node, ArrayCoerceExpr))
+ {
+ ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
+ Node *arraynode = (Node *) acoerce->arg;
+
+ if (OidIsValid(acoerce->elemfuncid))
+ context->total.per_tuple += get_func_cost(acoerce->elemfuncid) *
+ cpu_operator_cost * estimate_array_length(arraynode);
+ }
else if (IsA(node, RowCompareExpr))
{
/* Conservatively assume we will check all the columns */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.239 2007/03/17 00:11:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.240 2007/03/27 23:21:09 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
return true;
/* else fall through to check args */
}
- if (IsA(node, OpExpr))
+ else if (IsA(node, OpExpr))
{
OpExpr *expr = (OpExpr *) node;
return true;
/* else fall through to check args */
}
- if (IsA(node, DistinctExpr))
+ else if (IsA(node, DistinctExpr))
{
DistinctExpr *expr = (DistinctExpr *) node;
return true;
/* else fall through to check args */
}
- if (IsA(node, ScalarArrayOpExpr))
+ else if (IsA(node, ScalarArrayOpExpr))
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
return true;
/* else fall through to check args */
}
- if (IsA(node, NullIfExpr))
+ else if (IsA(node, ArrayCoerceExpr))
+ {
+ ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
+
+ if (OidIsValid(expr->elemfuncid) &&
+ func_volatile(expr->elemfuncid) != PROVOLATILE_IMMUTABLE)
+ return true;
+ /* else fall through to check args */
+ }
+ else if (IsA(node, NullIfExpr))
{
NullIfExpr *expr = (NullIfExpr *) node;
return true;
/* else fall through to check args */
}
- if (IsA(node, RowCompareExpr))
+ else if (IsA(node, RowCompareExpr))
{
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
ListCell *opid;
return true;
/* else fall through to check args */
}
- if (IsA(node, OpExpr))
+ else if (IsA(node, OpExpr))
{
OpExpr *expr = (OpExpr *) node;
return true;
/* else fall through to check args */
}
- if (IsA(node, DistinctExpr))
+ else if (IsA(node, DistinctExpr))
{
DistinctExpr *expr = (DistinctExpr *) node;
return true;
/* else fall through to check args */
}
- if (IsA(node, ScalarArrayOpExpr))
+ else if (IsA(node, ScalarArrayOpExpr))
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
return true;
/* else fall through to check args */
}
- if (IsA(node, NullIfExpr))
+ else if (IsA(node, ArrayCoerceExpr))
+ {
+ ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
+
+ if (OidIsValid(expr->elemfuncid) &&
+ func_volatile(expr->elemfuncid) == PROVOLATILE_VOLATILE)
+ return true;
+ /* else fall through to check args */
+ }
+ else if (IsA(node, NullIfExpr))
{
NullIfExpr *expr = (NullIfExpr *) node;
return true;
/* else fall through to check args */
}
- if (IsA(node, RowCompareExpr))
+ else if (IsA(node, RowCompareExpr))
{
/* RowCompare probably can't have volatile ops, but check anyway */
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
}
if (IsA(node, SubPlan))
return true;
+ /* ArrayCoerceExpr is strict at the array level, regardless of elemfunc */
if (IsA(node, FieldStore))
return true;
if (IsA(node, CaseExpr))
result = find_nonnullable_rels_walker((Node *) expr->arg, top_level);
}
+ else if (IsA(node, ArrayCoerceExpr))
+ {
+ /* ArrayCoerceExpr is strict at the array level */
+ ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
+
+ result = find_nonnullable_rels_walker((Node *) expr->arg, top_level);
+ }
else if (IsA(node, ConvertRowtypeExpr))
{
/* not clear this is useful, but it can't hurt */
if (r->relabelformat == COERCE_IMPLICIT_CAST)
return strip_implicit_coercions((Node *) r->arg);
}
+ else if (IsA(node, ArrayCoerceExpr))
+ {
+ ArrayCoerceExpr *c = (ArrayCoerceExpr *) node;
+
+ if (c->coerceformat == COERCE_IMPLICIT_CAST)
+ return strip_implicit_coercions((Node *) c->arg);
+ }
else if (IsA(node, ConvertRowtypeExpr))
{
ConvertRowtypeExpr *c = (ConvertRowtypeExpr *) node;
((FuncExpr *) node)->funcformat = COERCE_DONTCARE;
else if (IsA(node, RelabelType))
((RelabelType *) node)->relabelformat = COERCE_DONTCARE;
+ else if (IsA(node, ArrayCoerceExpr))
+ ((ArrayCoerceExpr *) node)->coerceformat = COERCE_DONTCARE;
else if (IsA(node, ConvertRowtypeExpr))
((ConvertRowtypeExpr *) node)->convertformat = COERCE_DONTCARE;
else if (IsA(node, RowExpr))
break;
case T_RelabelType:
return walker(((RelabelType *) node)->arg, context);
+ case T_ArrayCoerceExpr:
+ return walker(((ArrayCoerceExpr *) node)->arg, context);
case T_ConvertRowtypeExpr:
return walker(((ConvertRowtypeExpr *) node)->arg, context);
case T_CaseExpr:
return (Node *) newnode;
}
break;
+ case T_ArrayCoerceExpr:
+ {
+ ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
+ ArrayCoerceExpr *newnode;
+
+ FLATCOPY(newnode, acoerce, ArrayCoerceExpr);
+ MUTATE(newnode->arg, acoerce->arg, Expr *);
+ return (Node *) newnode;
+ }
+ break;
case T_ConvertRowtypeExpr:
{
ConvertRowtypeExpr *convexpr = (ConvertRowtypeExpr *) node;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.151 2007/03/17 00:11:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.152 2007/03/27 23:21:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
CoercionForm cformat, bool isExplicit,
bool hideInputCoercion);
static void hide_coercion_node(Node *node);
-static Node *build_coercion_expression(Node *node, Oid funcId,
+static Node *build_coercion_expression(Node *node,
+ Oid funcId, bool arrayCoerce,
Oid targetTypeId, int32 targetTypMod,
CoercionForm cformat, bool isExplicit);
static Node *coerce_record_to_complex(ParseState *pstate, Node *node,
{
Node *result;
Oid funcId;
+ bool arrayCoerce;
if (targetTypeId == inputTypeId ||
node == NULL)
return (Node *) param;
}
if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
- &funcId))
+ &funcId, &arrayCoerce))
{
- if (OidIsValid(funcId))
+ if (OidIsValid(funcId) || arrayCoerce)
{
/*
* Generate an expression tree representing run-time application
baseTypeMod = targetTypeMod;
baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);
- result = build_coercion_expression(node, funcId,
+ result = build_coercion_expression(node, funcId, arrayCoerce,
baseTypeId, baseTypeMod,
cformat,
(cformat != COERCE_IMPLICIT_CAST));
Oid inputTypeId = input_typeids[i];
Oid targetTypeId = target_typeids[i];
Oid funcId;
+ bool arrayCoerce;
/* no problem if same type */
if (inputTypeId == targetTypeId)
* both binary-compatible and coercion-function cases.
*/
if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
- &funcId))
+ &funcId, &arrayCoerce))
continue;
/*
bool hideInputCoercion)
{
Oid funcId;
+ bool arrayCoerce;
/*
* A negative typmod is assumed to mean that no coercion is wanted. Also,
if (targetTypMod < 0 || targetTypMod == exprTypmod(node))
return node;
- funcId = find_typmod_coercion_function(targetTypeId);
-
- if (OidIsValid(funcId))
+ if (find_typmod_coercion_function(targetTypeId,
+ &funcId, &arrayCoerce))
{
/* Suppress display of nested coercion steps */
if (hideInputCoercion)
hide_coercion_node(node);
- node = build_coercion_expression(node, funcId,
+ node = build_coercion_expression(node, funcId, arrayCoerce,
targetTypeId, targetTypMod,
cformat, isExplicit);
}
((FuncExpr *) node)->funcformat = COERCE_IMPLICIT_CAST;
else if (IsA(node, RelabelType))
((RelabelType *) node)->relabelformat = COERCE_IMPLICIT_CAST;
+ else if (IsA(node, ArrayCoerceExpr))
+ ((ArrayCoerceExpr *) node)->coerceformat = COERCE_IMPLICIT_CAST;
else if (IsA(node, ConvertRowtypeExpr))
((ConvertRowtypeExpr *) node)->convertformat = COERCE_IMPLICIT_CAST;
else if (IsA(node, RowExpr))
/*
* build_coercion_expression()
- * Construct a function-call expression for applying a pg_cast entry.
+ * Construct an expression tree for applying a pg_cast entry.
*
- * This is used for both type-coercion and length-coercion functions,
+ * This is used for both type-coercion and length-coercion operations,
* since there is no difference in terms of the calling convention.
*/
static Node *
-build_coercion_expression(Node *node, Oid funcId,
+build_coercion_expression(Node *node,
+ Oid funcId, bool arrayCoerce,
Oid targetTypeId, int32 targetTypMod,
CoercionForm cformat, bool isExplicit)
{
- HeapTuple tp;
- Form_pg_proc procstruct;
- int nargs;
- List *args;
- Const *cons;
-
- tp = SearchSysCache(PROCOID,
- ObjectIdGetDatum(funcId),
- 0, 0, 0);
- if (!HeapTupleIsValid(tp))
- elog(ERROR, "cache lookup failed for function %u", funcId);
- procstruct = (Form_pg_proc) GETSTRUCT(tp);
-
- /*
- * Asserts essentially check that function is a legal coercion function.
- * We can't make the seemingly obvious tests on prorettype and
- * proargtypes[0], because of various binary-compatibility cases.
- */
- /* Assert(targetTypeId == procstruct->prorettype); */
- Assert(!procstruct->proretset);
- Assert(!procstruct->proisagg);
- nargs = procstruct->pronargs;
- Assert(nargs >= 1 && nargs <= 3);
- /* Assert(procstruct->proargtypes.values[0] == exprType(node)); */
- Assert(nargs < 2 || procstruct->proargtypes.values[1] == INT4OID);
- Assert(nargs < 3 || procstruct->proargtypes.values[2] == BOOLOID);
+ int nargs = 0;
- ReleaseSysCache(tp);
+ if (OidIsValid(funcId))
+ {
+ HeapTuple tp;
+ Form_pg_proc procstruct;
- args = list_make1(node);
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for function %u", funcId);
+ procstruct = (Form_pg_proc) GETSTRUCT(tp);
- if (nargs >= 2)
- {
- /* Pass target typmod as an int4 constant */
- cons = makeConst(INT4OID,
- -1,
- sizeof(int32),
- Int32GetDatum(targetTypMod),
- false,
- true);
-
- args = lappend(args, cons);
+ /*
+ * 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
+ * various binary-compatibility cases.
+ */
+ /* Assert(targetTypeId == procstruct->prorettype); */
+ Assert(!procstruct->proretset);
+ Assert(!procstruct->proisagg);
+ nargs = procstruct->pronargs;
+ Assert(nargs >= 1 && nargs <= 3);
+ /* Assert(procstruct->proargtypes.values[0] == exprType(node)); */
+ Assert(nargs < 2 || procstruct->proargtypes.values[1] == INT4OID);
+ Assert(nargs < 3 || procstruct->proargtypes.values[2] == BOOLOID);
+
+ ReleaseSysCache(tp);
}
- if (nargs == 3)
+ if (arrayCoerce)
{
- /* Pass it a boolean isExplicit parameter, too */
- cons = makeConst(BOOLOID,
- -1,
- sizeof(bool),
- BoolGetDatum(isExplicit),
- false,
- true);
-
- args = lappend(args, cons);
+ /* 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
+ {
+ /* We build an ordinary FuncExpr with special arguments */
+ List *args;
+ Const *cons;
+
+ Assert(OidIsValid(funcId));
+
+ args = list_make1(node);
- return (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat);
+ if (nargs >= 2)
+ {
+ /* Pass target typmod as an int4 constant */
+ cons = makeConst(INT4OID,
+ -1,
+ sizeof(int32),
+ Int32GetDatum(targetTypMod),
+ false,
+ true);
+
+ args = lappend(args, cons);
+ }
+
+ if (nargs == 3)
+ {
+ /* Pass it a boolean isExplicit parameter, too */
+ cons = makeConst(BOOLOID,
+ -1,
+ sizeof(bool),
+ BoolGetDatum(isExplicit),
+ false,
+ true);
+
+ args = lappend(args, cons);
+ }
+
+ return (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat);
+ }
}
*
* 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.
+ * 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).
*
* NOTE: *funcid == InvalidOid does not necessarily mean that no work is
* needed to do the coercion; if the target is a domain then we may need to
bool
find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
CoercionContext ccontext,
- Oid *funcid)
+ Oid *funcid, bool *arrayCoerce)
{
bool result = false;
HeapTuple tuple;
*funcid = InvalidOid;
+ *arrayCoerce = false;
/* Perhaps the types are domains; if so, look at their base types */
if (OidIsValid(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,
- * use array_type_coerce() or array_type_length_coerce().
+ * report that with arrayCoerce = true.
*
* Hack: disallow coercions to oidvector and int2vector, which
* otherwise tend to capture coercions that should go to "real" array
* types. We want those types to be considered "real" arrays for many
- * purposes, but not this one. (Also, array_type_coerce isn't
+ * purposes, but not this one. (Also, ArrayCoerceExpr isn't
* 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;
(sourceElemType = get_element_type(sourceTypeId)) != InvalidOid)
{
if (find_coercion_pathway(targetElemType, sourceElemType,
- ccontext, &elemfuncid))
+ ccontext,
+ &elemfuncid, &elemarraycoerce) &&
+ !elemarraycoerce)
{
- if (!OidIsValid(elemfuncid))
- {
- /* binary-compatible element type conversion */
- *funcid = F_ARRAY_TYPE_COERCE;
- }
- else
- {
- /* does the function take a typmod arg? */
- if (get_func_nargs(elemfuncid) > 1)
- *funcid = F_ARRAY_TYPE_LENGTH_COERCE;
- else
- *funcid = F_ARRAY_TYPE_COERCE;
- }
+ *funcid = elemfuncid;
+ *arrayCoerce = true;
result = true;
}
}
*
* 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
- * array_length_coerce() as the coercion function to use.
+ * one associated with the element type. If one exists, we report it with
+ * *arrayCoerce set to true.
*/
-Oid
-find_typmod_coercion_function(Oid typeId)
+bool
+find_typmod_coercion_function(Oid typeId,
+ Oid *funcid, bool *arrayCoerce)
{
- Oid funcid = InvalidOid;
- bool isArray = false;
Type targetType;
Form_pg_type typeForm;
HeapTuple tuple;
+ *funcid = InvalidOid;
+ *arrayCoerce = false;
+
targetType = typeidType(typeId);
typeForm = (Form_pg_type) GETSTRUCT(targetType);
{
/* Yes, switch our attention to the element type */
typeId = typeForm->typelem;
- isArray = true;
+ *arrayCoerce = true;
}
ReleaseSysCache(targetType);
{
Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(tuple);
- funcid = castForm->castfunc;
+ *funcid = castForm->castfunc;
ReleaseSysCache(tuple);
}
- /*
- * Now, if we did find a coercion function for an array element type,
- * report array_length_coerce() as the function to use.
- */
- if (isArray && OidIsValid(funcid))
- funcid = F_ARRAY_LENGTH_COERCE;
-
- return funcid;
+ return OidIsValid(*funcid);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.214 2007/03/17 01:15:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.215 2007/03/27 23:21:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
case T_FieldSelect:
case T_FieldStore:
case T_RelabelType:
+ case T_ArrayCoerceExpr:
case T_ConvertRowtypeExpr:
case T_CaseTestExpr:
case T_CoerceToDomain:
case T_RelabelType:
type = ((RelabelType *) expr)->resulttype;
break;
+ case T_ArrayCoerceExpr:
+ type = ((ArrayCoerceExpr *) expr)->resulttype;
+ break;
case T_ConvertRowtypeExpr:
type = ((ConvertRowtypeExpr *) expr)->resulttype;
break;
return ((FieldSelect *) expr)->resulttypmod;
case T_RelabelType:
return ((RelabelType *) expr)->resulttypmod;
+ case T_ArrayCoerceExpr:
+ return ((ArrayCoerceExpr *) expr)->resulttypmod;
case T_CaseExpr:
{
/*
bool
exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
{
- FuncExpr *func;
- int nargs;
- Const *second_arg;
-
if (coercedTypmod != NULL)
*coercedTypmod = -1; /* default result on failure */
- /* Is it a function-call at all? */
- if (expr == NULL || !IsA(expr, FuncExpr))
- return false;
- func = (FuncExpr *) expr;
-
/*
- * If it didn't come from a coercion context, reject.
+ * Scalar-type length coercions are FuncExprs, array-type length
+ * coercions are ArrayCoerceExprs
*/
- if (func->funcformat != COERCE_EXPLICIT_CAST &&
- func->funcformat != COERCE_IMPLICIT_CAST)
- return false;
+ if (expr && IsA(expr, FuncExpr))
+ {
+ FuncExpr *func = (FuncExpr *) expr;
+ int nargs;
+ Const *second_arg;
- /*
- * 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;
+ /*
+ * If it didn't come from a coercion context, reject.
+ */
+ if (func->funcformat != COERCE_EXPLICIT_CAST &&
+ func->funcformat != COERCE_IMPLICIT_CAST)
+ return false;
- second_arg = (Const *) lsecond(func->args);
- if (!IsA(second_arg, Const) ||
- second_arg->consttype != INT4OID ||
- second_arg->constisnull)
- 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;
- /*
- * OK, it is indeed a length-coercion function.
- */
- if (coercedTypmod != NULL)
- *coercedTypmod = DatumGetInt32(second_arg->constvalue);
+ 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 true;
+ return false;
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.194 2007/02/01 19:10:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.195 2007/03/27 23:21:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
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) &&
- cfuncid == InvalidOid))
+ COERCION_EXPLICIT,
+ &cfuncid, &arrayCoerce) &&
+ cfuncid == InvalidOid && !arrayCoerce))
{
- /* Yup, it's a type coercion */
+ /* Yup, it's a trivial type coercion */
*funcid = InvalidOid;
*rettype = targetType;
*retset = false;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.137 2007/02/27 23:48:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.138 2007/03/27 23:21:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
int *st, int *endp,
int typlen, bool typbyval, char typalign);
static int array_cmp(FunctionCallInfo fcinfo);
-static Datum array_type_length_coerce_internal(ArrayType *src,
- int32 desttypmod,
- bool isExplicit,
- FmgrInfo *fmgr_info);
/*
orignitems - orig_offset);
}
-/*
- * array_type_coerce -- allow explicit or assignment coercion from
- * one array type to another.
- *
- * array_type_length_coerce -- the same, for cases where both type and length
- * coercion are done by a single function on the element type.
- *
- * Caller should have already verified that the source element type can be
- * coerced into the target element type.
- */
-Datum
-array_type_coerce(PG_FUNCTION_ARGS)
-{
- ArrayType *src = PG_GETARG_ARRAYTYPE_P(0);
- FmgrInfo *fmgr_info = fcinfo->flinfo;
-
- return array_type_length_coerce_internal(src, -1, false, fmgr_info);
-}
-
-Datum
-array_type_length_coerce(PG_FUNCTION_ARGS)
-{
- ArrayType *src = PG_GETARG_ARRAYTYPE_P(0);
- int32 desttypmod = PG_GETARG_INT32(1);
- bool isExplicit = PG_GETARG_BOOL(2);
- FmgrInfo *fmgr_info = fcinfo->flinfo;
-
- return array_type_length_coerce_internal(src, desttypmod,
- isExplicit, fmgr_info);
-}
-
-static Datum
-array_type_length_coerce_internal(ArrayType *src,
- int32 desttypmod,
- bool isExplicit,
- FmgrInfo *fmgr_info)
-{
- Oid src_elem_type = ARR_ELEMTYPE(src);
- typedef struct
- {
- Oid srctype;
- Oid desttype;
- FmgrInfo coerce_finfo;
- ArrayMapState amstate;
- } atc_extra;
- atc_extra *my_extra;
- FunctionCallInfoData locfcinfo;
-
- /*
- * We arrange to look up the coercion function only once per series of
- * calls, assuming the input data type doesn't change underneath us.
- * (Output type can't change.)
- */
- my_extra = (atc_extra *) fmgr_info->fn_extra;
- if (my_extra == NULL)
- {
- fmgr_info->fn_extra = MemoryContextAllocZero(fmgr_info->fn_mcxt,
- sizeof(atc_extra));
- my_extra = (atc_extra *) fmgr_info->fn_extra;
- }
-
- if (my_extra->srctype != src_elem_type)
- {
- Oid tgt_type = get_fn_expr_rettype(fmgr_info);
- Oid tgt_elem_type;
- Oid funcId;
-
- if (tgt_type == InvalidOid)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("could not determine target array type")));
-
- tgt_elem_type = get_element_type(tgt_type);
- if (tgt_elem_type == InvalidOid)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("target type is not an array")));
-
- /*
- * We don't deal with domain constraints yet, so bail out. This isn't
- * currently a problem, because we also don't support arrays of domain
- * type elements either. But in the future we might. At that point
- * consideration should be given to removing the check below and
- * adding a domain constraints check to the coercion.
- */
- if (getBaseType(tgt_elem_type) != tgt_elem_type)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("array coercion to domain type elements not "
- "currently supported")));
-
- if (!find_coercion_pathway(tgt_elem_type, src_elem_type,
- COERCION_EXPLICIT, &funcId))
- {
- /* should never happen, but check anyway */
- elog(ERROR, "no conversion function from %s to %s",
- format_type_be(src_elem_type),
- format_type_be(tgt_elem_type));
- }
- if (OidIsValid(funcId))
- fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt);
- else
- my_extra->coerce_finfo.fn_oid = InvalidOid;
- my_extra->srctype = src_elem_type;
- my_extra->desttype = tgt_elem_type;
- }
-
- /*
- * If it's binary-compatible, modify the element type in the array header,
- * but otherwise leave the array as we received it.
- */
- if (my_extra->coerce_finfo.fn_oid == InvalidOid)
- {
- ArrayType *result;
-
- result = (ArrayType *) DatumGetPointer(datumCopy(PointerGetDatum(src),
- false, -1));
- ARR_ELEMTYPE(result) = my_extra->desttype;
- PG_RETURN_ARRAYTYPE_P(result);
- }
-
- /*
- * Use array_map to apply the function to each array element.
- *
- * We pass on the desttypmod and isExplicit flags whether or not the
- * function wants them.
- */
- InitFunctionCallInfoData(locfcinfo, &my_extra->coerce_finfo, 3,
- NULL, NULL);
- locfcinfo.arg[0] = PointerGetDatum(src);
- locfcinfo.arg[1] = Int32GetDatum(desttypmod);
- locfcinfo.arg[2] = BoolGetDatum(isExplicit);
- locfcinfo.argnull[0] = false;
- locfcinfo.argnull[1] = false;
- locfcinfo.argnull[2] = false;
-
- return array_map(&locfcinfo, my_extra->srctype, my_extra->desttype,
- &my_extra->amstate);
-}
-
-/*
- * array_length_coerce -- apply the element type's length-coercion routine
- * to each element of the given array.
- */
-Datum
-array_length_coerce(PG_FUNCTION_ARGS)
-{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
- int32 desttypmod = PG_GETARG_INT32(1);
- bool isExplicit = PG_GETARG_BOOL(2);
- FmgrInfo *fmgr_info = fcinfo->flinfo;
- typedef struct
- {
- Oid elemtype;
- FmgrInfo coerce_finfo;
- ArrayMapState amstate;
- } alc_extra;
- alc_extra *my_extra;
- FunctionCallInfoData locfcinfo;
-
- /* If no typmod is provided, shortcircuit the whole thing */
- if (desttypmod < 0)
- PG_RETURN_ARRAYTYPE_P(v);
-
- /*
- * We arrange to look up the element type's coercion function only once
- * per series of calls, assuming the element type doesn't change
- * underneath us.
- */
- my_extra = (alc_extra *) fmgr_info->fn_extra;
- if (my_extra == NULL)
- {
- fmgr_info->fn_extra = MemoryContextAllocZero(fmgr_info->fn_mcxt,
- sizeof(alc_extra));
- my_extra = (alc_extra *) fmgr_info->fn_extra;
- }
-
- if (my_extra->elemtype != ARR_ELEMTYPE(v))
- {
- Oid funcId;
-
- funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v));
-
- if (OidIsValid(funcId))
- fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt);
- else
- my_extra->coerce_finfo.fn_oid = InvalidOid;
- my_extra->elemtype = ARR_ELEMTYPE(v);
- }
-
- /*
- * If we didn't find a coercion function, return the array unmodified
- * (this should not happen in the normal course of things, but might
- * happen if this function is called manually).
- */
- if (my_extra->coerce_finfo.fn_oid == InvalidOid)
- PG_RETURN_ARRAYTYPE_P(v);
-
- /*
- * Use array_map to apply the function to each array element.
- *
- * Note: we pass isExplicit whether or not the function wants it ...
- */
- InitFunctionCallInfoData(locfcinfo, &my_extra->coerce_finfo, 3,
- NULL, NULL);
- locfcinfo.arg[0] = PointerGetDatum(v);
- locfcinfo.arg[1] = Int32GetDatum(desttypmod);
- locfcinfo.arg[2] = BoolGetDatum(isExplicit);
- locfcinfo.argnull[0] = false;
- locfcinfo.argnull[1] = false;
- locfcinfo.argnull[2] = false;
-
- return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v),
- &my_extra->amstate);
-}
-
/*
* accumArrayResult - accumulate one (more) Datum for an array result
*
*
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.93 2007/03/25 19:45:14 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.94 2007/03/27 23:21:10 tgl Exp $
*
* ----------
*/
Oid lefttype,
righttype,
castfunc;
+ bool arrayCoerce;
/* We always need to know how to call the equality operator */
fmgr_info_cxt(get_opcode(eq_opr), &entry->eq_opr_finfo,
/*
* If we chose to use a cast from FK to PK type, we may have to
* apply the cast function to get to the operator's input type.
+ *
+ * XXX eventually it would be good to support array-coercion cases
+ * 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.
*/
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))
+ &castfunc, &arrayCoerce)
+ || arrayCoerce) /* XXX fixme */
{
/* If target is ANYARRAY, assume it's OK, else punt. */
if (lefttype != ANYARRAYOID)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.256 2007/03/18 16:50:42 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.257 2007/03/27 23:21:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
case T_RelabelType:
return isSimpleNode((Node *) ((RelabelType *) node)->arg,
node, prettyFlags);
+ case T_ArrayCoerceExpr:
+ return isSimpleNode((Node *) ((ArrayCoerceExpr *) node)->arg,
+ node, prettyFlags);
case T_ConvertRowtypeExpr:
return isSimpleNode((Node *) ((ConvertRowtypeExpr *) node)->arg,
node, prettyFlags);
}
break;
+ case T_ArrayCoerceExpr:
+ {
+ ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
+ Node *arg = (Node *) acoerce->arg;
+
+ if (acoerce->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,
+ acoerce->resulttype,
+ acoerce->resulttypmod,
+ node);
+ }
+ }
+ break;
+
case T_ConvertRowtypeExpr:
{
ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.230 2007/03/21 22:18:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.231 2007/03/27 23:21:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* strip_array_coercion - strip binary-compatible relabeling from an array expr
*
- * For array values, the parser doesn't generate simple RelabelType nodes,
- * but function calls of array_type_coerce() or array_type_length_coerce().
- * If we want to cope with binary-compatible situations we have to look
- * through these calls whenever the element-type coercion is binary-compatible.
+ * For array values, the parser normally generates ArrayCoerceExpr conversions,
+ * but it seems possible that RelabelType might show up. Also, the planner
+ * is not currently tense about collapsing stacked ArrayCoerceExpr nodes,
+ * so we need to be ready to deal with more than one level.
*/
static Node *
strip_array_coercion(Node *node)
{
- /* could be more than one level, so loop */
for (;;)
{
- if (node && IsA(node, RelabelType))
+ if (node && IsA(node, ArrayCoerceExpr) &&
+ ((ArrayCoerceExpr *) node)->elemfuncid == InvalidOid)
{
- /* We don't really expect this case, but may as well cope */
- node = (Node *) ((RelabelType *) node)->arg;
+ node = (Node *) ((ArrayCoerceExpr *) node)->arg;
}
- else if (node && IsA(node, FuncExpr))
+ else if (node && IsA(node, RelabelType))
{
- FuncExpr *fexpr = (FuncExpr *) node;
- Node *arg1;
- Oid src_elem_type;
- Oid tgt_elem_type;
- Oid funcId;
-
- /* must be the right function(s) */
- if (!(fexpr->funcid == F_ARRAY_TYPE_COERCE ||
- fexpr->funcid == F_ARRAY_TYPE_LENGTH_COERCE))
- break;
-
- /* fetch source and destination array element types */
- arg1 = (Node *) linitial(fexpr->args);
- src_elem_type = get_element_type(exprType(arg1));
- if (src_elem_type == InvalidOid)
- break; /* probably shouldn't happen */
- tgt_elem_type = get_element_type(fexpr->funcresulttype);
- if (tgt_elem_type == InvalidOid)
- break; /* probably shouldn't happen */
-
- /* find out how to coerce */
- if (!find_coercion_pathway(tgt_elem_type, src_elem_type,
- COERCION_EXPLICIT, &funcId))
- break; /* definitely shouldn't happen */
-
- if (OidIsValid(funcId))
- break; /* non-binary-compatible coercion */
-
- node = arg1; /* OK to look through the node */
+ /* We don't really expect this case, but may as well cope */
+ node = (Node *) ((RelabelType *) node)->arg;
}
else
break;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.104 2007/02/09 03:35:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.105 2007/03/27 23:21:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
args = ((DistinctExpr *) expr)->args;
else if (IsA(expr, ScalarArrayOpExpr))
args = ((ScalarArrayOpExpr *) expr)->args;
+ else if (IsA(expr, ArrayCoerceExpr))
+ args = list_make1(((ArrayCoerceExpr *) expr)->arg);
else if (IsA(expr, NullIfExpr))
args = ((NullIfExpr *) expr)->args;
else
argtype = exprType((Node *) list_nth(args, argnum));
/*
- * special hack for ScalarArrayOpExpr: what the underlying function will
- * actually get passed is the element type of the array.
+ * special hack for ScalarArrayOpExpr and ArrayCoerceExpr: what the
+ * underlying function will actually get passed is the element type of
+ * the array.
*/
if (IsA(expr, ScalarArrayOpExpr) &&
argnum == 1)
argtype = get_element_type(argtype);
+ else if (IsA(expr, ArrayCoerceExpr) &&
+ argnum == 0)
+ argtype = get_element_type(argtype);
return argtype;
}
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.395 2007/03/26 16:58:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.396 2007/03/27 23:21:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200703261
+#define CATALOG_VERSION_NO 200703271
#endif
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.450 2007/03/22 20:14:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.451 2007/03/27 23:21:11 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
DESCR("prepend element onto front of array");
DATA(insert OID = 383 ( array_cat PGNSP PGUID 12 1 0 f f f f i 2 2277 "2277 2277" _null_ _null_ _null_ array_cat - _null_ ));
DESCR("concatenate two arrays");
-DATA(insert OID = 384 ( array_coerce PGNSP PGUID 12 1 0 f f t f s 1 2277 "2277" _null_ _null_ _null_ array_type_coerce - _null_ ));
-DESCR("coerce array to another array type");
DATA(insert OID = 394 ( string_to_array PGNSP PGUID 12 1 0 f f t f i 2 1009 "25 25" _null_ _null_ _null_ text_to_array - _null_ ));
DESCR("split delimited text into text[]");
DATA(insert OID = 395 ( array_to_string PGNSP PGUID 12 1 0 f f t f i 2 25 "2277 25" _null_ _null_ _null_ array_to_text - _null_ ));
DATA(insert OID = 1290 ( int8 PGNSP PGUID 12 1 0 f f t f i 1 20 "25" _null_ _null_ _null_ text_int8 - _null_ ));
DESCR("convert text to int8");
-DATA(insert OID = 1291 ( array_length_coerce PGNSP PGUID 12 1 0 f f t f s 3 2277 "2277 23 16" _null_ _null_ _null_ array_length_coerce - _null_ ));
-DESCR("adjust any array to new element typmod");
-
DATA(insert OID = 1292 ( tideq PGNSP PGUID 12 1 0 f f t f i 2 16 "27 27" _null_ _null_ _null_ tideq - _null_ ));
DESCR("equal");
DATA(insert OID = 1293 ( currtid PGNSP PGUID 12 1 0 f f t f v 2 27 "26 27" _null_ _null_ _null_ currtid_byreloid - _null_ ));
DESCR("convert time to interval");
DATA(insert OID = 1372 ( char_length PGNSP PGUID 12 1 0 f f t f i 1 23 "1042" _null_ _null_ _null_ bpcharlen - _null_ ));
DESCR("character length");
-
-DATA(insert OID = 1373 ( array_type_length_coerce PGNSP PGUID 12 1 0 f f t f s 3 2277 "2277 23 16" _null_ _null_ _null_ array_type_length_coerce - _null_ ));
-DESCR("coerce array to another type and adjust element typmod");
-
DATA(insert OID = 1374 ( octet_length PGNSP PGUID 12 1 0 f f t f i 1 23 "25" _null_ _null_ _null_ textoctetlen - _null_ ));
DESCR("octet length");
DATA(insert OID = 1375 ( octet_length PGNSP PGUID 12 1 0 f f t f i 1 23 "1042" _null_ _null_ _null_ bpcharoctetlen - _null_ ));
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.170 2007/02/27 01:11:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.171 2007/03/27 23:21:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
TupleDesc argdesc; /* tupdesc for most recent input */
} FieldStoreState;
+/* ----------------
+ * ArrayCoerceExprState node
+ * ----------------
+ */
+typedef struct ArrayCoerceExprState
+{
+ ExprState xprstate;
+ ExprState *arg; /* input array value */
+ Oid resultelemtype; /* element type of result array */
+ FmgrInfo elemfunc; /* lookup info for element coercion function */
+ /* use struct pointer to avoid including array.h here */
+ struct ArrayMapState *amstate; /* workspace for array_map */
+} ArrayCoerceExprState;
+
/* ----------------
* ConvertRowtypeExprState node
* ----------------
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.196 2007/02/20 17:32:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.197 2007/03/27 23:21:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
T_FieldSelect,
T_FieldStore,
T_RelabelType,
+ T_ArrayCoerceExpr,
T_ConvertRowtypeExpr,
T_CaseExpr,
T_CaseWhen,
T_SubPlanState,
T_FieldSelectState,
T_FieldStoreState,
+ T_ArrayCoerceExprState,
T_ConvertRowtypeExprState,
T_CaseExprState,
T_CaseWhenState,
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.128 2007/03/17 00:11:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.129 2007/03/27 23:21:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
CoercionForm relabelformat; /* how to display this node */
} RelabelType;
+/* ----------------
+ * ArrayCoerceExpr
+ *
+ * ArrayCoerceExpr represents a type coercion from one array type to another,
+ * which is implemented by applying the indicated element-type coercion
+ * function to each element of the source array. If elemfuncid is InvalidOid
+ * then the element types are binary-compatible, but the coercion still
+ * requires some effort (we have to fix the element type ID stored in the
+ * array header).
+ * ----------------
+ */
+
+typedef struct ArrayCoerceExpr
+{
+ Expr xpr;
+ Expr *arg; /* input expression (yields an array) */
+ Oid elemfuncid; /* OID of element coercion function, or 0 */
+ Oid resulttype; /* output type of coercion (an array type) */
+ int32 resulttypmod; /* output typmod (also element typmod) */
+ bool isExplicit; /* conversion semantics flag to pass to func */
+ CoercionForm coerceformat; /* how to display this node */
+} ArrayCoerceExpr;
+
/* ----------------
* ConvertRowtypeExpr
*
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.69 2007/01/05 22:19:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.70 2007/03/27 23:21:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
CoercionContext ccontext,
- Oid *funcid);
-extern Oid find_typmod_coercion_function(Oid typeId);
+ Oid *funcid, bool *arrayCoerce);
+extern bool find_typmod_coercion_function(Oid typeId,
+ Oid *funcid, bool *arrayCoerce);
#endif /* PARSE_COERCE_H */
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.63 2007/02/27 23:48:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.64 2007/03/27 23:21:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Datum array_dims(PG_FUNCTION_ARGS);
extern Datum array_lower(PG_FUNCTION_ARGS);
extern Datum array_upper(PG_FUNCTION_ARGS);
-extern Datum array_type_coerce(PG_FUNCTION_ARGS);
-extern Datum array_type_length_coerce(PG_FUNCTION_ARGS);
-extern Datum array_length_coerce(PG_FUNCTION_ARGS);
extern Datum array_larger(PG_FUNCTION_ARGS);
extern Datum array_smaller(PG_FUNCTION_ARGS);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.191 2007/03/25 23:27:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.192 2007/03/27 23:21:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
case T_RelabelType:
return exec_simple_check_node((Node *) ((RelabelType *) node)->arg);
+ case T_ArrayCoerceExpr:
+ return exec_simple_check_node((Node *) ((ArrayCoerceExpr *) node)->arg);
+
case T_ConvertRowtypeExpr:
return exec_simple_check_node((Node *) ((ConvertRowtypeExpr *) node)->arg);