diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 6260c25445..c813ba98de 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,6 +1,6 @@ @@ -168,6 +168,11 @@ operators + + pg_pltemplate + template data for procedural languages + + pg_proc functions and procedures @@ -3027,6 +3032,106 @@ + + <structname>pg_pltemplate</structname> + + + pg_pltemplate + + + + The catalog pg_pltemplate stores + template information for procedural languages. + A template for a language allows the language to be created in a + particular database by a simple CREATE LANGUAGE command, + with no need to specify implementation details. + + + + Unlike most system catalogs, pg_pltemplate + is shared across all databases of a cluster: there is only one + copy of pg_pltemplate per cluster, not + one per database. This allows the information to be accessible in + each database as it is needed. + + + + <structname>pg_pltemplate</> Columns + + + + + Name + Type + References + Description + + + + + + tmplname + name + + Name of the language this template is for + + + + tmpltrusted + boolean + + True if language is considered trusted + + + + tmplhandler + text + + Name of call handler function + + + + tmplvalidator + text + + Name of validator function, or NULL if none + + + + tmpllibrary + text + + Path of shared library that implements language + + + + tmplacl + aclitem[] + + Access privileges for template (not yet used) + + + + +
+ + + There are not currently any commands that manipulate procedural language + templates; to change the built-in information, a superuser must modify + the table using ordinary INSERT, DELETE, or UPDATE commands. It is + likely that a future release of PostgreSQL + will offer commands to change the entries in a cleaner fashion. + + + + When implemented, the tmplacl field will provide + access control for the template itself (i.e., the right to create a + language using it), not for the languages created from the template. + + +
+ + <structname>pg_proc</structname> diff --git a/doc/src/sgml/ref/create_language.sgml b/doc/src/sgml/ref/create_language.sgml index 29bcade195..e76dd58687 100644 --- a/doc/src/sgml/ref/create_language.sgml +++ b/doc/src/sgml/ref/create_language.sgml @@ -1,5 +1,5 @@ @@ -48,22 +48,19 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name There are two forms of the CREATE LANGUAGE command. - In the first form, the user merely supplies the name of the desired + In the first form, the user supplies just the name of the desired language, and the PostgreSQL server consults - an internal table to determine the correct parameters. In - the second form, the user supplies the language parameters along with - the language name. The second form must be used to create a language - that is not present in the internal table, but this form is considered - obsolescent. (It is expected that future releases of - PostgreSQL will replace the internal table - with a system catalog that can be extended to support additional - languages.) + the pg_pltemplate + system catalog to determine the correct parameters. In the second form, + the user supplies the language parameters along with the language name. + The second form can be used to create a language that is not defined in + pg_pltemplate, but this approach is considered obsolescent. - When the server finds an entry in its internal table for the given - language name, it will use the table data even if the given command - includes language parameters. This behavior simplifies loading of + When the server finds an entry in the pg_pltemplate catalog + for the given language name, it will use the catalog data even if the + command includes language parameters. This behavior simplifies loading of old dump files, which are likely to contain out-of-date information about language support functions. @@ -165,8 +162,8 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name The TRUSTED option and the support function name(s) are - ignored if the server has information about the specified language - name in its internal table. + ignored if the server has an entry for the specified language + name in pg_pltemplate. @@ -207,9 +204,9 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name The call handler function and the validator function (if any) - must already exist if the server does not have information about - the language in its internal table. But when there is an entry - in the internal table, the functions need not already exist; + must already exist if the server does not have an entry for the language + in pg_pltemplate. But when there is an entry, + the functions need not already exist; they will be automatically defined if not present in the database. (This can result in CREATE LANGUAGE failing, if the shared library that implements the language is not available in @@ -239,8 +236,8 @@ CREATE LANGUAGE plpgsql; - For a language not known in the server's internal table, a sequence - such as this is needed: + For a language not known in the pg_pltemplate catalog, a + sequence such as this is needed: CREATE FUNCTION plsample_call_handler() RETURNS language_handler AS '$libdir/plsample' diff --git a/doc/src/sgml/ref/createlang.sgml b/doc/src/sgml/ref/createlang.sgml index f9f8dc1ea7..0e613caf00 100644 --- a/doc/src/sgml/ref/createlang.sgml +++ b/doc/src/sgml/ref/createlang.sgml @@ -1,5 +1,5 @@ @@ -40,11 +40,9 @@ PostgreSQL documentation createlang is a utility for adding a new programming language to a PostgreSQL database. - createlang can handle all the languages - supplied in the default PostgreSQL distribution, but - not languages provided by other parties. See + createlang is just a wrapper around the - for additional information. + command, which see for additional information. diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index c2dd227d1d..67a46e93c0 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -2,7 +2,7 @@ # # Makefile for backend/catalog # -# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.56 2005/07/14 05:13:39 tgl Exp $ +# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.57 2005/09/08 20:07:41 tgl Exp $ # #------------------------------------------------------------------------- @@ -32,8 +32,9 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\ pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \ pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \ - pg_namespace.h pg_conversion.h pg_database.h pg_shdepend.h \ - pg_authid.h pg_auth_members.h pg_tablespace.h pg_depend.h \ + pg_namespace.h pg_conversion.h pg_depend.h \ + pg_database.h pg_tablespace.h pg_pltemplate.h \ + pg_authid.h pg_auth_members.h pg_shdepend.h \ indexing.h \ ) diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index d6bb902274..c2bb4a2d9c 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.66 2005/08/22 17:38:20 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.67 2005/09/08 20:07:41 tgl Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -44,6 +44,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/defrem.h" +#include "commands/proclang.h" #include "miscadmin.h" #include "optimizer/cost.h" #include "parser/parse_func.h" @@ -543,17 +544,11 @@ CreateFunction(CreateFunctionStmt *stmt) PointerGetDatum(languageName), 0, 0, 0); if (!HeapTupleIsValid(languageTuple)) - /* Add any new languages to this list to invoke the hint. */ ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("language \"%s\" does not exist", languageName), - (strcmp(languageName, "plperl") == 0 || - strcmp(languageName, "plperlu") == 0 || - strcmp(languageName, "plpgsql") == 0 || - strcmp(languageName, "plpythonu") == 0 || - strcmp(languageName, "pltcl") == 0 || - strcmp(languageName, "pltclu") == 0) ? - errhint("You need to use \"createlang\" to load the language into the database.") : 0)); + (PLTemplateExists(languageName) ? + errhint("Use CREATE LANGUAGE to load the language into the database.") : 0))); languageOid = HeapTupleGetOid(languageTuple); languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 499523ae00..4155dc179a 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -7,18 +7,20 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.61 2005/09/05 23:50:48 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.62 2005/09/08 20:07:42 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "access/genam.h" #include "access/heapam.h" #include "catalog/dependency.h" #include "catalog/indexing.h" #include "catalog/namespace.h" #include "catalog/pg_language.h" #include "catalog/pg_namespace.h" +#include "catalog/pg_pltemplate.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "commands/proclang.h" @@ -35,11 +37,10 @@ typedef struct { - char *lanname; /* PL name */ - bool lantrusted; /* trusted? */ - char *lanhandler; /* name of handler function */ - char *lanvalidator; /* name of validator function, or NULL */ - char *lanlibrary; /* path of shared library */ + bool tmpltrusted; /* trusted? */ + char *tmplhandler; /* name of handler function */ + char *tmplvalidator; /* name of validator function, or NULL */ + char *tmpllibrary; /* path of shared library */ } PLTemplate; static void create_proc_lang(const char *languageName, @@ -90,12 +91,19 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) { List *funcname; + /* + * Give a notice if we are ignoring supplied parameters. + */ + if (stmt->plhandler) + ereport(NOTICE, + (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters"))); + /* * Find or create the handler function, which we force to be in * the pg_catalog schema. If already present, it must have the * correct return type. */ - funcname = SystemFuncName(pltemplate->lanhandler); + funcname = SystemFuncName(pltemplate->tmplhandler); handlerOid = LookupFuncName(funcname, 0, funcargtypes, true); if (OidIsValid(handlerOid)) { @@ -108,15 +116,15 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) } else { - handlerOid = ProcedureCreate(pltemplate->lanhandler, + handlerOid = ProcedureCreate(pltemplate->tmplhandler, PG_CATALOG_NAMESPACE, false, /* replace */ false, /* returnsSet */ LANGUAGE_HANDLEROID, ClanguageId, F_FMGR_C_VALIDATOR, - pltemplate->lanhandler, - pltemplate->lanlibrary, + pltemplate->tmplhandler, + pltemplate->tmpllibrary, false, /* isAgg */ false, /* security_definer */ false, /* isStrict */ @@ -131,22 +139,22 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) * Likewise for the validator, if required; but we don't care about * its return type. */ - if (pltemplate->lanvalidator) + if (pltemplate->tmplvalidator) { - funcname = SystemFuncName(pltemplate->lanvalidator); + funcname = SystemFuncName(pltemplate->tmplvalidator); funcargtypes[0] = OIDOID; valOid = LookupFuncName(funcname, 1, funcargtypes, true); if (!OidIsValid(valOid)) { - valOid = ProcedureCreate(pltemplate->lanvalidator, + valOid = ProcedureCreate(pltemplate->tmplvalidator, PG_CATALOG_NAMESPACE, false, /* replace */ false, /* returnsSet */ VOIDOID, ClanguageId, F_FMGR_C_VALIDATOR, - pltemplate->lanvalidator, - pltemplate->lanlibrary, + pltemplate->tmplvalidator, + pltemplate->tmpllibrary, false, /* isAgg */ false, /* security_definer */ false, /* isStrict */ @@ -162,7 +170,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) /* ok, create it */ create_proc_lang(languageName, handlerOid, valOid, - pltemplate->lantrusted); + pltemplate->tmpltrusted); } else { @@ -170,17 +178,13 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) * No template, so use the provided information. If there's * no handler clause, the user is trying to rely on a template * that we don't have, so complain accordingly. - * - * XXX In 8.2, replace the detail message with a hint to look in - * pg_pltemplate. */ if (!stmt->plhandler) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unsupported language \"%s\"", languageName), - errdetail("Supported languages are plpgsql, pltcl, pltclu, " - "plperl, plperlu, and plpythonu."))); + errhint("The supported languages are listed in the pg_pltemplate system catalog."))); /* * Lookup the PL handler function and check that it is of the expected @@ -291,41 +295,76 @@ create_proc_lang(const char *languageName, /* * Look to see if we have template information for the given language name. - * - * XXX for PG 8.1, the template info is hard-wired. This is to be replaced - * by a shared system catalog in 8.2. - * - * XXX if you add languages to this list, add them also to the errdetail - * message above and the list in functioncmds.c. Those hard-wired lists - * should go away in 8.2, also. */ static PLTemplate * find_language_template(const char *languageName) { - static PLTemplate templates[] = { - { "plpgsql", true, "plpgsql_call_handler", "plpgsql_validator", - "$libdir/plpgsql" }, - { "pltcl", true, "pltcl_call_handler", NULL, - "$libdir/pltcl" }, - { "pltclu", false, "pltclu_call_handler", NULL, - "$libdir/pltcl" }, - { "plperl", true, "plperl_call_handler", "plperl_validator", - "$libdir/plperl" }, - { "plperlu", false, "plperl_call_handler", "plperl_validator", - "$libdir/plperl" }, - { "plpythonu", false, "plpython_call_handler", NULL, - "$libdir/plpython" }, - { NULL, false, NULL, NULL, NULL } - }; + PLTemplate *result; + Relation rel; + SysScanDesc scan; + ScanKeyData key; + HeapTuple tup; - PLTemplate *ptr; + rel = heap_open(PLTemplateRelationId, AccessShareLock); - for (ptr = templates; ptr->lanname != NULL; ptr++) + ScanKeyInit(&key, + Anum_pg_pltemplate_tmplname, + BTEqualStrategyNumber, F_NAMEEQ, + NameGetDatum(languageName)); + scan = systable_beginscan(rel, PLTemplateNameIndexId, true, + SnapshotNow, 1, &key); + + tup = systable_getnext(scan); + if (HeapTupleIsValid(tup)) { - if (strcmp(languageName, ptr->lanname) == 0) - return ptr; + Form_pg_pltemplate tmpl = (Form_pg_pltemplate) GETSTRUCT(tup); + Datum datum; + bool isnull; + + result = (PLTemplate *) palloc0(sizeof(PLTemplate)); + result->tmpltrusted = tmpl->tmpltrusted; + + /* Remaining fields are variable-width so we need heap_getattr */ + datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler, + RelationGetDescr(rel), &isnull); + if (!isnull) + result->tmplhandler = + DatumGetCString(DirectFunctionCall1(textout, datum)); + + datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator, + RelationGetDescr(rel), &isnull); + if (!isnull) + result->tmplvalidator = + DatumGetCString(DirectFunctionCall1(textout, datum)); + + datum = heap_getattr(tup, Anum_pg_pltemplate_tmpllibrary, + RelationGetDescr(rel), &isnull); + if (!isnull) + result->tmpllibrary = + DatumGetCString(DirectFunctionCall1(textout, datum)); + + /* Ignore template if handler or library info is missing */ + if (!result->tmplhandler || !result->tmpllibrary) + result = NULL; } - return NULL; + else + result = NULL; + + systable_endscan(scan); + + heap_close(rel, AccessShareLock); + + return result; +} + + +/* + * This just returns TRUE if we have a valid template for a given language + */ +bool +PLTemplateExists(const char *languageName) +{ + return (find_language_template(languageName) != NULL); } diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 3b3b792847..745975a2b5 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.300 2005/08/15 23:00:14 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.301 2005/09/08 20:07:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200508152 +#define CATALOG_VERSION_NO 200509081 #endif diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 0c4c095e40..bb4ce868fb 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.90 2005/07/14 05:13:42 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.91 2005/09/08 20:07:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -93,6 +93,9 @@ DECLARE_UNIQUE_INDEX(pg_auth_members_role_member_index,2694, on pg_auth_members DECLARE_UNIQUE_INDEX(pg_auth_members_member_role_index,2695, on pg_auth_members using btree(member oid_ops, roleid oid_ops)); #define AuthMemMemRoleIndexId 2695 +DECLARE_UNIQUE_INDEX(pg_autovacuum_vacrelid_index,1250, on pg_autovacuum using btree(vacrelid oid_ops)); +#define AutovacuumRelidIndexId 1250 + DECLARE_UNIQUE_INDEX(pg_cast_oid_index,2660, on pg_cast using btree(oid oid_ops)); #define CastOidIndexId 2660 DECLARE_UNIQUE_INDEX(pg_cast_source_target_index,2661, on pg_cast using btree(castsource oid_ops, casttarget oid_ops)); @@ -169,6 +172,9 @@ DECLARE_UNIQUE_INDEX(pg_operator_oid_index,2688, on pg_operator using btree(oid DECLARE_UNIQUE_INDEX(pg_operator_oprname_l_r_n_index,2689, on pg_operator using btree(oprname name_ops, oprleft oid_ops, oprright oid_ops, oprnamespace oid_ops)); #define OperatorNameNspIndexId 2689 +DECLARE_UNIQUE_INDEX(pg_pltemplate_name_index,1137, on pg_pltemplate using btree(tmplname name_ops)); +#define PLTemplateNameIndexId 1137 + DECLARE_UNIQUE_INDEX(pg_proc_oid_index,2690, on pg_proc using btree(oid oid_ops)); #define ProcedureOidIndexId 2690 DECLARE_UNIQUE_INDEX(pg_proc_proname_args_nsp_index,2691, on pg_proc using btree(proname name_ops, proargtypes oidvector_ops, pronamespace oid_ops)); @@ -210,9 +216,6 @@ DECLARE_UNIQUE_INDEX(pg_type_oid_index,2703, on pg_type using btree(oid oid_ops) DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index,2704, on pg_type using btree(typname name_ops, typnamespace oid_ops)); #define TypeNameNspIndexId 2704 -DECLARE_UNIQUE_INDEX(pg_autovacuum_vacrelid_index,1250, on pg_autovacuum using btree(vacrelid oid_ops)); -#define AutovacuumRelidIndexId 1250 - /* last step of initialization script: build the indexes declared above */ BUILD_INDICES diff --git a/src/include/catalog/pg_pltemplate.h b/src/include/catalog/pg_pltemplate.h new file mode 100644 index 0000000000..3c4ff9f868 --- /dev/null +++ b/src/include/catalog/pg_pltemplate.h @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------------- + * + * pg_pltemplate.h + * definition of the system "PL template" relation (pg_pltemplate) + * along with the relation's initial contents. + * + * + * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.1 2005/09/08 20:07:42 tgl Exp $ + * + * NOTES + * the genbki.sh script reads this file and generates .bki + * information from the DATA() statements. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_PLTEMPLATE_H +#define PG_PLTEMPLATE_H + +/* ---------------- + * postgres.h contains the system type definitions and the + * CATALOG(), BKI_BOOTSTRAP and DATA() sugar words so this file + * can be read by both genbki.sh and the C compiler. + * ---------------- + */ + +/* ---------------- + * pg_pltemplate definition. cpp turns this into + * typedef struct FormData_pg_pltemplate + * ---------------- + */ +#define PLTemplateRelationId 1136 + +CATALOG(pg_pltemplate,1136) BKI_SHARED_RELATION BKI_WITHOUT_OIDS +{ + NameData tmplname; /* name of PL */ + bool tmpltrusted; /* PL is trusted? */ + text tmplhandler; /* name of call handler function */ + text tmplvalidator; /* name of validator function, or NULL */ + text tmpllibrary; /* path of shared library */ + aclitem tmplacl[1]; /* access privileges for template */ +} FormData_pg_pltemplate; + +/* ---------------- + * Form_pg_pltemplate corresponds to a pointer to a row with + * the format of pg_pltemplate relation. + * ---------------- + */ +typedef FormData_pg_pltemplate *Form_pg_pltemplate; + +/* ---------------- + * compiler constants for pg_pltemplate + * ---------------- + */ +#define Natts_pg_pltemplate 6 +#define Anum_pg_pltemplate_tmplname 1 +#define Anum_pg_pltemplate_tmpltrusted 2 +#define Anum_pg_pltemplate_tmplhandler 3 +#define Anum_pg_pltemplate_tmplvalidator 4 +#define Anum_pg_pltemplate_tmpllibrary 5 +#define Anum_pg_pltemplate_tmplacl 6 + + +/* ---------------- + * initial contents of pg_pltemplate + * ---------------- + */ + +DATA(insert ( "plpgsql" t "plpgsql_call_handler" "plpgsql_validator" "$libdir/plpgsql" _null_ )); +DATA(insert ( "pltcl" t "pltcl_call_handler" _null_ "$libdir/pltcl" _null_ )); +DATA(insert ( "pltclu" f "pltclu_call_handler" _null_ "$libdir/pltcl" _null_ )); +DATA(insert ( "plperl" t "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ )); +DATA(insert ( "plperlu" f "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ )); +DATA(insert ( "plpythonu" f "plpython_call_handler" _null_ "$libdir/plpython" _null_ )); + +#endif /* PG_PLTEMPLATE_H */ diff --git a/src/include/commands/proclang.h b/src/include/commands/proclang.h index a446773cd4..7f38a8542a 100644 --- a/src/include/commands/proclang.h +++ b/src/include/commands/proclang.h @@ -15,5 +15,6 @@ extern void CreateProceduralLanguage(CreatePLangStmt *stmt); extern void DropProceduralLanguage(DropPLangStmt *stmt); extern void DropProceduralLanguageById(Oid langOid); extern void RenameLanguage(const char *oldname, const char *newname); +extern bool PLTemplateExists(const char *languageName); #endif /* PROCLANG_H */ diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index a6210a1705..250de98595 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -55,6 +55,7 @@ SELECT relname, relhasindex pg_namespace | t pg_opclass | t pg_operator | t + pg_pltemplate | t pg_proc | t pg_rewrite | t pg_shdepend | t @@ -67,7 +68,7 @@ SELECT relname, relhasindex shighway | t tenk1 | t tenk2 | t -(57 rows) +(58 rows) -- -- another sanity check: every system catalog that has OIDs should have