schema change (ugh) normalized immunity properly

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401332
This commit is contained in:
David Anderson 2007-08-14 05:42:44 +00:00
parent 309de7c510
commit b5df2dfb07
7 changed files with 221 additions and 258 deletions

View File

@ -14,10 +14,15 @@ CREATE TABLE sm_groups (
immunity enum('none','all','default') NOT NULL, immunity enum('none','all','default') NOT NULL,
flags varchar(30) NOT NULL, flags varchar(30) NOT NULL,
name varchar(120) NOT NULL, name varchar(120) NOT NULL,
groups_immune varchar(255),
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE sm_group_immunity (
group_id int(10) unsigned NOT NULL,
other_id int(10) unsigned NOT NULL,
PRIMARY KEY (group_id, other_id)
);
CREATE TABLE sm_group_overrides ( CREATE TABLE sm_group_overrides (
group_id int(10) unsigned NOT NULL, group_id int(10) unsigned NOT NULL,
type enum('command','group') NOT NULL, type enum('command','group') NOT NULL,

View File

@ -12,8 +12,13 @@ CREATE TABLE sm_groups (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
immunity varchar(16) NOT NULL CHECK(immunity IN ('none', 'default', 'global', 'all')), immunity varchar(16) NOT NULL CHECK(immunity IN ('none', 'default', 'global', 'all')),
flags varchar(30) NOT NULL, flags varchar(30) NOT NULL,
name varchar(120) NOT NULL, name varchar(120) NOT NULL
groups_immune varchar(255) );
CREATE TABLE sm_group_immunity (
group_id INTEGER NOT NULL,
other_id INTEGER NOT NULL,
PRIMARY KEY (group_id, other_id)
); );
CREATE TABLE sm_group_overrides ( CREATE TABLE sm_group_overrides (

View File

@ -101,7 +101,7 @@ FetchUsers(Handle:db)
decl String:query[255], String:error[255]; decl String:query[255], String:error[255];
new Handle:hQuery, Handle:hGroupQuery; new Handle:hQuery, Handle:hGroupQuery;
Format(query, sizeof(query), "SELECT id, authtype, identity, passwd, flags, name FROM sm_admins"); Format(query, sizeof(query), "SELECT id, authtype, identity, password, flags, name FROM sm_admins");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE) if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{ {
SQL_GetError(db, error, sizeof(error)); SQL_GetError(db, error, sizeof(error));
@ -185,7 +185,7 @@ FetchGroups(Handle:db)
decl String:query[255]; decl String:query[255];
new Handle:hQuery; new Handle:hQuery;
Format(query, sizeof(query), "SELECT id, immunity, flags, name, groups_immune FROM sm_groups"); Format(query, sizeof(query), "SELECT immunity, flags, name FROM sm_groups");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE) if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{ {
@ -196,24 +196,18 @@ FetchGroups(Handle:db)
return; return;
} }
/* We cache basic group info so we can do reverse lookups */
new Handle:groups = CreateArray(3);
/* Now start fetching groups */ /* Now start fetching groups */
decl String:immunity[16]; decl String:immunity[16];
decl String:flags[32]; decl String:flags[32];
decl String:name[128]; decl String:name[128];
decl String:grp_immunity[256];
while (SQL_FetchRow(hQuery)) while (SQL_FetchRow(hQuery))
{ {
new id = SQL_FetchInt(hQuery, 0); SQL_FetchString(hQuery, 0, immunity, sizeof(immunity));
SQL_FetchString(hQuery, 1, immunity, sizeof(immunity)); SQL_FetchString(hQuery, 1, flags, sizeof(flags));
SQL_FetchString(hQuery, 2, flags, sizeof(flags)); SQL_FetchString(hQuery, 2, name, sizeof(name));
SQL_FetchString(hQuery, 3, name, sizeof(name));
SQL_FetchString(hQuery, 4, grp_immunity, sizeof(grp_immunity));
#if defined _DEBUG #if defined _DEBUG
PrintToServer("Adding group (%d, %s, %s, %s, %s)", id, immunity, flags, name, grp_immunity); PrintToServer("Adding group (%s, %s, %s)", immunity, flags, name);
#endif #endif
/* Find or create the group */ /* Find or create the group */
@ -245,53 +239,79 @@ FetchGroups(Handle:db)
} else if (StrEqual(immunity, "global")) { } else if (StrEqual(immunity, "global")) {
SetAdmGroupImmunity(gid, Immunity_Global, true); SetAdmGroupImmunity(gid, Immunity_Global, true);
} }
new Handle:immunity_list = UTIL_ExplodeNumberString(grp_immunity);
/* Now, save all this for later */
decl data[3];
data[0] = id;
data[1] = _:gid;
data[2] = _:immunity_list;
PushArrayArray(groups, data);
} }
CloseHandle(hQuery); CloseHandle(hQuery);
/* Second pass - resolve immunity and group overrides */ /**
new num_groups = GetArraySize(groups); * Get immunity in a big lump. This is a nasty query but it gets the job done.
for (new i=0; i<num_groups; i++) */
{ new len = 0;
decl data[3]; len += Format(query[len], sizeof(query)-len, "SELECT g1.name, g2.name FROM sm_group_immunity gi");
GetArrayArray(groups, i, data); len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g1 ON g1.id = gi.group_id ");
len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g2 ON g2.id = gi.other_id");
new id = data[0];
new GroupId:gid = GroupId:data[1];
new Handle:immunity_list = Handle:data[2];
/* Query to get per-group override list */
Format(query,
sizeof(query),
"SELECT type, name, access FROM sm_group_overrides WHERE group_id = %d",
id);
/* Fetch the override query results */
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE) if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{ {
decl String:error[255]; decl String:error[255];
SQL_GetError(db, error, sizeof(error)); SQL_GetError(db, error, sizeof(error));
LogError("FetchOverrides() query failed: %s", query); LogError("FetchGroups() query failed: %s", query);
LogError("Query error: %s", error); LogError("Query error: %s", error);
} else { return;
}
while (SQL_FetchRow(hQuery))
{
decl String:group1[80];
decl String:group2[80];
new GroupId:gid1, GroupId:gid2;
SQL_FetchString(hQuery, 0, group1, sizeof(group1));
SQL_FetchString(hQuery, 1, group2, sizeof(group2));
if (((gid1 = FindAdmGroup(group1)) == INVALID_GROUP_ID)
|| (gid2 = FindAdmGroup(group2)) == INVALID_GROUP_ID)
{
continue;
}
SetAdmGroupImmuneFrom(gid1, gid2);
#if defined _DEBUG
PrintToServer("SetAdmGroupImmuneFrom(%d, %d)", gid1, gid2);
#endif
}
CloseHandle(hQuery);
/**
* Fetch overrides in a lump query.
*/
Format(query, sizeof(query), "SELECT g.name, go.type, go.name, go.access FROM sm_group_overrides go LEFT JOIN sm_groups g ON go.group_id = g.id");
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
decl String:error[255];
SQL_GetError(db, error, sizeof(error));
LogError("FetchGroups() query failed: %s", query);
LogError("Query error: %s", error);
return;
}
decl String:type[16]; decl String:type[16];
decl String:cmd[64]; decl String:cmd[64];
decl String:access[16]; decl String:access[16];
while (SQL_FetchRow(hQuery)) while (SQL_FetchRow(hQuery))
{ {
SQL_FetchString(hQuery, 0, type, sizeof(type)); SQL_FetchString(hQuery, 0, name, sizeof(name));
SQL_FetchString(hQuery, 1, cmd, sizeof(cmd)); SQL_FetchString(hQuery, 1, type, sizeof(type));
SQL_FetchString(hQuery, 2, access, sizeof(access)); SQL_FetchString(hQuery, 2, cmd, sizeof(cmd));
SQL_FetchString(hQuery, 3, access, sizeof(access));
new GroupId:gid;
if ((gid = FindAdmGroup(name)) == INVALID_GROUP_ID)
{
continue;
}
new OverrideType:o_type = Override_Command; new OverrideType:o_type = Override_Command;
if (StrEqual(type, "group")) if (StrEqual(type, "group"))
@ -311,44 +331,10 @@ FetchGroups(Handle:db)
AddAdmGroupCmdOverride(gid, cmd, o_type, o_rule); AddAdmGroupCmdOverride(gid, cmd, o_type, o_rule);
} }
CloseHandle(hQuery); CloseHandle(hQuery);
} }
/* Lastly, resolve the immunity list if any */
new immunity_count;
if (immunity_list != INVALID_HANDLE
&& ((immunity_count = GetArraySize(immunity_list)) > 0))
{
for (new j=0; j<immunity_count; j++)
{
new other_id = GetArrayCell(immunity_list, j);
if (other_id == id)
{
continue;
}
/* See if we can find this other ID */
new GroupId:other_gid;
if ((other_gid = UTIL_FindGroupInCache(groups, other_id)) != INVALID_GROUP_ID)
{
#if defined _DEBUG
PrintToServer("SetAdmGroupImmuneFrom(%d, %d)", gid, other_gid);
#endif
SetAdmGroupImmuneFrom(gid, other_gid);
}
}
}
if (immunity_list != INVALID_HANDLE)
{
CloseHandle(immunity_list);
}
}
CloseHandle(groups);
}
FetchOverrides(Handle:db) FetchOverrides(Handle:db)
{ {
decl String:query[255]; decl String:query[255];
@ -390,62 +376,3 @@ FetchOverrides(Handle:db)
CloseHandle(hQuery); CloseHandle(hQuery);
} }
stock GroupId:UTIL_FindGroupInCache(Handle:group_list, id)
{
new size = GetArraySize(group_list);
for (new i=0; i<size; i++)
{
decl data[3];
GetArrayArray(group_list, i, data);
if (data[0] == id)
{
return GroupId:data[1];
}
}
return INVALID_GROUP_ID;
}
/**
* Breaks a comma-delimited string into a list of numbers, returning a new
* dynamic array.
*
* @param text The string to split.
* @return A new array Handle which must be closed, or
* INVALID_HANDLE on no strings found.
*/
stock Handle:UTIL_ExplodeNumberString(const String:text[])
{
new Handle:array = INVALID_HANDLE;
decl String:buffer[32];
new reloc_idx, idx;
while ((idx = SplitString(text[reloc_idx], ",", buffer, sizeof(buffer))) != -1)
{
reloc_idx += idx;
if (text[reloc_idx] == '\0')
{
break;
}
if (array == INVALID_HANDLE)
{
array = CreateArray();
}
PushArrayCell(array, StringToInt(buffer));
}
if (text[reloc_idx] != '\0')
{
if (array == INVALID_HANDLE)
{
array = CreateArray();
}
PushArrayCell(array, StringToInt(text[reloc_idx]));
}
return array;
}

View File

@ -53,8 +53,8 @@ public Plugin:myinfo =
* was a 100% success in the fetch. This is so we can potentially implement * was a 100% success in the fetch. This is so we can potentially implement
* connection retries in the future. * connection retries in the future.
* *
* 4) Sequence numbers for the admin cache are ignored except for being * 4) Sequence numbers for the user cache are ignored except for being
* non-zero, which means players in-game should be re-checked for admin \ * non-zero, which means players in-game should be re-checked for admin
* powers. * powers.
*/ */
@ -525,6 +525,64 @@ FetchUsersWeCan(Handle:db)
RebuildCachePart[_:AdminCache_Admins] = 0; RebuildCachePart[_:AdminCache_Admins] = 0;
} }
public OnReceiveGroupImmunity(Handle:owner, Handle:hndl, const String:error[], any:data)
{
new Handle:pk = Handle:data;
ResetPack(pk);
/**
* Check if this is the latest result request.
*/
new sequence = ReadPackCell(pk);
if (RebuildCachePart[_:AdminCache_Groups] != sequence)
{
/* Discard everything, since we're out of sequence. */
CloseHandle(pk);
return;
}
/**
* If we need to use the results, make sure they succeeded.
*/
if (hndl == INVALID_HANDLE)
{
decl String:query[255];
ReadPackString(pk, query, sizeof(query));
LogError("SQL error receiving group immunity: %s", error);
LogError("Query dump: %s", query);
CloseHandle(pk);
return;
}
/* We're done with the pack forever. */
CloseHandle(pk);
while (SQL_FetchRow(hndl))
{
decl String:group1[80];
decl String:group2[80];
new GroupId:gid1, GroupId:gid2;
SQL_FetchString(hndl, 0, group1, sizeof(group1));
SQL_FetchString(hndl, 1, group2, sizeof(group2));
if (((gid1 = FindAdmGroup(group1)) == INVALID_GROUP_ID)
|| (gid2 = FindAdmGroup(group2)) == INVALID_GROUP_ID)
{
continue;
}
SetAdmGroupImmuneFrom(gid1, gid2);
#if defined _DEBUG
PrintToServer("SetAdmGroupImmuneFrom(%d, %d)", gid1, gid2);
#endif
}
/* Clear the sequence so another connect doesn't refetch */
RebuildCachePart[_:AdminCache_Groups] = 0;
}
public OnReceiveGroupOverrides(Handle:owner, Handle:hndl, const String:error[], any:data) public OnReceiveGroupOverrides(Handle:owner, Handle:hndl, const String:error[], any:data)
{ {
new Handle:pk = Handle:data; new Handle:pk = Handle:data;
@ -554,9 +612,6 @@ public OnReceiveGroupOverrides(Handle:owner, Handle:hndl, const String:error[],
return; return;
} }
/* We're done with the pack forever. */
CloseHandle(pk);
/** /**
* Fetch the overrides. * Fetch the overrides.
*/ */
@ -598,8 +653,20 @@ public OnReceiveGroupOverrides(Handle:owner, Handle:hndl, const String:error[],
AddAdmGroupCmdOverride(gid, command, o_type, o_rule); AddAdmGroupCmdOverride(gid, command, o_type, o_rule);
} }
/* Clear the sequence so another connect doesn't refetch */ /**
RebuildCachePart[_:AdminCache_Groups] = 0; * It's time to get the group immunity list.
*/
new len = 0;
decl String:query[256];
len += Format(query[len], sizeof(query)-len, "SELECT g1.name, g2.name FROM sm_group_immunity gi");
len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g1 ON g1.id = gi.group_id ");
len += Format(query[len], sizeof(query)-len, " LEFT JOIN sm_groups g2 ON g2.id = gi.other_id");
ResetPack(pk);
WritePackCell(pk, sequence);
WritePackString(pk, query);
SQL_TQuery(owner, OnReceiveGroupImmunity, query, pk, DBPrio_High);
} }
public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data) public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data)
@ -631,26 +698,20 @@ public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data
return; return;
} }
/* We cache basic group info so we can do reverse lookups */
new Handle:groups = CreateArray(3);
/** /**
* Now start fetching groups. * Now start fetching groups.
*/ */
decl String:immunity[16]; decl String:immunity[16];
decl String:flags[32]; decl String:flags[32];
decl String:name[128]; decl String:name[128];
decl String:grp_immunity[256];
while (SQL_FetchRow(hndl)) while (SQL_FetchRow(hndl))
{ {
new id = SQL_FetchInt(hndl, 0); SQL_FetchString(hndl, 0, immunity, sizeof(immunity));
SQL_FetchString(hndl, 1, immunity, sizeof(immunity)); SQL_FetchString(hndl, 1, flags, sizeof(flags));
SQL_FetchString(hndl, 2, flags, sizeof(flags)); SQL_FetchString(hndl, 2, name, sizeof(name));
SQL_FetchString(hndl, 3, name, sizeof(name));
SQL_FetchString(hndl, 4, grp_immunity, sizeof(grp_immunity));
#if defined _DEBUG #if defined _DEBUG
PrintToServer("Adding group (%d, %s, %s, %s, %s)", id, immunity, flags, name, grp_immunity); PrintToServer("Adding group (%s, %s, %s)", immunity, flags, name);
#endif #endif
/* Find or create the group */ /* Find or create the group */
@ -682,65 +743,10 @@ public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data
} else if (StrEqual(immunity, "global")) { } else if (StrEqual(immunity, "global")) {
SetAdmGroupImmunity(gid, Immunity_Global, true); SetAdmGroupImmunity(gid, Immunity_Global, true);
} }
new Handle:immunity_list = UTIL_ExplodeNumberString(grp_immunity);
/* Now, save all this for later */
decl savedata[3];
savedata[0] = id;
savedata[1] = _:gid;
savedata[2] = _:immunity_list;
PushArrayArray(groups, savedata);
} }
/** /**
* Resolve immunity now in a second pass. * It's time to get the group override list.
*/
new num_groups = GetArraySize(groups);
for (new i=0; i<num_groups; i++)
{
decl savedata[3];
GetArrayArray(groups, i, savedata);
new id = savedata[0];
new GroupId:gid = GroupId:savedata[1];
new Handle:immunity_list = Handle:savedata[2];
if (immunity_list != INVALID_HANDLE)
{
new immunity_count = GetArraySize(immunity_list);
for (new j=0; j<immunity_count; j++)
{
new other_id = GetArrayCell(immunity_list, j);
if (other_id == id)
{
continue;
}
/* See if we can find this other ID */
new GroupId:other_gid;
if ((other_gid = UTIL_FindGroupInCache(groups, other_id)) != INVALID_GROUP_ID)
{
#if defined _DEBUG
PrintToServer("SetAdmGroupImmuneFrom(%d, %d)", gid, other_gid);
#endif
SetAdmGroupImmuneFrom(gid, other_gid);
}
}
/**
* We close the Handle but don't zero it in the parent array... not worth
* the effort.
*/
CloseHandle(immunity_list);
}
}
CloseHandle(groups);
/**
* Now we're done with both passes. It's time to get the group override list.
*/ */
decl String:query[255]; decl String:query[255];
Format(query, Format(query,
@ -759,7 +765,7 @@ FetchGroups(Handle:db, sequence)
decl String:query[255]; decl String:query[255];
new Handle:pk; new Handle:pk;
Format(query, sizeof(query), "SELECT id, immunity, flags, name, groups_immune FROM sm_groups"); Format(query, sizeof(query), "SELECT immunity, flags, name FROM sm_groups");
pk = CreateDataPack(); pk = CreateDataPack();
WritePackCell(pk, sequence); WritePackCell(pk, sequence);

View File

@ -227,39 +227,54 @@ public Action:Command_DelGroup(client, args)
decl String:query[256]; decl String:query[256];
new Handle:hQuery;
Format(query, sizeof(query), "SELECT id FROM sm_groups WHERE name = '%s'", safe_name);
if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
{
return DoError(client, db, query, "Group retrieval query failed");
}
if (!SQL_FetchRow(hQuery))
{
ReplyToCommand(client, "[SM] %t", "SQL Group not found");
CloseHandle(hQuery);
CloseHandle(db);
return Plugin_Handled;
}
new id = SQL_FetchInt(hQuery, 0);
CloseHandle(hQuery);
/* Delete admin inheritance for this group */ /* Delete admin inheritance for this group */
Format(query, Format(query, sizeof(query), "DELETE FROM sm_admins_groups WHERE group_id = %d", id);
sizeof(query),
"DELETE FROM sm_admins_groups WHERE group_id IN (SELECT id FROM sm_groups WHERE name = '%s')",
safe_name);
if (!SQL_FastQuery(db, query)) if (!SQL_FastQuery(db, query))
{ {
return DoError(client, db, query, "Admin group deletion query failed"); return DoError(client, db, query, "Admin group deletion query failed");
} }
/* Delete group overrides */ /* Delete group overrides */
Format(query, Format(query, sizeof(query), "DELETE FROM sm_group_overrides WHERE group_id = %d", id);
sizeof(query),
"DELETE FROM sm_group_overrides WHERE group_id IN (SELECT id FROM sm_groups WHERE name = '%s')",
safe_name);
if (!SQL_FastQuery(db, query)) if (!SQL_FastQuery(db, query))
{ {
return DoError(client, db, query, "Group override deletion query failed"); return DoError(client, db, query, "Group override deletion query failed");
} }
/* Delete immunity */
Format(query, sizeof(query), "DELETE FROM sm_group_immunity WHERE group_id = %d OR other_id = %d", id, id);
if (!SQL_FastQuery(db, query))
{
return DoError(client, db, query, "Group immunity deletion query failed");
}
/* Finally delete the group */ /* Finally delete the group */
Format(query, sizeof(query), "DELETE FROM sm_groups WHERE name = '%s'", safe_name); Format(query, sizeof(query), "DELETE FROM sm_groups WHERE id = %d", id);
if (!SQL_FastQuery(db, query)) if (!SQL_FastQuery(db, query))
{ {
return DoError(client, db, query, "Group deletion query failed"); return DoError(client, db, query, "Group deletion query failed");
} }
if (SQL_GetAffectedRows(db))
{
ReplyToCommand(client, "[SM] %t", "SQL Group deleted"); ReplyToCommand(client, "[SM] %t", "SQL Group deleted");
} else {
ReplyToCommand(client, "[SM] %t", "SQL Group not found");
}
CloseHandle(db); CloseHandle(db);

View File

@ -5,6 +5,11 @@
"en" "Auth type must be either 'steam', 'name', or 'ip'." "en" "Auth type must be either 'steam', 'name', or 'ip'."
} }
"Invalid immunity"
{
"en" "Immunity must be 'none', 'default', or 'global'."
}
"SQL Admin already exists" "SQL Admin already exists"
{ {
"en" "An administrator with the given credentials already exists." "en" "An administrator with the given credentials already exists."