aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/commands/typecmds.c395
-rw-r--r--src/backend/utils/adt/rangetypes_gist.c113
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_amop.h22
-rw-r--r--src/include/catalog/pg_operator.h12
-rw-r--r--src/test/regress/expected/opr_sanity.out50
-rw-r--r--src/test/regress/expected/plpgsql.out14
-rw-r--r--src/test/regress/expected/rangetypes.out14
-rw-r--r--src/test/regress/sql/opr_sanity.sql20
-rw-r--r--src/test/regress/sql/plpgsql.sql10
-rw-r--r--src/test/regress/sql/rangetypes.sql7
11 files changed, 342 insertions, 317 deletions
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 8ffbc52fdef..54105f2c408 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);
/*
@@ -1155,6 +1154,61 @@ DefineEnum(CreateEnumStmt *stmt)
}
/*
+ * AlterEnum
+ * Adds a new label to an existing enum.
+ */
+void
+AlterEnum(AlterEnumStmt *stmt)
+{
+ Oid enum_type_oid;
+ TypeName *typename;
+ HeapTuple tup;
+
+ /* Make a TypeName so we can use standard type lookup machinery */
+ typename = makeTypeNameFromNameList(stmt->typeName);
+ enum_type_oid = typenameTypeId(NULL, typename);
+
+ tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
+
+ /* Check it's an enum and check user has permission to ALTER the enum */
+ checkEnumOwner(tup);
+
+ /* Add the new label */
+ AddEnumLabel(enum_type_oid, stmt->newVal,
+ stmt->newValNeighbor, stmt->newValIsAfter);
+
+ ReleaseSysCache(tup);
+}
+
+
+/*
+ * checkEnumOwner
+ *
+ * Check that the type is actually an enum and that the current user
+ * has permission to do ALTER TYPE on it. Throw an error if not.
+ */
+static void
+checkEnumOwner(HeapTuple tup)
+{
+ Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
+
+ /* Check that this is actually an enum */
+ if (typTup->typtype != TYPTYPE_ENUM)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("%s is not an enum",
+ format_type_be(HeapTupleGetOid(tup)))));
+
+ /* Permission check: must own type */
+ if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
+ format_type_be(HeapTupleGetOid(tup)));
+}
+
+
+/*
* DefineRange
* Registers a new range type.
*/
@@ -1162,20 +1216,21 @@ void
DefineRange(CreateRangeStmt *stmt)
{
char *typeName;
- char *rangeArrayName;
Oid typeNamespace;
Oid typoid;
+ char *rangeArrayName;
Oid rangeArrayOid;
- List *parameters = stmt->params;
+ Oid rangeSubtype = InvalidOid;
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;
+ 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;
@@ -1194,8 +1249,7 @@ DefineRange(CreateRangeStmt *stmt)
get_namespace_name(typeNamespace));
/*
- * Look to see if type already exists (presumably as a shell; if not,
- * TypeCreate will complain).
+ * Look to see if type already exists.
*/
typoid = GetSysCacheOid2(TYPENAMENSP,
CStringGetDatum(typeName),
@@ -1209,37 +1263,27 @@ DefineRange(CreateRangeStmt *stmt)
{
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 I/O function definitions.
+ * use in the range 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)));
}
+ /* Extract the parameters from the parameter list */
foreach(lc, stmt->params)
{
- DefElem *defel = lfirst(lc);
+ DefElem *defel = (DefElem *) lfirst(lc);
if (pg_strcasecmp(defel->defname, "subtype") == 0)
{
@@ -1247,16 +1291,16 @@ DefineRange(CreateRangeStmt *stmt)
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, "canonical") == 0)
+ else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
{
- if (OidIsValid(rangeCanonical))
+ if (rangeSubOpclassName != NIL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
- rangeCanonical = findRangeCanonicalFunction(
- defGetQualifiedName(defel), typoid);
+ rangeSubOpclassName = defGetQualifiedName(defel);
}
else if (pg_strcasecmp(defel->defname, "collation") == 0)
{
@@ -1266,63 +1310,87 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options")));
rangeCollationName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "analyze") == 0)
+ else if (pg_strcasecmp(defel->defname, "canonical") == 0)
{
- if (OidIsValid(rangeAnalyze))
+ if (rangeCanonicalName != NIL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
- rangeAnalyze = findTypeAnalyzeFunction(defGetQualifiedName(defel),
- typoid);
+ rangeCanonicalName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "subtype_opclass") == 0)
+ else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
{
- if (rangeSubOpclassName != NIL)
+ if (rangeSubtypeDiffName != NIL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
- rangeSubOpclassName = defGetQualifiedName(defel);
+ rangeSubtypeDiffName = defGetQualifiedName(defel);
}
- else if (pg_strcasecmp(defel->defname, "subtype_diff") == 0)
+ else if (pg_strcasecmp(defel->defname, "analyze") == 0)
{
- if (rangeSubtypeDiffName != NIL)
+ if (rangeAnalyzeName != NIL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
- rangeSubtypeDiffName = defGetQualifiedName(defel);
+ rangeAnalyzeName = defGetQualifiedName(defel);
}
else
- {
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("type attribute \"%s\" not recognized",
defel->defname)));
- continue;
- }
}
+ /* 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_typcollation(rangeSubtype);
- else
+ 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;
}
- 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);
+ /* 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);
@@ -1358,16 +1426,16 @@ DefineRange(CreateRangeStmt *stmt)
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 */
+ 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); /* typcollation */
+ InvalidOid); /* type's collation (ranges never have one) */
- /* create the entry in pg_range */
+ /* Create the entry in pg_range */
RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
rangeCanonical, rangeSubtypeDiff);
@@ -1411,61 +1479,64 @@ DefineRange(CreateRangeStmt *stmt)
pfree(rangeArrayName);
/* And create the constructor functions for this range type */
- makeRangeConstructor(typeName, typeNamespace, typoid, rangeSubtype);
+ makeRangeConstructors(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.
+ * 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.
+ * 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)
+makeRangeConstructors(const char *name, Oid namespace,
+ Oid rangeOid, Oid subtype)
{
- ObjectAddress referenced;
+ 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;
- referenced.classId = TypeRelationId;
- referenced.objectId = rangeOid;
- referenced.objectSubId = 0;
-
constructorArgTypes[0] = subtype;
constructorArgTypes[1] = subtype;
constructorArgTypes[2] = TEXTOID;
- for (i = 0; i < 4; i++)
+ referenced.classId = TypeRelationId;
+ referenced.objectId = rangeOid;
+ referenced.objectSubId = 0;
+
+ for (i = 0; i < lengthof(prosrc); i++)
{
oidvector *constructorArgTypesVector;
- ObjectAddress myself;
Oid procOid;
- char *prosrc[4] = {"range_constructor0",
- "range_constructor1",
- "range_constructor2",
- "range_constructor3"};
- constructorArgTypesVector = buildoidvector(constructorArgTypes, i);
+ constructorArgTypesVector = buildoidvector(constructorArgTypes,
+ pronargs[i]);
- procOid = ProcedureCreate(
- name, /* name */
+ procOid = ProcedureCreate(name, /* name: same as range type */
namespace, /* namespace */
false, /* replace */
- false, /* return set */
+ false, /* returns 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 */
+ NULL, /* probin */
+ false, /* isAgg */
+ false, /* isWindowFunc */
+ false, /* security_definer */
+ false, /* isStrict */
PROVOLATILE_IMMUTABLE, /* volatility */
- constructorArgTypesVector, /* param types */
+ constructorArgTypesVector, /* parameterTypes */
PointerGetDatum(NULL), /* allParameterTypes */
PointerGetDatum(NULL), /* parameterModes */
PointerGetDatum(NULL), /* parameterNames */
@@ -1482,64 +1553,11 @@ makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype)
myself.classId = ProcedureRelationId;
myself.objectId = procOid;
myself.objectSubId = 0;
+
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
}
}
-/*
- * AlterEnum
- * Adds a new label to an existing enum.
- */
-void
-AlterEnum(AlterEnumStmt *stmt)
-{
- Oid enum_type_oid;
- TypeName *typename;
- HeapTuple tup;
-
- /* Make a TypeName so we can use standard type lookup machinery */
- typename = makeTypeNameFromNameList(stmt->typeName);
- enum_type_oid = typenameTypeId(NULL, typename);
-
- tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid));
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "cache lookup failed for type %u", enum_type_oid);
-
- /* Check it's an enum and check user has permission to ALTER the enum */
- checkEnumOwner(tup);
-
- /* Add the new label */
- AddEnumLabel(enum_type_oid, stmt->newVal,
- stmt->newValNeighbor, stmt->newValIsAfter);
-
- ReleaseSysCache(tup);
-}
-
-
-/*
- * checkEnumOwner
- *
- * Check that the type is actually an enum and that the current user
- * has permission to do ALTER TYPE on it. Throw an error if not.
- */
-static void
-checkEnumOwner(HeapTuple tup)
-{
- Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
-
- /* Check that this is actually an enum */
- if (typTup->typtype != TYPTYPE_ENUM)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("%s is not an enum",
- format_type_be(HeapTupleGetOid(tup)))));
-
- /* Permission check: must own type */
- if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
- format_type_be(HeapTupleGetOid(tup)));
-}
-
/*
* Find suitable I/O functions for a type.
@@ -1802,98 +1820,119 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid)
}
/*
+ * 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)
+ {
+ opcid = get_opclass_oid(BTREE_AM_OID, opcname, false);
- if (opcname == NIL)
+ /*
+ * 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)
+findRangeCanonicalFunction(List *procname, Oid typeOid)
{
- Oid argList[2];
+ Oid argList[1];
Oid procOid;
+ /*
+ * Range canonical functions must take and return the range type, and must
+ * be immutable.
+ */
argList[0] = typeOid;
- argList[1] = typeOid;
- procOid = LookupFuncName(procname, 2, argList, true);
+ procOid = LookupFuncName(procname, 1, argList, true);
if (!OidIsValid(procOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function %s does not exist",
- func_signature_string(procname, 2, NIL, argList))));
+ func_signature_string(procname, 1, NIL, argList))));
- if (get_func_rettype(procOid) != FLOAT8OID)
+ if (get_func_rettype(procOid) != typeOid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("range subtype diff function %s must return type \"float8\"",
- func_signature_string(procname, 2, NIL, argList))));
+ errmsg("range canonical function %s must return range type",
+ func_signature_string(procname, 1, 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))));
+ errmsg("range canonical function %s must be immutable",
+ func_signature_string(procname, 1, NIL, argList))));
return procOid;
}
-/*
- * Used to find a range's 'canonical' function.
- */
static Oid
-findRangeCanonicalFunction(List *procname, Oid typeOid)
+findRangeSubtypeDiffFunction(List *procname, Oid subtype)
{
- Oid argList[1];
+ Oid argList[2];
Oid procOid;
- argList[0] = typeOid;
+ /*
+ * 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, 1, argList, true);
+ 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, 1, NIL, argList))));
+ func_signature_string(procname, 2, NIL, argList))));
- if (get_func_rettype(procOid) != typeOid)
+ if (get_func_rettype(procOid) != FLOAT8OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("range canonical function %s must return range type",
- NameListToString(procname))));
+ 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 canonical function %s must be immutable",
- func_signature_string(procname, 1, NIL, argList))));
+ errmsg("range subtype diff function %s must be immutable",
+ func_signature_string(procname, 2, NIL, argList))));
return procOid;
}
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 3eb177a5ced..3fc05d2650b 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 6ed527b23e6..c397151370c 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 108ed89c20a..a240063a3fd 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 2d1a2800a48..eac5cb94e6f 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 19b559ffa17..db74fcb9e69 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 fc9d4019444..238bf5f0aec 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 dec748406f9..130446d0069 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 7f936c81547..b0d143087e8 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 2906943f06f..b47c2de312a 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 bdd40cf5a9d..b34a0d7c347 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
--