Commit a4ffcc8e authored by Tom Lane's avatar Tom Lane

More code review for rangetypes patch.

Fix up some infelicitous coding in DefineRange, and add some missing error
checks.  Rearrange operator strategy number assignments for GiST anyrange
opclass so that they don't make such a mess of opr_sanity's table of
operator names associated with different strategy numbers.  Assign
hopefully-temporary selectivity estimators to range operators that didn't
have one --- poor as the estimates are, they're still a lot better than the
default 0.5 estimate, and they'll shut up the opr_sanity test that wants to
see selectivity estimators on all built-in operators.
parent 9b97b7f8
...@@ -67,7 +67,6 @@ ...@@ -67,7 +67,6 @@
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/rangetypes.h"
#include "utils/rel.h" #include "utils/rel.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/tqual.h" #include "utils/tqual.h"
...@@ -85,6 +84,8 @@ typedef struct ...@@ -85,6 +84,8 @@ typedef struct
/* Potentially set by contrib/pg_upgrade_support functions */ /* Potentially set by contrib/pg_upgrade_support functions */
Oid binary_upgrade_next_array_pg_type_oid = InvalidOid; 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 findTypeInputFunction(List *procname, Oid typeOid);
static Oid findTypeOutputFunction(List *procname, Oid typeOid); static Oid findTypeOutputFunction(List *procname, Oid typeOid);
static Oid findTypeReceiveFunction(List *procname, Oid typeOid); static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
...@@ -92,9 +93,9 @@ static Oid findTypeSendFunction(List *procname, Oid typeOid); ...@@ -92,9 +93,9 @@ static Oid findTypeSendFunction(List *procname, Oid typeOid);
static Oid findTypeTypmodinFunction(List *procname); static Oid findTypeTypmodinFunction(List *procname);
static Oid findTypeTypmodoutFunction(List *procname); static Oid findTypeTypmodoutFunction(List *procname);
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid); static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
static Oid findRangeSubOpclass(List *opcname, Oid subtype);
static Oid findRangeCanonicalFunction(List *procname, Oid typeOid); static Oid findRangeCanonicalFunction(List *procname, Oid typeOid);
static Oid findRangeSubOpclass(List *procname, Oid typeOid); static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
static Oid findRangeSubtypeDiffFunction(List *procname, Oid typeOid);
static void validateDomainConstraint(Oid domainoid, char *ccbin); static void validateDomainConstraint(Oid domainoid, char *ccbin);
static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode); static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
static void checkDomainOwner(HeapTuple tup); static void checkDomainOwner(HeapTuple tup);
...@@ -103,8 +104,6 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace, ...@@ -103,8 +104,6 @@ static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
Oid baseTypeOid, Oid baseTypeOid,
int typMod, Constraint *constr, int typMod, Constraint *constr,
char *domainName); char *domainName);
static void makeRangeConstructor(char *name, Oid namespace, Oid rettype,
Oid subtype);
/* /*
...@@ -1154,6 +1153,61 @@ DefineEnum(CreateEnumStmt *stmt) ...@@ -1154,6 +1153,61 @@ DefineEnum(CreateEnumStmt *stmt)
pfree(enumArrayName); pfree(enumArrayName);
} }
/*
* 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 * DefineRange
* Registers a new range type. * Registers a new range type.
...@@ -1162,20 +1216,21 @@ void ...@@ -1162,20 +1216,21 @@ void
DefineRange(CreateRangeStmt *stmt) DefineRange(CreateRangeStmt *stmt)
{ {
char *typeName; char *typeName;
char *rangeArrayName;
Oid typeNamespace; Oid typeNamespace;
Oid typoid; Oid typoid;
char *rangeArrayName;
Oid rangeArrayOid; Oid rangeArrayOid;
List *parameters = stmt->params; Oid rangeSubtype = InvalidOid;
List *rangeSubOpclassName = NIL; List *rangeSubOpclassName = NIL;
List *rangeSubtypeDiffName = NIL;
List *rangeCollationName = NIL; List *rangeCollationName = NIL;
Oid rangeCollation = InvalidOid; List *rangeCanonicalName = NIL;
regproc rangeAnalyze = InvalidOid; List *rangeSubtypeDiffName = NIL;
Oid rangeSubtype = InvalidOid; List *rangeAnalyzeName = NIL;
regproc rangeSubOpclass = InvalidOid; Oid rangeSubOpclass;
regproc rangeCanonical = InvalidOid; Oid rangeCollation;
regproc rangeSubtypeDiff = InvalidOid; regproc rangeCanonical;
regproc rangeSubtypeDiff;
regproc rangeAnalyze;
int16 subtyplen; int16 subtyplen;
bool subtypbyval; bool subtypbyval;
char subtypalign; char subtypalign;
...@@ -1194,8 +1249,7 @@ DefineRange(CreateRangeStmt *stmt) ...@@ -1194,8 +1249,7 @@ DefineRange(CreateRangeStmt *stmt)
get_namespace_name(typeNamespace)); get_namespace_name(typeNamespace));
/* /*
* Look to see if type already exists (presumably as a shell; if not, * Look to see if type already exists.
* TypeCreate will complain).
*/ */
typoid = GetSysCacheOid2(TYPENAMENSP, typoid = GetSysCacheOid2(TYPENAMENSP,
CStringGetDatum(typeName), CStringGetDatum(typeName),
...@@ -1209,37 +1263,27 @@ DefineRange(CreateRangeStmt *stmt) ...@@ -1209,37 +1263,27 @@ DefineRange(CreateRangeStmt *stmt)
{ {
if (moveArrayTypeName(typoid, typeName, typeNamespace)) if (moveArrayTypeName(typoid, typeName, typeNamespace))
typoid = InvalidOid; 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 * 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)) if (!OidIsValid(typoid))
{ {
typoid = TypeShellMake(typeName, typeNamespace, GetUserId()); typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
/* Make new shell type visible for modification below */ /* Make new shell type visible for modification below */
CommandCounterIncrement(); 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) foreach(lc, stmt->params)
{ {
DefElem *defel = lfirst(lc); DefElem *defel = (DefElem *) lfirst(lc);
if (pg_strcasecmp(defel->defname, "subtype") == 0) if (pg_strcasecmp(defel->defname, "subtype") == 0)
{ {
...@@ -1247,16 +1291,16 @@ DefineRange(CreateRangeStmt *stmt) ...@@ -1247,16 +1291,16 @@ DefineRange(CreateRangeStmt *stmt)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
/* we can look up the subtype name immediately */
rangeSubtype = typenameTypeId(NULL, defGetTypeName(defel)); 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, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
rangeCanonical = findRangeCanonicalFunction( rangeSubOpclassName = defGetQualifiedName(defel);
defGetQualifiedName(defel), typoid);
} }
else if (pg_strcasecmp(defel->defname, "collation") == 0) else if (pg_strcasecmp(defel->defname, "collation") == 0)
{ {
...@@ -1266,63 +1310,87 @@ DefineRange(CreateRangeStmt *stmt) ...@@ -1266,63 +1310,87 @@ DefineRange(CreateRangeStmt *stmt)
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
rangeCollationName = defGetQualifiedName(defel); 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, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
rangeAnalyze = findTypeAnalyzeFunction(defGetQualifiedName(defel), rangeCanonicalName = defGetQualifiedName(defel);
typoid);
} }
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, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"))); 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, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
rangeSubtypeDiffName = defGetQualifiedName(defel); rangeAnalyzeName = defGetQualifiedName(defel);
} }
else else
{
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("type attribute \"%s\" not recognized", errmsg("type attribute \"%s\" not recognized",
defel->defname))); defel->defname)));
continue;
}
} }
/* Must have a subtype */
if (!OidIsValid(rangeSubtype)) if (!OidIsValid(rangeSubtype))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("type attribute \"subtype\" is required"))); 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 (type_is_collatable(rangeSubtype))
{ {
if (rangeCollationName == NIL) if (rangeCollationName != NIL)
rangeCollation = get_typcollation(rangeSubtype);
else
rangeCollation = get_collation_oid(rangeCollationName, false); rangeCollation = get_collation_oid(rangeCollationName, false);
else
rangeCollation = get_typcollation(rangeSubtype);
} }
else if (rangeCollationName != NIL) else
{
if (rangeCollationName != NIL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE), (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("range collation specified but subtype does not support collation"))); errmsg("range collation specified but subtype does not support collation")));
rangeCollation = InvalidOid;
}
rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype); /* Identify support functions, if provided */
if (rangeCanonicalName != NIL)
rangeCanonical = findRangeCanonicalFunction(rangeCanonicalName,
typoid);
else
rangeCanonical = InvalidOid;
if (rangeSubtypeDiffName != NIL) if (rangeSubtypeDiffName != NIL)
rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName, rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
rangeSubtype); rangeSubtype);
else
rangeSubtypeDiff = InvalidOid;
if (rangeAnalyzeName != NIL)
rangeAnalyze = findTypeAnalyzeFunction(rangeAnalyzeName,
typoid);
else
rangeAnalyze = InvalidOid;
get_typlenbyvalalign(rangeSubtype, get_typlenbyvalalign(rangeSubtype,
&subtyplen, &subtypbyval, &subtypalign); &subtyplen, &subtypbyval, &subtypalign);
...@@ -1358,16 +1426,16 @@ DefineRange(CreateRangeStmt *stmt) ...@@ -1358,16 +1426,16 @@ DefineRange(CreateRangeStmt *stmt)
rangeArrayOid, /* array type we are about to create */ rangeArrayOid, /* array type we are about to create */
InvalidOid, /* base type ID (only for domains) */ InvalidOid, /* base type ID (only for domains) */
NULL, /* never a default type value */ NULL, /* never a default type value */
NULL, /* binary default isn't sent either */ NULL, /* no binary form available either */
false, /* never passed by value */ false, /* never passed by value */
alignment, /* alignment */ alignment, /* alignment */
'x', /* TOAST strategy (always extended) */ 'x', /* TOAST strategy (always extended) */
-1, /* typMod (Domains only) */ -1, /* typMod (Domains only) */
0, /* Array dimensions of typbasetype */ 0, /* Array dimensions of typbasetype */
false, /* Type NOT NULL */ 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, RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
rangeCanonical, rangeSubtypeDiff); rangeCanonical, rangeSubtypeDiff);
...@@ -1411,61 +1479,64 @@ DefineRange(CreateRangeStmt *stmt) ...@@ -1411,61 +1479,64 @@ DefineRange(CreateRangeStmt *stmt)
pfree(rangeArrayName); pfree(rangeArrayName);
/* And create the constructor functions for this range type */ /* 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 * Because there may exist several range types over the same subtype, the
* can't be determined from the subtype. This means that constructors can't be * range type can't be uniquely determined from the subtype. So it's
* polymorphic, and so we must generate a new constructor for every range type * impossible to define a polymorphic constructor; we have to generate new
* defined. * constructor functions explicitly for each range type.
* *
* We actually define 4 functions with 0 through 3 arguments. This is just to * We actually define 4 functions, with 0 through 3 arguments. This is just
* offer more convenience for the user. * to offer more convenience for the user.
*/ */
static void 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]; Oid constructorArgTypes[3];
ObjectAddress myself,
referenced;
int i; int i;
referenced.classId = TypeRelationId;
referenced.objectId = rangeOid;
referenced.objectSubId = 0;
constructorArgTypes[0] = subtype; constructorArgTypes[0] = subtype;
constructorArgTypes[1] = subtype; constructorArgTypes[1] = subtype;
constructorArgTypes[2] = TEXTOID; 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; oidvector *constructorArgTypesVector;
ObjectAddress myself;
Oid procOid; Oid procOid;
char *prosrc[4] = {"range_constructor0",
"range_constructor1",
"range_constructor2",
"range_constructor3"};
constructorArgTypesVector = buildoidvector(constructorArgTypes, i); constructorArgTypesVector = buildoidvector(constructorArgTypes,
pronargs[i]);
procOid = ProcedureCreate( procOid = ProcedureCreate(name, /* name: same as range type */
name, /* name */
namespace, /* namespace */ namespace, /* namespace */
false, /* replace */ false, /* replace */
false, /* return set */ false, /* returns set */
rangeOid, /* return type */ rangeOid, /* return type */
INTERNALlanguageId, /* language */ INTERNALlanguageId, /* language */
F_FMGR_INTERNAL_VALIDATOR, /* language validator */ F_FMGR_INTERNAL_VALIDATOR, /* language validator */
prosrc[i], /* prosrc */ prosrc[i], /* prosrc */
NULL, /* probin */ NULL, /* probin */
false, /* agg */ false, /* isAgg */
false, /* window */ false, /* isWindowFunc */
false, /* security definer */ false, /* security_definer */
false, /* strict */ false, /* isStrict */
PROVOLATILE_IMMUTABLE, /* volatility */ PROVOLATILE_IMMUTABLE, /* volatility */
constructorArgTypesVector, /* param types */ constructorArgTypesVector, /* parameterTypes */
PointerGetDatum(NULL), /* allParameterTypes */ PointerGetDatum(NULL), /* allParameterTypes */
PointerGetDatum(NULL), /* parameterModes */ PointerGetDatum(NULL), /* parameterModes */
PointerGetDatum(NULL), /* parameterNames */ PointerGetDatum(NULL), /* parameterNames */
...@@ -1482,64 +1553,11 @@ makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype) ...@@ -1482,64 +1553,11 @@ makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype)
myself.classId = ProcedureRelationId; myself.classId = ProcedureRelationId;
myself.objectId = procOid; myself.objectId = procOid;
myself.objectSubId = 0; myself.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); 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. * Find suitable I/O functions for a type.
...@@ -1801,99 +1819,120 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid) ...@@ -1801,99 +1819,120 @@ findTypeAnalyzeFunction(List *procname, Oid typeOid)
return procOid; return procOid;
} }
/*
* Find suitable support functions and opclasses for a range type.
*/
/* /*
* Find named btree opclass for subtype, or default btree opclass if * 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 static Oid
findRangeSubOpclass(List *opcname, Oid subtype) findRangeSubOpclass(List *opcname, Oid subtype)
{ {
Oid opcid; 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); opcid = GetDefaultOpClass(subtype, BTREE_AM_OID);
if (!OidIsValid(opcid)) if (!OidIsValid(opcid))
{ {
/* We spell the error message identically to GetIndexOpClass */
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("data type %s has no default operator class for access method \"btree\"", errmsg("data type %s has no default operator class for access method \"%s\"",
format_type_be(subtype)), format_type_be(subtype), "btree"),
errhint("You must specify an operator class for the data type or define a default operator class for the data type."))); 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; return opcid;
} }
/*
* Used to find a range's 'canonical' function.
*/
static Oid static Oid
findRangeSubtypeDiffFunction(List *procname, Oid typeOid) findRangeCanonicalFunction(List *procname, Oid typeOid)
{ {
Oid argList[2]; Oid argList[1];
Oid procOid; Oid procOid;
/*
* Range canonical functions must take and return the range type, and must
* be immutable.
*/
argList[0] = typeOid; argList[0] = typeOid;
argList[1] = typeOid;
procOid = LookupFuncName(procname, 2, argList, true); procOid = LookupFuncName(procname, 1, argList, true);
if (!OidIsValid(procOid)) if (!OidIsValid(procOid))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function %s does not exist", 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, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("range subtype diff function %s must return type \"float8\"", errmsg("range canonical function %s must return range type",
func_signature_string(procname, 2, NIL, argList)))); func_signature_string(procname, 1, NIL, argList))));
if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE) if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("range subtype diff function %s must be immutable", errmsg("range canonical function %s must be immutable",
func_signature_string(procname, 2, NIL, argList)))); func_signature_string(procname, 1, NIL, argList))));
return procOid; return procOid;
} }
/*
* Used to find a range's 'canonical' function.
*/
static Oid static Oid
findRangeCanonicalFunction(List *procname, Oid typeOid) findRangeSubtypeDiffFunction(List *procname, Oid subtype)
{ {
Oid argList[1]; Oid argList[2];
Oid procOid; 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)) if (!OidIsValid(procOid))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function %s does not exist", 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, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("range canonical function %s must return range type", errmsg("range subtype diff function %s must return type double precision",
NameListToString(procname)))); func_signature_string(procname, 2, NIL, argList))));
if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE) if (func_volatile(procOid) != PROVOLATILE_IMMUTABLE)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("range canonical function %s must be immutable", errmsg("range subtype diff function %s must be immutable",
func_signature_string(procname, 1, NIL, argList)))); func_signature_string(procname, 2, NIL, argList))));
return procOid; return procOid;
} }
......
...@@ -21,18 +21,19 @@ ...@@ -21,18 +21,19 @@
/* Operator strategy numbers used in the GiST range opclass */ /* Operator strategy numbers used in the GiST range opclass */
#define RANGESTRAT_EQ 1 /* Numbers are chosen to match up operator names with existing usages */
#define RANGESTRAT_NE 2 #define RANGESTRAT_BEFORE 1
#define RANGESTRAT_OVERLEFT 2
#define RANGESTRAT_OVERLAPS 3 #define RANGESTRAT_OVERLAPS 3
#define RANGESTRAT_CONTAINS_ELEM 4 #define RANGESTRAT_OVERRIGHT 4
#define RANGESTRAT_ELEM_CONTAINED_BY 5 #define RANGESTRAT_AFTER 5
#define RANGESTRAT_CONTAINS 6 #define RANGESTRAT_ADJACENT 6
#define RANGESTRAT_CONTAINED_BY 7 #define RANGESTRAT_CONTAINS 7
#define RANGESTRAT_BEFORE 8 #define RANGESTRAT_CONTAINED_BY 8
#define RANGESTRAT_AFTER 9 #define RANGESTRAT_CONTAINS_ELEM 16
#define RANGESTRAT_OVERLEFT 10 #define RANGESTRAT_ELEM_CONTAINED_BY 17
#define RANGESTRAT_OVERRIGHT 11 #define RANGESTRAT_EQ 18
#define RANGESTRAT_ADJACENT 12 #define RANGESTRAT_NE 19
#define RangeIsEmpty(r) (range_get_flags(r) & RANGE_EMPTY) #define RangeIsEmpty(r) (range_get_flags(r) & RANGE_EMPTY)
...@@ -460,47 +461,33 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, ...@@ -460,47 +461,33 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy,
switch (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: case RANGESTRAT_BEFORE:
if (RangeIsEmpty(key)) if (RangeIsEmpty(key))
return false; return false;
proc = range_overright; proc = range_overright;
negate = true; negate = true;
break; break;
case RANGESTRAT_AFTER:
if (RangeIsEmpty(key))
return false;
proc = range_overleft;
negate = true;
break;
case RANGESTRAT_OVERLEFT: case RANGESTRAT_OVERLEFT:
if (RangeIsEmpty(key)) if (RangeIsEmpty(key))
return false; return false;
proc = range_after; proc = range_after;
negate = true; negate = true;
break; break;
case RANGESTRAT_OVERLAPS:
proc = range_overlaps;
break;
case RANGESTRAT_OVERRIGHT: case RANGESTRAT_OVERRIGHT:
if (RangeIsEmpty(key)) if (RangeIsEmpty(key))
return false; return false;
proc = range_before; proc = range_before;
negate = true; negate = true;
break; break;
case RANGESTRAT_AFTER:
if (RangeIsEmpty(key))
return false;
proc = range_overleft;
negate = true;
break;
case RANGESTRAT_ADJACENT: case RANGESTRAT_ADJACENT:
if (RangeIsEmpty(key) || RangeIsEmpty(query)) if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false; return false;
...@@ -510,6 +497,20 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy, ...@@ -510,6 +497,20 @@ range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy,
return true; return true;
proc = range_overlaps; proc = range_overlaps;
break; 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: default:
elog(ERROR, "unrecognized range strategy: %d", strategy); elog(ERROR, "unrecognized range strategy: %d", strategy);
proc = NULL; /* keep compiler quiet */ proc = NULL; /* keep compiler quiet */
...@@ -536,48 +537,48 @@ range_gist_consistent_leaf(FmgrInfo *flinfo, StrategyNumber strategy, ...@@ -536,48 +537,48 @@ range_gist_consistent_leaf(FmgrInfo *flinfo, StrategyNumber strategy,
switch (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: case RANGESTRAT_BEFORE:
if (RangeIsEmpty(key) || RangeIsEmpty(query)) if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false; return false;
proc = range_before; proc = range_before;
break; break;
case RANGESTRAT_AFTER:
if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
proc = range_after;
break;
case RANGESTRAT_OVERLEFT: case RANGESTRAT_OVERLEFT:
if (RangeIsEmpty(key) || RangeIsEmpty(query)) if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false; return false;
proc = range_overleft; proc = range_overleft;
break; break;
case RANGESTRAT_OVERLAPS:
proc = range_overlaps;
break;
case RANGESTRAT_OVERRIGHT: case RANGESTRAT_OVERRIGHT:
if (RangeIsEmpty(key) || RangeIsEmpty(query)) if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false; return false;
proc = range_overright; proc = range_overright;
break; break;
case RANGESTRAT_AFTER:
if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
proc = range_after;
break;
case RANGESTRAT_ADJACENT: case RANGESTRAT_ADJACENT:
if (RangeIsEmpty(key) || RangeIsEmpty(query)) if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false; return false;
proc = range_adjacent; proc = range_adjacent;
break; 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: default:
elog(ERROR, "unrecognized range strategy: %d", strategy); elog(ERROR, "unrecognized range strategy: %d", strategy);
proc = NULL; /* keep compiler quiet */ proc = NULL; /* keep compiler quiet */
......
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201111171 #define CATALOG_VERSION_NO 201111211
#endif #endif
...@@ -726,17 +726,17 @@ DATA(insert ( 3903 3831 3831 1 s 3882 405 0 )); ...@@ -726,17 +726,17 @@ DATA(insert ( 3903 3831 3831 1 s 3882 405 0 ));
/* /*
* GiST range_ops * GiST range_ops
*/ */
DATA(insert ( 3919 3831 3831 1 s 3882 783 0 )); DATA(insert ( 3919 3831 3831 1 s 3893 783 0 ));
DATA(insert ( 3919 3831 3831 2 s 3883 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 3831 3 s 3888 783 0 ));
DATA(insert ( 3919 3831 2283 4 s 3889 783 0 )); DATA(insert ( 3919 3831 3831 4 s 3896 783 0 ));
DATA(insert ( 3919 2283 3831 5 s 3891 783 0 )); DATA(insert ( 3919 3831 3831 5 s 3894 783 0 ));
DATA(insert ( 3919 3831 3831 6 s 3890 783 0 )); DATA(insert ( 3919 3831 3831 6 s 3897 783 0 ));
DATA(insert ( 3919 3831 3831 7 s 3892 783 0 )); DATA(insert ( 3919 3831 3831 7 s 3890 783 0 ));
DATA(insert ( 3919 3831 3831 8 s 3893 783 0 )); DATA(insert ( 3919 3831 3831 8 s 3892 783 0 ));
DATA(insert ( 3919 3831 3831 9 s 3894 783 0 )); DATA(insert ( 3919 3831 2283 16 s 3889 783 0 ));
DATA(insert ( 3919 3831 3831 10 s 3895 783 0 )); DATA(insert ( 3919 2283 3831 17 s 3891 783 0 ));
DATA(insert ( 3919 3831 3831 11 s 3896 783 0 )); DATA(insert ( 3919 3831 3831 18 s 3882 783 0 ));
DATA(insert ( 3919 3831 3831 12 s 3897 783 0 )); DATA(insert ( 3919 3831 3831 19 s 3883 783 0 ));
#endif /* PG_AMOP_H */ #endif /* PG_AMOP_H */
...@@ -1674,15 +1674,15 @@ DATA(insert OID = 3886 ( ">=" PGNSP PGUID b f f 3831 3831 16 3885 3884 range ...@@ -1674,15 +1674,15 @@ DATA(insert OID = 3886 ( ">=" PGNSP PGUID b f f 3831 3831 16 3885 3884 range
DESCR("greater than or equal"); DESCR("greater than or equal");
DATA(insert OID = 3887 ( ">" PGNSP PGUID b f f 3831 3831 16 3884 3885 range_gt scalargtsel scalargtjoinsel )); DATA(insert OID = 3887 ( ">" PGNSP PGUID b f f 3831 3831 16 3884 3885 range_gt scalargtsel scalargtjoinsel ));
DESCR("greater than"); 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"); 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"); 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"); 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"); 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"); DESCR("is contained by");
DATA(insert OID = 3893 ( "<<" PGNSP PGUID b f f 3831 3831 16 3894 0 range_before scalarltsel scalarltjoinsel )); DATA(insert OID = 3893 ( "<<" PGNSP PGUID b f f 3831 3831 16 3894 0 range_before scalarltsel scalarltjoinsel ));
DESCR("is left of"); DESCR("is left of");
...@@ -1692,7 +1692,7 @@ DATA(insert OID = 3895 ( "&<" PGNSP PGUID b f f 3831 3831 16 0 0 range_overl ...@@ -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"); DESCR("overlaps or is left of");
DATA(insert OID = 3896 ( "&>" PGNSP PGUID b f f 3831 3831 16 0 0 range_overright scalargtsel scalargtjoinsel )); DATA(insert OID = 3896 ( "&>" PGNSP PGUID b f f 3831 3831 16 0 0 range_overright scalargtsel scalargtjoinsel ));
DESCR("overlaps or is right of"); 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"); DESCR("is adjacent to");
DATA(insert OID = 3898 ( "+" PGNSP PGUID b f f 3831 3831 3831 3898 0 range_union - - )); DATA(insert OID = 3898 ( "+" PGNSP PGUID b f f 3831 3831 3831 3898 0 range_union - - ));
DESCR("range union"); DESCR("range union");
......
...@@ -140,16 +140,16 @@ WHERE p1.oid < p2.oid AND ...@@ -140,16 +140,16 @@ WHERE p1.oid < p2.oid AND
-- need to be modified whenever new pairs of types are made binary-equivalent, -- need to be modified whenever new pairs of types are made binary-equivalent,
-- or when new polymorphic built-in functions are added! -- or when new polymorphic built-in functions are added!
-- Note: ignore aggregate functions here, since they all point to the same -- 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 SELECT DISTINCT p1.prorettype, p2.prorettype
FROM pg_proc AS p1, pg_proc AS p2 FROM pg_proc AS p1, pg_proc AS p2
WHERE p1.oid != p2.oid AND WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND p1.prolang = 12 AND p2.prolang = 12 AND
NOT p1.proisagg AND NOT p2.proisagg AND NOT p1.proisagg AND NOT p2.proisagg AND
(p1.prorettype < p2.prorettype) AND p1.prosrc NOT LIKE E'range\\_constructor_' AND
-- range constructor functions are shared by all range types. p2.prosrc NOT LIKE E'range\\_constructor_' AND
NOT p1.prosrc LIKE 'range_constructor%' (p1.prorettype < p2.prorettype)
ORDER BY 1, 2; ORDER BY 1, 2;
prorettype | prorettype prorettype | prorettype
------------+------------ ------------+------------
...@@ -163,9 +163,9 @@ WHERE p1.oid != p2.oid AND ...@@ -163,9 +163,9 @@ WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND p1.prolang = 12 AND p2.prolang = 12 AND
NOT p1.proisagg AND NOT p2.proisagg AND NOT p1.proisagg AND NOT p2.proisagg AND
(p1.proargtypes[0] < p2.proargtypes[0]) AND p1.prosrc NOT LIKE E'range\\_constructor_' AND
-- range constructor functions are shared by all range types. p2.prosrc NOT LIKE E'range\\_constructor_' AND
NOT p1.prosrc LIKE 'range_constructor%' (p1.proargtypes[0] < p2.proargtypes[0])
ORDER BY 1, 2; ORDER BY 1, 2;
proargtypes | proargtypes proargtypes | proargtypes
-------------+------------- -------------+-------------
...@@ -182,9 +182,9 @@ WHERE p1.oid != p2.oid AND ...@@ -182,9 +182,9 @@ WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND p1.prolang = 12 AND p2.prolang = 12 AND
NOT p1.proisagg AND NOT p2.proisagg AND NOT p1.proisagg AND NOT p2.proisagg AND
(p1.proargtypes[1] < p2.proargtypes[1]) AND p1.prosrc NOT LIKE E'range\\_constructor_' AND
-- range constructor functions are shared by all range types. p2.prosrc NOT LIKE E'range\\_constructor_' AND
NOT p1.prosrc LIKE 'range_constructor%' (p1.proargtypes[1] < p2.proargtypes[1])
ORDER BY 1, 2; ORDER BY 1, 2;
proargtypes | proargtypes proargtypes | proargtypes
-------------+------------- -------------+-------------
...@@ -1021,34 +1021,28 @@ ORDER BY 1, 2, 3; ...@@ -1021,34 +1021,28 @@ ORDER BY 1, 2, 3;
403 | 5 | ~>~ 403 | 5 | ~>~
405 | 1 | = 405 | 1 | =
783 | 1 | << 783 | 1 | <<
783 | 1 | =
783 | 1 | @@ 783 | 1 | @@
783 | 2 | &< 783 | 2 | &<
783 | 2 | <>
783 | 3 | && 783 | 3 | &&
783 | 4 | &> 783 | 4 | &>
783 | 4 | @>
783 | 5 | <@
783 | 5 | >> 783 | 5 | >>
783 | 6 | @> 783 | 6 | -|-
783 | 6 | ~= 783 | 6 | ~=
783 | 7 | <@
783 | 7 | @> 783 | 7 | @>
783 | 8 | <<
783 | 8 | <@ 783 | 8 | <@
783 | 9 | &<| 783 | 9 | &<|
783 | 9 | >>
783 | 10 | &<
783 | 10 | <<| 783 | 10 | <<|
783 | 10 | <^ 783 | 10 | <^
783 | 11 | &>
783 | 11 | >^ 783 | 11 | >^
783 | 11 | |>> 783 | 11 | |>>
783 | 12 | -|-
783 | 12 | |&> 783 | 12 | |&>
783 | 13 | ~ 783 | 13 | ~
783 | 14 | @ 783 | 14 | @
783 | 15 | <-> 783 | 15 | <->
783 | 16 | @>
783 | 17 | <@
783 | 18 | =
783 | 19 | <>
783 | 27 | @> 783 | 27 | @>
783 | 28 | <@ 783 | 28 | <@
783 | 47 | @> 783 | 47 | @>
...@@ -1061,7 +1055,7 @@ ORDER BY 1, 2, 3; ...@@ -1061,7 +1055,7 @@ ORDER BY 1, 2, 3;
2742 | 2 | @@@ 2742 | 2 | @@@
2742 | 3 | <@ 2742 | 3 | <@
2742 | 4 | = 2742 | 4 | =
(51 rows) (45 rows)
-- Check that all opclass search operators have selectivity estimators. -- Check that all opclass search operators have selectivity estimators.
-- This is not absolutely required, but it seems a reasonable thing -- This is not absolutely required, but it seems a reasonable thing
...@@ -1071,14 +1065,8 @@ FROM pg_amop AS p1, pg_operator AS p2 ...@@ -1071,14 +1065,8 @@ FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND WHERE p1.amopopr = p2.oid AND p1.amoppurpose = 's' AND
(p2.oprrest = 0 OR p2.oprjoin = 0); (p2.oprrest = 0 OR p2.oprjoin = 0);
amopfamily | amopopr | oid | oprname amopfamily | amopopr | oid | oprname
------------+---------+------+--------- ------------+---------+-----+---------
3919 | 3888 | 3888 | && (0 rows)
3919 | 3889 | 3889 | @>
3919 | 3891 | 3891 | <@
3919 | 3890 | 3890 | @>
3919 | 3892 | 3892 | <@
3919 | 3897 | 3897 | -|-
(6 rows)
-- Check that each opclass in an opfamily has associated operators, that is -- Check that each opclass in an opfamily has associated operators, that is
-- ones whose oprleft matches opcintype (possibly by coercion). -- ones whose oprleft matches opcintype (possibly by coercion).
......
...@@ -4571,17 +4571,3 @@ ERROR: value for domain orderedarray violates check constraint "sorted" ...@@ -4571,17 +4571,3 @@ ERROR: value for domain orderedarray violates check constraint "sorted"
CONTEXT: PL/pgSQL function "testoa" line 5 at assignment CONTEXT: PL/pgSQL function "testoa" line 5 at assignment
drop function arrayassign1(); drop function arrayassign1();
drop function testoa(x1 int, x2 int, x3 int); 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)
...@@ -936,6 +936,20 @@ select range_add_bounds(numrange(1.0001, 123.123)); ...@@ -936,6 +936,20 @@ select range_add_bounds(numrange(1.0001, 123.123));
124.1231 124.1231
(1 row) (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 -- Arrays of ranges
-- --
......
...@@ -125,7 +125,7 @@ WHERE p1.oid < p2.oid AND ...@@ -125,7 +125,7 @@ WHERE p1.oid < p2.oid AND
-- need to be modified whenever new pairs of types are made binary-equivalent, -- need to be modified whenever new pairs of types are made binary-equivalent,
-- or when new polymorphic built-in functions are added! -- or when new polymorphic built-in functions are added!
-- Note: ignore aggregate functions here, since they all point to the same -- 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 SELECT DISTINCT p1.prorettype, p2.prorettype
FROM pg_proc AS p1, pg_proc AS p2 FROM pg_proc AS p1, pg_proc AS p2
...@@ -133,9 +133,9 @@ WHERE p1.oid != p2.oid AND ...@@ -133,9 +133,9 @@ WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND p1.prolang = 12 AND p2.prolang = 12 AND
NOT p1.proisagg AND NOT p2.proisagg AND NOT p1.proisagg AND NOT p2.proisagg AND
(p1.prorettype < p2.prorettype) AND p1.prosrc NOT LIKE E'range\\_constructor_' AND
-- range constructor functions are shared by all range types. p2.prosrc NOT LIKE E'range\\_constructor_' AND
NOT p1.prosrc LIKE 'range_constructor%' (p1.prorettype < p2.prorettype)
ORDER BY 1, 2; ORDER BY 1, 2;
SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0] SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
...@@ -144,9 +144,9 @@ WHERE p1.oid != p2.oid AND ...@@ -144,9 +144,9 @@ WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND p1.prolang = 12 AND p2.prolang = 12 AND
NOT p1.proisagg AND NOT p2.proisagg AND NOT p1.proisagg AND NOT p2.proisagg AND
(p1.proargtypes[0] < p2.proargtypes[0]) AND p1.prosrc NOT LIKE E'range\\_constructor_' AND
-- range constructor functions are shared by all range types. p2.prosrc NOT LIKE E'range\\_constructor_' AND
NOT p1.prosrc LIKE 'range_constructor%' (p1.proargtypes[0] < p2.proargtypes[0])
ORDER BY 1, 2; ORDER BY 1, 2;
SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1] SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
...@@ -155,9 +155,9 @@ WHERE p1.oid != p2.oid AND ...@@ -155,9 +155,9 @@ WHERE p1.oid != p2.oid AND
p1.prosrc = p2.prosrc AND p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND p1.prolang = 12 AND p2.prolang = 12 AND
NOT p1.proisagg AND NOT p2.proisagg AND NOT p1.proisagg AND NOT p2.proisagg AND
(p1.proargtypes[1] < p2.proargtypes[1]) AND p1.prosrc NOT LIKE E'range\\_constructor_' AND
-- range constructor functions are shared by all range types. p2.prosrc NOT LIKE E'range\\_constructor_' AND
NOT p1.prosrc LIKE 'range_constructor%' (p1.proargtypes[1] < p2.proargtypes[1])
ORDER BY 1, 2; ORDER BY 1, 2;
SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2] SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]
......
...@@ -3600,13 +3600,3 @@ select testoa(1,2,1); -- fail at update ...@@ -3600,13 +3600,3 @@ select testoa(1,2,1); -- fail at update
drop function arrayassign1(); drop function arrayassign1();
drop function testoa(x1 int, x2 int, x3 int); 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]);
...@@ -327,6 +327,13 @@ create function range_add_bounds(anyrange) ...@@ -327,6 +327,13 @@ create function range_add_bounds(anyrange)
select range_add_bounds(numrange(1.0001, 123.123)); 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 -- Arrays of ranges
-- --
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment