diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 4d66020a34..ee5896b281 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,4 +1,4 @@ - + @@ -347,7 +347,9 @@ amstrategies int2 - Number of operator strategies for this access method + Number of operator strategies for this access method, + or zero if access method does not have a fixed set of operator + strategies diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 4407e2785c..d4dec74650 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -9,12 +9,14 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.49 2006/10/04 00:29:51 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.50 2006/12/18 18:56:28 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include + #include "access/genam.h" #include "access/heapam.h" #include "catalog/dependency.h" @@ -73,8 +75,8 @@ DefineOpClass(CreateOpClassStmt *stmt) storageoid, /* storage datatype oid, if any */ namespaceoid, /* namespace to create opclass in */ opclassoid; /* oid of opclass we create */ - int numOperators, /* amstrategies value */ - numProcs; /* amsupport value */ + int maxOpNumber, /* amstrategies value */ + maxProcNumber; /* amsupport value */ bool amstorage; /* amstorage flag */ List *operators; /* OpClassMember list for operators */ List *procedures; /* OpClassMember list for support procs */ @@ -112,8 +114,11 @@ DefineOpClass(CreateOpClassStmt *stmt) amoid = HeapTupleGetOid(tup); pg_am = (Form_pg_am) GETSTRUCT(tup); - numOperators = pg_am->amstrategies; - numProcs = pg_am->amsupport; + maxOpNumber = pg_am->amstrategies; + /* if amstrategies is zero, just enforce that op numbers fit in int16 */ + if (maxOpNumber <= 0) + maxOpNumber = SHRT_MAX; + maxProcNumber = pg_am->amsupport; amstorage = pg_am->amstorage; /* XXX Should we make any privilege check against the AM? */ @@ -176,12 +181,12 @@ DefineOpClass(CreateOpClassStmt *stmt) switch (item->itemtype) { case OPCLASS_ITEM_OPERATOR: - if (item->number <= 0 || item->number > numOperators) + if (item->number <= 0 || item->number > maxOpNumber) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("invalid operator number %d," " must be between 1 and %d", - item->number, numOperators))); + item->number, maxOpNumber))); if (item->args != NIL) { TypeName *typeName1 = (TypeName *) linitial(item->args); @@ -220,12 +225,12 @@ DefineOpClass(CreateOpClassStmt *stmt) addClassMember(&operators, member, false); break; case OPCLASS_ITEM_FUNCTION: - if (item->number <= 0 || item->number > numProcs) + if (item->number <= 0 || item->number > maxProcNumber) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("invalid procedure number %d," " must be between 1 and %d", - item->number, numProcs))); + item->number, maxProcNumber))); funcOid = LookupFuncNameTypeNames(item->name, item->args, false); #ifdef NOT_USED diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index de14ddd2dc..70a77bd3bd 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.127 2006/10/04 00:29:55 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.128 2006/12/18 18:56:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -190,10 +190,17 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, * Fetch the ordering operators associated with the index, if any. */ amorderstrategy = indexRelation->rd_am->amorderstrategy; - if (amorderstrategy != 0) + if (amorderstrategy > 0) { int oprindex = amorderstrategy - 1; + /* + * Index AM must have a fixed set of strategies for it to + * make sense to specify amorderstrategy, so we need not + * allow the case amstrategies == 0. + */ + Assert(oprindex < indexRelation->rd_am->amstrategies); + for (i = 0; i < ncolumns; i++) { info->ordering[i] = indexRelation->rd_operator[oprindex]; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index e6bcdfb054..8822ab6262 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.362 2006/12/10 22:13:26 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.363 2006/12/18 18:56:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200612101 +#define CATALOG_VERSION_NO 200612181 #endif diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h index 7b155bf828..00d6c90ce4 100644 --- a/src/include/catalog/pg_am.h +++ b/src/include/catalog/pg_am.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.46 2006/07/31 20:09:05 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.47 2006/12/18 18:56:29 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -40,7 +40,9 @@ CATALOG(pg_am,2601) { NameData amname; /* access method name */ int2 amstrategies; /* total NUMBER of strategies (operators) by - * which we can traverse/search this AM */ + * which we can traverse/search this AM. + * Zero if AM does not have a fixed set of + * strategy assignments. */ int2 amsupport; /* total NUMBER of support functions that this * AM uses */ int2 amorderstrategy;/* if this AM has a sort order, the strategy @@ -114,10 +116,10 @@ DESCR("b-tree index access method"); DATA(insert OID = 405 ( hash 1 1 0 f f f f f f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions )); DESCR("hash index access method"); #define HASH_AM_OID 405 -DATA(insert OID = 783 ( gist 100 7 0 f t t t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions )); +DATA(insert OID = 783 ( gist 0 7 0 f t t t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions )); DESCR("GiST index access method"); #define GIST_AM_OID 783 -DATA(insert OID = 2742 ( gin 100 4 0 f f f f t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions )); +DATA(insert OID = 2742 ( gin 0 4 0 f f f f t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions )); DESCR("GIN index access method"); #define GIN_AM_OID 2742 diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 8aba9f87b2..0be263e6d8 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -773,7 +773,7 @@ WHERE p1.amopclaid = 0 OR p1.amopstrategy <= 0 OR p1.amopopr = 0; SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.amname FROM pg_amop AS p1, pg_am AS p2, pg_opclass AS p3 WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND - p1.amopstrategy > p2.amstrategies; + p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0; amopclaid | amopopr | oid | amname -----------+---------+-----+-------- (0 rows) @@ -781,12 +781,11 @@ WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND -- Detect missing pg_amop entries: should have as many strategy operators -- as AM expects for each opclass for the AM. When nondefault subtypes are -- present, enforce condition separately for each subtype. --- We have to exclude GiST and GIN, unfortunately, since they haven't got --- any fixed requirements about strategy operators. +-- We can't check this for AMs with variable strategy sets. SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amopsubtype FROM pg_am AS p1, pg_opclass AS p2, pg_amop AS p3 WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND - p1.amname != 'gist' AND p1.amname != 'gin' AND + p1.amstrategies <> 0 AND p1.amstrategies != (SELECT count(*) FROM pg_amop AS p4 WHERE p4.amopclaid = p2.oid AND p4.amopsubtype = p3.amopsubtype); diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 8428624582..7fc9915275 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -642,18 +642,17 @@ WHERE p1.amopclaid = 0 OR p1.amopstrategy <= 0 OR p1.amopopr = 0; SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.amname FROM pg_amop AS p1, pg_am AS p2, pg_opclass AS p3 WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND - p1.amopstrategy > p2.amstrategies; + p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0; -- Detect missing pg_amop entries: should have as many strategy operators -- as AM expects for each opclass for the AM. When nondefault subtypes are -- present, enforce condition separately for each subtype. --- We have to exclude GiST and GIN, unfortunately, since they haven't got --- any fixed requirements about strategy operators. +-- We can't check this for AMs with variable strategy sets. SELECT p1.oid, p1.amname, p2.oid, p2.opcname, p3.amopsubtype FROM pg_am AS p1, pg_opclass AS p2, pg_amop AS p3 WHERE p2.opcamid = p1.oid AND p3.amopclaid = p2.oid AND - p1.amname != 'gist' AND p1.amname != 'gin' AND + p1.amstrategies <> 0 AND p1.amstrategies != (SELECT count(*) FROM pg_amop AS p4 WHERE p4.amopclaid = p2.oid AND p4.amopsubtype = p3.amopsubtype);