mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03: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:
@ -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);
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user