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