diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 8ffbc52fde..54105f2c40 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -67,7 +67,6 @@ #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/memutils.h" -#include "utils/rangetypes.h" #include "utils/rel.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -85,6 +84,8 @@ typedef struct /* Potentially set by contrib/pg_upgrade_support functions */ Oid binary_upgrade_next_array_pg_type_oid = InvalidOid; +static void makeRangeConstructors(const char *name, Oid namespace, + Oid rangeOid, Oid subtype); static Oid findTypeInputFunction(List *procname, Oid typeOid); static Oid findTypeOutputFunction(List *procname, Oid typeOid); static Oid findTypeReceiveFunction(List *procname, Oid typeOid); @@ -92,9 +93,9 @@ static Oid findTypeSendFunction(List *procname, Oid typeOid); static Oid findTypeTypmodinFunction(List *procname); static Oid findTypeTypmodoutFunction(List *procname); static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid); +static Oid findRangeSubOpclass(List *opcname, Oid subtype); static Oid findRangeCanonicalFunction(List *procname, Oid typeOid); -static Oid findRangeSubOpclass(List *procname, Oid typeOid); -static Oid findRangeSubtypeDiffFunction(List *procname, Oid typeOid); +static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype); static void validateDomainConstraint(Oid domainoid, char *ccbin); static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode); static void checkDomainOwner(HeapTuple tup); @@ -103,8 +104,6 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, char *domainName); -static void makeRangeConstructor(char *name, Oid namespace, Oid rettype, - Oid subtype); /* @@ -1154,338 +1153,6 @@ DefineEnum(CreateEnumStmt *stmt) pfree(enumArrayName); } -/* - * DefineRange - * Registers a new range type. - */ -void -DefineRange(CreateRangeStmt *stmt) -{ - char *typeName; - char *rangeArrayName; - Oid typeNamespace; - Oid typoid; - Oid rangeArrayOid; - List *parameters = stmt->params; - List *rangeSubOpclassName = NIL; - List *rangeSubtypeDiffName = NIL; - List *rangeCollationName = NIL; - Oid rangeCollation = InvalidOid; - regproc rangeAnalyze = InvalidOid; - Oid rangeSubtype = InvalidOid; - regproc rangeSubOpclass = InvalidOid; - regproc rangeCanonical = InvalidOid; - regproc rangeSubtypeDiff = InvalidOid; - int16 subtyplen; - bool subtypbyval; - char subtypalign; - char alignment; - AclResult aclresult; - ListCell *lc; - - /* Convert list of names to a name and namespace */ - typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, - &typeName); - - /* Check we have creation rights in target namespace */ - aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(typeNamespace)); - - /* - * Look to see if type already exists (presumably as a shell; if not, - * TypeCreate will complain). - */ - typoid = GetSysCacheOid2(TYPENAMENSP, - CStringGetDatum(typeName), - ObjectIdGetDatum(typeNamespace)); - - /* - * If it's not a shell, see if it's an autogenerated array type, and if so - * rename it out of the way. - */ - if (OidIsValid(typoid) && get_typisdefined(typoid)) - { - if (moveArrayTypeName(typoid, typeName, typeNamespace)) - typoid = InvalidOid; - } - - /* - * If it doesn't exist, create it as a shell, so that the OID is known for - * use in the I/O function definitions. - */ - if (!OidIsValid(typoid)) - { - typoid = TypeShellMake(typeName, typeNamespace, GetUserId()); - /* Make new shell type visible for modification below */ - CommandCounterIncrement(); - - /* - * If the command was a parameterless CREATE TYPE, we're done --- - * creating the shell type was all we're supposed to do. - */ - if (parameters == NIL) - return; - } - else - { - /* Complain if dummy CREATE TYPE and entry already exists */ - if (parameters == NIL) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("type \"%s\" already exists", typeName))); - } - - foreach(lc, stmt->params) - { - DefElem *defel = lfirst(lc); - - if (pg_strcasecmp(defel->defname, "subtype") == 0) - { - if (OidIsValid(rangeSubtype)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel)); - } - else if (pg_strcasecmp(defel->defname, "canonical") == 0) - { - if (OidIsValid(rangeCanonical)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - rangeCanonical = findRangeCanonicalFunction( - defGetQualifiedName(defel), typoid); - } - else if (pg_strcasecmp(defel->defname, "collation") == 0) - { - if (rangeCollationName != NIL) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - rangeCollationName = defGetQualifiedName(defel); - } - else if (pg_strcasecmp(defel->defname, "analyze") == 0) - { - if (OidIsValid(rangeAnalyze)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - rangeAnalyze = findTypeAnalyzeFunction(defGetQualifiedName(defel), - typoid); - } - else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0) - { - if (rangeSubOpclassName != NIL) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - rangeSubOpclassName = defGetQualifiedName(defel); - } - else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0) - { - if (rangeSubtypeDiffName != NIL) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("conflicting or redundant options"))); - rangeSubtypeDiffName = defGetQualifiedName(defel); - } - else - { - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("type attribute \"%s\" not recognized", - defel->defname))); - continue; - } - } - - if (!OidIsValid(rangeSubtype)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("type attribute \"subtype\" is required"))); - - if (type_is_collatable(rangeSubtype)) - { - if (rangeCollationName == NIL) - rangeCollation = get_typcollation(rangeSubtype); - else - rangeCollation = get_collation_oid(rangeCollationName, false); - } - else if (rangeCollationName != NIL) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("range collation specified but subtype does not support collation"))); - - rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype); - - if (rangeSubtypeDiffName != NIL) - rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName, - rangeSubtype); - - get_typlenbyvalalign(rangeSubtype, - &subtyplen, &subtypbyval, &subtypalign); - - /* alignment must be 'i' or 'd' for ranges */ - alignment = (subtypalign == 'd') ? 'd' : 'i'; - - /* Allocate OID for array type */ - rangeArrayOid = AssignTypeArrayOid(); - - /* Create the pg_type entry */ - typoid = - TypeCreate(InvalidOid, /* no predetermined type OID */ - typeName, /* type name */ - typeNamespace, /* namespace */ - InvalidOid, /* relation oid (n/a here) */ - 0, /* relation kind (ditto) */ - GetUserId(), /* owner's ID */ - -1, /* internal size (always varlena) */ - TYPTYPE_RANGE, /* type-type (range type) */ - TYPCATEGORY_RANGE, /* type-category (range type) */ - false, /* range types are never preferred */ - DEFAULT_TYPDELIM, /* array element delimiter */ - F_RANGE_IN, /* input procedure */ - F_RANGE_OUT, /* output procedure */ - F_RANGE_RECV, /* receive procedure */ - F_RANGE_SEND, /* send procedure */ - InvalidOid, /* typmodin procedure - none */ - InvalidOid, /* typmodout procedure - none */ - rangeAnalyze, /* analyze procedure */ - InvalidOid, /* element type ID - none */ - false, /* this is not an array type */ - rangeArrayOid, /* array type we are about to create */ - InvalidOid, /* base type ID (only for domains) */ - NULL, /* never a default type value */ - NULL, /* binary default isn't sent either */ - false, /* never passed by value */ - alignment, /* alignment */ - 'x', /* TOAST strategy (always extended) */ - -1, /* typMod (Domains only) */ - 0, /* Array dimensions of typbasetype */ - false, /* Type NOT NULL */ - InvalidOid); /* typcollation */ - - /* create the entry in pg_range */ - RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass, - rangeCanonical, rangeSubtypeDiff); - - /* - * Create the array type that goes with it. - */ - rangeArrayName = makeArrayTypeName(typeName, typeNamespace); - - TypeCreate(rangeArrayOid, /* force assignment of this type OID */ - rangeArrayName, /* type name */ - typeNamespace, /* namespace */ - InvalidOid, /* relation oid (n/a here) */ - 0, /* relation kind (ditto) */ - GetUserId(), /* owner's ID */ - -1, /* internal size (always varlena) */ - TYPTYPE_BASE, /* type-type (base type) */ - TYPCATEGORY_ARRAY, /* type-category (array) */ - false, /* array types are never preferred */ - DEFAULT_TYPDELIM, /* array element delimiter */ - F_ARRAY_IN, /* input procedure */ - F_ARRAY_OUT, /* output procedure */ - F_ARRAY_RECV, /* receive procedure */ - F_ARRAY_SEND, /* send procedure */ - InvalidOid, /* typmodin procedure - none */ - InvalidOid, /* typmodout procedure - none */ - InvalidOid, /* analyze procedure - default */ - typoid, /* element type ID */ - true, /* yes this is an array type */ - InvalidOid, /* no further array type */ - InvalidOid, /* base type ID */ - NULL, /* never a default type value */ - NULL, /* binary default isn't sent either */ - false, /* never passed by value */ - alignment, /* alignment - same as range's */ - 'x', /* ARRAY is always toastable */ - -1, /* typMod (Domains only) */ - 0, /* Array dimensions of typbasetype */ - false, /* Type NOT NULL */ - InvalidOid); /* typcollation */ - - pfree(rangeArrayName); - - /* And create the constructor functions for this range type */ - makeRangeConstructor(typeName, typeNamespace, typoid, rangeSubtype); -} - -/* - * Because there may exist several range types over one subtype, the range type - * can't be determined from the subtype. This means that constructors can't be - * polymorphic, and so we must generate a new constructor for every range type - * defined. - * - * We actually define 4 functions with 0 through 3 arguments. This is just to - * offer more convenience for the user. - */ -static void -makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype) -{ - ObjectAddress referenced; - Oid constructorArgTypes[3]; - int i; - - referenced.classId = TypeRelationId; - referenced.objectId = rangeOid; - referenced.objectSubId = 0; - - constructorArgTypes[0] = subtype; - constructorArgTypes[1] = subtype; - constructorArgTypes[2] = TEXTOID; - - for (i = 0; i < 4; i++) - { - oidvector *constructorArgTypesVector; - ObjectAddress myself; - Oid procOid; - char *prosrc[4] = {"range_constructor0", - "range_constructor1", - "range_constructor2", - "range_constructor3"}; - - constructorArgTypesVector = buildoidvector(constructorArgTypes, i); - - procOid = ProcedureCreate( - name, /* name */ - namespace, /* namespace */ - false, /* replace */ - false, /* return set */ - rangeOid, /* return type */ - INTERNALlanguageId, /* language */ - F_FMGR_INTERNAL_VALIDATOR, /* language validator */ - prosrc[i], /* prosrc */ - NULL, /* probin */ - false, /* agg */ - false, /* window */ - false, /* security definer */ - false, /* strict */ - PROVOLATILE_IMMUTABLE, /* volatility */ - constructorArgTypesVector, /* param types */ - PointerGetDatum(NULL), /* allParameterTypes */ - PointerGetDatum(NULL), /* parameterModes */ - PointerGetDatum(NULL), /* parameterNames */ - NIL, /* parameterDefaults */ - PointerGetDatum(NULL), /* proconfig */ - 1.0, /* procost */ - 0.0); /* prorows */ - - /* - * Make the constructors internally-dependent on the range type so - * that they go away silently when the type is dropped. Note that - * pg_dump depends on this choice to avoid dumping the constructors. - */ - myself.classId = ProcedureRelationId; - myself.objectId = procOid; - myself.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); - } -} - /* * AlterEnum * Adds a new label to an existing enum. @@ -1541,6 +1208,357 @@ checkEnumOwner(HeapTuple tup) } +/* + * DefineRange + * Registers a new range type. + */ +void +DefineRange(CreateRangeStmt *stmt) +{ + char *typeName; + Oid typeNamespace; + Oid typoid; + char *rangeArrayName; + Oid rangeArrayOid; + Oid rangeSubtype = InvalidOid; + List *rangeSubOpclassName = NIL; + List *rangeCollationName = NIL; + List *rangeCanonicalName = NIL; + List *rangeSubtypeDiffName = NIL; + List *rangeAnalyzeName = NIL; + Oid rangeSubOpclass; + Oid rangeCollation; + regproc rangeCanonical; + regproc rangeSubtypeDiff; + regproc rangeAnalyze; + int16 subtyplen; + bool subtypbyval; + char subtypalign; + char alignment; + AclResult aclresult; + ListCell *lc; + + /* Convert list of names to a name and namespace */ + typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, + &typeName); + + /* Check we have creation rights in target namespace */ + aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(typeNamespace)); + + /* + * Look to see if type already exists. + */ + typoid = GetSysCacheOid2(TYPENAMENSP, + CStringGetDatum(typeName), + ObjectIdGetDatum(typeNamespace)); + + /* + * If it's not a shell, see if it's an autogenerated array type, and if so + * rename it out of the way. + */ + if (OidIsValid(typoid) && get_typisdefined(typoid)) + { + if (moveArrayTypeName(typoid, typeName, typeNamespace)) + typoid = InvalidOid; + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("type \"%s\" already exists", typeName))); + } + + /* + * If it doesn't exist, create it as a shell, so that the OID is known for + * use in the range function definitions. + */ + if (!OidIsValid(typoid)) + { + typoid = TypeShellMake(typeName, typeNamespace, GetUserId()); + /* Make new shell type visible for modification below */ + CommandCounterIncrement(); + } + + /* Extract the parameters from the parameter list */ + foreach(lc, stmt->params) + { + DefElem *defel = (DefElem *) lfirst(lc); + + if (pg_strcasecmp(defel->defname, "subtype") == 0) + { + if (OidIsValid(rangeSubtype)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + /* we can look up the subtype name immediately */ + rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel)); + } + else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0) + { + if (rangeSubOpclassName != NIL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + rangeSubOpclassName = defGetQualifiedName(defel); + } + else if (pg_strcasecmp(defel->defname, "collation") == 0) + { + if (rangeCollationName != NIL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + rangeCollationName = defGetQualifiedName(defel); + } + else if (pg_strcasecmp(defel->defname, "canonical") == 0) + { + if (rangeCanonicalName != NIL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + rangeCanonicalName = defGetQualifiedName(defel); + } + else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0) + { + if (rangeSubtypeDiffName != NIL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + rangeSubtypeDiffName = defGetQualifiedName(defel); + } + else if (pg_strcasecmp(defel->defname, "analyze") == 0) + { + if (rangeAnalyzeName != NIL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("conflicting or redundant options"))); + rangeAnalyzeName = defGetQualifiedName(defel); + } + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("type attribute \"%s\" not recognized", + defel->defname))); + } + + /* Must have a subtype */ + if (!OidIsValid(rangeSubtype)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("type attribute \"subtype\" is required"))); + /* disallow ranges of pseudotypes */ + if (get_typtype(rangeSubtype) == TYPTYPE_PSEUDO) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("range subtype cannot be %s", + format_type_be(rangeSubtype)))); + + /* Identify subopclass */ + rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype); + + /* Identify collation to use, if any */ + if (type_is_collatable(rangeSubtype)) + { + if (rangeCollationName != NIL) + rangeCollation = get_collation_oid(rangeCollationName, false); + else + rangeCollation = get_typcollation(rangeSubtype); + } + else + { + if (rangeCollationName != NIL) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("range collation specified but subtype does not support collation"))); + rangeCollation = InvalidOid; + } + + /* Identify support functions, if provided */ + if (rangeCanonicalName != NIL) + rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName, + typoid); + else + rangeCanonical = InvalidOid; + + if (rangeSubtypeDiffName != NIL) + rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName, + rangeSubtype); + else + rangeSubtypeDiff = InvalidOid; + + if (rangeAnalyzeName != NIL) + rangeAnalyze = findTypeAnalyzeFunction(rangeAnalyzeName, + typoid); + else + rangeAnalyze = InvalidOid; + + get_typlenbyvalalign(rangeSubtype, + &subtyplen, &subtypbyval, &subtypalign); + + /* alignment must be 'i' or 'd' for ranges */ + alignment = (subtypalign == 'd') ? 'd' : 'i'; + + /* Allocate OID for array type */ + rangeArrayOid = AssignTypeArrayOid(); + + /* Create the pg_type entry */ + typoid = + TypeCreate(InvalidOid, /* no predetermined type OID */ + typeName, /* type name */ + typeNamespace, /* namespace */ + InvalidOid, /* relation oid (n/a here) */ + 0, /* relation kind (ditto) */ + GetUserId(), /* owner's ID */ + -1, /* internal size (always varlena) */ + TYPTYPE_RANGE, /* type-type (range type) */ + TYPCATEGORY_RANGE, /* type-category (range type) */ + false, /* range types are never preferred */ + DEFAULT_TYPDELIM, /* array element delimiter */ + F_RANGE_IN, /* input procedure */ + F_RANGE_OUT, /* output procedure */ + F_RANGE_RECV, /* receive procedure */ + F_RANGE_SEND, /* send procedure */ + InvalidOid, /* typmodin procedure - none */ + InvalidOid, /* typmodout procedure - none */ + rangeAnalyze, /* analyze procedure */ + InvalidOid, /* element type ID - none */ + false, /* this is not an array type */ + rangeArrayOid, /* array type we are about to create */ + InvalidOid, /* base type ID (only for domains) */ + NULL, /* never a default type value */ + NULL, /* no binary form available either */ + false, /* never passed by value */ + alignment, /* alignment */ + 'x', /* TOAST strategy (always extended) */ + -1, /* typMod (Domains only) */ + 0, /* Array dimensions of typbasetype */ + false, /* Type NOT NULL */ + InvalidOid); /* type's collation (ranges never have one) */ + + /* Create the entry in pg_range */ + RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass, + rangeCanonical, rangeSubtypeDiff); + + /* + * Create the array type that goes with it. + */ + rangeArrayName = makeArrayTypeName(typeName, typeNamespace); + + TypeCreate(rangeArrayOid, /* force assignment of this type OID */ + rangeArrayName, /* type name */ + typeNamespace, /* namespace */ + InvalidOid, /* relation oid (n/a here) */ + 0, /* relation kind (ditto) */ + GetUserId(), /* owner's ID */ + -1, /* internal size (always varlena) */ + TYPTYPE_BASE, /* type-type (base type) */ + TYPCATEGORY_ARRAY, /* type-category (array) */ + false, /* array types are never preferred */ + DEFAULT_TYPDELIM, /* array element delimiter */ + F_ARRAY_IN, /* input procedure */ + F_ARRAY_OUT, /* output procedure */ + F_ARRAY_RECV, /* receive procedure */ + F_ARRAY_SEND, /* send procedure */ + InvalidOid, /* typmodin procedure - none */ + InvalidOid, /* typmodout procedure - none */ + InvalidOid, /* analyze procedure - default */ + typoid, /* element type ID */ + true, /* yes this is an array type */ + InvalidOid, /* no further array type */ + InvalidOid, /* base type ID */ + NULL, /* never a default type value */ + NULL, /* binary default isn't sent either */ + false, /* never passed by value */ + alignment, /* alignment - same as range's */ + 'x', /* ARRAY is always toastable */ + -1, /* typMod (Domains only) */ + 0, /* Array dimensions of typbasetype */ + false, /* Type NOT NULL */ + InvalidOid); /* typcollation */ + + pfree(rangeArrayName); + + /* And create the constructor functions for this range type */ + makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype); +} + +/* + * Because there may exist several range types over the same subtype, the + * range type can't be uniquely determined from the subtype. So it's + * impossible to define a polymorphic constructor; we have to generate new + * constructor functions explicitly for each range type. + * + * We actually define 4 functions, with 0 through 3 arguments. This is just + * to offer more convenience for the user. + */ +static void +makeRangeConstructors(const char *name, Oid namespace, + Oid rangeOid, Oid subtype) +{ + static const char * const prosrc[4] = {"range_constructor0", + "range_constructor1", + "range_constructor2", + "range_constructor3"}; + static const int pronargs[4] = {0, 1, 2, 3}; + + Oid constructorArgTypes[3]; + ObjectAddress myself, + referenced; + int i; + + constructorArgTypes[0] = subtype; + constructorArgTypes[1] = subtype; + constructorArgTypes[2] = TEXTOID; + + referenced.classId = TypeRelationId; + referenced.objectId = rangeOid; + referenced.objectSubId = 0; + + for (i = 0; i < lengthof(prosrc); i++) + { + oidvector *constructorArgTypesVector; + Oid procOid; + + constructorArgTypesVector = buildoidvector(constructorArgTypes, + pronargs[i]); + + procOid = ProcedureCreate(name, /* name: same as range type */ + namespace, /* namespace */ + false, /* replace */ + false, /* returns set */ + rangeOid, /* return type */ + INTERNALlanguageId, /* language */ + F_FMGR_INTERNAL_VALIDATOR, /* language validator */ + prosrc[i], /* prosrc */ + NULL, /* probin */ + false, /* isAgg */ + false, /* isWindowFunc */ + false, /* security_definer */ + false, /* isStrict */ + PROVOLATILE_IMMUTABLE, /* volatility */ + constructorArgTypesVector, /* parameterTypes */ + PointerGetDatum(NULL), /* allParameterTypes */ + PointerGetDatum(NULL), /* parameterModes */ + PointerGetDatum(NULL), /* parameterNames */ + NIL, /* parameterDefaults */ + PointerGetDatum(NULL), /* proconfig */ + 1.0, /* procost */ + 0.0); /* prorows */ + + /* + * Make the constructors internally-dependent on the range type so + * that they go away silently when the type is dropped. Note that + * pg_dump depends on this choice to avoid dumping the constructors. + */ + myself.classId = ProcedureRelationId; + myself.objectId = procOid; + myself.objectSubId = 0; + + recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); + } +} + + /* * Find suitable I/O functions for a type. * @@ -1801,78 +1819,63 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid) return procOid; } +/* + * Find suitable support functions and opclasses for a range type. + */ + /* * Find named btree opclass for subtype, or default btree opclass if - * opcname is NIL. This will be used for comparing values of subtype. + * opcname is NIL. */ static Oid findRangeSubOpclass(List *opcname, Oid subtype) { Oid opcid; + Oid opInputType; - if (opcname == NIL) + if (opcname != NIL) + { + opcid = get_opclass_oid(BTREE_AM_OID, opcname, false); + + /* + * Verify that the operator class accepts this datatype. Note we will + * accept binary compatibility. + */ + opInputType = get_opclass_input_type(opcid); + if (!IsBinaryCoercible(subtype, opInputType)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("operator class \"%s\" does not accept data type %s", + NameListToString(opcname), + format_type_be(subtype)))); + } + else { opcid = GetDefaultOpClass(subtype, BTREE_AM_OID); if (!OidIsValid(opcid)) { + /* We spell the error message identically to GetIndexOpClass */ ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("data type %s has no default operator class for access method \"btree\"", - format_type_be(subtype)), - errhint("You must specify an operator class for the data type or define a default operator class for the data type."))); + errmsg("data type %s has no default operator class for access method \"%s\"", + format_type_be(subtype), "btree"), + errhint("You must specify an operator class for the range type or define a default operator class for the subtype."))); } - return opcid; } - opcid = get_opclass_oid(BTREE_AM_OID, opcname, false); - return opcid; } -/* - * Used to find a range's 'canonical' function. - */ -static Oid -findRangeSubtypeDiffFunction(List *procname, Oid typeOid) -{ - Oid argList[2]; - Oid procOid; - - argList[0] = typeOid; - argList[1] = typeOid; - - procOid = LookupFuncName(procname, 2, argList, true); - - if (!OidIsValid(procOid)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_FUNCTION), - errmsg("function %s does not exist", - func_signature_string(procname, 2, NIL, argList)))); - - if (get_func_rettype(procOid) != FLOAT8OID) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("range subtype diff function %s must return type \"float8\"", - func_signature_string(procname, 2, NIL, argList)))); - - if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE) - ereport(ERROR, - (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("range subtype diff function %s must be immutable", - func_signature_string(procname, 2, NIL, argList)))); - - return procOid; -} - -/* - * Used to find a range's 'canonical' function. - */ static Oid findRangeCanonicalFunction(List *procname, Oid typeOid) { Oid argList[1]; Oid procOid; + /* + * Range canonical functions must take and return the range type, and must + * be immutable. + */ argList[0] = typeOid; procOid = LookupFuncName(procname, 1, argList, true); @@ -1887,7 +1890,7 @@ findRangeCanonicalFunction(List *procname, Oid typeOid) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("range canonical function %s must return range type", - NameListToString(procname)))); + func_signature_string(procname, 1, NIL, argList)))); if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE) ereport(ERROR, @@ -1898,6 +1901,42 @@ findRangeCanonicalFunction(List *procname, Oid typeOid) return procOid; } +static Oid +findRangeSubtypeDiffFunction(List *procname, Oid subtype) +{ + Oid argList[2]; + Oid procOid; + + /* + * Range subtype diff functions must take two arguments of the subtype, + * must return float8, and must be immutable. + */ + argList[0] = subtype; + argList[1] = subtype; + + procOid = LookupFuncName(procname, 2, argList, true); + + if (!OidIsValid(procOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(procname, 2, NIL, argList)))); + + if (get_func_rettype(procOid) != FLOAT8OID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("range subtype diff function %s must return type double precision", + func_signature_string(procname, 2, NIL, argList)))); + + if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("range subtype diff function %s must be immutable", + func_signature_string(procname, 2, NIL, argList)))); + + return procOid; +} + /* * AssignTypeArrayOid * diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c index 3eb177a5ce..3fc05d2650 100644 --- a/src/backend/utils/adt/rangetypes_gist.c +++ b/src/backend/utils/adt/rangetypes_gist.c @@ -21,18 +21,19 @@ /* Operator strategy numbers used in the GiST range opclass */ -#define RANGESTRAT_EQ 1 -#define RANGESTRAT_NE 2 +/* Numbers are chosen to match up operator names with existing usages */ +#define RANGESTRAT_BEFORE 1 +#define RANGESTRAT_OVERLEFT 2 #define RANGESTRAT_OVERLAPS 3 -#define RANGESTRAT_CONTAINS_ELEM 4 -#define RANGESTRAT_ELEM_CONTAINED_BY 5 -#define RANGESTRAT_CONTAINS 6 -#define RANGESTRAT_CONTAINED_BY 7 -#define RANGESTRAT_BEFORE 8 -#define RANGESTRAT_AFTER 9 -#define RANGESTRAT_OVERLEFT 10 -#define RANGESTRAT_OVERRIGHT 11 -#define RANGESTRAT_ADJACENT 12 +#define RANGESTRAT_OVERRIGHT 4 +#define RANGESTRAT_AFTER 5 +#define RANGESTRAT_ADJACENT 6 +#define RANGESTRAT_CONTAINS 7 +#define RANGESTRAT_CONTAINED_BY 8 +#define RANGESTRAT_CONTAINS_ELEM 16 +#define RANGESTRAT_ELEM_CONTAINED_BY 17 +#define RANGESTRAT_EQ 18 +#define RANGESTRAT_NE 19 #define RangeIsEmpty(r) (range_get_flags(r) & RANGE_EMPTY) @@ -460,47 +461,33 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, switch (strategy) { - case RANGESTRAT_EQ: - proc = range_contains; - break; - case RANGESTRAT_NE: - return true; - break; - case RANGESTRAT_OVERLAPS: - proc = range_overlaps; - break; - case RANGESTRAT_CONTAINS_ELEM: - case RANGESTRAT_CONTAINS: - proc = range_contains; - break; - case RANGESTRAT_ELEM_CONTAINED_BY: - case RANGESTRAT_CONTAINED_BY: - return true; - break; case RANGESTRAT_BEFORE: if (RangeIsEmpty(key)) return false; proc = range_overright; negate = true; break; - case RANGESTRAT_AFTER: - if (RangeIsEmpty(key)) - return false; - proc = range_overleft; - negate = true; - break; case RANGESTRAT_OVERLEFT: if (RangeIsEmpty(key)) return false; proc = range_after; negate = true; break; + case RANGESTRAT_OVERLAPS: + proc = range_overlaps; + break; case RANGESTRAT_OVERRIGHT: if (RangeIsEmpty(key)) return false; proc = range_before; negate = true; break; + case RANGESTRAT_AFTER: + if (RangeIsEmpty(key)) + return false; + proc = range_overleft; + negate = true; + break; case RANGESTRAT_ADJACENT: if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; @@ -510,6 +497,20 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, return true; proc = range_overlaps; break; + case RANGESTRAT_CONTAINS: + case RANGESTRAT_CONTAINS_ELEM: + proc = range_contains; + break; + case RANGESTRAT_CONTAINED_BY: + case RANGESTRAT_ELEM_CONTAINED_BY: + return true; + break; + case RANGESTRAT_EQ: + proc = range_contains; + break; + case RANGESTRAT_NE: + return true; + break; default: elog(ERROR, "unrecognized range strategy: %d", strategy); proc = NULL; /* keep compiler quiet */ @@ -536,48 +537,48 @@ range_gist_consistent_leaf(FmgrInfo *flinfo, StrategyNumber strategy, switch (strategy) { - case RANGESTRAT_EQ: - proc = range_eq; - break; - case RANGESTRAT_NE: - proc = range_ne; - break; - case RANGESTRAT_OVERLAPS: - proc = range_overlaps; - break; - case RANGESTRAT_CONTAINS_ELEM: - case RANGESTRAT_CONTAINS: - proc = range_contains; - break; - case RANGESTRAT_ELEM_CONTAINED_BY: - case RANGESTRAT_CONTAINED_BY: - proc = range_contained_by; - break; case RANGESTRAT_BEFORE: if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; proc = range_before; break; - case RANGESTRAT_AFTER: - if (RangeIsEmpty(key) || RangeIsEmpty(query)) - return false; - proc = range_after; - break; case RANGESTRAT_OVERLEFT: if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; proc = range_overleft; break; + case RANGESTRAT_OVERLAPS: + proc = range_overlaps; + break; case RANGESTRAT_OVERRIGHT: if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; proc = range_overright; break; + case RANGESTRAT_AFTER: + if (RangeIsEmpty(key) || RangeIsEmpty(query)) + return false; + proc = range_after; + break; case RANGESTRAT_ADJACENT: if (RangeIsEmpty(key) || RangeIsEmpty(query)) return false; proc = range_adjacent; break; + case RANGESTRAT_CONTAINS: + case RANGESTRAT_CONTAINS_ELEM: + proc = range_contains; + break; + case RANGESTRAT_CONTAINED_BY: + case RANGESTRAT_ELEM_CONTAINED_BY: + proc = range_contained_by; + break; + case RANGESTRAT_EQ: + proc = range_eq; + break; + case RANGESTRAT_NE: + proc = range_ne; + break; default: elog(ERROR, "unrecognized range strategy: %d", strategy); proc = NULL; /* keep compiler quiet */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 6ed527b23e..c397151370 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201111171 +#define CATALOG_VERSION_NO 201111211 #endif diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index 108ed89c20..a240063a3f 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -726,17 +726,17 @@ DATA(insert ( 3903 3831 3831 1 s 3882 405 0 )); /* * GiST range_ops */ -DATA(insert ( 3919 3831 3831 1 s 3882 783 0 )); -DATA(insert ( 3919 3831 3831 2 s 3883 783 0 )); +DATA(insert ( 3919 3831 3831 1 s 3893 783 0 )); +DATA(insert ( 3919 3831 3831 2 s 3895 783 0 )); DATA(insert ( 3919 3831 3831 3 s 3888 783 0 )); -DATA(insert ( 3919 3831 2283 4 s 3889 783 0 )); -DATA(insert ( 3919 2283 3831 5 s 3891 783 0 )); -DATA(insert ( 3919 3831 3831 6 s 3890 783 0 )); -DATA(insert ( 3919 3831 3831 7 s 3892 783 0 )); -DATA(insert ( 3919 3831 3831 8 s 3893 783 0 )); -DATA(insert ( 3919 3831 3831 9 s 3894 783 0 )); -DATA(insert ( 3919 3831 3831 10 s 3895 783 0 )); -DATA(insert ( 3919 3831 3831 11 s 3896 783 0 )); -DATA(insert ( 3919 3831 3831 12 s 3897 783 0 )); +DATA(insert ( 3919 3831 3831 4 s 3896 783 0 )); +DATA(insert ( 3919 3831 3831 5 s 3894 783 0 )); +DATA(insert ( 3919 3831 3831 6 s 3897 783 0 )); +DATA(insert ( 3919 3831 3831 7 s 3890 783 0 )); +DATA(insert ( 3919 3831 3831 8 s 3892 783 0 )); +DATA(insert ( 3919 3831 2283 16 s 3889 783 0 )); +DATA(insert ( 3919 2283 3831 17 s 3891 783 0 )); +DATA(insert ( 3919 3831 3831 18 s 3882 783 0 )); +DATA(insert ( 3919 3831 3831 19 s 3883 783 0 )); #endif /* PG_AMOP_H */ diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index 2d1a2800a4..eac5cb94e6 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -1674,15 +1674,15 @@ DATA(insert OID = 3886 ( ">=" PGNSP PGUID b f f 3831 3831 16 3885 3884 range DESCR("greater than or equal"); DATA(insert OID = 3887 ( ">" PGNSP PGUID b f f 3831 3831 16 3884 3885 range_gt scalargtsel scalargtjoinsel )); DESCR("greater than"); -DATA(insert OID = 3888 ( "&&" PGNSP PGUID b f f 3831 3831 16 3888 0 range_overlaps - - )); +DATA(insert OID = 3888 ( "&&" PGNSP PGUID b f f 3831 3831 16 3888 0 range_overlaps areasel areajoinsel )); DESCR("overlaps"); -DATA(insert OID = 3889 ( "@>" PGNSP PGUID b f f 3831 2283 16 3891 0 range_contains_elem - - )); +DATA(insert OID = 3889 ( "@>" PGNSP PGUID b f f 3831 2283 16 3891 0 range_contains_elem contsel contjoinsel )); DESCR("contains"); -DATA(insert OID = 3890 ( "@>" PGNSP PGUID b f f 3831 3831 16 3892 0 range_contains - - )); +DATA(insert OID = 3890 ( "@>" PGNSP PGUID b f f 3831 3831 16 3892 0 range_contains contsel contjoinsel )); DESCR("contains"); -DATA(insert OID = 3891 ( "<@" PGNSP PGUID b f f 2283 3831 16 3889 0 elem_contained_by_range - - )); +DATA(insert OID = 3891 ( "<@" PGNSP PGUID b f f 2283 3831 16 3889 0 elem_contained_by_range contsel contjoinsel )); DESCR("is contained by"); -DATA(insert OID = 3892 ( "<@" PGNSP PGUID b f f 3831 3831 16 3890 0 range_contained_by - - )); +DATA(insert OID = 3892 ( "<@" PGNSP PGUID b f f 3831 3831 16 3890 0 range_contained_by contsel contjoinsel )); DESCR("is contained by"); DATA(insert OID = 3893 ( "<<" PGNSP PGUID b f f 3831 3831 16 3894 0 range_before scalarltsel scalarltjoinsel )); DESCR("is left of"); @@ -1692,7 +1692,7 @@ DATA(insert OID = 3895 ( "&<" PGNSP PGUID b f f 3831 3831 16 0 0 range_overl DESCR("overlaps or is left of"); DATA(insert OID = 3896 ( "&>" PGNSP PGUID b f f 3831 3831 16 0 0 range_overright scalargtsel scalargtjoinsel )); DESCR("overlaps or is right of"); -DATA(insert OID = 3897 ( "-|-" PGNSP PGUID b f f 3831 3831 16 3897 0 range_adjacent - - )); +DATA(insert OID = 3897 ( "-|-" PGNSP PGUID b f f 3831 3831 16 3897 0 range_adjacent contsel contjoinsel )); DESCR("is adjacent to"); DATA(insert OID = 3898 ( "+" PGNSP PGUID b f f 3831 3831 3831 3898 0 range_union - - )); DESCR("range union"); diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 19b559ffa1..db74fcb9e6 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -140,16 +140,16 @@ WHERE p1.oid < p2.oid AND -- need to be modified whenever new pairs of types are made binary-equivalent, -- or when new polymorphic built-in functions are added! -- Note: ignore aggregate functions here, since they all point to the same --- dummy built-in function. +-- dummy built-in function. Likewise, ignore range constructor functions. SELECT DISTINCT p1.prorettype, p2.prorettype FROM pg_proc AS p1, pg_proc AS p2 WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND NOT p1.proisagg AND NOT p2.proisagg AND - (p1.prorettype < p2.prorettype) AND - -- range constructor functions are shared by all range types. - NOT p1.prosrc LIKE 'range_constructor%' + p1.prosrc NOT LIKE E'range\\_constructor_' AND + p2.prosrc NOT LIKE E'range\\_constructor_' AND + (p1.prorettype < p2.prorettype) ORDER BY 1, 2; prorettype | prorettype ------------+------------ @@ -163,9 +163,9 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND NOT p1.proisagg AND NOT p2.proisagg AND - (p1.proargtypes[0] < p2.proargtypes[0]) AND - -- range constructor functions are shared by all range types. - NOT p1.prosrc LIKE 'range_constructor%' + p1.prosrc NOT LIKE E'range\\_constructor_' AND + p2.prosrc NOT LIKE E'range\\_constructor_' AND + (p1.proargtypes[0] < p2.proargtypes[0]) ORDER BY 1, 2; proargtypes | proargtypes -------------+------------- @@ -182,9 +182,9 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND NOT p1.proisagg AND NOT p2.proisagg AND - (p1.proargtypes[1] < p2.proargtypes[1]) AND - -- range constructor functions are shared by all range types. - NOT p1.prosrc LIKE 'range_constructor%' + p1.prosrc NOT LIKE E'range\\_constructor_' AND + p2.prosrc NOT LIKE E'range\\_constructor_' AND + (p1.proargtypes[1] < p2.proargtypes[1]) ORDER BY 1, 2; proargtypes | proargtypes -------------+------------- @@ -1021,34 +1021,28 @@ ORDER BY 1, 2, 3; 403 | 5 | ~>~ 405 | 1 | = 783 | 1 | << - 783 | 1 | = 783 | 1 | @@ 783 | 2 | &< - 783 | 2 | <> 783 | 3 | && 783 | 4 | &> - 783 | 4 | @> - 783 | 5 | <@ 783 | 5 | >> - 783 | 6 | @> + 783 | 6 | -|- 783 | 6 | ~= - 783 | 7 | <@ 783 | 7 | @> - 783 | 8 | << 783 | 8 | <@ 783 | 9 | &<| - 783 | 9 | >> - 783 | 10 | &< 783 | 10 | <<| 783 | 10 | <^ - 783 | 11 | &> 783 | 11 | >^ 783 | 11 | |>> - 783 | 12 | -|- 783 | 12 | |&> 783 | 13 | ~ 783 | 14 | @ 783 | 15 | <-> + 783 | 16 | @> + 783 | 17 | <@ + 783 | 18 | = + 783 | 19 | <> 783 | 27 | @> 783 | 28 | <@ 783 | 47 | @> @@ -1061,7 +1055,7 @@ ORDER BY 1, 2, 3; 2742 | 2 | @@@ 2742 | 3 | <@ 2742 | 4 | = -(51 rows) +(45 rows) -- Check that all opclass search operators have selectivity estimators. -- This is not absolutely required, but it seems a reasonable thing @@ -1070,15 +1064,9 @@ SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname FROM pg_amop AS p1, pg_operator AS p2 WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND (p2.oprrest = 0 OR p2.oprjoin = 0); - amopfamily | amopopr | oid | oprname -------------+---------+------+--------- - 3919 | 3888 | 3888 | && - 3919 | 3889 | 3889 | @> - 3919 | 3891 | 3891 | <@ - 3919 | 3890 | 3890 | @> - 3919 | 3892 | 3892 | <@ - 3919 | 3897 | 3897 | -|- -(6 rows) + amopfamily | amopopr | oid | oprname +------------+---------+-----+--------- +(0 rows) -- Check that each opclass in an opfamily has associated operators, that is -- ones whose oprleft matches opcintype (possibly by coercion). diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out index fc9d401944..238bf5f0ae 100644 --- a/src/test/regress/expected/plpgsql.out +++ b/src/test/regress/expected/plpgsql.out @@ -4571,17 +4571,3 @@ ERROR: value for domain orderedarray violates check constraint "sorted" CONTEXT: PL/pgSQL function "testoa" line 5 at assignment drop function arrayassign1(); drop function testoa(x1 int, x2 int, x3 int); --- Test resolve_polymorphic_argtypes() codepath. It is only taken when --- a function is invoked from a different backend from where it's defined, --- so we create the a function with polymorphic argument, reconnect, and --- and then call it. -create function rangetypes_plpgsql(out a anyelement, b anyrange, c anyarray) - language plpgsql as - $$ begin a := upper(b) + c[1]; return; end; $$; -\c - -select rangetypes_plpgsql(int4range(1,10),ARRAY[2,20]); - rangetypes_plpgsql --------------------- - 12 -(1 row) - diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out index dec748406f..130446d006 100644 --- a/src/test/regress/expected/rangetypes.out +++ b/src/test/regress/expected/rangetypes.out @@ -936,6 +936,20 @@ select range_add_bounds(numrange(1.0001, 123.123)); 124.1231 (1 row) +create function rangetypes_sql(q anyrange, b anyarray, out c anyelement) + as $$ select upper($1) + $2[1] $$ + language sql; +select rangetypes_sql(int4range(1,10), ARRAY[2,20]); + rangetypes_sql +---------------- + 12 +(1 row) + +select rangetypes_sql(numrange(1,10), ARRAY[2,20]); -- match failure +ERROR: function rangetypes_sql(numrange, integer[]) does not exist +LINE 1: select rangetypes_sql(numrange(1,10), ARRAY[2,20]); + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. -- -- Arrays of ranges -- diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 7f936c8154..b0d143087e 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -125,7 +125,7 @@ WHERE p1.oid < p2.oid AND -- need to be modified whenever new pairs of types are made binary-equivalent, -- or when new polymorphic built-in functions are added! -- Note: ignore aggregate functions here, since they all point to the same --- dummy built-in function. +-- dummy built-in function. Likewise, ignore range constructor functions. SELECT DISTINCT p1.prorettype, p2.prorettype FROM pg_proc AS p1, pg_proc AS p2 @@ -133,9 +133,9 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND NOT p1.proisagg AND NOT p2.proisagg AND - (p1.prorettype < p2.prorettype) AND - -- range constructor functions are shared by all range types. - NOT p1.prosrc LIKE 'range_constructor%' + p1.prosrc NOT LIKE E'range\\_constructor_' AND + p2.prosrc NOT LIKE E'range\\_constructor_' AND + (p1.prorettype < p2.prorettype) ORDER BY 1, 2; SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0] @@ -144,9 +144,9 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND NOT p1.proisagg AND NOT p2.proisagg AND - (p1.proargtypes[0] < p2.proargtypes[0]) AND - -- range constructor functions are shared by all range types. - NOT p1.prosrc LIKE 'range_constructor%' + p1.prosrc NOT LIKE E'range\\_constructor_' AND + p2.prosrc NOT LIKE E'range\\_constructor_' AND + (p1.proargtypes[0] < p2.proargtypes[0]) ORDER BY 1, 2; SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1] @@ -155,9 +155,9 @@ WHERE p1.oid != p2.oid AND p1.prosrc = p2.prosrc AND p1.prolang = 12 AND p2.prolang = 12 AND NOT p1.proisagg AND NOT p2.proisagg AND - (p1.proargtypes[1] < p2.proargtypes[1]) AND - -- range constructor functions are shared by all range types. - NOT p1.prosrc LIKE 'range_constructor%' + p1.prosrc NOT LIKE E'range\\_constructor_' AND + p2.prosrc NOT LIKE E'range\\_constructor_' AND + (p1.proargtypes[1] < p2.proargtypes[1]) ORDER BY 1, 2; SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2] diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql index 2906943f06..b47c2de312 100644 --- a/src/test/regress/sql/plpgsql.sql +++ b/src/test/regress/sql/plpgsql.sql @@ -3600,13 +3600,3 @@ select testoa(1,2,1); -- fail at update drop function arrayassign1(); drop function testoa(x1 int, x2 int, x3 int); - --- Test resolve_polymorphic_argtypes() codepath. It is only taken when --- a function is invoked from a different backend from where it's defined, --- so we create the a function with polymorphic argument, reconnect, and --- and then call it. -create function rangetypes_plpgsql(out a anyelement, b anyrange, c anyarray) - language plpgsql as - $$ begin a := upper(b) + c[1]; return; end; $$; -\c - -select rangetypes_plpgsql(int4range(1,10),ARRAY[2,20]); diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql index bdd40cf5a9..b34a0d7c34 100644 --- a/src/test/regress/sql/rangetypes.sql +++ b/src/test/regress/sql/rangetypes.sql @@ -327,6 +327,13 @@ create function range_add_bounds(anyrange) select range_add_bounds(numrange(1.0001, 123.123)); +create function rangetypes_sql(q anyrange, b anyarray, out c anyelement) + as $$ select upper($1) + $2[1] $$ + language sql; + +select rangetypes_sql(int4range(1,10), ARRAY[2,20]); +select rangetypes_sql(numrange(1,10), ARRAY[2,20]); -- match failure + -- -- Arrays of ranges --