summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane2010-11-24 19:20:39 +0000
committerTom Lane2010-11-24 19:22:17 +0000
commit725d52d0c27cffe8c99bb78e2b0d2480d5cd702b (patch)
tree23aae31466c0f7e0e65762946b0012d30e92ab4d /src/backend
parent4fc09ad00c3cc95003a5523d85999da1dd4f9d75 (diff)
Create the system catalog infrastructure needed for KNNGIST.
This commit adds columns amoppurpose and amopsortfamily to pg_amop, and column amcanorderbyop to pg_am. For the moment all the entries in amcanorderbyop are "false", since the underlying support isn't there yet. Also, extend the CREATE OPERATOR CLASS/ALTER OPERATOR FAMILY commands with [ FOR SEARCH | FOR ORDER BY sort_operator_family ] clauses to allow the new columns of pg_amop to be populated, and create pg_dump support for dumping that information. I also added some documentation, although it's perhaps a bit premature given that the feature doesn't do anything useful yet. Teodor Sigaev, Robert Haas, Tom Lane
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/opclasscmds.c78
-rw-r--r--src/backend/nodes/copyfuncs.c1
-rw-r--r--src/backend/nodes/equalfuncs.c1
-rw-r--r--src/backend/optimizer/util/plancat.c1
-rw-r--r--src/backend/optimizer/util/predtest.c8
-rw-r--r--src/backend/parser/gram.y14
-rw-r--r--src/backend/utils/cache/lsyscache.c15
-rw-r--r--src/backend/utils/cache/syscache.c4
8 files changed, 106 insertions, 16 deletions
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 8c493363166..132c4ee1e53 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -54,6 +54,7 @@ typedef struct
int number; /* strategy or support proc number */
Oid lefttype; /* lefttype */
Oid righttype; /* righttype */
+ Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
@@ -457,6 +458,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
CreateOpClassItem *item = lfirst(l);
Oid operOid;
Oid funcOid;
+ Oid sortfamilyOid;
OpFamilyMember *member;
Assert(IsA(item, CreateOpClassItem));
@@ -486,6 +488,13 @@ DefineOpClass(CreateOpClassStmt *stmt)
false, -1);
}
+ if (item->order_family)
+ sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
+ item->order_family,
+ false);
+ else
+ sortfamilyOid = InvalidOid;
+
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Caller must own operator and its underlying function */
@@ -502,6 +511,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = operOid;
member->number = item->number;
+ member->sortfamily = sortfamilyOid;
assignOperTypes(member, amoid, typeoid);
addFamilyMember(&operators, member, false);
break;
@@ -825,6 +835,7 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
CreateOpClassItem *item = lfirst(l);
Oid operOid;
Oid funcOid;
+ Oid sortfamilyOid;
OpFamilyMember *member;
Assert(IsA(item, CreateOpClassItem));
@@ -854,6 +865,13 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
operOid = InvalidOid; /* keep compiler quiet */
}
+ if (item->order_family)
+ sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
+ item->order_family,
+ false);
+ else
+ sortfamilyOid = InvalidOid;
+
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Caller must own operator and its underlying function */
@@ -870,6 +888,7 @@ AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = operOid;
member->number = item->number;
+ member->sortfamily = sortfamilyOid;
assignOperTypes(member, amoid, InvalidOid);
addFamilyMember(&operators, member, false);
break;
@@ -1043,16 +1062,51 @@ assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
opform = (Form_pg_operator) GETSTRUCT(optup);
/*
- * Opfamily operators must be binary ops returning boolean.
+ * Opfamily operators must be binary.
*/
if (opform->oprkind != 'b')
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("index operators must be binary")));
- if (opform->oprresult != BOOLOID)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("index operators must return boolean")));
+
+ if (OidIsValid(member->sortfamily))
+ {
+ /*
+ * Ordering op, check index supports that. (We could perhaps also
+ * check that the operator returns a type supported by the sortfamily,
+ * but that seems more trouble than it's worth here. If it does not,
+ * the operator will never be matchable to any ORDER BY clause, but
+ * no worse consequences can ensue. Also, trying to check that would
+ * create an ordering hazard during dump/reload: it's possible that
+ * the family has been created but not yet populated with the required
+ * operators.)
+ */
+ HeapTuple amtup;
+ Form_pg_am pg_am;
+
+ amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (amtup == NULL)
+ elog(ERROR, "cache lookup failed for access method %u", amoid);
+ pg_am = (Form_pg_am) GETSTRUCT(amtup);
+
+ if (!pg_am->amcanorderbyop)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("access method \"%s\" does not support ordering operators",
+ NameStr(pg_am->amname))));
+
+ ReleaseSysCache(amtup);
+ }
+ else
+ {
+ /*
+ * Search operators must return boolean.
+ */
+ if (opform->oprresult != BOOLOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("index search operators must return boolean")));
+ }
/*
* If lefttype/righttype isn't specified, use the operator's input types
@@ -1206,6 +1260,7 @@ storeOperators(List *opfamilyname, Oid amoid,
foreach(l, operators)
{
OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
+ char oppurpose;
/*
* If adding to an existing family, check for conflict with an
@@ -1225,6 +1280,8 @@ storeOperators(List *opfamilyname, Oid amoid,
format_type_be(op->righttype),
NameListToString(opfamilyname))));
+ oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
+
/* Create the pg_amop entry */
memset(values, 0, sizeof(values));
memset(nulls, false, sizeof(nulls));
@@ -1233,8 +1290,10 @@ storeOperators(List *opfamilyname, Oid amoid,
values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
+ values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
+ values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
tup = heap_form_tuple(rel->rd_att, values, nulls);
@@ -1275,6 +1334,15 @@ storeOperators(List *opfamilyname, Oid amoid,
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
}
+
+ /* A search operator also needs a dep on the referenced opfamily */
+ if (OidIsValid(op->sortfamily))
+ {
+ referenced.classId = OperatorFamilyRelationId;
+ referenced.objectId = op->sortfamily;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ }
}
heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bbfbab2e39b..0e0b4dc598a 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2991,6 +2991,7 @@ _copyCreateOpClassItem(CreateOpClassItem *from)
COPY_NODE_FIELD(name);
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(number);
+ COPY_NODE_FIELD(order_family);
COPY_NODE_FIELD(class_args);
COPY_NODE_FIELD(storedtype);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index be4b835585c..2d2b8c77634 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1464,6 +1464,7 @@ _equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
COMPARE_NODE_FIELD(name);
COMPARE_NODE_FIELD(args);
COMPARE_SCALAR_FIELD(number);
+ COMPARE_NODE_FIELD(order_family);
COMPARE_NODE_FIELD(class_args);
COMPARE_NODE_FIELD(storedtype);
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 73132ddf5ca..908b4f7205d 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -212,6 +212,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
info->relam = indexRelation->rd_rel->relam;
info->amcostestimate = indexRelation->rd_am->amcostestimate;
+ info->amcanorderbyop = indexRelation->rd_am->amcanorderbyop;
info->amoptionalkey = indexRelation->rd_am->amoptionalkey;
info->amsearchnulls = indexRelation->rd_am->amsearchnulls;
info->amhasgettuple = OidIsValid(indexRelation->rd_am->amgettuple);
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index 5ab4a31e152..d7ccba0a112 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -1661,8 +1661,9 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
* From the same opfamily, find a strategy number for the clause_op,
* if possible
*/
- clause_tuple = SearchSysCache2(AMOPOPID,
+ clause_tuple = SearchSysCache3(AMOPOPID,
ObjectIdGetDatum(clause_op),
+ CharGetDatum(AMOP_SEARCH),
ObjectIdGetDatum(opfamily_id));
if (HeapTupleIsValid(clause_tuple))
{
@@ -1677,8 +1678,9 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
}
else if (OidIsValid(clause_op_negator))
{
- clause_tuple = SearchSysCache2(AMOPOPID,
- ObjectIdGetDatum(clause_op_negator),
+ clause_tuple = SearchSysCache3(AMOPOPID,
+ ObjectIdGetDatum(clause_op_negator),
+ CharGetDatum(AMOP_SEARCH),
ObjectIdGetDatum(opfamily_id));
if (HeapTupleIsValid(clause_tuple))
{
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index f0c2cd06ea6..1c17be89214 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -295,7 +295,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
ctext_expr_list ctext_row def_list indirection opt_indirection
reloption_list group_clause TriggerFuncArgs select_limit
opt_select_limit opclass_item_list opclass_drop_list
- opt_opfamily transaction_mode_list_or_empty
+ opclass_purpose opt_opfamily transaction_mode_list_or_empty
OptTableFuncElementList TableFuncElementList opt_type_modifiers
prep_type_clause
execute_param_clause using_clause returning_clause
@@ -3935,22 +3935,25 @@ opclass_item_list:
;
opclass_item:
- OPERATOR Iconst any_operator opt_recheck
+ OPERATOR Iconst any_operator opclass_purpose opt_recheck
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->name = $3;
n->args = NIL;
n->number = $2;
+ n->order_family = $4;
$$ = (Node *) n;
}
- | OPERATOR Iconst any_operator oper_argtypes opt_recheck
+ | OPERATOR Iconst any_operator oper_argtypes opclass_purpose
+ opt_recheck
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->name = $3;
n->args = $4;
n->number = $2;
+ n->order_family = $5;
$$ = (Node *) n;
}
| FUNCTION Iconst func_name func_args
@@ -3989,6 +3992,11 @@ opt_opfamily: FAMILY any_name { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
+opclass_purpose: FOR SEARCH { $$ = NIL; }
+ | FOR ORDER BY any_name { $$ = $4; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
opt_recheck: RECHECK
{
/*
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index df765e9d5e3..9beae0d9ef1 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -46,12 +46,15 @@ get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
* op_in_opfamily
*
* Return t iff operator 'opno' is in operator family 'opfamily'.
+ *
+ * This function only considers search operators, not ordering operators.
*/
bool
op_in_opfamily(Oid opno, Oid opfamily)
{
- return SearchSysCacheExists2(AMOPOPID,
+ return SearchSysCacheExists3(AMOPOPID,
ObjectIdGetDatum(opno),
+ CharGetDatum(AMOP_SEARCH),
ObjectIdGetDatum(opfamily));
}
@@ -60,6 +63,8 @@ op_in_opfamily(Oid opno, Oid opfamily)
*
* Get the operator's strategy number within the specified opfamily,
* or 0 if it's not a member of the opfamily.
+ *
+ * This function only considers search operators, not ordering operators.
*/
int
get_op_opfamily_strategy(Oid opno, Oid opfamily)
@@ -68,8 +73,9 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
Form_pg_amop amop_tup;
int result;
- tp = SearchSysCache2(AMOPOPID,
+ tp = SearchSysCache3(AMOPOPID,
ObjectIdGetDatum(opno),
+ CharGetDatum(AMOP_SEARCH),
ObjectIdGetDatum(opfamily));
if (!HeapTupleIsValid(tp))
return 0;
@@ -85,6 +91,8 @@ get_op_opfamily_strategy(Oid opno, Oid opfamily)
* Get the operator's strategy number and declared input data types
* within the specified opfamily.
*
+ * This function only considers search operators, not ordering operators.
+ *
* Caller should already have verified that opno is a member of opfamily,
* therefore we raise an error if the tuple is not found.
*/
@@ -97,8 +105,9 @@ get_op_opfamily_properties(Oid opno, Oid opfamily,
HeapTuple tp;
Form_pg_amop amop_tup;
- tp = SearchSysCache2(AMOPOPID,
+ tp = SearchSysCache3(AMOPOPID,
ObjectIdGetDatum(opno),
+ CharGetDatum(AMOP_SEARCH),
ObjectIdGetDatum(opfamily));
if (!HeapTupleIsValid(tp))
elog(ERROR, "operator %u is not a member of opfamily %u",
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 94bef7dd018..08a14431b16 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -135,11 +135,11 @@ static const struct cachedesc cacheinfo[] = {
},
{AccessMethodOperatorRelationId, /* AMOPOPID */
AccessMethodOperatorIndexId,
- 2,
+ 3,
{
Anum_pg_amop_amopopr,
+ Anum_pg_amop_amoppurpose,
Anum_pg_amop_amopfamily,
- 0,
0
},
64