diff options
author | Tom Lane | 2010-11-24 19:20:39 +0000 |
---|---|---|
committer | Tom Lane | 2010-11-24 19:22:17 +0000 |
commit | 725d52d0c27cffe8c99bb78e2b0d2480d5cd702b (patch) | |
tree | 23aae31466c0f7e0e65762946b0012d30e92ab4d /src/backend | |
parent | 4fc09ad00c3cc95003a5523d85999da1dd4f9d75 (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.c | 78 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/util/plancat.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/util/predtest.c | 8 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 14 | ||||
-rw-r--r-- | src/backend/utils/cache/lsyscache.c | 15 | ||||
-rw-r--r-- | src/backend/utils/cache/syscache.c | 4 |
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 |