diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c index 86e8c6b..8194519 100644 *** a/src/backend/catalog/pg_aggregate.c --- b/src/backend/catalog/pg_aggregate.c *************** *** 305,310 **** lookup_agg_function(List *fnName, --- 305,311 ---- Oid *rettype) { Oid fnOid; + Oid vartype; bool retset; int nvargs; Oid *true_oid_array; *************** *** 321,327 **** lookup_agg_function(List *fnName, */ fdresult = func_get_detail(fnName, NIL, NIL, nargs, input_types, false, false, ! &fnOid, rettype, &retset, &nvargs, &true_oid_array, NULL); /* only valid case is a normal function not returning a set */ --- 322,328 ---- */ fdresult = func_get_detail(fnName, NIL, NIL, nargs, input_types, false, false, ! &fnOid, rettype, &vartype, &retset, &nvargs, &true_oid_array, NULL); /* only valid case is a normal function not returning a set */ diff --git a/src/backend/catalog/pg_proc.index 6250b07..8fdd88e 100644 *** a/src/backend/catalog/pg_proc.c --- b/src/backend/catalog/pg_proc.c *************** *** 272,278 **** ProcedureCreate(const char *procedureName, variadicType = ANYELEMENTOID; break; default: ! variadicType = get_element_type(allParams[i]); if (!OidIsValid(variadicType)) elog(ERROR, "variadic parameter is not an array"); break; --- 272,278 ---- variadicType = ANYELEMENTOID; break; default: ! variadicType = get_base_element_type(allParams[i]); if (!OidIsValid(variadicType)) elog(ERROR, "variadic parameter is not an array"); break; diff --git a/src/backend/commands/fuindex 03da168..717c632 100644 *** a/src/backend/commands/functioncmds.c --- b/src/backend/commands/functioncmds.c *************** *** 273,279 **** examine_parameter_list(List *parameters, Oid languageOid, /* okay */ break; default: ! if (!OidIsValid(get_element_type(toid))) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("VARIADIC parameter must be an array"))); --- 273,279 ---- /* okay */ break; default: ! if (!OidIsValid(get_base_element_type(toid))) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("VARIADIC parameter must be an array"))); diff --git a/src/backend/parser/parse_coerindex 0418972..990ee29 100644 *** a/src/backend/parser/parse_coerce.c --- b/src/backend/parser/parse_coerce.c *************** *** 1326,1332 **** check_generic_type_consistency(Oid *actual_arg_types, return true; } ! array_typelem = get_element_type(array_typeid); if (!OidIsValid(array_typelem)) return false; /* should be an array, but isn't */ --- 1326,1332 ---- return true; } ! array_typelem = get_base_element_type(array_typeid); if (!OidIsValid(array_typelem)) return false; /* should be an array, but isn't */ *************** *** 1513,1519 **** enforce_generic_type_consistency(Oid *actual_arg_types, } else { ! array_typelem = get_element_type(array_typeid); if (!OidIsValid(array_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), --- 1513,1519 ---- } else { ! array_typelem = get_base_element_type(array_typeid); if (!OidIsValid(array_typelem)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), *************** *** 1656,1662 **** resolve_generic_type(Oid declared_type, if (context_declared_type == ANYARRAYOID) { /* Use actual type, but it must be an array */ ! Oid array_typelem = get_element_type(context_actual_type); if (!OidIsValid(array_typelem)) ereport(ERROR, --- 1656,1662 ---- if (context_declared_type == ANYARRAYOID) { /* Use actual type, but it must be an array */ ! Oid array_typelem = get_base_element_type(context_actual_type); if (!OidIsValid(array_typelem)) ereport(ERROR, *************** *** 1687,1693 **** resolve_generic_type(Oid declared_type, if (context_declared_type == ANYARRAYOID) { /* Use the element type corresponding to actual type */ ! Oid array_typelem = get_element_type(context_actual_type); if (!OidIsValid(array_typelem)) ereport(ERROR, --- 1687,1693 ---- if (context_declared_type == ANYARRAYOID) { /* Use the element type corresponding to actual type */ ! Oid array_typelem = get_base_element_type(context_actual_type); if (!OidIsValid(array_typelem)) ereport(ERROR, diff --git a/src/backend/parser/parse_fuindex 75f1e20..acf9317 100644 *** a/src/backend/parser/parse_func.c --- b/src/backend/parser/parse_func.c *************** *** 64,69 **** ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, --- 64,70 ---- WindowDef *over, bool is_column, int location) { Oid rettype; + Oid vartype; Oid funcid; ListCell *l; ListCell *nextl; *************** *** 212,218 **** ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, fdresult = func_get_detail(funcname, fargs, argnames, nargs, actual_arg_types, !func_variadic, true, ! &funcid, &rettype, &retset, &nvargs, &declared_arg_types, &argdefaults); if (fdresult == FUNCDETAIL_COERCION) { --- 213,219 ---- fdresult = func_get_detail(funcname, fargs, argnames, nargs, actual_arg_types, !func_variadic, true, ! &funcid, &rettype, &vartype, &retset, &nvargs, &declared_arg_types, &argdefaults); if (fdresult == FUNCDETAIL_COERCION) { *************** *** 371,377 **** ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, newa->multidims = false; newa->location = exprLocation((Node *) vargs); ! fargs = lappend(fargs, newa); } /* build the appropriate output structure */ --- 372,403 ---- newa->multidims = false; newa->location = exprLocation((Node *) vargs); ! /* ! * If the VARIADIC parameter is anyarray, look for other anyarray ! * arguments that constrain its true type. If we don't find one, the ! * standard array type of the variadic element type fills in. ! */ ! if (vartype == ANYARRAYOID) ! { ! int i; ! ! vartype = newa->array_typeid; ! for (i = 0; i < nargs; i++) ! if (declared_arg_types[i] == ANYARRAYOID) ! { ! vartype = actual_arg_types[i]; ! break; ! } ! } ! ! /* VARIADIC parameter type may be a domain - coerce it */ ! fargs = lappend(fargs, coerce_type(pstate, ! (Node *) newa, ! newa->array_typeid, ! vartype, -1, ! COERCION_IMPLICIT, ! COERCE_IMPLICIT_CAST, ! -1)); } /* build the appropriate output structure */ *************** *** 929,934 **** func_get_detail(List *funcname, --- 955,961 ---- bool expand_defaults, Oid *funcid, /* return value */ Oid *rettype, /* return value */ + Oid *vartype, /* return value */ bool *retset, /* return value */ int *nvargs, /* return value */ Oid **true_typeids, /* return value */ *************** *** 940,945 **** func_get_detail(List *funcname, --- 967,973 ---- /* initialize output arguments to silence compiler warnings */ *funcid = InvalidOid; *rettype = InvalidOid; + *vartype = InvalidOid; *retset = false; *nvargs = 0; *true_typeids = NULL; *************** *** 1050,1055 **** func_get_detail(List *funcname, --- 1078,1084 ---- /* Treat it as a type coercion */ *funcid = InvalidOid; *rettype = targetType; + *vartype = InvalidOid; *retset = false; *nvargs = 0; *true_typeids = argtypes; *************** *** 1148,1153 **** func_get_detail(List *funcname, --- 1177,1186 ---- best_candidate->oid); pform = (Form_pg_proc) GETSTRUCT(ftup); *rettype = pform->prorettype; + if (*nvargs > 0) + *vartype = pform->proargtypes.values[pform->pronargs - 1]; + else + *vartype = InvalidOid; *retset = pform->proretset; /* fetch default args if caller wants 'em */ if (argdefaults && best_candidate->ndargs > 0) diff --git a/src/backend/utils/adt/arrindex 274e867..6f9824d 100644 *** a/src/backend/utils/adt/array_userfuncs.c --- b/src/backend/utils/adt/array_userfuncs.c *************** *** 32,37 **** array_push(PG_FUNCTION_ARGS) --- 32,38 ---- *lb; ArrayType *result; int indx; + Oid array_type; Oid element_type; int16 typlen; bool typbyval; *************** *** 47,57 **** array_push(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data types"))); ! arg0_elemid = get_element_type(arg0_typeid); ! arg1_elemid = get_element_type(arg1_typeid); if (arg0_elemid != InvalidOid) { if (PG_ARGISNULL(0)) v = construct_empty_array(arg0_elemid); else --- 48,59 ---- (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not determine input data types"))); ! arg0_elemid = get_base_element_type(arg0_typeid); ! arg1_elemid = get_base_element_type(arg1_typeid); if (arg0_elemid != InvalidOid) { + array_type = arg0_typeid; if (PG_ARGISNULL(0)) v = construct_empty_array(arg0_elemid); else *************** *** 64,69 **** array_push(PG_FUNCTION_ARGS) --- 66,72 ---- } else if (arg1_elemid != InvalidOid) { + array_type = arg1_typeid; if (PG_ARGISNULL(1)) v = construct_empty_array(arg1_elemid); else *************** *** 156,161 **** array_push(PG_FUNCTION_ARGS) --- 159,171 ---- if (ARR_NDIM(v) == 1) ARR_LBOUND(result)[0] = ARR_LBOUND(v)[0]; + /* + * If the input array type is a domain, our returned value must also + * conform to the constraints of that domain. + */ + if (getBaseType(array_type) != array_type) + domain_check(PointerGetDatum(result), false, array_type, NULL, NULL); + PG_RETURN_ARRAYTYPE_P(result); } *************** *** 195,200 **** array_cat(PG_FUNCTION_ARGS) --- 205,211 ---- Oid element_type; Oid element_type1; Oid element_type2; + Oid array_type; int32 dataoffset; /* Concatenating a null array is a no-op, just return the other input */ *************** *** 396,401 **** array_cat(PG_FUNCTION_ARGS) --- 407,421 ---- nitems2); } + /* + * If the input array type is a domain, our returned value must also + * conform to the constraints of that domain. Earlier exits did not need + * this check, because they merely returned input data unchanged. + */ + array_type = get_fn_expr_argtype(fcinfo->flinfo, 0); + if (getBaseType(array_type) != array_type) + domain_check(PointerGetDatum(result), false, array_type, NULL, NULL); + PG_RETURN_ARRAYTYPE_P(result); } diff --git a/src/backend/utils/adt/ruleutils.cindex 3ab90cb..b7bdd0b 100644 *** a/src/backend/utils/adt/ruleutils.c --- b/src/backend/utils/adt/ruleutils.c *************** *** 7001,7006 **** generate_function_name(Oid funcid, int nargs, List *argnames, --- 7001,7007 ---- FuncDetailCode p_result; Oid p_funcid; Oid p_rettype; + Oid p_vartype; bool p_retset; int p_nvargs; Oid *p_true_typeids; *************** *** 7020,7026 **** generate_function_name(Oid funcid, int nargs, List *argnames, p_result = func_get_detail(list_make1(makeString(proname)), NIL, argnames, nargs, argtypes, !OidIsValid(procform->provariadic), true, ! &p_funcid, &p_rettype, &p_retset, &p_nvargs, &p_true_typeids, NULL); if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE || --- 7021,7027 ---- p_result = func_get_detail(list_make1(makeString(proname)), NIL, argnames, nargs, argtypes, !OidIsValid(procform->provariadic), true, ! &p_funcid, &p_rettype, &p_vartype, &p_retset, &p_nvargs, &p_true_typeids, NULL); if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE || diff --git a/src/include/parser/parse_fuindex 2fe6f90..01f4954 100644 *** a/src/include/parser/parse_func.h --- b/src/include/parser/parse_func.h *************** *** 52,58 **** extern FuncDetailCode func_get_detail(List *funcname, List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, ! Oid *funcid, Oid *rettype, bool *retset, int *nvargs, Oid **true_typeids, List **argdefaults); --- 52,58 ---- List *fargs, List *fargnames, int nargs, Oid *argtypes, bool expand_variadic, bool expand_defaults, ! Oid *funcid, Oid *rettype, Oid *vartype, bool *retset, int *nvargs, Oid **true_typeids, List **argdefaults); diff --git a/src/test/regress/expectedindex 7d72791..6c1d2ee 100644 *** a/src/test/regress/expected/domain.out --- b/src/test/regress/expected/domain.out *************** *** 595,597 **** select array_elem_check(-1); --- 595,637 ---- ERROR: value for domain orderedpair violates check constraint "orderedpair_check" CONTEXT: PL/pgSQL function "array_elem_check" line 5 at assignment drop function array_elem_check(int); + select array_append('{1}'::orderedpair, 2); + array_append + -------------- + {1,2} + (1 row) + + select array_prepend(2, '{1}'::orderedpair); -- fail + ERROR: value for domain orderedpair violates check constraint "orderedpair_check" + select array_cat('{2}'::orderedpair, '{1}'); -- fail + ERROR: value for domain orderedpair violates check constraint "orderedpair_check" + create or replace function domain_variadic(variadic orderedpair) + returns int + as 'select $1[2] - $1[1]' language sql; + select domain_variadic(1, 2); + domain_variadic + ----------------- + 1 + (1 row) + + select domain_variadic(2, 1); -- fail + ERROR: value for domain orderedpair violates check constraint "orderedpair_check" + select domain_variadic(variadic array[1,2]); + domain_variadic + ----------------- + 1 + (1 row) + + select domain_variadic(variadic array[2,1]); -- fail + ERROR: value for domain orderedpair violates check constraint "orderedpair_check" + create or replace function domain_poly_variadic(anyarray, variadic anyarray) + returns int + as 'select array_length($1, 1) * array_length($2, 1)' language sql; + select domain_poly_variadic('{2}'::orderedpair, 3, 4); + domain_poly_variadic + ---------------------- + 2 + (1 row) + + select domain_poly_variadic('{2}'::orderedpair, 3, 1); -- fail + ERROR: value for domain orderedpair violates check constraint "orderedpair_check" diff --git a/src/test/regress/sql/domain.sqindex 545af62..180fdcf 100644 *** a/src/test/regress/sql/domain.sql --- b/src/test/regress/sql/domain.sql *************** *** 466,468 **** select array_elem_check(3); --- 466,486 ---- select array_elem_check(-1); drop function array_elem_check(int); + + select array_append('{1}'::orderedpair, 2); + select array_prepend(2, '{1}'::orderedpair); -- fail + select array_cat('{2}'::orderedpair, '{1}'); -- fail + + create or replace function domain_variadic(variadic orderedpair) + returns int + as 'select $1[2] - $1[1]' language sql; + select domain_variadic(1, 2); + select domain_variadic(2, 1); -- fail + select domain_variadic(variadic array[1,2]); + select domain_variadic(variadic array[2,1]); -- fail + + create or replace function domain_poly_variadic(anyarray, variadic anyarray) + returns int + as 'select array_length($1, 1) * array_length($2, 1)' language sql; + select domain_poly_variadic('{2}'::orderedpair, 3, 4); + select domain_poly_variadic('{2}'::orderedpair, 3, 1); -- fail