From c06f6a6bc2bce09df9b945ac29de152daec0dcf7 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 27 Apr 2002 21:24:34 +0000 Subject: [PATCH] Support toasting of shared system relations, and provide toast tables for pg_database, pg_shadow, pg_group, all of which now have potentially-long fields. Along the way, get rid of SharedSystemRelationNames list: shared rels are now identified in their include/pg_catalog/*.h files by a BKI_SHARED_RELATION macro, while indexes and toast rels inherit sharedness automatically from their parent table. Fix some bugs with failure to detoast pg_group.grolist during ALTER GROUP. --- src/backend/bootstrap/bootparse.y | 52 +-- src/backend/bootstrap/bootscanner.l | 5 +- src/backend/bootstrap/bootstrap.c | 40 ++- src/backend/catalog/README | 11 +- src/backend/catalog/catalog.c | 25 +- src/backend/catalog/genbki.sh | 9 +- src/backend/catalog/heap.c | 28 +- src/backend/catalog/index.c | 56 ++- src/backend/commands/cluster.c | 3 +- src/backend/commands/dbcommands.c | 40 ++- src/backend/commands/tablecmds.c | 19 +- src/backend/commands/user.c | 528 +++++++++++----------------- src/backend/executor/execMain.c | 3 +- src/backend/utils/cache/relcache.c | 23 +- src/backend/utils/init/globals.c | 37 +- src/backend/utils/init/miscinit.c | 5 +- src/backend/utils/init/postinit.c | 7 +- src/bin/initdb/initdb.sh | 5 +- src/include/bootstrap/bootstrap.h | 4 +- src/include/catalog/catalog.h | 3 +- src/include/catalog/catname.h | 4 +- src/include/catalog/catversion.h | 4 +- src/include/catalog/heap.h | 4 +- src/include/catalog/pg_database.h | 4 +- src/include/catalog/pg_group.h | 4 +- src/include/catalog/pg_shadow.h | 7 +- src/include/postgres.h | 4 +- 27 files changed, 403 insertions(+), 531 deletions(-) diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index e98eae3a42..e6250d0c50 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -1,15 +1,15 @@ %{ /*------------------------------------------------------------------------- * - * backendparse.y - * yacc parser grammer for the "backend" initialization program. + * bootparse.y + * yacc parser grammar for the "backend" initialization program. * * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.45 2002/04/17 20:57:56 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.46 2002/04/27 21:24:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -88,8 +88,9 @@ int num_columns_read = 0; %type boot_index_params %type boot_index_param -%type boot_const boot_ident -%type optbootstrap optwithoutoids boot_tuple boot_tuplelist +%type boot_const boot_ident +%type optbootstrap optsharedrelation optwithoutoids +%type boot_tuple boot_tuplelist %type optoideq %token CONST ID @@ -97,7 +98,7 @@ int num_columns_read = 0; %token STRING XDEFINE %token XDECLARE INDEX ON USING XBUILD INDICES UNIQUE %token COMMA EQUALS LPAREN RPAREN -%token OBJ_ID XBOOTSTRAP XWITHOUT_OIDS NULLVAL +%token OBJ_ID XBOOTSTRAP XSHARED_RELATION XWITHOUT_OIDS NULLVAL %start TopLevel %nonassoc low @@ -150,16 +151,14 @@ Boot_CloseStmt: ; Boot_CreateStmt: - XCREATE optbootstrap optwithoutoids boot_ident LPAREN + XCREATE optbootstrap optsharedrelation optwithoutoids boot_ident LPAREN { do_start(); numattr = 0; - if ($2) - elog(DEBUG3, "creating bootstrap relation %s...", - LexIDStr($4)); - else - elog(DEBUG3, "creating relation %s...", - LexIDStr($4)); + elog(DEBUG3, "creating%s%s relation %s...", + $2 ? " bootstrap" : "", + $3 ? " shared" : "", + LexIDStr($5)); } boot_typelist { @@ -171,21 +170,22 @@ Boot_CreateStmt: if ($2) { - extern Relation reldesc; TupleDesc tupdesc; - if (reldesc) + if (boot_reldesc) { elog(DEBUG3, "create bootstrap: warning, open relation exists, closing first"); closerel(NULL); } tupdesc = CreateTupleDesc(numattr, attrtypes); - reldesc = heap_create(LexIDStr($4), - PG_CATALOG_NAMESPACE, - tupdesc, - true, true); - reldesc->rd_rel->relhasoids = ! ($3); + boot_reldesc = heap_create(LexIDStr($5), + PG_CATALOG_NAMESPACE, + tupdesc, + $3, + true, + true); + boot_reldesc->rd_rel->relhasoids = ! ($4); elog(DEBUG3, "bootstrap relation created"); } else @@ -194,11 +194,12 @@ Boot_CreateStmt: TupleDesc tupdesc; tupdesc = CreateTupleDesc(numattr,attrtypes); - id = heap_create_with_catalog(LexIDStr($4), + id = heap_create_with_catalog(LexIDStr($5), PG_CATALOG_NAMESPACE, tupdesc, RELKIND_RELATION, - ! ($3), + $3, + ! ($4), true); elog(DEBUG3, "relation created with oid %u", id); } @@ -221,7 +222,7 @@ Boot_InsertStmt: if (num_columns_read != numattr) elog(ERROR, "incorrect number of columns in row (expected %d, got %d)", numattr, num_columns_read); - if (reldesc == (Relation)NULL) + if (boot_reldesc == (Relation) NULL) { elog(ERROR, "relation not open"); err_out(); @@ -283,6 +284,11 @@ optbootstrap: | { $$ = 0; } ; +optsharedrelation: + XSHARED_RELATION { $$ = 1; } + | { $$ = 0; } + ; + optwithoutoids: XWITHOUT_OIDS { $$ = 1; } | { $$ = 0; } diff --git a/src/backend/bootstrap/bootscanner.l b/src/backend/bootstrap/bootscanner.l index 47f0c8c131..b471dcc66e 100644 --- a/src/backend/bootstrap/bootscanner.l +++ b/src/backend/bootstrap/bootscanner.l @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootscanner.l,v 1.21 2001/08/10 18:57:33 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootscanner.l,v 1.22 2002/04/27 21:24:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -71,6 +71,8 @@ create { return(XCREATE); } OID { return(OBJ_ID); } bootstrap { return(XBOOTSTRAP); } +"shared_relation" { return(XSHARED_RELATION); } +"without_oids" { return(XWITHOUT_OIDS); } _null_ { return(NULLVAL); } insert { return(INSERT_TUPLE); } @@ -94,7 +96,6 @@ insert { return(INSERT_TUPLE); } "index" { return(INDEX); } "on" { return(ON); } "using" { return(USING); } -"without_oids" { return(XWITHOUT_OIDS); } {arrayid} { yylval.ival = EnterString(MapArrayTypeName((char*)yytext)); diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 07d013232c..6028b2db48 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.126 2002/04/25 02:56:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.127 2002/04/27 21:24:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -59,6 +59,9 @@ static void cleanup(void); * global variables * ---------------- */ + +Relation boot_reldesc; /* current relation descriptor */ + /* * In the lexical analyzer, we need to get the reference number quickly from * the string, and the string from the reference number. Thus we have @@ -500,20 +503,20 @@ boot_openrel(char *relname) heap_close(rel, NoLock); } - if (reldesc != NULL) + if (boot_reldesc != NULL) closerel(NULL); elog(DEBUG3, "open relation %s, attrsize %d", relname ? relname : "(null)", (int) ATTRIBUTE_TUPLE_SIZE); - reldesc = heap_openr(relname, NoLock); - numattr = reldesc->rd_rel->relnatts; + boot_reldesc = heap_openr(relname, NoLock); + numattr = boot_reldesc->rd_rel->relnatts; for (i = 0; i < numattr; i++) { if (attrtypes[i] == NULL) attrtypes[i] = AllocateAttribute(); memmove((char *) attrtypes[i], - (char *) reldesc->rd_att->attrs[i], + (char *) boot_reldesc->rd_att->attrs[i], ATTRIBUTE_TUPLE_SIZE); /* Some old pg_attribute tuples might not have attisset. */ @@ -523,8 +526,9 @@ boot_openrel(char *relname) * defined yet. */ if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0) - attrtypes[i]->attisset = get_attisset(RelationGetRelid(reldesc), - NameStr(attrtypes[i]->attname)); + attrtypes[i]->attisset = + get_attisset(RelationGetRelid(boot_reldesc), + NameStr(attrtypes[i]->attname)); else attrtypes[i]->attisset = false; @@ -547,9 +551,9 @@ closerel(char *name) { if (name) { - if (reldesc) + if (boot_reldesc) { - if (strcmp(RelationGetRelationName(reldesc), name) != 0) + if (strcmp(RelationGetRelationName(boot_reldesc), name) != 0) elog(ERROR, "closerel: close of '%s' when '%s' was expected", name, relname ? relname : "(null)"); } @@ -559,13 +563,13 @@ closerel(char *name) } - if (reldesc == NULL) + if (boot_reldesc == NULL) elog(ERROR, "no open relation to close"); else { elog(DEBUG3, "close relation %s", relname ? relname : "(null)"); - heap_close(reldesc, NoLock); - reldesc = (Relation) NULL; + heap_close(boot_reldesc, NoLock); + boot_reldesc = (Relation) NULL; } } @@ -585,7 +589,7 @@ DefineAttr(char *name, char *type, int attnum) int attlen; Oid typeoid; - if (reldesc != NULL) + if (boot_reldesc != NULL) { elog(LOG, "warning: no open relations allowed with 'create' command"); closerel(relname); @@ -674,7 +678,7 @@ InsertOneTuple(Oid objectid) if (objectid != (Oid) 0) tuple->t_data->t_oid = objectid; - heap_insert(reldesc, tuple); + heap_insert(boot_reldesc, tuple); heap_freetuple(tuple); elog(DEBUG3, "row inserted"); @@ -706,13 +710,13 @@ InsertOneValue(char *value, int i) elog(DEBUG3, "Typ != NULL"); app = Typ; - while (*app && (*app)->am_oid != reldesc->rd_att->attrs[i]->atttypid) + while (*app && (*app)->am_oid != boot_reldesc->rd_att->attrs[i]->atttypid) ++app; ap = *app; if (ap == NULL) { elog(FATAL, "unable to find atttypid %u in Typ list", - reldesc->rd_att->attrs[i]->atttypid); + boot_reldesc->rd_att->attrs[i]->atttypid); } values[i] = OidFunctionCall3(ap->am_typ.typinput, CStringGetDatum(value), @@ -806,8 +810,8 @@ cleanup() elog(FATAL, "Memory manager fault: cleanup called twice.\n"); proc_exit(1); } - if (reldesc != (Relation) NULL) - heap_close(reldesc, NoLock); + if (boot_reldesc != (Relation) NULL) + heap_close(boot_reldesc, NoLock); CommitTransactionCommand(); proc_exit(Warnings); } diff --git a/src/backend/catalog/README b/src/backend/catalog/README index 26dac4892a..2a688eda1b 100644 --- a/src/backend/catalog/README +++ b/src/backend/catalog/README @@ -1,4 +1,4 @@ -$Header: /cvsroot/pgsql/src/backend/catalog/README,v 1.6 2002/04/15 23:46:13 momjian Exp $ +$Header: /cvsroot/pgsql/src/backend/catalog/README,v 1.7 2002/04/27 21:24:33 tgl Exp $ This directory contains .c files that manipulate the system catalogs; src/include/catalog contains the .h files that define the structure @@ -69,15 +69,14 @@ manually create appropriate entries for them in the pre-loaded contents of pg_class, pg_attribute, and pg_type. You'll also need to add code to function heap_create() in heap.c to force the correct OID to be assigned when the table is first referenced. (It's near the top of the function with the comment -beginning in 'Real ugly stuff'.) Avoid making new catalogs be bootstrap +beginning in "Real ugly stuff".) Avoid making new catalogs be bootstrap catalogs if at all possible; generally, only tables that must be written to in order to create a table should be bootstrapped. - Certain BOOTSTRAP tables must be at the start of the Makefile -POSTGRES_BKI_SRCS variable, as these will not be created through standard -function means, but will be written directly to disk. That's how pg_class is -created without depending on functions which depend on the existence of -pg_class. The list of files this currently includes is: +POSTGRES_BKI_SRCS variable, as these will not be created through the standard +heap_create_with_catalog process, because it needs these tables to exist +already. The list of files this currently includes is: pg_proc.h pg_type.h pg_attribute.h pg_class.h Also, indexing.h must be last, since the indexes can't be created until all the tables are in place. There are reputedly some other order dependencies diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index 6e19877275..251ecacf2f 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.45 2002/04/12 20:38:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.46 2002/04/27 21:24:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -177,29 +177,6 @@ IsReservedName(const char *name) name[2] == '_'); } -/* - * IsSharedSystemRelationName - * True iff name is the name of a shared system catalog relation. - * - * Note: This function assumes that this is a system relation - * in the first place. If that is not known, check the namespace - * (with IsSystemNamespace) before calling this function. - */ -bool -IsSharedSystemRelationName(const char *relname) -{ - int i; - - i = 0; - while (SharedSystemRelationNames[i] != NULL) - { - if (strcmp(SharedSystemRelationNames[i], relname) == 0) - return TRUE; - i++; - } - return FALSE; -} - /* * newoid - returns a unique identifier across all catalogs. diff --git a/src/backend/catalog/genbki.sh b/src/backend/catalog/genbki.sh index 4edb86cdba..94db1c6518 100644 --- a/src/backend/catalog/genbki.sh +++ b/src/backend/catalog/genbki.sh @@ -10,7 +10,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/catalog/Attic/genbki.sh,v 1.26 2002/03/26 19:15:24 tgl Exp $ +# $Header: /cvsroot/pgsql/src/backend/catalog/Attic/genbki.sh,v 1.27 2002/04/27 21:24:33 tgl Exp $ # # NOTES # non-essential whitespace is removed from the generated file. @@ -217,6 +217,7 @@ BEGIN { inside = 0; raw = 0; bootstrap = ""; + shared_relation = ""; without_oids = ""; nc = 0; reln_open = 0; @@ -331,6 +332,9 @@ raw == 1 { print; next; } if ($0 ~ /BOOTSTRAP/) { bootstrap = "bootstrap "; } + if ($0 ~ /BKI_SHARED_RELATION/) { + shared_relation = "shared_relation "; + } if ($0 ~ /BKI_WITHOUT_OIDS/) { without_oids = "without_oids "; } @@ -358,7 +362,7 @@ inside == 1 { # if this is the last line, then output the bki catalog stuff. # ---- if ($1 ~ /}/) { - print "create " bootstrap without_oids catalog; + print "create " bootstrap shared_relation without_oids catalog; print "\t("; for (j=1; jrd_att->attrs[0]->attrelid; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index d563d65418..cc17b71923 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.176 2002/04/12 20:38:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.177 2002/04/27 21:24:34 tgl Exp $ * * * INTERFACE ROUTINES @@ -67,7 +67,6 @@ static TupleDesc BuildFuncTupleDesc(Oid funcOid, static TupleDesc ConstructTupleDescriptor(Relation heapRelation, int numatts, AttrNumber *attNums, Oid *classObjectId); -static void ConstructIndexReldesc(Relation indexRelation, Oid amoid); static void UpdateRelationRelation(Relation indexRelation); static void InitializeAttributeOids(Relation indexRelation, int numatts, Oid indexoid); @@ -305,26 +304,6 @@ ConstructTupleDescriptor(Relation heapRelation, return indexTupDesc; } -/* ---------------------------------------------------------------- - * ConstructIndexReldesc - * ---------------------------------------------------------------- - */ -static void -ConstructIndexReldesc(Relation indexRelation, Oid amoid) -{ - /* - * Set up some additional fields of the index' pg_class entry. In - * particular, initialize knowledge of whether the index is shared. - */ - indexRelation->rd_rel->relowner = GetUserId(); - indexRelation->rd_rel->relam = amoid; - indexRelation->rd_rel->relisshared = - IsSystemNamespace(RelationGetNamespace(indexRelation)) && - IsSharedSystemRelationName(RelationGetRelationName(indexRelation)); - indexRelation->rd_rel->relkind = RELKIND_INDEX; - indexRelation->rd_rel->relhasoids = false; -} - /* ---------------------------------------------------------------- * UpdateRelationRelation * ---------------------------------------------------------------- @@ -561,6 +540,7 @@ index_create(Oid heapRelationId, Relation heapRelation; Relation indexRelation; TupleDesc indexTupDesc; + bool shared_relation; Oid namespaceId; Oid indexoid; @@ -571,7 +551,12 @@ index_create(Oid heapRelationId, */ heapRelation = heap_open(heapRelationId, ShareLock); + /* + * The index will be in the same namespace as its parent table, + * and is shared across databases if and only if the parent is. + */ namespaceId = RelationGetNamespace(heapRelation); + shared_relation = heapRelation->rd_rel->relisshared; /* * check parameters @@ -585,6 +570,16 @@ index_create(Oid heapRelationId, IsNormalProcessingMode()) elog(ERROR, "User-defined indexes on system catalogs are not supported"); + /* + * We cannot allow indexing a shared relation after initdb (because + * there's no way to make the entry in other databases' pg_class). + * Unfortunately we can't distinguish initdb from a manually started + * standalone backend. However, we can at least prevent this mistake + * under normal multi-user operation. + */ + if (shared_relation && IsUnderPostmaster) + elog(ERROR, "Shared indexes cannot be created after initdb"); + if (get_relname_relid(indexRelationName, namespaceId)) elog(ERROR, "index named \"%s\" already exists", indexRelationName); @@ -607,6 +602,7 @@ index_create(Oid heapRelationId, indexRelation = heap_create(indexRelationName, namespaceId, indexTupDesc, + shared_relation, false, allow_system_table_mods); indexoid = RelationGetRelid(indexRelation); @@ -619,16 +615,18 @@ index_create(Oid heapRelationId, LockRelation(indexRelation, AccessExclusiveLock); /* - * construct the index relation descriptor + * Fill in fields of the index's pg_class entry that are not set + * correctly by heap_create. * - * XXX should have a proper way to create cataloged relations + * XXX should have a cleaner way to create cataloged indexes */ - ConstructIndexReldesc(indexRelation, accessMethodObjectId); + indexRelation->rd_rel->relowner = GetUserId(); + indexRelation->rd_rel->relam = accessMethodObjectId; + indexRelation->rd_rel->relkind = RELKIND_INDEX; + indexRelation->rd_rel->relhasoids = false; - /* ---------------- - * add index to catalogs - * (append RELATION tuple) - * ---------------- + /* + * store index's pg_class entry */ UpdateRelationRelation(indexRelation); diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 8883eddc49..01a45b0625 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.78 2002/04/15 05:22:03 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.79 2002/04/27 21:24:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -152,6 +152,7 @@ copy_heap(Oid OIDOldHeap, const char *NewName) RelationGetNamespace(OldHeap), tupdesc, OldHeap->rd_rel->relkind, + OldHeap->rd_rel->relisshared, OldHeap->rd_rel->relhasoids, allowSystemTableMods); diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 9b5c47969a..41f122767a 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.87 2002/04/21 00:26:42 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.88 2002/04/27 21:24:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -475,11 +475,14 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) elog(ERROR, "permission denied"); MemSet(repl_repl, ' ', sizeof(repl_repl)); - repl_repl[Anum_pg_database_datconfig-1] = 'r'; + if (strcmp(stmt->variable, "all")==0 && stmt->value == NULL) + { /* RESET ALL */ repl_null[Anum_pg_database_datconfig-1] = 'n'; + repl_val[Anum_pg_database_datconfig-1] = (Datum) 0; + } else { Datum datum; @@ -491,16 +494,12 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) datum = heap_getattr(tuple, Anum_pg_database_datconfig, RelationGetDescr(rel), &isnull); + a = isnull ? ((ArrayType *) NULL) : DatumGetArrayTypeP(datum); + if (valuestr) - a = GUCArrayAdd(isnull - ? NULL - : (ArrayType *) pg_detoast_datum((struct varlena *)datum), - stmt->variable, valuestr); + a = GUCArrayAdd(a, stmt->variable, valuestr); else - a = GUCArrayDelete(isnull - ? NULL - : (ArrayType *) pg_detoast_datum((struct varlena *)datum), - stmt->variable); + a = GUCArrayDelete(a, stmt->variable); repl_val[Anum_pg_database_datconfig-1] = PointerGetDatum(a); } @@ -546,8 +545,6 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP, if (gottuple) { Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple); - text *tmptext; - bool isnull; /* oid of the database */ if (dbIdP) @@ -573,16 +570,21 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP, /* database path (as registered in pg_database) */ if (dbpath) { - tmptext = DatumGetTextP(heap_getattr(tuple, - Anum_pg_database_datpath, - RelationGetDescr(relation), - &isnull)); + Datum datum; + bool isnull; + + datum = heap_getattr(tuple, + Anum_pg_database_datpath, + RelationGetDescr(relation), + &isnull); if (!isnull) { - Assert(VARSIZE(tmptext) - VARHDRSZ < MAXPGPATH); + text *pathtext = DatumGetTextP(datum); + int pathlen = VARSIZE(pathtext) - VARHDRSZ; - strncpy(dbpath, VARDATA(tmptext), VARSIZE(tmptext) - VARHDRSZ); - *(dbpath + VARSIZE(tmptext) - VARHDRSZ) = '\0'; + Assert(pathlen >= 0 && pathlen < MAXPGPATH); + strncpy(dbpath, VARDATA(pathtext), pathlen); + *(dbpath + pathlen) = '\0'; } else strcpy(dbpath, ""); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 32930710c6..79b54aa7a5 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.11 2002/04/27 03:45:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.12 2002/04/27 21:24:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -200,6 +200,7 @@ DefineRelation(CreateStmt *stmt, char relkind) namespaceId, descriptor, relkind, + false, stmt->hasoids || parentHasOids, allowSystemTableMods); @@ -2840,6 +2841,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent) HeapTuple reltup; HeapTupleData classtuple; TupleDesc tupdesc; + bool shared_relation; Relation class_rel; Buffer buffer; Relation ridescs[Num_pg_class_indices]; @@ -2856,6 +2858,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent) */ rel = heap_open(relOid, AccessExclusiveLock); + /* Check permissions */ if (rel->rd_rel->relkind != RELKIND_RELATION) elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", RelationGetRelationName(rel)); @@ -2863,6 +2866,19 @@ AlterTableCreateToastTable(Oid relOid, bool silent) if (!pg_class_ownercheck(relOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel)); + /* + * Toast table is shared if and only if its parent is. + * + * We cannot allow toasting a shared relation after initdb (because + * there's no way to mark it toasted in other databases' pg_class). + * Unfortunately we can't distinguish initdb from a manually started + * standalone backend. However, we can at least prevent this mistake + * under normal multi-user operation. + */ + shared_relation = rel->rd_rel->relisshared; + if (shared_relation && IsUnderPostmaster) + elog(ERROR, "Shared relations cannot be toasted after initdb"); + /* * lock the pg_class tuple for update (is that really needed?) */ @@ -2962,6 +2978,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent) PG_TOAST_NAMESPACE, tupdesc, RELKIND_TOASTVALUE, + shared_relation, false, true); diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 771375b88d..d906c7c236 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.98 2002/04/27 15:30:07 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.99 2002/04/27 21:24:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -40,7 +40,10 @@ extern bool Password_encryption; static void CheckPgUserAclNotNull(void); - +static void UpdateGroupMembership(Relation group_rel, HeapTuple group_tuple, + List *members); +static IdList *IdListToArray(List *members); +static List *IdArrayToList(IdList *oldarray); /* @@ -151,16 +154,11 @@ write_group_file(Relation urel, Relation grel) bool first_user = true; datum = heap_getattr(tuple, Anum_pg_group_groname, dsc, &isnull); - if (isnull) - continue; /* ignore NULL groupnames */ - groname = NameStr(*DatumGetName(datum)); - - grolist_datum = heap_getattr(tuple, Anum_pg_group_grolist, dsc, &isnull); - /* Ignore NULL group lists */ + /* ignore NULL groupnames --- shouldn't happen */ if (isnull) continue; + groname = NameStr(*DatumGetName(datum)); - grolist_p = DatumGetIdListP(grolist_datum); /* * Check for illegal characters in the group name. */ @@ -171,8 +169,15 @@ write_group_file(Relation urel, Relation grel) continue; } + grolist_datum = heap_getattr(tuple, Anum_pg_group_grolist, dsc, &isnull); + /* Ignore NULL group lists */ + if (isnull) + continue; + /* be sure the IdList is not toasted */ - /* scan it */ + grolist_p = DatumGetIdListP(grolist_datum); + + /* scan grolist */ num = IDLIST_NUM(grolist_p); aidp = IDLIST_DAT(grolist_p); for (i = 0; i < num; ++i) @@ -290,8 +295,9 @@ write_user_file(Relation urel) int i; datum = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &isnull); + /* ignore NULL usernames (shouldn't happen) */ if (isnull) - continue; /* ignore NULL usernames */ + continue; usename = NameStr(*DatumGetName(datum)); datum = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &isnull); @@ -516,24 +522,19 @@ CreateUser(CreateUserStmt *stmt) while (!user_exists && !sysid_exists && HeapTupleIsValid(tuple = heap_getnext(scan, 0))) { - Datum datum; - bool null; + Form_pg_shadow shadow_form = (Form_pg_shadow) GETSTRUCT(tuple); + int32 this_sysid; - datum = heap_getattr(tuple, Anum_pg_shadow_usename, - pg_shadow_dsc, &null); - Assert(!null); - user_exists = (strcmp(NameStr(*DatumGetName(datum)), stmt->user) == 0); + user_exists = (strcmp(NameStr(shadow_form->usename), stmt->user) == 0); - datum = heap_getattr(tuple, Anum_pg_shadow_usesysid, - pg_shadow_dsc, &null); - Assert(!null); + this_sysid = shadow_form->usesysid; if (havesysid) /* customized id wanted */ - sysid_exists = (DatumGetInt32(datum) == sysid); + sysid_exists = (this_sysid == sysid); else { /* pick 1 + max */ - if (DatumGetInt32(datum) > max_id) - max_id = DatumGetInt32(datum); + if (this_sysid > max_id) + max_id = this_sysid; } } heap_endscan(scan); @@ -551,10 +552,12 @@ CreateUser(CreateUserStmt *stmt) /* * Build a tuple to insert */ + MemSet(new_record, 0, sizeof(new_record)); + MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); + new_record[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->user)); new_record[Anum_pg_shadow_usesysid - 1] = Int32GetDatum(sysid); - AssertState(BoolIsValid(createdb)); new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb); new_record[Anum_pg_shadow_usetrace - 1] = BoolGetDatum(false); @@ -577,20 +580,14 @@ CreateUser(CreateUserStmt *stmt) DirectFunctionCall1(textin, CStringGetDatum(encrypted_password)); } } + else + new_record_nulls[Anum_pg_shadow_passwd - 1] = 'n'; + if (validUntil) new_record[Anum_pg_shadow_valuntil - 1] = DirectFunctionCall1(nabstimein, CStringGetDatum(validUntil)); - - new_record_nulls[Anum_pg_shadow_usename - 1] = ' '; - new_record_nulls[Anum_pg_shadow_usesysid - 1] = ' '; - - new_record_nulls[Anum_pg_shadow_usecreatedb - 1] = ' '; - new_record_nulls[Anum_pg_shadow_usetrace - 1] = ' '; - new_record_nulls[Anum_pg_shadow_usesuper - 1] = ' '; - new_record_nulls[Anum_pg_shadow_usecatupd - 1] = ' '; - - new_record_nulls[Anum_pg_shadow_passwd - 1] = password ? ' ' : 'n'; - new_record_nulls[Anum_pg_shadow_valuntil - 1] = validUntil ? ' ' : 'n'; + else + new_record_nulls[Anum_pg_shadow_valuntil - 1] = 'n'; new_record_nulls[Anum_pg_shadow_useconfig - 1] = 'n'; @@ -651,11 +648,11 @@ AlterUser(AlterUserStmt *stmt) { Datum new_record[Natts_pg_shadow]; char new_record_nulls[Natts_pg_shadow]; + char new_record_repl[Natts_pg_shadow]; Relation pg_shadow_rel; TupleDesc pg_shadow_dsc; HeapTuple tuple, new_tuple; - bool null; List *option; char *password = NULL; /* PostgreSQL user password */ bool encrypt_password = Password_encryption; /* encrypt password? */ @@ -749,33 +746,23 @@ AlterUser(AlterUserStmt *stmt) elog(ERROR, "ALTER USER: user \"%s\" does not exist", stmt->user); /* - * Build a tuple to update, perusing the information just obtained + * Build an updated tuple, perusing the information just obtained */ + MemSet(new_record, 0, sizeof(new_record)); + MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); + MemSet(new_record_repl, ' ', sizeof(new_record_repl)); + new_record[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->user)); - new_record_nulls[Anum_pg_shadow_usename - 1] = ' '; - - /* sysid - leave as is */ - new_record[Anum_pg_shadow_usesysid - 1] = heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null); - new_record_nulls[Anum_pg_shadow_usesysid - 1] = null ? 'n' : ' '; + new_record_repl[Anum_pg_shadow_usename - 1] = 'r'; /* createdb */ - if (createdb < 0) - { - /* don't change */ - new_record[Anum_pg_shadow_usecreatedb - 1] = heap_getattr(tuple, Anum_pg_shadow_usecreatedb, pg_shadow_dsc, &null); - new_record_nulls[Anum_pg_shadow_usecreatedb - 1] = null ? 'n' : ' '; - } - else + if (createdb >= 0) { new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb > 0); - new_record_nulls[Anum_pg_shadow_usecreatedb - 1] = ' '; + new_record_repl[Anum_pg_shadow_usecreatedb - 1] = 'r'; } - /* trace - leave as is */ - new_record[Anum_pg_shadow_usetrace - 1] = heap_getattr(tuple, Anum_pg_shadow_usetrace, pg_shadow_dsc, &null); - new_record_nulls[Anum_pg_shadow_usetrace - 1] = null ? 'n' : ' '; - /* * createuser (superuser) and catupd * @@ -784,22 +771,13 @@ AlterUser(AlterUserStmt *stmt) * with a situation where no existing superuser can alter the * catalogs, including pg_shadow! */ - if (createuser < 0) - { - /* don't change */ - new_record[Anum_pg_shadow_usesuper - 1] = heap_getattr(tuple, Anum_pg_shadow_usesuper, pg_shadow_dsc, &null); - new_record_nulls[Anum_pg_shadow_usesuper - 1] = null ? 'n' : ' '; - - new_record[Anum_pg_shadow_usecatupd - 1] = heap_getattr(tuple, Anum_pg_shadow_usecatupd, pg_shadow_dsc, &null); - new_record_nulls[Anum_pg_shadow_usecatupd - 1] = null ? 'n' : ' '; - } - else + if (createuser >= 0) { new_record[Anum_pg_shadow_usesuper - 1] = BoolGetDatum(createuser > 0); - new_record_nulls[Anum_pg_shadow_usesuper - 1] = ' '; + new_record_repl[Anum_pg_shadow_usesuper - 1] = 'r'; new_record[Anum_pg_shadow_usecatupd - 1] = BoolGetDatum(createuser > 0); - new_record_nulls[Anum_pg_shadow_usecatupd - 1] = ' '; + new_record_repl[Anum_pg_shadow_usecatupd - 1] = 'r'; } /* password */ @@ -816,14 +794,7 @@ AlterUser(AlterUserStmt *stmt) new_record[Anum_pg_shadow_passwd - 1] = DirectFunctionCall1(textin, CStringGetDatum(encrypted_password)); } - new_record_nulls[Anum_pg_shadow_passwd - 1] = ' '; - } - else - { - /* leave as is */ - new_record[Anum_pg_shadow_passwd - 1] = - heap_getattr(tuple, Anum_pg_shadow_passwd, pg_shadow_dsc, &null); - new_record_nulls[Anum_pg_shadow_passwd - 1] = null ? 'n' : ' '; + new_record_repl[Anum_pg_shadow_passwd - 1] = 'r'; } /* valid until */ @@ -831,22 +802,11 @@ AlterUser(AlterUserStmt *stmt) { new_record[Anum_pg_shadow_valuntil - 1] = DirectFunctionCall1(nabstimein, CStringGetDatum(validUntil)); - new_record_nulls[Anum_pg_shadow_valuntil - 1] = ' '; - } - else - { - /* leave as is */ - new_record[Anum_pg_shadow_valuntil - 1] = - heap_getattr(tuple, Anum_pg_shadow_valuntil, pg_shadow_dsc, &null); - new_record_nulls[Anum_pg_shadow_valuntil - 1] = null ? 'n' : ' '; + new_record_repl[Anum_pg_shadow_valuntil - 1] = 'r'; } - /* leave useconfig as is */ - new_record[Anum_pg_shadow_useconfig - 1] = - heap_getattr(tuple, Anum_pg_shadow_useconfig, pg_shadow_dsc, &null); - new_record_nulls[Anum_pg_shadow_useconfig - 1] = null ? 'n' : ' '; - - new_tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls); + new_tuple = heap_modifytuple(tuple, pg_shadow_rel, new_record, + new_record_nulls, new_record_repl); simple_heap_update(pg_shadow_rel, &tuple->t_self, new_tuple); /* Update indexes */ @@ -876,7 +836,6 @@ AlterUser(AlterUserStmt *stmt) } - /* * ALTER USER ... SET */ @@ -896,6 +855,10 @@ AlterUserSet(AlterUserSetStmt *stmt) ? ((A_Const *) lfirst(stmt->value))->val.val.str : NULL); + /* + * RowExclusiveLock is sufficient, because we don't need to update + * the flat password file. + */ rel = heap_openr(ShadowRelationName, RowExclusiveLock); oldtuple = SearchSysCache(SHADOWNAME, PointerGetDatum(stmt->user), @@ -925,16 +888,12 @@ AlterUserSet(AlterUserSetStmt *stmt) datum = SysCacheGetAttr(SHADOWNAME, oldtuple, Anum_pg_shadow_useconfig, &isnull); + array = isnull ? ((ArrayType *) NULL) : DatumGetArrayTypeP(datum); + if (valuestr) - array = GUCArrayAdd(isnull - ? NULL - : (ArrayType *) pg_detoast_datum((struct varlena *)datum), - stmt->variable, valuestr); + array = GUCArrayAdd(array, stmt->variable, valuestr); else - array = GUCArrayDelete(isnull - ? NULL - : (ArrayType *) pg_detoast_datum((struct varlena *)datum), - stmt->variable); + array = GUCArrayDelete(array, stmt->variable); repl_val[Anum_pg_shadow_useconfig-1] = PointerGetDatum(array); } @@ -982,16 +941,14 @@ DropUser(DropUserStmt *stmt) foreach(item, stmt->users) { + const char *user = strVal(lfirst(item)); HeapTuple tuple, tmp_tuple; Relation pg_rel; TupleDesc pg_dsc; ScanKeyData scankey; HeapScanDesc scan; - Datum datum; - bool null; int32 usesysid; - const char *user = strVal(lfirst(item)); tuple = SearchSysCache(SHADOWNAME, PointerGetDatum(user), @@ -1000,7 +957,7 @@ DropUser(DropUserStmt *stmt) elog(ERROR, "DROP USER: user \"%s\" does not exist%s", user, (length(stmt->users) > 1) ? " (no users removed)" : ""); - usesysid = DatumGetInt32(heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null)); + usesysid = ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid; if (usesysid == GetUserId()) elog(ERROR, "current user cannot be dropped"); @@ -1028,10 +985,7 @@ DropUser(DropUserStmt *stmt) { char *dbname; - datum = heap_getattr(tmp_tuple, Anum_pg_database_datname, - pg_dsc, &null); - Assert(!null); - dbname = NameStr(*DatumGetName(datum)); + dbname = NameStr(((Form_pg_database) GETSTRUCT(tmp_tuple))->datname); elog(ERROR, "DROP USER: user \"%s\" owns database \"%s\", cannot be removed%s", user, dbname, (length(stmt->users) > 1) ? " (no users removed)" : ""); @@ -1066,8 +1020,7 @@ DropUser(DropUserStmt *stmt) AlterGroupStmt ags; /* the group name from which to try to drop the user: */ - datum = heap_getattr(tmp_tuple, Anum_pg_group_groname, pg_dsc, &null); - ags.name = DatumGetCString(DirectFunctionCall1(nameout, datum)); + ags.name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tmp_tuple))->groname)); ags.action = -1; ags.listUsers = makeList1(makeInteger(usesysid)); AlterGroup(&ags, "DROP USER"); @@ -1202,24 +1155,19 @@ CreateGroup(CreateGroupStmt *stmt) while (!group_exists && !sysid_exists && HeapTupleIsValid(tuple = heap_getnext(scan, false))) { - Datum datum; - bool null; + Form_pg_group group_form = (Form_pg_group) GETSTRUCT(tuple); + int32 this_sysid; - datum = heap_getattr(tuple, Anum_pg_group_groname, - pg_group_dsc, &null); - Assert(!null); - group_exists = (strcmp(NameStr(*DatumGetName(datum)), stmt->name) == 0); + group_exists = (strcmp(NameStr(group_form->groname), stmt->name) == 0); - datum = heap_getattr(tuple, Anum_pg_group_grosysid, - pg_group_dsc, &null); - Assert(!null); + this_sysid = group_form->grosysid; if (havesysid) /* customized id wanted */ - sysid_exists = (DatumGetInt32(datum) == sysid); + sysid_exists = (this_sysid == sysid); else { /* pick 1 + max */ - if (DatumGetInt32(datum) > max_id) - max_id = DatumGetInt32(datum); + if (this_sysid > max_id) + max_id = this_sysid; } } heap_endscan(scan); @@ -1231,44 +1179,30 @@ CreateGroup(CreateGroupStmt *stmt) elog(ERROR, "CREATE GROUP: group sysid %d is already assigned", sysid); + if (!havesysid) + sysid = max_id + 1; + /* * Translate the given user names to ids */ foreach(item, userElts) { const char *groupuser = strVal(lfirst(item)); - Value *v; + int32 userid = get_usesysid(groupuser); - v = makeInteger(get_usesysid(groupuser)); - if (!member(v, newlist)) - newlist = lappend(newlist, v); + if (!intMember(userid, newlist)) + newlist = lappendi(newlist, userid); } /* build an array to insert */ if (newlist) - { - int i; - - userarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32)); - userarray->size = ARR_OVERHEAD(1) + length(newlist) * sizeof(int32); - userarray->flags = 0; - ARR_NDIM(userarray) = 1; /* one dimensional array */ - ARR_LBOUND(userarray)[0] = 1; /* axis starts at one */ - ARR_DIMS(userarray)[0] = length(newlist); /* axis is this long */ - /* fill the array */ - i = 0; - foreach(item, newlist) - ((int *) ARR_DATA_PTR(userarray))[i++] = intVal(lfirst(item)); - } + userarray = IdListToArray(newlist); else userarray = NULL; /* * Form a tuple to insert */ - if (!havesysid) - sysid = max_id + 1; - new_record[Anum_pg_group_groname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->name)); new_record[Anum_pg_group_grosysid - 1] = Int32GetDatum(sysid); @@ -1318,6 +1252,11 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag) Relation pg_group_rel; TupleDesc pg_group_dsc; HeapTuple group_tuple; + IdList *oldarray; + Datum datum; + bool null; + List *newlist, + *item; /* * Make sure the user can do this. @@ -1337,6 +1276,14 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag) if (!HeapTupleIsValid(group_tuple)) elog(ERROR, "%s: group \"%s\" does not exist", tag, stmt->name); + /* Fetch old group membership. */ + datum = heap_getattr(group_tuple, Anum_pg_group_grolist, + pg_group_dsc, &null); + oldarray = null ? ((IdList *) NULL) : DatumGetIdListP(datum); + + /* initialize list with old array contents */ + newlist = IdArrayToList(oldarray); + /* * Now decide what to do. */ @@ -1345,49 +1292,18 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag) if (stmt->action == +1) /* add users, might also be invoked by * create user */ { - Datum new_record[Natts_pg_group]; - char new_record_nulls[Natts_pg_group]; - ArrayType *newarray, - *oldarray; - List *newlist = NIL, - *item; - HeapTuple tuple; - bool null = false; - Datum datum = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null); - int i; - - oldarray = (ArrayType *) datum; - Assert(null || ARR_NDIM(oldarray) == 1); - /* first add the old array to the hitherto empty list */ - if (!null) - for (i = ARR_LBOUND(oldarray)[0]; i < ARR_LBOUND(oldarray)[0] + ARR_DIMS(oldarray)[0]; i++) - { - int index, - arrval; - Value *v; - bool valueNull; - - index = i; - arrval = DatumGetInt32(array_ref(oldarray, 1, &index, true /* by value */ , - sizeof(int), 0, &valueNull)); - v = makeInteger(arrval); - /* filter out duplicates */ - if (!member(v, newlist)) - newlist = lappend(newlist, v); - } - /* - * now convert the to be added usernames to sysids and add them to + * convert the to be added usernames to sysids and add them to * the list */ foreach(item, stmt->listUsers) { - Value *v; + int32 sysid; if (strcmp(tag, "ALTER GROUP") == 0) { /* Get the uid of the proposed user to add. */ - v = makeInteger(get_usesysid(strVal(lfirst(item)))); + sysid = get_usesysid(strVal(lfirst(item))); } else if (strcmp(tag, "CREATE USER") == 0) { @@ -1395,16 +1311,16 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag) * in this case we already know the uid and it wouldn't be * in the cache anyway yet */ - v = lfirst(item); + sysid = intVal(lfirst(item)); } else { elog(ERROR, "AlterGroup: unknown tag %s", tag); - v = NULL; /* keep compiler quiet */ + sysid = 0; /* keep compiler quiet */ } - if (!member(v, newlist)) - newlist = lappend(newlist, v); + if (!intMember(sysid, newlist)) + newlist = lappendi(newlist, sysid); else /* * we silently assume here that this error will only come @@ -1414,147 +1330,47 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag) tag, strVal(lfirst(item)), stmt->name); } - newarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32)); - newarray->size = ARR_OVERHEAD(1) + length(newlist) * sizeof(int32); - newarray->flags = 0; - ARR_NDIM(newarray) = 1; /* one dimensional array */ - ARR_LBOUND(newarray)[0] = 1; /* axis starts at one */ - ARR_DIMS(newarray)[0] = length(newlist); /* axis is this long */ - /* fill the array */ - i = 0; - foreach(item, newlist) - ((int *) ARR_DATA_PTR(newarray))[i++] = intVal(lfirst(item)); - - /* - * Form a tuple with the new array and write it back. - */ - new_record[Anum_pg_group_groname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->name)); - new_record_nulls[Anum_pg_group_groname - 1] = ' '; - new_record[Anum_pg_group_grosysid - 1] = heap_getattr(group_tuple, Anum_pg_group_grosysid, pg_group_dsc, &null); - new_record_nulls[Anum_pg_group_grosysid - 1] = null ? 'n' : ' '; - new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(newarray); - new_record_nulls[Anum_pg_group_grolist - 1] = newarray ? ' ' : 'n'; - - tuple = heap_formtuple(pg_group_dsc, new_record, new_record_nulls); - simple_heap_update(pg_group_rel, &group_tuple->t_self, tuple); - - /* Update indexes */ - if (RelationGetForm(pg_group_rel)->relhasindex) - { - Relation idescs[Num_pg_group_indices]; - - CatalogOpenIndices(Num_pg_group_indices, - Name_pg_group_indices, idescs); - CatalogIndexInsert(idescs, Num_pg_group_indices, pg_group_rel, - tuple); - CatalogCloseIndices(Num_pg_group_indices, idescs); - } + /* Do the update */ + UpdateGroupMembership(pg_group_rel, group_tuple, newlist); } /* endif alter group add user */ else if (stmt->action == -1) /* drop users from group */ { - Datum datum; - bool null; bool is_dropuser = strcmp(tag, "DROP USER") == 0; - datum = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null); - if (null) + if (newlist == NIL) { if (!is_dropuser) elog(WARNING, "ALTER GROUP: group \"%s\" does not have any members", stmt->name); } else { - HeapTuple tuple; - Datum new_record[Natts_pg_group]; - char new_record_nulls[Natts_pg_group]; - ArrayType *oldarray, - *newarray; - List *newlist = NIL, - *item; - int i; - - oldarray = (ArrayType *) datum; - Assert(ARR_NDIM(oldarray) == 1); - /* first add the old array to the hitherto empty list */ - for (i = ARR_LBOUND(oldarray)[0]; i < ARR_LBOUND(oldarray)[0] + ARR_DIMS(oldarray)[0]; i++) - { - int index, - arrval; - Value *v; - bool valueNull; - - index = i; - arrval = DatumGetInt32(array_ref(oldarray, 1, &index, true /* by value */ , - sizeof(int), 0, &valueNull)); - v = makeInteger(arrval); - /* filter out duplicates */ - if (!member(v, newlist)) - newlist = lappend(newlist, v); - } - /* - * now convert the to be dropped usernames to sysids and + * convert the to be dropped usernames to sysids and * remove them from the list */ foreach(item, stmt->listUsers) { - Value *v; + int32 sysid; if (!is_dropuser) { /* Get the uid of the proposed user to drop. */ - v = makeInteger(get_usesysid(strVal(lfirst(item)))); + sysid = get_usesysid(strVal(lfirst(item))); } else { /* for dropuser we already know the uid */ - v = lfirst(item); + sysid = intVal(lfirst(item)); } - if (member(v, newlist)) - newlist = LispRemove(v, newlist); + if (intMember(sysid, newlist)) + newlist = lremovei(sysid, newlist); else if (!is_dropuser) elog(WARNING, "ALTER GROUP: user \"%s\" is not in group \"%s\"", strVal(lfirst(item)), stmt->name); } - newarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32)); - newarray->size = ARR_OVERHEAD(1) + length(newlist) * sizeof(int32); - newarray->flags = 0; - ARR_NDIM(newarray) = 1; /* one dimensional array */ - ARR_LBOUND(newarray)[0] = 1; /* axis starts at one */ - ARR_DIMS(newarray)[0] = length(newlist); /* axis is this long */ - /* fill the array */ - i = 0; - foreach(item, newlist) - ((int *) ARR_DATA_PTR(newarray))[i++] = intVal(lfirst(item)); - - /* - * Insert the new tuple with the updated user list - */ - new_record[Anum_pg_group_groname - 1] = - DirectFunctionCall1(namein, CStringGetDatum(stmt->name)); - new_record_nulls[Anum_pg_group_groname - 1] = ' '; - new_record[Anum_pg_group_grosysid - 1] = heap_getattr(group_tuple, Anum_pg_group_grosysid, pg_group_dsc, &null); - new_record_nulls[Anum_pg_group_grosysid - 1] = null ? 'n' : ' '; - new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(newarray); - new_record_nulls[Anum_pg_group_grolist - 1] = newarray ? ' ' : 'n'; - - tuple = heap_formtuple(pg_group_dsc, new_record, new_record_nulls); - simple_heap_update(pg_group_rel, &group_tuple->t_self, tuple); - - /* Update indexes */ - if (RelationGetForm(pg_group_rel)->relhasindex) - { - Relation idescs[Num_pg_group_indices]; - - CatalogOpenIndices(Num_pg_group_indices, - Name_pg_group_indices, idescs); - CatalogIndexInsert(idescs, Num_pg_group_indices, pg_group_rel, - tuple); - CatalogCloseIndices(Num_pg_group_indices, idescs); - } - + /* Do the update */ + UpdateGroupMembership(pg_group_rel, group_tuple, newlist); } /* endif group not null */ } /* endif alter group drop user */ @@ -1571,6 +1387,107 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag) update_pg_pwd_and_pg_group(NULL); } +/* + * Subroutine for AlterGroup: given a pg_group tuple and a desired new + * membership (expressed as an integer list), form and write an updated tuple. + * The pg_group relation must be open and locked already. + */ +static void +UpdateGroupMembership(Relation group_rel, HeapTuple group_tuple, + List *members) +{ + IdList *newarray; + Datum new_record[Natts_pg_group]; + char new_record_nulls[Natts_pg_group]; + char new_record_repl[Natts_pg_group]; + HeapTuple tuple; + + newarray = IdListToArray(members); + + /* + * Form an updated tuple with the new array and write it back. + */ + MemSet(new_record, 0, sizeof(new_record)); + MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); + MemSet(new_record_repl, ' ', sizeof(new_record_repl)); + + new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(newarray); + new_record_repl[Anum_pg_group_grolist - 1] = 'r'; + + tuple = heap_modifytuple(group_tuple, group_rel, + new_record, new_record_nulls, new_record_repl); + + simple_heap_update(group_rel, &group_tuple->t_self, tuple); + + /* Update indexes */ + if (RelationGetForm(group_rel)->relhasindex) + { + Relation idescs[Num_pg_group_indices]; + + CatalogOpenIndices(Num_pg_group_indices, + Name_pg_group_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_group_indices, group_rel, + tuple); + CatalogCloseIndices(Num_pg_group_indices, idescs); + } +} + + +/* + * Convert an integer list of sysids to an array. + */ +static IdList * +IdListToArray(List *members) +{ + int nmembers = length(members); + IdList *newarray; + List *item; + int i; + + newarray = palloc(ARR_OVERHEAD(1) + nmembers * sizeof(int32)); + newarray->size = ARR_OVERHEAD(1) + nmembers * sizeof(int32); + newarray->flags = 0; + ARR_NDIM(newarray) = 1; /* one dimensional array */ + ARR_LBOUND(newarray)[0] = 1; /* axis starts at one */ + ARR_DIMS(newarray)[0] = nmembers; /* axis is this long */ + i = 0; + foreach(item, members) + { + ((int *) ARR_DATA_PTR(newarray))[i++] = lfirsti(item); + } + + return newarray; +} + +/* + * Convert an array of sysids to an integer list. + */ +static List * +IdArrayToList(IdList *oldarray) +{ + List *newlist = NIL; + int hibound, + i; + + if (oldarray == NULL) + return NIL; + + Assert(ARR_NDIM(oldarray) == 1); + + hibound = ARR_DIMS(oldarray)[0]; + + for (i = 0; i < hibound; i++) + { + int32 sysid; + + sysid = ((int *) ARR_DATA_PTR(oldarray))[i]; + /* filter out any duplicates --- probably a waste of time */ + if (!intMember(sysid, newlist)) + newlist = lappendi(newlist, sysid); + } + + return newlist; +} /* @@ -1580,10 +1497,7 @@ void DropGroup(DropGroupStmt *stmt) { Relation pg_group_rel; - HeapScanDesc scan; HeapTuple tuple; - TupleDesc pg_group_dsc; - bool gro_exists = false; /* * Make sure the user can do this. @@ -1592,34 +1506,18 @@ DropGroup(DropGroupStmt *stmt) elog(ERROR, "DROP GROUP: permission denied"); /* - * Scan the pg_group table and delete all matching groups. + * Drop the group. */ pg_group_rel = heap_openr(GroupRelationName, ExclusiveLock); - pg_group_dsc = RelationGetDescr(pg_group_rel); - scan = heap_beginscan(pg_group_rel, false, SnapshotNow, 0, NULL); - while (HeapTupleIsValid(tuple = heap_getnext(scan, false))) - { - Datum datum; - bool null; - - datum = heap_getattr(tuple, Anum_pg_group_groname, - pg_group_dsc, &null); - if (!null && strcmp(NameStr(*DatumGetName(datum)), stmt->name) == 0) - { - gro_exists = true; - simple_heap_delete(pg_group_rel, &tuple->t_self); - } - } - - heap_endscan(scan); - - /* - * Did we find any? - */ - if (!gro_exists) + tuple = SearchSysCacheCopy(GRONAME, + PointerGetDatum(stmt->name), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) elog(ERROR, "DROP GROUP: group \"%s\" does not exist", stmt->name); + simple_heap_delete(pg_group_rel, &tuple->t_self); + heap_close(pg_group_rel, NoLock); /* diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index da12fa9a1d..68fcb325a6 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -27,7 +27,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.159 2002/04/27 03:45:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.160 2002/04/27 21:24:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -733,6 +733,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate) namespaceId, tupdesc, RELKIND_RELATION, + false, true, allowSystemTableMods); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 983055ef78..66954ff816 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.162 2002/04/19 16:36:08 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.163 2002/04/27 21:24:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1319,7 +1319,10 @@ LookupOpclassInfo(Oid operatorClassOid, * The relation descriptor is built just from the supplied parameters, * without actually looking at any system table entries. We cheat * quite a lot since we only need to work for a few basic system - * catalogs... + * catalogs. + * + * formrdesc is currently used for: pg_class, pg_attribute, pg_proc, + * and pg_type (see RelationCacheInitialize). * * Note that these catalogs can't have constraints, default values, * rules, or triggers, since we don't cope with any of that. @@ -1374,9 +1377,10 @@ formrdesc(const char *relationName, /* * It's important to distinguish between shared and non-shared * relations, even at bootstrap time, to make sure we know where they - * are stored. + * are stored. At present, all relations that formrdesc is used for + * are not shared. */ - relation->rd_rel->relisshared = IsSharedSystemRelationName(relationName); + relation->rd_rel->relisshared = false; relation->rd_rel->relpages = 1; relation->rd_rel->reltuples = 1; @@ -1434,15 +1438,8 @@ formrdesc(const char *relationName, /* In bootstrap mode, we have no indexes */ if (!IsBootstrapProcessingMode()) { - /* - * This list is incomplete, but it only has to work for the set of - * rels that formrdesc is used for ... - */ - if (strcmp(relationName, RelationRelationName) == 0 || - strcmp(relationName, AttributeRelationName) == 0 || - strcmp(relationName, ProcedureRelationName) == 0 || - strcmp(relationName, TypeRelationName) == 0) - relation->rd_rel->relhasindex = true; + /* Otherwise, all the rels formrdesc is used for have indexes */ + relation->rd_rel->relhasindex = true; } /* diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 4572a8f05e..a73822e8fe 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.63 2002/03/02 21:39:33 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.64 2002/04/27 21:24:34 tgl Exp $ * * NOTES * Globals used all over the place should be declared here and not @@ -18,14 +18,6 @@ */ #include "postgres.h" -#include -#include -#include -#include -#include - -#include "catalog/catname.h" -#include "catalog/indexing.h" #include "libpq/pqcomm.h" #include "miscadmin.h" #include "storage/backendid.h" @@ -47,14 +39,11 @@ struct Port *MyProcPort; long MyCancelKey; char *DataDir = NULL; - /* * The PGDATA directory user says to use, or defaults to via environment * variable. NULL if no option given and no environment variable set */ -Relation reldesc; /* current relation descriptor */ - char OutputFileName[MAXPGPATH]; char pg_pathname[MAXPGPATH]; /* full path to postgres @@ -85,27 +74,3 @@ bool allowSystemTableMods = false; int SortMem = 512; int VacuumMem = 8192; int NBuffers = DEF_NBUFFERS; - - -/* ---------------- - * List of relations that are shared across all databases in an installation. - * - * This used to be binary-searched, requiring that it be kept in sorted order. - * We just do a linear search now so there's no requirement that the list - * be ordered. The list is so small it shouldn't make much difference. - * make sure the list is null-terminated - * - jolly 8/19/95 - * ---------------- - */ -char *SharedSystemRelationNames[] = { - DatabaseRelationName, - DatabaseNameIndex, - DatabaseOidIndex, - GroupRelationName, - GroupNameIndex, - GroupSysidIndex, - ShadowRelationName, - ShadowNameIndex, - ShadowSysidIndex, - NULL -}; diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 9ef8b1c87c..c112f1a44b 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.86 2002/04/04 04:25:49 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.87 2002/04/27 21:24:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -612,9 +612,8 @@ InitializeSessionUserId(const char *username) Anum_pg_shadow_useconfig, &isnull); if (!isnull) { - ArrayType *a; + ArrayType *a = DatumGetArrayTypeP(datum); - a = (ArrayType *) pg_detoast_datum((struct varlena *)datum); ProcessGUCArray(a, PGC_S_USER); } diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 0d36d70bea..a2d9758cc1 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.102 2002/04/01 03:34:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.103 2002/04/27 21:24:34 tgl Exp $ * * *------------------------------------------------------------------------- @@ -138,7 +138,7 @@ ReverifyMyDatabase(const char *name) #endif /* - * Set up datbase-specific configuration variables. + * Set up database-specific configuration variables. */ if (IsUnderPostmaster) { @@ -149,9 +149,8 @@ ReverifyMyDatabase(const char *name) RelationGetDescr(pgdbrel), &isnull); if (!isnull) { - ArrayType *a; + ArrayType *a = DatumGetArrayTypeP(datum); - a = (ArrayType *) pg_detoast_datum((struct varlena *)datum); ProcessGUCArray(a, PGC_S_DATABASE); } } diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh index 195e4f8a83..9a6b78217b 100644 --- a/src/bin/initdb/initdb.sh +++ b/src/bin/initdb/initdb.sh @@ -27,7 +27,7 @@ # Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # -# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.151 2002/04/21 00:26:43 tgl Exp $ +# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.152 2002/04/27 21:24:34 tgl Exp $ # #------------------------------------------------------------------------- @@ -658,10 +658,13 @@ $ECHO_N "enabling unlimited row size for system tables... "$ECHO_C "$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <