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.
This commit is contained in:
Tom Lane 2002-04-27 21:24:34 +00:00
parent 108871f4fc
commit c06f6a6bc2
27 changed files with 403 additions and 531 deletions

View File

@ -1,15 +1,15 @@
%{ %{
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* backendparse.y * bootparse.y
* yacc parser grammer for the "backend" initialization program. * yacc parser grammar for the "backend" initialization program.
* *
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * 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 <list> boot_index_params %type <list> boot_index_params
%type <ielem> boot_index_param %type <ielem> boot_index_param
%type <ival> boot_const boot_ident %type <ival> boot_const boot_ident
%type <ival> optbootstrap optwithoutoids boot_tuple boot_tuplelist %type <ival> optbootstrap optsharedrelation optwithoutoids
%type <ival> boot_tuple boot_tuplelist
%type <oidval> optoideq %type <oidval> optoideq
%token <ival> CONST ID %token <ival> CONST ID
@ -97,7 +98,7 @@ int num_columns_read = 0;
%token STRING XDEFINE %token STRING XDEFINE
%token XDECLARE INDEX ON USING XBUILD INDICES UNIQUE %token XDECLARE INDEX ON USING XBUILD INDICES UNIQUE
%token COMMA EQUALS LPAREN RPAREN %token COMMA EQUALS LPAREN RPAREN
%token OBJ_ID XBOOTSTRAP XWITHOUT_OIDS NULLVAL %token OBJ_ID XBOOTSTRAP XSHARED_RELATION XWITHOUT_OIDS NULLVAL
%start TopLevel %start TopLevel
%nonassoc low %nonassoc low
@ -150,16 +151,14 @@ Boot_CloseStmt:
; ;
Boot_CreateStmt: Boot_CreateStmt:
XCREATE optbootstrap optwithoutoids boot_ident LPAREN XCREATE optbootstrap optsharedrelation optwithoutoids boot_ident LPAREN
{ {
do_start(); do_start();
numattr = 0; numattr = 0;
if ($2) elog(DEBUG3, "creating%s%s relation %s...",
elog(DEBUG3, "creating bootstrap relation %s...", $2 ? " bootstrap" : "",
LexIDStr($4)); $3 ? " shared" : "",
else LexIDStr($5));
elog(DEBUG3, "creating relation %s...",
LexIDStr($4));
} }
boot_typelist boot_typelist
{ {
@ -171,21 +170,22 @@ Boot_CreateStmt:
if ($2) if ($2)
{ {
extern Relation reldesc;
TupleDesc tupdesc; TupleDesc tupdesc;
if (reldesc) if (boot_reldesc)
{ {
elog(DEBUG3, "create bootstrap: warning, open relation exists, closing first"); elog(DEBUG3, "create bootstrap: warning, open relation exists, closing first");
closerel(NULL); closerel(NULL);
} }
tupdesc = CreateTupleDesc(numattr, attrtypes); tupdesc = CreateTupleDesc(numattr, attrtypes);
reldesc = heap_create(LexIDStr($4), boot_reldesc = heap_create(LexIDStr($5),
PG_CATALOG_NAMESPACE, PG_CATALOG_NAMESPACE,
tupdesc, tupdesc,
true, true); $3,
reldesc->rd_rel->relhasoids = ! ($3); true,
true);
boot_reldesc->rd_rel->relhasoids = ! ($4);
elog(DEBUG3, "bootstrap relation created"); elog(DEBUG3, "bootstrap relation created");
} }
else else
@ -194,11 +194,12 @@ Boot_CreateStmt:
TupleDesc tupdesc; TupleDesc tupdesc;
tupdesc = CreateTupleDesc(numattr,attrtypes); tupdesc = CreateTupleDesc(numattr,attrtypes);
id = heap_create_with_catalog(LexIDStr($4), id = heap_create_with_catalog(LexIDStr($5),
PG_CATALOG_NAMESPACE, PG_CATALOG_NAMESPACE,
tupdesc, tupdesc,
RELKIND_RELATION, RELKIND_RELATION,
! ($3), $3,
! ($4),
true); true);
elog(DEBUG3, "relation created with oid %u", id); elog(DEBUG3, "relation created with oid %u", id);
} }
@ -221,7 +222,7 @@ Boot_InsertStmt:
if (num_columns_read != numattr) if (num_columns_read != numattr)
elog(ERROR, "incorrect number of columns in row (expected %d, got %d)", elog(ERROR, "incorrect number of columns in row (expected %d, got %d)",
numattr, num_columns_read); numattr, num_columns_read);
if (reldesc == (Relation)NULL) if (boot_reldesc == (Relation) NULL)
{ {
elog(ERROR, "relation not open"); elog(ERROR, "relation not open");
err_out(); err_out();
@ -283,6 +284,11 @@ optbootstrap:
| { $$ = 0; } | { $$ = 0; }
; ;
optsharedrelation:
XSHARED_RELATION { $$ = 1; }
| { $$ = 0; }
;
optwithoutoids: optwithoutoids:
XWITHOUT_OIDS { $$ = 1; } XWITHOUT_OIDS { $$ = 1; }
| { $$ = 0; } | { $$ = 0; }

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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); } OID { return(OBJ_ID); }
bootstrap { return(XBOOTSTRAP); } bootstrap { return(XBOOTSTRAP); }
"shared_relation" { return(XSHARED_RELATION); }
"without_oids" { return(XWITHOUT_OIDS); }
_null_ { return(NULLVAL); } _null_ { return(NULLVAL); }
insert { return(INSERT_TUPLE); } insert { return(INSERT_TUPLE); }
@ -94,7 +96,6 @@ insert { return(INSERT_TUPLE); }
"index" { return(INDEX); } "index" { return(INDEX); }
"on" { return(ON); } "on" { return(ON); }
"using" { return(USING); } "using" { return(USING); }
"without_oids" { return(XWITHOUT_OIDS); }
{arrayid} { {arrayid} {
yylval.ival = EnterString(MapArrayTypeName((char*)yytext)); yylval.ival = EnterString(MapArrayTypeName((char*)yytext));

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 * global variables
* ---------------- * ----------------
*/ */
Relation boot_reldesc; /* current relation descriptor */
/* /*
* In the lexical analyzer, we need to get the reference number quickly from * 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 * the string, and the string from the reference number. Thus we have
@ -500,20 +503,20 @@ boot_openrel(char *relname)
heap_close(rel, NoLock); heap_close(rel, NoLock);
} }
if (reldesc != NULL) if (boot_reldesc != NULL)
closerel(NULL); closerel(NULL);
elog(DEBUG3, "open relation %s, attrsize %d", relname ? relname : "(null)", elog(DEBUG3, "open relation %s, attrsize %d", relname ? relname : "(null)",
(int) ATTRIBUTE_TUPLE_SIZE); (int) ATTRIBUTE_TUPLE_SIZE);
reldesc = heap_openr(relname, NoLock); boot_reldesc = heap_openr(relname, NoLock);
numattr = reldesc->rd_rel->relnatts; numattr = boot_reldesc->rd_rel->relnatts;
for (i = 0; i < numattr; i++) for (i = 0; i < numattr; i++)
{ {
if (attrtypes[i] == NULL) if (attrtypes[i] == NULL)
attrtypes[i] = AllocateAttribute(); attrtypes[i] = AllocateAttribute();
memmove((char *) attrtypes[i], memmove((char *) attrtypes[i],
(char *) reldesc->rd_att->attrs[i], (char *) boot_reldesc->rd_att->attrs[i],
ATTRIBUTE_TUPLE_SIZE); ATTRIBUTE_TUPLE_SIZE);
/* Some old pg_attribute tuples might not have attisset. */ /* Some old pg_attribute tuples might not have attisset. */
@ -523,8 +526,9 @@ boot_openrel(char *relname)
* defined yet. * defined yet.
*/ */
if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0) if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0)
attrtypes[i]->attisset = get_attisset(RelationGetRelid(reldesc), attrtypes[i]->attisset =
NameStr(attrtypes[i]->attname)); get_attisset(RelationGetRelid(boot_reldesc),
NameStr(attrtypes[i]->attname));
else else
attrtypes[i]->attisset = false; attrtypes[i]->attisset = false;
@ -547,9 +551,9 @@ closerel(char *name)
{ {
if (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", elog(ERROR, "closerel: close of '%s' when '%s' was expected",
name, relname ? relname : "(null)"); 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"); elog(ERROR, "no open relation to close");
else else
{ {
elog(DEBUG3, "close relation %s", relname ? relname : "(null)"); elog(DEBUG3, "close relation %s", relname ? relname : "(null)");
heap_close(reldesc, NoLock); heap_close(boot_reldesc, NoLock);
reldesc = (Relation) NULL; boot_reldesc = (Relation) NULL;
} }
} }
@ -585,7 +589,7 @@ DefineAttr(char *name, char *type, int attnum)
int attlen; int attlen;
Oid typeoid; Oid typeoid;
if (reldesc != NULL) if (boot_reldesc != NULL)
{ {
elog(LOG, "warning: no open relations allowed with 'create' command"); elog(LOG, "warning: no open relations allowed with 'create' command");
closerel(relname); closerel(relname);
@ -674,7 +678,7 @@ InsertOneTuple(Oid objectid)
if (objectid != (Oid) 0) if (objectid != (Oid) 0)
tuple->t_data->t_oid = objectid; tuple->t_data->t_oid = objectid;
heap_insert(reldesc, tuple); heap_insert(boot_reldesc, tuple);
heap_freetuple(tuple); heap_freetuple(tuple);
elog(DEBUG3, "row inserted"); elog(DEBUG3, "row inserted");
@ -706,13 +710,13 @@ InsertOneValue(char *value, int i)
elog(DEBUG3, "Typ != NULL"); elog(DEBUG3, "Typ != NULL");
app = Typ; 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; ++app;
ap = *app; ap = *app;
if (ap == NULL) if (ap == NULL)
{ {
elog(FATAL, "unable to find atttypid %u in Typ list", 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, values[i] = OidFunctionCall3(ap->am_typ.typinput,
CStringGetDatum(value), CStringGetDatum(value),
@ -806,8 +810,8 @@ cleanup()
elog(FATAL, "Memory manager fault: cleanup called twice.\n"); elog(FATAL, "Memory manager fault: cleanup called twice.\n");
proc_exit(1); proc_exit(1);
} }
if (reldesc != (Relation) NULL) if (boot_reldesc != (Relation) NULL)
heap_close(reldesc, NoLock); heap_close(boot_reldesc, NoLock);
CommitTransactionCommand(); CommitTransactionCommand();
proc_exit(Warnings); proc_exit(Warnings);
} }

View File

@ -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; This directory contains .c files that manipulate the system catalogs;
src/include/catalog contains the .h files that define the structure 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 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 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 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 catalogs if at all possible; generally, only tables that must be written to
in order to create a table should be bootstrapped. in order to create a table should be bootstrapped.
- Certain BOOTSTRAP tables must be at the start of the Makefile - Certain BOOTSTRAP tables must be at the start of the Makefile
POSTGRES_BKI_SRCS variable, as these will not be created through standard POSTGRES_BKI_SRCS variable, as these will not be created through the standard
function means, but will be written directly to disk. That's how pg_class is heap_create_with_catalog process, because it needs these tables to exist
created without depending on functions which depend on the existence of already. The list of files this currently includes is:
pg_class. The list of files this currently includes is:
pg_proc.h pg_type.h pg_attribute.h pg_class.h 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 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 the tables are in place. There are reputedly some other order dependencies

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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] == '_'); 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. * newoid - returns a unique identifier across all catalogs.

View File

@ -10,7 +10,7 @@
# #
# #
# IDENTIFICATION # 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 # NOTES
# non-essential whitespace is removed from the generated file. # non-essential whitespace is removed from the generated file.
@ -217,6 +217,7 @@ BEGIN {
inside = 0; inside = 0;
raw = 0; raw = 0;
bootstrap = ""; bootstrap = "";
shared_relation = "";
without_oids = ""; without_oids = "";
nc = 0; nc = 0;
reln_open = 0; reln_open = 0;
@ -331,6 +332,9 @@ raw == 1 { print; next; }
if ($0 ~ /BOOTSTRAP/) { if ($0 ~ /BOOTSTRAP/) {
bootstrap = "bootstrap "; bootstrap = "bootstrap ";
} }
if ($0 ~ /BKI_SHARED_RELATION/) {
shared_relation = "shared_relation ";
}
if ($0 ~ /BKI_WITHOUT_OIDS/) { if ($0 ~ /BKI_WITHOUT_OIDS/) {
without_oids = "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 this is the last line, then output the bki catalog stuff.
# ---- # ----
if ($1 ~ /}/) { if ($1 ~ /}/) {
print "create " bootstrap without_oids catalog; print "create " bootstrap shared_relation without_oids catalog;
print "\t("; print "\t(";
for (j=1; j<i-1; j++) { for (j=1; j<i-1; j++) {
@ -375,6 +379,7 @@ inside == 1 {
reln_open = 1; reln_open = 1;
inside = 0; inside = 0;
bootstrap = ""; bootstrap = "";
shared_relation = "";
without_oids = ""; without_oids = "";
next; next;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
@ -210,11 +210,12 @@ Relation
heap_create(const char *relname, heap_create(const char *relname,
Oid relnamespace, Oid relnamespace,
TupleDesc tupDesc, TupleDesc tupDesc,
bool shared_relation,
bool storage_create, bool storage_create,
bool allow_system_table_mods) bool allow_system_table_mods)
{ {
Oid relid; Oid relid;
Oid dbid = MyDatabaseId; Oid dbid = shared_relation ? InvalidOid : MyDatabaseId;
bool nailme = false; bool nailme = false;
RelFileNode rnode; RelFileNode rnode;
Relation rel; Relation rel;
@ -225,16 +226,15 @@ heap_create(const char *relname,
if (!allow_system_table_mods && if (!allow_system_table_mods &&
(IsSystemNamespace(relnamespace) || IsToastNamespace(relnamespace)) && (IsSystemNamespace(relnamespace) || IsToastNamespace(relnamespace)) &&
IsNormalProcessingMode()) IsNormalProcessingMode())
elog(ERROR, "invalid relation \"%s\"; " elog(ERROR, "cannot create %s.%s: "
"system catalog modifications are currently disallowed", "system catalog modifications are currently disallowed",
relname); get_namespace_name(relnamespace), relname);
/* /*
* Real ugly stuff to assign the proper relid in the relation * Real ugly stuff to assign the proper relid in the relation
* descriptor follows. Note that only "bootstrapped" relations whose * descriptor follows. Note that only "bootstrapped" relations whose
* OIDs are hard-coded in pg_class.h need be listed here. We also * OIDs are hard-coded in pg_class.h should be listed here. We also
* have to take special care for those rels that should be nailed * have to recognize those rels that must be nailed in cache.
* in cache and/or are shared across databases.
*/ */
if (IsSystemNamespace(relnamespace)) if (IsSystemNamespace(relnamespace))
{ {
@ -260,24 +260,19 @@ heap_create(const char *relname,
} }
else if (strcmp(ShadowRelationName, relname) == 0) else if (strcmp(ShadowRelationName, relname) == 0)
{ {
dbid = InvalidOid;
relid = RelOid_pg_shadow; relid = RelOid_pg_shadow;
} }
else if (strcmp(GroupRelationName, relname) == 0) else if (strcmp(GroupRelationName, relname) == 0)
{ {
dbid = InvalidOid;
relid = RelOid_pg_group; relid = RelOid_pg_group;
} }
else if (strcmp(DatabaseRelationName, relname) == 0) else if (strcmp(DatabaseRelationName, relname) == 0)
{ {
dbid = InvalidOid;
relid = RelOid_pg_database; relid = RelOid_pg_database;
} }
else else
{ {
relid = newoid(); relid = newoid();
if (IsSharedSystemRelationName(relname))
dbid = InvalidOid;
} }
} }
else else
@ -651,6 +646,7 @@ heap_create_with_catalog(const char *relname,
Oid relnamespace, Oid relnamespace,
TupleDesc tupdesc, TupleDesc tupdesc,
char relkind, char relkind,
bool shared_relation,
bool relhasoids, bool relhasoids,
bool allow_system_table_mods) bool allow_system_table_mods)
{ {
@ -678,8 +674,12 @@ heap_create_with_catalog(const char *relname,
* necessary anymore, but we may as well avoid the cycles of creating * necessary anymore, but we may as well avoid the cycles of creating
* and deleting the file in case we fail.) * and deleting the file in case we fail.)
*/ */
new_rel_desc = heap_create(relname, relnamespace, tupdesc, new_rel_desc = heap_create(relname,
false, allow_system_table_mods); relnamespace,
tupdesc,
shared_relation,
false,
allow_system_table_mods);
/* Fetch the relation OID assigned by heap_create */ /* Fetch the relation OID assigned by heap_create */
new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid; new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
@ -67,7 +67,6 @@ static TupleDesc BuildFuncTupleDesc(Oid funcOid,
static TupleDesc ConstructTupleDescriptor(Relation heapRelation, static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
int numatts, AttrNumber *attNums, int numatts, AttrNumber *attNums,
Oid *classObjectId); Oid *classObjectId);
static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
static void UpdateRelationRelation(Relation indexRelation); static void UpdateRelationRelation(Relation indexRelation);
static void InitializeAttributeOids(Relation indexRelation, static void InitializeAttributeOids(Relation indexRelation,
int numatts, Oid indexoid); int numatts, Oid indexoid);
@ -305,26 +304,6 @@ ConstructTupleDescriptor(Relation heapRelation,
return indexTupDesc; 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 * UpdateRelationRelation
* ---------------------------------------------------------------- * ----------------------------------------------------------------
@ -561,6 +540,7 @@ index_create(Oid heapRelationId,
Relation heapRelation; Relation heapRelation;
Relation indexRelation; Relation indexRelation;
TupleDesc indexTupDesc; TupleDesc indexTupDesc;
bool shared_relation;
Oid namespaceId; Oid namespaceId;
Oid indexoid; Oid indexoid;
@ -571,7 +551,12 @@ index_create(Oid heapRelationId,
*/ */
heapRelation = heap_open(heapRelationId, ShareLock); 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); namespaceId = RelationGetNamespace(heapRelation);
shared_relation = heapRelation->rd_rel->relisshared;
/* /*
* check parameters * check parameters
@ -585,6 +570,16 @@ index_create(Oid heapRelationId,
IsNormalProcessingMode()) IsNormalProcessingMode())
elog(ERROR, "User-defined indexes on system catalogs are not supported"); 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)) if (get_relname_relid(indexRelationName, namespaceId))
elog(ERROR, "index named \"%s\" already exists", elog(ERROR, "index named \"%s\" already exists",
indexRelationName); indexRelationName);
@ -607,6 +602,7 @@ index_create(Oid heapRelationId,
indexRelation = heap_create(indexRelationName, indexRelation = heap_create(indexRelationName,
namespaceId, namespaceId,
indexTupDesc, indexTupDesc,
shared_relation,
false, false,
allow_system_table_mods); allow_system_table_mods);
indexoid = RelationGetRelid(indexRelation); indexoid = RelationGetRelid(indexRelation);
@ -619,16 +615,18 @@ index_create(Oid heapRelationId,
LockRelation(indexRelation, AccessExclusiveLock); 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 * store index's pg_class entry
* (append RELATION tuple)
* ----------------
*/ */
UpdateRelationRelation(indexRelation); UpdateRelationRelation(indexRelation);

View File

@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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), RelationGetNamespace(OldHeap),
tupdesc, tupdesc,
OldHeap->rd_rel->relkind, OldHeap->rd_rel->relkind,
OldHeap->rd_rel->relisshared,
OldHeap->rd_rel->relhasoids, OldHeap->rd_rel->relhasoids,
allowSystemTableMods); allowSystemTableMods);

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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"); elog(ERROR, "permission denied");
MemSet(repl_repl, ' ', sizeof(repl_repl)); MemSet(repl_repl, ' ', sizeof(repl_repl));
repl_repl[Anum_pg_database_datconfig-1] = 'r'; repl_repl[Anum_pg_database_datconfig-1] = 'r';
if (strcmp(stmt->variable, "all")==0 && stmt->value == NULL) if (strcmp(stmt->variable, "all")==0 && stmt->value == NULL)
{
/* RESET ALL */ /* RESET ALL */
repl_null[Anum_pg_database_datconfig-1] = 'n'; repl_null[Anum_pg_database_datconfig-1] = 'n';
repl_val[Anum_pg_database_datconfig-1] = (Datum) 0;
}
else else
{ {
Datum datum; Datum datum;
@ -491,16 +494,12 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
datum = heap_getattr(tuple, Anum_pg_database_datconfig, datum = heap_getattr(tuple, Anum_pg_database_datconfig,
RelationGetDescr(rel), &isnull); RelationGetDescr(rel), &isnull);
a = isnull ? ((ArrayType *) NULL) : DatumGetArrayTypeP(datum);
if (valuestr) if (valuestr)
a = GUCArrayAdd(isnull a = GUCArrayAdd(a, stmt->variable, valuestr);
? NULL
: (ArrayType *) pg_detoast_datum((struct varlena *)datum),
stmt->variable, valuestr);
else else
a = GUCArrayDelete(isnull a = GUCArrayDelete(a, stmt->variable);
? NULL
: (ArrayType *) pg_detoast_datum((struct varlena *)datum),
stmt->variable);
repl_val[Anum_pg_database_datconfig-1] = PointerGetDatum(a); 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) if (gottuple)
{ {
Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple); Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple);
text *tmptext;
bool isnull;
/* oid of the database */ /* oid of the database */
if (dbIdP) if (dbIdP)
@ -573,16 +570,21 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
/* database path (as registered in pg_database) */ /* database path (as registered in pg_database) */
if (dbpath) if (dbpath)
{ {
tmptext = DatumGetTextP(heap_getattr(tuple, Datum datum;
Anum_pg_database_datpath, bool isnull;
RelationGetDescr(relation),
&isnull)); datum = heap_getattr(tuple,
Anum_pg_database_datpath,
RelationGetDescr(relation),
&isnull);
if (!isnull) if (!isnull)
{ {
Assert(VARSIZE(tmptext) - VARHDRSZ < MAXPGPATH); text *pathtext = DatumGetTextP(datum);
int pathlen = VARSIZE(pathtext) - VARHDRSZ;
strncpy(dbpath, VARDATA(tmptext), VARSIZE(tmptext) - VARHDRSZ); Assert(pathlen >= 0 && pathlen < MAXPGPATH);
*(dbpath + VARSIZE(tmptext) - VARHDRSZ) = '\0'; strncpy(dbpath, VARDATA(pathtext), pathlen);
*(dbpath + pathlen) = '\0';
} }
else else
strcpy(dbpath, ""); strcpy(dbpath, "");

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, namespaceId,
descriptor, descriptor,
relkind, relkind,
false,
stmt->hasoids || parentHasOids, stmt->hasoids || parentHasOids,
allowSystemTableMods); allowSystemTableMods);
@ -2840,6 +2841,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
HeapTuple reltup; HeapTuple reltup;
HeapTupleData classtuple; HeapTupleData classtuple;
TupleDesc tupdesc; TupleDesc tupdesc;
bool shared_relation;
Relation class_rel; Relation class_rel;
Buffer buffer; Buffer buffer;
Relation ridescs[Num_pg_class_indices]; Relation ridescs[Num_pg_class_indices];
@ -2856,6 +2858,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
*/ */
rel = heap_open(relOid, AccessExclusiveLock); rel = heap_open(relOid, AccessExclusiveLock);
/* Check permissions */
if (rel->rd_rel->relkind != RELKIND_RELATION) if (rel->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
RelationGetRelationName(rel)); RelationGetRelationName(rel));
@ -2863,6 +2866,19 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
if (!pg_class_ownercheck(relOid, GetUserId())) if (!pg_class_ownercheck(relOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel)); 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?) * lock the pg_class tuple for update (is that really needed?)
*/ */
@ -2962,6 +2978,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
PG_TOAST_NAMESPACE, PG_TOAST_NAMESPACE,
tupdesc, tupdesc,
RELKIND_TOASTVALUE, RELKIND_TOASTVALUE,
shared_relation,
false, false,
true); true);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; extern bool Password_encryption;
static void CheckPgUserAclNotNull(void); 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; bool first_user = true;
datum = heap_getattr(tuple, Anum_pg_group_groname, dsc, &isnull); datum = heap_getattr(tuple, Anum_pg_group_groname, dsc, &isnull);
if (isnull) /* ignore NULL groupnames --- shouldn't happen */
continue; /* ignore NULL groupnames */
groname = NameStr(*DatumGetName(datum));
grolist_datum = heap_getattr(tuple, Anum_pg_group_grolist, dsc, &isnull);
/* Ignore NULL group lists */
if (isnull) if (isnull)
continue; continue;
groname = NameStr(*DatumGetName(datum));
grolist_p = DatumGetIdListP(grolist_datum);
/* /*
* Check for illegal characters in the group name. * Check for illegal characters in the group name.
*/ */
@ -171,8 +169,15 @@ write_group_file(Relation urel, Relation grel)
continue; 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 */ /* be sure the IdList is not toasted */
/* scan it */ grolist_p = DatumGetIdListP(grolist_datum);
/* scan grolist */
num = IDLIST_NUM(grolist_p); num = IDLIST_NUM(grolist_p);
aidp = IDLIST_DAT(grolist_p); aidp = IDLIST_DAT(grolist_p);
for (i = 0; i < num; ++i) for (i = 0; i < num; ++i)
@ -290,8 +295,9 @@ write_user_file(Relation urel)
int i; int i;
datum = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &isnull); datum = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &isnull);
/* ignore NULL usernames (shouldn't happen) */
if (isnull) if (isnull)
continue; /* ignore NULL usernames */ continue;
usename = NameStr(*DatumGetName(datum)); usename = NameStr(*DatumGetName(datum));
datum = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &isnull); datum = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &isnull);
@ -516,24 +522,19 @@ CreateUser(CreateUserStmt *stmt)
while (!user_exists && !sysid_exists && while (!user_exists && !sysid_exists &&
HeapTupleIsValid(tuple = heap_getnext(scan, 0))) HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
{ {
Datum datum; Form_pg_shadow shadow_form = (Form_pg_shadow) GETSTRUCT(tuple);
bool null; int32 this_sysid;
datum = heap_getattr(tuple, Anum_pg_shadow_usename, user_exists = (strcmp(NameStr(shadow_form->usename), stmt->user) == 0);
pg_shadow_dsc, &null);
Assert(!null);
user_exists = (strcmp(NameStr(*DatumGetName(datum)), stmt->user) == 0);
datum = heap_getattr(tuple, Anum_pg_shadow_usesysid, this_sysid = shadow_form->usesysid;
pg_shadow_dsc, &null);
Assert(!null);
if (havesysid) /* customized id wanted */ if (havesysid) /* customized id wanted */
sysid_exists = (DatumGetInt32(datum) == sysid); sysid_exists = (this_sysid == sysid);
else else
{ {
/* pick 1 + max */ /* pick 1 + max */
if (DatumGetInt32(datum) > max_id) if (this_sysid > max_id)
max_id = DatumGetInt32(datum); max_id = this_sysid;
} }
} }
heap_endscan(scan); heap_endscan(scan);
@ -551,10 +552,12 @@ CreateUser(CreateUserStmt *stmt)
/* /*
* Build a tuple to insert * 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] = new_record[Anum_pg_shadow_usename - 1] =
DirectFunctionCall1(namein, CStringGetDatum(stmt->user)); DirectFunctionCall1(namein, CStringGetDatum(stmt->user));
new_record[Anum_pg_shadow_usesysid - 1] = Int32GetDatum(sysid); new_record[Anum_pg_shadow_usesysid - 1] = Int32GetDatum(sysid);
AssertState(BoolIsValid(createdb)); AssertState(BoolIsValid(createdb));
new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb); new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(createdb);
new_record[Anum_pg_shadow_usetrace - 1] = BoolGetDatum(false); new_record[Anum_pg_shadow_usetrace - 1] = BoolGetDatum(false);
@ -577,20 +580,14 @@ CreateUser(CreateUserStmt *stmt)
DirectFunctionCall1(textin, CStringGetDatum(encrypted_password)); DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
} }
} }
else
new_record_nulls[Anum_pg_shadow_passwd - 1] = 'n';
if (validUntil) if (validUntil)
new_record[Anum_pg_shadow_valuntil - 1] = new_record[Anum_pg_shadow_valuntil - 1] =
DirectFunctionCall1(nabstimein, CStringGetDatum(validUntil)); DirectFunctionCall1(nabstimein, CStringGetDatum(validUntil));
else
new_record_nulls[Anum_pg_shadow_usename - 1] = ' '; new_record_nulls[Anum_pg_shadow_valuntil - 1] = 'n';
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';
new_record_nulls[Anum_pg_shadow_useconfig - 1] = 'n'; new_record_nulls[Anum_pg_shadow_useconfig - 1] = 'n';
@ -651,11 +648,11 @@ AlterUser(AlterUserStmt *stmt)
{ {
Datum new_record[Natts_pg_shadow]; Datum new_record[Natts_pg_shadow];
char new_record_nulls[Natts_pg_shadow]; char new_record_nulls[Natts_pg_shadow];
char new_record_repl[Natts_pg_shadow];
Relation pg_shadow_rel; Relation pg_shadow_rel;
TupleDesc pg_shadow_dsc; TupleDesc pg_shadow_dsc;
HeapTuple tuple, HeapTuple tuple,
new_tuple; new_tuple;
bool null;
List *option; List *option;
char *password = NULL; /* PostgreSQL user password */ char *password = NULL; /* PostgreSQL user password */
bool encrypt_password = Password_encryption; /* encrypt 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); 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, new_record[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein,
CStringGetDatum(stmt->user)); CStringGetDatum(stmt->user));
new_record_nulls[Anum_pg_shadow_usename - 1] = ' '; new_record_repl[Anum_pg_shadow_usename - 1] = 'r';
/* 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' : ' ';
/* createdb */ /* createdb */
if (createdb < 0) 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
{ {
new_record[Anum_pg_shadow_usecreatedb - 1] = BoolGetDatum(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 * createuser (superuser) and catupd
* *
@ -784,22 +771,13 @@ AlterUser(AlterUserStmt *stmt)
* with a situation where no existing superuser can alter the * with a situation where no existing superuser can alter the
* catalogs, including pg_shadow! * catalogs, including pg_shadow!
*/ */
if (createuser < 0) 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
{ {
new_record[Anum_pg_shadow_usesuper - 1] = BoolGetDatum(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[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 */ /* password */
@ -816,14 +794,7 @@ AlterUser(AlterUserStmt *stmt)
new_record[Anum_pg_shadow_passwd - 1] = new_record[Anum_pg_shadow_passwd - 1] =
DirectFunctionCall1(textin, CStringGetDatum(encrypted_password)); DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
} }
new_record_nulls[Anum_pg_shadow_passwd - 1] = ' '; new_record_repl[Anum_pg_shadow_passwd - 1] = 'r';
}
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' : ' ';
} }
/* valid until */ /* valid until */
@ -831,22 +802,11 @@ AlterUser(AlterUserStmt *stmt)
{ {
new_record[Anum_pg_shadow_valuntil - 1] = new_record[Anum_pg_shadow_valuntil - 1] =
DirectFunctionCall1(nabstimein, CStringGetDatum(validUntil)); 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_tuple = heap_modifytuple(tuple, pg_shadow_rel, new_record,
new_record[Anum_pg_shadow_useconfig - 1] = new_record_nulls, new_record_repl);
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);
simple_heap_update(pg_shadow_rel, &tuple->t_self, new_tuple); simple_heap_update(pg_shadow_rel, &tuple->t_self, new_tuple);
/* Update indexes */ /* Update indexes */
@ -876,7 +836,6 @@ AlterUser(AlterUserStmt *stmt)
} }
/* /*
* ALTER USER ... SET * ALTER USER ... SET
*/ */
@ -896,6 +855,10 @@ AlterUserSet(AlterUserSetStmt *stmt)
? ((A_Const *) lfirst(stmt->value))->val.val.str ? ((A_Const *) lfirst(stmt->value))->val.val.str
: NULL); : NULL);
/*
* RowExclusiveLock is sufficient, because we don't need to update
* the flat password file.
*/
rel = heap_openr(ShadowRelationName, RowExclusiveLock); rel = heap_openr(ShadowRelationName, RowExclusiveLock);
oldtuple = SearchSysCache(SHADOWNAME, oldtuple = SearchSysCache(SHADOWNAME,
PointerGetDatum(stmt->user), PointerGetDatum(stmt->user),
@ -925,16 +888,12 @@ AlterUserSet(AlterUserSetStmt *stmt)
datum = SysCacheGetAttr(SHADOWNAME, oldtuple, datum = SysCacheGetAttr(SHADOWNAME, oldtuple,
Anum_pg_shadow_useconfig, &isnull); Anum_pg_shadow_useconfig, &isnull);
array = isnull ? ((ArrayType *) NULL) : DatumGetArrayTypeP(datum);
if (valuestr) if (valuestr)
array = GUCArrayAdd(isnull array = GUCArrayAdd(array, stmt->variable, valuestr);
? NULL
: (ArrayType *) pg_detoast_datum((struct varlena *)datum),
stmt->variable, valuestr);
else else
array = GUCArrayDelete(isnull array = GUCArrayDelete(array, stmt->variable);
? NULL
: (ArrayType *) pg_detoast_datum((struct varlena *)datum),
stmt->variable);
repl_val[Anum_pg_shadow_useconfig-1] = PointerGetDatum(array); repl_val[Anum_pg_shadow_useconfig-1] = PointerGetDatum(array);
} }
@ -982,16 +941,14 @@ DropUser(DropUserStmt *stmt)
foreach(item, stmt->users) foreach(item, stmt->users)
{ {
const char *user = strVal(lfirst(item));
HeapTuple tuple, HeapTuple tuple,
tmp_tuple; tmp_tuple;
Relation pg_rel; Relation pg_rel;
TupleDesc pg_dsc; TupleDesc pg_dsc;
ScanKeyData scankey; ScanKeyData scankey;
HeapScanDesc scan; HeapScanDesc scan;
Datum datum;
bool null;
int32 usesysid; int32 usesysid;
const char *user = strVal(lfirst(item));
tuple = SearchSysCache(SHADOWNAME, tuple = SearchSysCache(SHADOWNAME,
PointerGetDatum(user), PointerGetDatum(user),
@ -1000,7 +957,7 @@ DropUser(DropUserStmt *stmt)
elog(ERROR, "DROP USER: user \"%s\" does not exist%s", user, elog(ERROR, "DROP USER: user \"%s\" does not exist%s", user,
(length(stmt->users) > 1) ? " (no users removed)" : ""); (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()) if (usesysid == GetUserId())
elog(ERROR, "current user cannot be dropped"); elog(ERROR, "current user cannot be dropped");
@ -1028,10 +985,7 @@ DropUser(DropUserStmt *stmt)
{ {
char *dbname; char *dbname;
datum = heap_getattr(tmp_tuple, Anum_pg_database_datname, dbname = NameStr(((Form_pg_database) GETSTRUCT(tmp_tuple))->datname);
pg_dsc, &null);
Assert(!null);
dbname = NameStr(*DatumGetName(datum));
elog(ERROR, "DROP USER: user \"%s\" owns database \"%s\", cannot be removed%s", elog(ERROR, "DROP USER: user \"%s\" owns database \"%s\", cannot be removed%s",
user, dbname, user, dbname,
(length(stmt->users) > 1) ? " (no users removed)" : ""); (length(stmt->users) > 1) ? " (no users removed)" : "");
@ -1066,8 +1020,7 @@ DropUser(DropUserStmt *stmt)
AlterGroupStmt ags; AlterGroupStmt ags;
/* the group name from which to try to drop the user: */ /* 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 = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tmp_tuple))->groname));
ags.name = DatumGetCString(DirectFunctionCall1(nameout, datum));
ags.action = -1; ags.action = -1;
ags.listUsers = makeList1(makeInteger(usesysid)); ags.listUsers = makeList1(makeInteger(usesysid));
AlterGroup(&ags, "DROP USER"); AlterGroup(&ags, "DROP USER");
@ -1202,24 +1155,19 @@ CreateGroup(CreateGroupStmt *stmt)
while (!group_exists && !sysid_exists && while (!group_exists && !sysid_exists &&
HeapTupleIsValid(tuple = heap_getnext(scan, false))) HeapTupleIsValid(tuple = heap_getnext(scan, false)))
{ {
Datum datum; Form_pg_group group_form = (Form_pg_group) GETSTRUCT(tuple);
bool null; int32 this_sysid;
datum = heap_getattr(tuple, Anum_pg_group_groname, group_exists = (strcmp(NameStr(group_form->groname), stmt->name) == 0);
pg_group_dsc, &null);
Assert(!null);
group_exists = (strcmp(NameStr(*DatumGetName(datum)), stmt->name) == 0);
datum = heap_getattr(tuple, Anum_pg_group_grosysid, this_sysid = group_form->grosysid;
pg_group_dsc, &null);
Assert(!null);
if (havesysid) /* customized id wanted */ if (havesysid) /* customized id wanted */
sysid_exists = (DatumGetInt32(datum) == sysid); sysid_exists = (this_sysid == sysid);
else else
{ {
/* pick 1 + max */ /* pick 1 + max */
if (DatumGetInt32(datum) > max_id) if (this_sysid > max_id)
max_id = DatumGetInt32(datum); max_id = this_sysid;
} }
} }
heap_endscan(scan); heap_endscan(scan);
@ -1231,44 +1179,30 @@ CreateGroup(CreateGroupStmt *stmt)
elog(ERROR, "CREATE GROUP: group sysid %d is already assigned", elog(ERROR, "CREATE GROUP: group sysid %d is already assigned",
sysid); sysid);
if (!havesysid)
sysid = max_id + 1;
/* /*
* Translate the given user names to ids * Translate the given user names to ids
*/ */
foreach(item, userElts) foreach(item, userElts)
{ {
const char *groupuser = strVal(lfirst(item)); const char *groupuser = strVal(lfirst(item));
Value *v; int32 userid = get_usesysid(groupuser);
v = makeInteger(get_usesysid(groupuser)); if (!intMember(userid, newlist))
if (!member(v, newlist)) newlist = lappendi(newlist, userid);
newlist = lappend(newlist, v);
} }
/* build an array to insert */ /* build an array to insert */
if (newlist) if (newlist)
{ userarray = IdListToArray(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));
}
else else
userarray = NULL; userarray = NULL;
/* /*
* Form a tuple to insert * Form a tuple to insert
*/ */
if (!havesysid)
sysid = max_id + 1;
new_record[Anum_pg_group_groname - 1] = new_record[Anum_pg_group_groname - 1] =
DirectFunctionCall1(namein, CStringGetDatum(stmt->name)); DirectFunctionCall1(namein, CStringGetDatum(stmt->name));
new_record[Anum_pg_group_grosysid - 1] = Int32GetDatum(sysid); new_record[Anum_pg_group_grosysid - 1] = Int32GetDatum(sysid);
@ -1318,6 +1252,11 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
Relation pg_group_rel; Relation pg_group_rel;
TupleDesc pg_group_dsc; TupleDesc pg_group_dsc;
HeapTuple group_tuple; HeapTuple group_tuple;
IdList *oldarray;
Datum datum;
bool null;
List *newlist,
*item;
/* /*
* Make sure the user can do this. * Make sure the user can do this.
@ -1337,6 +1276,14 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
if (!HeapTupleIsValid(group_tuple)) if (!HeapTupleIsValid(group_tuple))
elog(ERROR, "%s: group \"%s\" does not exist", tag, stmt->name); 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. * 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 if (stmt->action == +1) /* add users, might also be invoked by
* create user */ * 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 * the list
*/ */
foreach(item, stmt->listUsers) foreach(item, stmt->listUsers)
{ {
Value *v; int32 sysid;
if (strcmp(tag, "ALTER GROUP") == 0) if (strcmp(tag, "ALTER GROUP") == 0)
{ {
/* Get the uid of the proposed user to add. */ /* 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) 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 this case we already know the uid and it wouldn't be
* in the cache anyway yet * in the cache anyway yet
*/ */
v = lfirst(item); sysid = intVal(lfirst(item));
} }
else else
{ {
elog(ERROR, "AlterGroup: unknown tag %s", tag); elog(ERROR, "AlterGroup: unknown tag %s", tag);
v = NULL; /* keep compiler quiet */ sysid = 0; /* keep compiler quiet */
} }
if (!member(v, newlist)) if (!intMember(sysid, newlist))
newlist = lappend(newlist, v); newlist = lappendi(newlist, sysid);
else else
/* /*
* we silently assume here that this error will only come * 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); tag, strVal(lfirst(item)), stmt->name);
} }
newarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32)); /* Do the update */
newarray->size = ARR_OVERHEAD(1) + length(newlist) * sizeof(int32); UpdateGroupMembership(pg_group_rel, group_tuple, newlist);
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);
}
} /* endif alter group add user */ } /* endif alter group add user */
else if (stmt->action == -1) /* drop users from group */ else if (stmt->action == -1) /* drop users from group */
{ {
Datum datum;
bool null;
bool is_dropuser = strcmp(tag, "DROP USER") == 0; bool is_dropuser = strcmp(tag, "DROP USER") == 0;
datum = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null); if (newlist == NIL)
if (null)
{ {
if (!is_dropuser) if (!is_dropuser)
elog(WARNING, "ALTER GROUP: group \"%s\" does not have any members", stmt->name); elog(WARNING, "ALTER GROUP: group \"%s\" does not have any members", stmt->name);
} }
else 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 * remove them from the list
*/ */
foreach(item, stmt->listUsers) foreach(item, stmt->listUsers)
{ {
Value *v; int32 sysid;
if (!is_dropuser) if (!is_dropuser)
{ {
/* Get the uid of the proposed user to drop. */ /* Get the uid of the proposed user to drop. */
v = makeInteger(get_usesysid(strVal(lfirst(item)))); sysid = get_usesysid(strVal(lfirst(item)));
} }
else else
{ {
/* for dropuser we already know the uid */ /* for dropuser we already know the uid */
v = lfirst(item); sysid = intVal(lfirst(item));
} }
if (member(v, newlist)) if (intMember(sysid, newlist))
newlist = LispRemove(v, newlist); newlist = lremovei(sysid, newlist);
else if (!is_dropuser) else if (!is_dropuser)
elog(WARNING, "ALTER GROUP: user \"%s\" is not in group \"%s\"", strVal(lfirst(item)), stmt->name); 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)); /* Do the update */
newarray->size = ARR_OVERHEAD(1) + length(newlist) * sizeof(int32); UpdateGroupMembership(pg_group_rel, group_tuple, newlist);
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);
}
} /* endif group not null */ } /* endif group not null */
} /* endif alter group drop user */ } /* endif alter group drop user */
@ -1571,6 +1387,107 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
update_pg_pwd_and_pg_group(NULL); 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) DropGroup(DropGroupStmt *stmt)
{ {
Relation pg_group_rel; Relation pg_group_rel;
HeapScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
TupleDesc pg_group_dsc;
bool gro_exists = false;
/* /*
* Make sure the user can do this. * Make sure the user can do this.
@ -1592,34 +1506,18 @@ DropGroup(DropGroupStmt *stmt)
elog(ERROR, "DROP GROUP: permission denied"); 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_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))) tuple = SearchSysCacheCopy(GRONAME,
{ PointerGetDatum(stmt->name),
Datum datum; 0, 0, 0);
bool null; if (!HeapTupleIsValid(tuple))
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)
elog(ERROR, "DROP GROUP: group \"%s\" does not exist", stmt->name); 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); heap_close(pg_group_rel, NoLock);
/* /*

View File

@ -27,7 +27,7 @@
* *
* *
* IDENTIFICATION * 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, namespaceId,
tupdesc, tupdesc,
RELKIND_RELATION, RELKIND_RELATION,
false,
true, true,
allowSystemTableMods); allowSystemTableMods);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, * The relation descriptor is built just from the supplied parameters,
* without actually looking at any system table entries. We cheat * without actually looking at any system table entries. We cheat
* quite a lot since we only need to work for a few basic system * 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, * Note that these catalogs can't have constraints, default values,
* rules, or triggers, since we don't cope with any of that. * 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 * It's important to distinguish between shared and non-shared
* relations, even at bootstrap time, to make sure we know where they * 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->relpages = 1;
relation->rd_rel->reltuples = 1; relation->rd_rel->reltuples = 1;
@ -1434,15 +1438,8 @@ formrdesc(const char *relationName,
/* In bootstrap mode, we have no indexes */ /* In bootstrap mode, we have no indexes */
if (!IsBootstrapProcessingMode()) if (!IsBootstrapProcessingMode())
{ {
/* /* Otherwise, all the rels formrdesc is used for have indexes */
* This list is incomplete, but it only has to work for the set of relation->rd_rel->relhasindex = true;
* 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;
} }
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Globals used all over the place should be declared here and not * Globals used all over the place should be declared here and not
@ -18,14 +18,6 @@
*/ */
#include "postgres.h" #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 "libpq/pqcomm.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/backendid.h" #include "storage/backendid.h"
@ -47,14 +39,11 @@ struct Port *MyProcPort;
long MyCancelKey; long MyCancelKey;
char *DataDir = NULL; char *DataDir = NULL;
/* /*
* The PGDATA directory user says to use, or defaults to via environment * The PGDATA directory user says to use, or defaults to via environment
* variable. NULL if no option given and no environment variable set * variable. NULL if no option given and no environment variable set
*/ */
Relation reldesc; /* current relation descriptor */
char OutputFileName[MAXPGPATH]; char OutputFileName[MAXPGPATH];
char pg_pathname[MAXPGPATH]; /* full path to postgres char pg_pathname[MAXPGPATH]; /* full path to postgres
@ -85,27 +74,3 @@ bool allowSystemTableMods = false;
int SortMem = 512; int SortMem = 512;
int VacuumMem = 8192; int VacuumMem = 8192;
int NBuffers = DEF_NBUFFERS; 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
};

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); Anum_pg_shadow_useconfig, &isnull);
if (!isnull) if (!isnull)
{ {
ArrayType *a; ArrayType *a = DatumGetArrayTypeP(datum);
a = (ArrayType *) pg_detoast_datum((struct varlena *)datum);
ProcessGUCArray(a, PGC_S_USER); ProcessGUCArray(a, PGC_S_USER);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 #endif
/* /*
* Set up datbase-specific configuration variables. * Set up database-specific configuration variables.
*/ */
if (IsUnderPostmaster) if (IsUnderPostmaster)
{ {
@ -149,9 +149,8 @@ ReverifyMyDatabase(const char *name)
RelationGetDescr(pgdbrel), &isnull); RelationGetDescr(pgdbrel), &isnull);
if (!isnull) if (!isnull)
{ {
ArrayType *a; ArrayType *a = DatumGetArrayTypeP(datum);
a = (ArrayType *) pg_detoast_datum((struct varlena *)datum);
ProcessGUCArray(a, PGC_S_DATABASE); ProcessGUCArray(a, PGC_S_DATABASE);
} }
} }

View File

@ -27,7 +27,7 @@
# Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group # Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California # 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 <<EOF "$PGPATH"/postgres $PGSQL_OPT template1 >/dev/null <<EOF
ALTER TABLE pg_attrdef CREATE TOAST TABLE; ALTER TABLE pg_attrdef CREATE TOAST TABLE;
ALTER TABLE pg_database CREATE TOAST TABLE;
ALTER TABLE pg_description 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_proc CREATE TOAST TABLE;
ALTER TABLE pg_relcheck CREATE TOAST TABLE; ALTER TABLE pg_relcheck CREATE TOAST TABLE;
ALTER TABLE pg_rewrite CREATE TOAST TABLE; ALTER TABLE pg_rewrite CREATE TOAST TABLE;
ALTER TABLE pg_shadow CREATE TOAST TABLE;
ALTER TABLE pg_statistic CREATE TOAST TABLE; ALTER TABLE pg_statistic CREATE TOAST TABLE;
EOF EOF
if [ "$?" -ne 0 ]; then if [ "$?" -ne 0 ]; then

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -31,7 +31,7 @@ typedef struct hashnode
} hashnode; } hashnode;
extern Relation reldesc; extern Relation boot_reldesc;
extern Form_pg_attribute attrtypes[MAXATTR]; extern Form_pg_attribute attrtypes[MAXATTR];
extern int numattr; extern int numattr;
extern int BootstrapMain(int ac, char *av[]); extern int BootstrapMain(int ac, char *av[]);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -30,7 +30,6 @@ extern bool IsSystemNamespace(Oid namespaceId);
extern bool IsToastNamespace(Oid namespaceId); extern bool IsToastNamespace(Oid namespaceId);
extern bool IsReservedName(const char *name); extern bool IsReservedName(const char *name);
extern bool IsSharedSystemRelationName(const char *relname);
extern Oid newoid(void); extern Oid newoid(void);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -42,6 +42,4 @@
#define RelCheckRelationName "pg_relcheck" #define RelCheckRelationName "pg_relcheck"
#define TriggerRelationName "pg_trigger" #define TriggerRelationName "pg_trigger"
extern char *SharedSystemRelationNames[];
#endif /* CATNAME_H */ #endif /* CATNAME_H */

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200204251 #define CATALOG_VERSION_NO 200204271
#endif #endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -30,6 +30,7 @@ typedef struct RawColumnDefault
extern Relation heap_create(const char *relname, extern Relation heap_create(const char *relname,
Oid relnamespace, Oid relnamespace,
TupleDesc tupDesc, TupleDesc tupDesc,
bool shared_relation,
bool storage_create, bool storage_create,
bool allow_system_table_mods); bool allow_system_table_mods);
@ -39,6 +40,7 @@ extern Oid heap_create_with_catalog(const char *relname,
Oid relnamespace, Oid relnamespace,
TupleDesc tupdesc, TupleDesc tupdesc,
char relkind, char relkind,
bool shared_relation,
bool relhasoids, bool relhasoids,
bool allow_system_table_mods); bool allow_system_table_mods);

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -31,7 +31,7 @@
* typedef struct FormData_pg_database * typedef struct FormData_pg_database
* ---------------- * ----------------
*/ */
CATALOG(pg_database) BOOTSTRAP CATALOG(pg_database) BOOTSTRAP BKI_SHARED_RELATION
{ {
NameData datname; /* database name */ NameData datname; /* database name */
int4 datdba; /* sysid of owner */ int4 datdba; /* sysid of owner */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -25,7 +25,7 @@
* ---------------- * ----------------
*/ */
CATALOG(pg_group) BOOTSTRAP BKI_WITHOUT_OIDS CATALOG(pg_group) BOOTSTRAP BKI_SHARED_RELATION BKI_WITHOUT_OIDS
{ {
NameData groname; NameData groname;
int4 grosysid; int4 grosysid;

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -29,7 +29,7 @@
* typedef struct FormData_pg_shadow * typedef struct FormData_pg_shadow
* ---------------- * ----------------
*/ */
CATALOG(pg_shadow) BOOTSTRAP BKI_WITHOUT_OIDS CATALOG(pg_shadow) BOOTSTRAP BKI_SHARED_RELATION BKI_WITHOUT_OIDS
{ {
NameData usename; NameData usename;
int4 usesysid; int4 usesysid;
@ -37,8 +37,9 @@ CATALOG(pg_shadow) BOOTSTRAP BKI_WITHOUT_OIDS
bool usetrace; bool usetrace;
bool usesuper; /* read this field via superuser() only */ bool usesuper; /* read this field via superuser() only */
bool usecatupd; bool usecatupd;
/* remaining fields may be null; use heap_getattr to read them! */
text passwd; text passwd;
int4 valuntil; int4 valuntil; /* actually abstime */
text useconfig[1]; text useconfig[1];
} FormData_pg_shadow; } FormData_pg_shadow;

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1995, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -597,7 +597,7 @@ extern int assertTest(int val);
#define CATALOG(x) typedef struct CppConcat(FormData_,x) #define CATALOG(x) typedef struct CppConcat(FormData_,x)
#define BOOTSTRAP #define BOOTSTRAP
#define BKI_SHARED_RELATION
#define BKI_WITHOUT_OIDS #define BKI_WITHOUT_OIDS
/* these need to expand into some harmless, repeatable declaration */ /* these need to expand into some harmless, repeatable declaration */