%{
/*-------------------------------------------------------------------------
*
- * 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 $
*
*-------------------------------------------------------------------------
*/
%type <list> boot_index_params
%type <ielem> boot_index_param
-%type <ival> boot_const boot_ident
-%type <ival> optbootstrap optwithoutoids boot_tuple boot_tuplelist
+%type <ival> boot_const boot_ident
+%type <ival> optbootstrap optsharedrelation optwithoutoids
+%type <ival> boot_tuple boot_tuplelist
%type <oidval> optoideq
%token <ival> CONST ID
%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
;
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
{
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
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);
}
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();
| { $$ = 0; }
;
+optsharedrelation:
+ XSHARED_RELATION { $$ = 1; }
+ | { $$ = 0; }
+ ;
+
optwithoutoids:
XWITHOUT_OIDS { $$ = 1; }
| { $$ = 0; }
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
OID { return(OBJ_ID); }
bootstrap { return(XBOOTSTRAP); }
+"shared_relation" { return(XSHARED_RELATION); }
+"without_oids" { return(XWITHOUT_OIDS); }
_null_ { return(NULLVAL); }
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));
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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
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. */
* 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;
{
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)");
}
}
- 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;
}
}
int attlen;
Oid typeoid;
- if (reldesc != NULL)
+ if (boot_reldesc != NULL)
{
elog(LOG, "warning: no open relations allowed with 'create' command");
closerel(relname);
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");
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),
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);
}
-$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
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
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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.
#
#
# 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.
inside = 0;
raw = 0;
bootstrap = "";
+ shared_relation = "";
without_oids = "";
nc = 0;
reln_open = 0;
if ($0 ~ /BOOTSTRAP/) {
bootstrap = "bootstrap ";
}
+ if ($0 ~ /BKI_SHARED_RELATION/) {
+ shared_relation = "shared_relation ";
+ }
if ($0 ~ /BKI_WITHOUT_OIDS/) {
without_oids = "without_oids ";
}
# 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; j<i-1; j++) {
reln_open = 1;
inside = 0;
bootstrap = "";
+ shared_relation = "";
without_oids = "";
next;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.196 2002/04/12 20:38:18 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.197 2002/04/27 21:24:33 tgl Exp $
*
*
* INTERFACE ROUTINES
heap_create(const char *relname,
Oid relnamespace,
TupleDesc tupDesc,
+ bool shared_relation,
bool storage_create,
bool allow_system_table_mods)
{
Oid relid;
- Oid dbid = MyDatabaseId;
+ Oid dbid = shared_relation ? InvalidOid : MyDatabaseId;
bool nailme = false;
RelFileNode rnode;
Relation rel;
if (!allow_system_table_mods &&
(IsSystemNamespace(relnamespace) || IsToastNamespace(relnamespace)) &&
IsNormalProcessingMode())
- elog(ERROR, "invalid relation \"%s\"; "
+ elog(ERROR, "cannot create %s.%s: "
"system catalog modifications are currently disallowed",
- relname);
+ get_namespace_name(relnamespace), relname);
/*
* Real ugly stuff to assign the proper relid in the relation
* descriptor follows. Note that only "bootstrapped" relations whose
- * OIDs are hard-coded in pg_class.h need be listed here. We also
- * have to take special care for those rels that should be nailed
- * in cache and/or are shared across databases.
+ * OIDs are hard-coded in pg_class.h should be listed here. We also
+ * have to recognize those rels that must be nailed in cache.
*/
if (IsSystemNamespace(relnamespace))
{
}
else if (strcmp(ShadowRelationName, relname) == 0)
{
- dbid = InvalidOid;
relid = RelOid_pg_shadow;
}
else if (strcmp(GroupRelationName, relname) == 0)
{
- dbid = InvalidOid;
relid = RelOid_pg_group;
}
else if (strcmp(DatabaseRelationName, relname) == 0)
{
- dbid = InvalidOid;
relid = RelOid_pg_database;
}
else
{
relid = newoid();
- if (IsSharedSystemRelationName(relname))
- dbid = InvalidOid;
}
}
else
Oid relnamespace,
TupleDesc tupdesc,
char relkind,
+ bool shared_relation,
bool relhasoids,
bool allow_system_table_mods)
{
* necessary anymore, but we may as well avoid the cycles of creating
* and deleting the file in case we fail.)
*/
- new_rel_desc = heap_create(relname, relnamespace, tupdesc,
- false, allow_system_table_mods);
+ new_rel_desc = heap_create(relname,
+ relnamespace,
+ tupdesc,
+ shared_relation,
+ false,
+ allow_system_table_mods);
/* Fetch the relation OID assigned by heap_create */
new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid;
*
*
* 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
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);
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
* ----------------------------------------------------------------
Relation heapRelation;
Relation indexRelation;
TupleDesc indexTupDesc;
+ bool shared_relation;
Oid namespaceId;
Oid indexoid;
*/
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
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);
indexRelation = heap_create(indexRelationName,
namespaceId,
indexTupDesc,
+ shared_relation,
false,
allow_system_table_mods);
indexoid = RelationGetRelid(indexRelation);
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
RelationGetNamespace(OldHeap),
tupdesc,
OldHeap->rd_rel->relkind,
+ OldHeap->rd_rel->relisshared,
OldHeap->rd_rel->relhasoids,
allowSystemTableMods);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
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);
}
if (gottuple)
{
Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
- text *tmptext;
- bool isnull;
/* oid of the database */
if (dbIdP)
/* 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, "");
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
namespaceId,
descriptor,
relkind,
+ false,
stmt->hasoids || parentHasOids,
allowSystemTableMods);
HeapTuple reltup;
HeapTupleData classtuple;
TupleDesc tupdesc;
+ bool shared_relation;
Relation class_rel;
Buffer buffer;
Relation ridescs[Num_pg_class_indices];
*/
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));
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?)
*/
PG_TOAST_NAMESPACE,
tupdesc,
RELKIND_TOASTVALUE,
+ shared_relation,
false,
true);
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
/*
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.
*/
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)
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);
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);
/*
* 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);
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';
{
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? */
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
*
* 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 */
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 */
{
new_record[Anum_pg_shadow_valuntil - 1] =
DirectFunctionCall1(nabstimein, CStringGetDatum(validUntil));
- new_record_nulls[Anum_pg_shadow_valuntil - 1] = ' ';
+ new_record_repl[Anum_pg_shadow_valuntil - 1] = 'r';
}
- 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' : ' ';
- }
-
- /* 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 */
}
-
/*
* ALTER USER ... SET
*/
? ((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),
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);
}
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),
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");
{
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)" : "");
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");
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);
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);
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.
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.
*/
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)
{
* 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
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 */
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;
+}
/*
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.
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);
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
namespaceId,
tupdesc,
RELKIND_RELATION,
+ false,
true,
allowSystemTableMods);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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.
/*
* 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;
/* 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;
}
/*
*
*
* 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
*/
#include "postgres.h"
-#include <fcntl.h>
-#include <sys/file.h>
-#include <sys/types.h>
-#include <math.h>
-#include <unistd.h>
-
-#include "catalog/catname.h"
-#include "catalog/indexing.h"
#include "libpq/pqcomm.h"
#include "miscadmin.h"
#include "storage/backendid.h"
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
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
-};
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
}
*
*
* 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 $
*
*
*-------------------------------------------------------------------------
#endif
/*
- * Set up datbase-specific configuration variables.
+ * Set up database-specific configuration variables.
*/
if (IsUnderPostmaster)
{
RelationGetDescr(pgdbrel), &isnull);
if (!isnull)
{
- ArrayType *a;
+ ArrayType *a = DatumGetArrayTypeP(datum);
- a = (ArrayType *) pg_detoast_datum((struct varlena *)datum);
ProcessGUCArray(a, PGC_S_DATABASE);
}
}
# 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 $
#
#-------------------------------------------------------------------------
"$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
ALTER TABLE pg_attrdef CREATE TOAST TABLE;
+ALTER TABLE pg_database CREATE TOAST TABLE;
ALTER TABLE pg_description CREATE TOAST TABLE;
+ALTER TABLE pg_group CREATE TOAST TABLE;
ALTER TABLE pg_proc CREATE TOAST TABLE;
ALTER TABLE pg_relcheck CREATE TOAST TABLE;
ALTER TABLE pg_rewrite CREATE TOAST TABLE;
+ALTER TABLE pg_shadow CREATE TOAST TABLE;
ALTER TABLE pg_statistic CREATE TOAST TABLE;
EOF
if [ "$?" -ne 0 ]; then
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: bootstrap.h,v 1.28 2002/03/26 19:16:20 tgl Exp $
+ * $Id: bootstrap.h,v 1.29 2002/04/27 21:24:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
} hashnode;
-extern Relation reldesc;
+extern Relation boot_reldesc;
extern Form_pg_attribute attrtypes[MAXATTR];
extern int numattr;
extern int BootstrapMain(int ac, char *av[]);
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catalog.h,v 1.23 2002/04/12 20:38:30 tgl Exp $
+ * $Id: catalog.h,v 1.24 2002/04/27 21:24:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern bool IsToastNamespace(Oid namespaceId);
extern bool IsReservedName(const char *name);
-extern bool IsSharedSystemRelationName(const char *relname);
extern Oid newoid(void);
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catname.h,v 1.24 2002/03/22 21:34:44 tgl Exp $
+ * $Id: catname.h,v 1.25 2002/04/27 21:24:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define RelCheckRelationName "pg_relcheck"
#define TriggerRelationName "pg_trigger"
-extern char *SharedSystemRelationNames[];
-
#endif /* CATNAME_H */
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.127 2002/04/26 01:24:08 tgl Exp $
+ * $Id: catversion.h,v 1.128 2002/04/27 21:24:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200204251
+#define CATALOG_VERSION_NO 200204271
#endif
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: heap.h,v 1.49 2002/03/31 06:26:32 tgl Exp $
+ * $Id: heap.h,v 1.50 2002/04/27 21:24:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Relation heap_create(const char *relname,
Oid relnamespace,
TupleDesc tupDesc,
+ bool shared_relation,
bool storage_create,
bool allow_system_table_mods);
Oid relnamespace,
TupleDesc tupdesc,
char relkind,
+ bool shared_relation,
bool relhasoids,
bool allow_system_table_mods);
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_database.h,v 1.23 2002/04/21 00:26:43 tgl Exp $
+ * $Id: pg_database.h,v 1.24 2002/04/27 21:24:34 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
* typedef struct FormData_pg_database
* ----------------
*/
-CATALOG(pg_database) BOOTSTRAP
+CATALOG(pg_database) BOOTSTRAP BKI_SHARED_RELATION
{
NameData datname; /* database name */
int4 datdba; /* sysid of owner */
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_group.h,v 1.13 2001/11/05 17:46:32 momjian Exp $
+ * $Id: pg_group.h,v 1.14 2002/04/27 21:24:34 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
* ----------------
*/
-CATALOG(pg_group) BOOTSTRAP BKI_WITHOUT_OIDS
+CATALOG(pg_group) BOOTSTRAP BKI_SHARED_RELATION BKI_WITHOUT_OIDS
{
NameData groname;
int4 grosysid;
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_shadow.h,v 1.19 2002/04/11 05:32:03 petere Exp $
+ * $Id: pg_shadow.h,v 1.20 2002/04/27 21:24:34 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
* typedef struct FormData_pg_shadow
* ----------------
*/
-CATALOG(pg_shadow) BOOTSTRAP BKI_WITHOUT_OIDS
+CATALOG(pg_shadow) BOOTSTRAP BKI_SHARED_RELATION BKI_WITHOUT_OIDS
{
NameData usename;
int4 usesysid;
bool usetrace;
bool usesuper; /* read this field via superuser() only */
bool usecatupd;
+ /* remaining fields may be null; use heap_getattr to read them! */
text passwd;
- int4 valuntil;
+ int4 valuntil; /* actually abstime */
text useconfig[1];
} FormData_pg_shadow;
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1995, Regents of the University of California
*
- * $Id: postgres.h,v 1.56 2001/11/05 17:46:31 momjian Exp $
+ * $Id: postgres.h,v 1.57 2002/04/27 21:24:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define CATALOG(x) typedef struct CppConcat(FormData_,x)
#define BOOTSTRAP
-
+#define BKI_SHARED_RELATION
#define BKI_WITHOUT_OIDS
/* these need to expand into some harmless, repeatable declaration */