From b5df2dfb0763fe263c0412e96d94e19aa66621b9 Mon Sep 17 00:00:00 2001
From: David Anderson <dvander@alliedmods.net>
Date: Tue, 14 Aug 2007 05:42:44 +0000
Subject: [PATCH] schema change (ugh) normalized immunity properly

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401332
---
 configs/sql-init-scripts/admins-mysql.sql  |   7 +-
 configs/sql-init-scripts/admins-sqlite.sq3 | Bin 13312 -> 14336 bytes
 configs/sql-init-scripts/admins-sqlite.sql |   9 +-
 plugins/admin-sql-prefetch.sp              | 259 ++++++++-------------
 plugins/admin-sql-threaded.sp              | 154 ++++++------
 plugins/sql-admin-manager.sp               |  45 ++--
 translations/sqladmins.phrases.txt         |   5 +
 7 files changed, 221 insertions(+), 258 deletions(-)

diff --git a/configs/sql-init-scripts/admins-mysql.sql b/configs/sql-init-scripts/admins-mysql.sql
index c8e06d34..12c79ed5 100644
--- a/configs/sql-init-scripts/admins-mysql.sql
+++ b/configs/sql-init-scripts/admins-mysql.sql
@@ -14,10 +14,15 @@ CREATE TABLE sm_groups (
   immunity enum('none','all','default') NOT NULL,
   flags varchar(30) NOT NULL,
   name varchar(120) NOT NULL,
-  groups_immune varchar(255),
   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 (
   group_id int(10) unsigned NOT NULL,
   type enum('command','group') NOT NULL,
diff --git a/configs/sql-init-scripts/admins-sqlite.sq3 b/configs/sql-init-scripts/admins-sqlite.sq3
index 2883fd10060345631e3d453f64200109e3503c95..2b01c1c7aee47c8f5c8ed369003e21fa1e9cf9f2 100644
GIT binary patch
delta 430
zcmZq3XegK<Ey%`z3fMO4TxMouS;WJ!NPuON0E++*3&SG@hDS`SOySJ_6B{onH7PK%
zi_6P1w(yrECgr3S=f)?d<Ywj-!x>DI52}hyzNPq@DS&BmkYa#RV<|ION3$hNM|x3y
zX#q$Fguya-uF91VF3m<g7Itxcea0qk6ov7bxw)lznI)Al4R8Tg=O9<d5Lbl|M<*Xw
z1q^8gjmdvi6$J82GE$4;GgA~i{X$&bU4tesRF~2R+YA)cQGiKna%u7c1B0DGoPl{S
zQxlUdV<Mvlkn^0O(U)uT6jdEYUZBqwvU0PD2kTBgt1dmcNll)a&zy7eNp&+8p2kRy
z$?w!u7`Z14t8Za*W@i%*Hw3FXuBObw(PY6k`Gk@IBm3r`O6-hmj;w6rq52?cC8$H7
OUW_-y@CDl<0RaHArGv!)

delta 337
zcmZoDXvml#EvUu-0Zc%O5r~yH>Re_v6oZO_C|)4ufnshT%>~4qK+J)J**6QaTwtEW
z!NJ7*5y*VS%)`%EoEx8*lAD=V%(#h%MTCo)F@S+FfN>Gi(T$Bxj7$L{li8I5l$sPo
z*~R7M8C&>E5|eUL;d<Z<mdz}RjEu}p7GjfI)eI&#D2q=%qxMmRmuV3L8$&e%(=w*l
z%*PogG9@xpPi#!*Y7&+Ko7Y@AIZ;V`vYU$F<W8j{$~s&M3h71pr3J<DnYp>8d8rCz
ziABj7iA5Slrly))nvK3vlciL27`Z3At1M)dW)lzAovf!SJ()vQo*m?O7H9Fv_G(Tn
hY>kl;lT%bxCT~>}oIF!?36r_xWGz)QMvg@SJOJS(Oxged

diff --git a/configs/sql-init-scripts/admins-sqlite.sql b/configs/sql-init-scripts/admins-sqlite.sql
index 1c0e2795..2a608548 100644
--- a/configs/sql-init-scripts/admins-sqlite.sql
+++ b/configs/sql-init-scripts/admins-sqlite.sql
@@ -12,8 +12,13 @@ CREATE TABLE sm_groups (
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   immunity varchar(16) NOT NULL CHECK(immunity IN ('none', 'default', 'global', 'all')),
   flags varchar(30) NOT NULL,
-  name varchar(120) NOT NULL,
-  groups_immune varchar(255)
+  name varchar(120) NOT NULL
+);
+
+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 (
diff --git a/plugins/admin-sql-prefetch.sp b/plugins/admin-sql-prefetch.sp
index 4f2ad902..a5789bf2 100644
--- a/plugins/admin-sql-prefetch.sp
+++ b/plugins/admin-sql-prefetch.sp
@@ -101,7 +101,7 @@ FetchUsers(Handle:db)
 	decl String:query[255], String:error[255];
 	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)
 	{
 		SQL_GetError(db, error, sizeof(error));
@@ -185,7 +185,7 @@ FetchGroups(Handle:db)
 	decl String:query[255];
 	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)
 	{
@@ -196,24 +196,18 @@ FetchGroups(Handle:db)
 		return;
 	}
 	
-	/* We cache basic group info so we can do reverse lookups */
-	new Handle:groups = CreateArray(3);
-	
 	/* Now start fetching groups */
 	decl String:immunity[16];
 	decl String:flags[32];
 	decl String:name[128];
-	decl String:grp_immunity[256];
 	while (SQL_FetchRow(hQuery))
 	{
-		new id = SQL_FetchInt(hQuery, 0);
-		SQL_FetchString(hQuery, 1, immunity, sizeof(immunity));
-		SQL_FetchString(hQuery, 2, flags, sizeof(flags));
-		SQL_FetchString(hQuery, 3, name, sizeof(name));
-		SQL_FetchString(hQuery, 4, grp_immunity, sizeof(grp_immunity));
+		SQL_FetchString(hQuery, 0, immunity, sizeof(immunity));
+		SQL_FetchString(hQuery, 1, flags, sizeof(flags));
+		SQL_FetchString(hQuery, 2, name, sizeof(name));
 		
 #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
 		
 		/* Find or create the group */
@@ -245,108 +239,100 @@ FetchGroups(Handle:db)
 		} else if (StrEqual(immunity, "global")) {
 			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);
 	
-	/* Second pass - resolve immunity and group overrides */
-	new num_groups = GetArraySize(groups);
-	for (new i=0; i<num_groups; i++)
+	/** 
+	 * Get immunity in a big lump.  This is a nasty query but it gets the job done.
+	 */
+	new len = 0;
+	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");
+	
+	if ((hQuery = SQL_Query(db, query)) == INVALID_HANDLE)
 	{
-		decl data[3];
-		GetArrayArray(groups, i, data);
-		
-		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)
-		{
-			decl String:error[255];
-			SQL_GetError(db, error, sizeof(error));
-			LogError("FetchOverrides() query failed: %s", query);
-			LogError("Query error: %s", error);
-		} else {
-			decl String:type[16];
-			decl String:cmd[64];
-			decl String:access[16];
-			while (SQL_FetchRow(hQuery))
-			{
-				SQL_FetchString(hQuery, 0, type, sizeof(type));
-				SQL_FetchString(hQuery, 1, cmd, sizeof(cmd));
-				SQL_FetchString(hQuery, 2, access, sizeof(access));
-				
-				new OverrideType:o_type = Override_Command;
-				if (StrEqual(type, "group"))
-				{
-					o_type = Override_CommandGroup;
-				}
-				
-				new OverrideRule:o_rule = Command_Deny;
-				if (StrEqual(access, "allow"))
-				{
-					o_rule = Command_Allow;
-				}
-				
-				#if defined _DEBUG
-				PrintToServer("AddAdmGroupCmdOverride(%d, %s, %d, %d)", gid, cmd, o_type, o_rule);
-				#endif
-				
-				AddAdmGroupCmdOverride(gid, cmd, o_type, o_rule);
-			}
-			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);
-		}
+		decl String:error[255];
+		SQL_GetError(db, error, sizeof(error));
+		LogError("FetchGroups() query failed: %s", query);
+		LogError("Query error: %s", error);
+		return;
 	}
 	
-	CloseHandle(groups);
+	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:cmd[64];
+	decl String:access[16];
+	while (SQL_FetchRow(hQuery))
+	{
+		SQL_FetchString(hQuery, 0, name, sizeof(name));
+		SQL_FetchString(hQuery, 1, type, sizeof(type));
+		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;
+		if (StrEqual(type, "group"))
+		{
+			o_type = Override_CommandGroup;
+		}
+		
+		new OverrideRule:o_rule = Command_Deny;
+		if (StrEqual(access, "allow"))
+		{
+			o_rule = Command_Allow;
+		}
+				
+		#if defined _DEBUG
+		PrintToServer("AddAdmGroupCmdOverride(%d, %s, %d, %d)", gid, cmd, o_type, o_rule);
+		#endif
+		
+		AddAdmGroupCmdOverride(gid, cmd, o_type, o_rule);
+	}
+	
+	CloseHandle(hQuery);
 }
 
 FetchOverrides(Handle:db)
@@ -390,62 +376,3 @@ FetchOverrides(Handle:db)
 	
 	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;
-}
-
diff --git a/plugins/admin-sql-threaded.sp b/plugins/admin-sql-threaded.sp
index 0b7ff19c..d3bce734 100644
--- a/plugins/admin-sql-threaded.sp
+++ b/plugins/admin-sql-threaded.sp
@@ -53,8 +53,8 @@ public Plugin:myinfo =
  *    was a 100% success in the fetch.  This is so we can potentially implement 
  *    connection retries in the future.
  *
- * 4) Sequence numbers for the admin cache are ignored except for being 
- *    non-zero, which means players in-game should be re-checked for admin \
+ * 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 
  *    powers.
  */
 
@@ -525,6 +525,64 @@ FetchUsersWeCan(Handle:db)
 	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)
 {
 	new Handle:pk = Handle:data;
@@ -554,9 +612,6 @@ public OnReceiveGroupOverrides(Handle:owner, Handle:hndl, const String:error[],
 		return;
 	}
 	
-	/* We're done with the pack forever. */
-	CloseHandle(pk);
-	
 	/**
 	 * Fetch the overrides.
 	 */
@@ -598,8 +653,20 @@ public OnReceiveGroupOverrides(Handle:owner, Handle:hndl, const String:error[],
 		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)
@@ -631,26 +698,20 @@ public OnReceiveGroups(Handle:owner, Handle:hndl, const String:error[], any:data
 		return;
 	}
 	
-	/* We cache basic group info so we can do reverse lookups */
-	new Handle:groups = CreateArray(3);
-	
 	/**
 	 * Now start fetching groups.
 	 */
 	decl String:immunity[16];
 	decl String:flags[32];
 	decl String:name[128];
-	decl String:grp_immunity[256];
 	while (SQL_FetchRow(hndl))
 	{
-		new id = SQL_FetchInt(hndl, 0);
-		SQL_FetchString(hndl, 1, immunity, sizeof(immunity));
-		SQL_FetchString(hndl, 2, flags, sizeof(flags));
-		SQL_FetchString(hndl, 3, name, sizeof(name));
-		SQL_FetchString(hndl, 4, grp_immunity, sizeof(grp_immunity));
+		SQL_FetchString(hndl, 0, immunity, sizeof(immunity));
+		SQL_FetchString(hndl, 1, flags, sizeof(flags));
+		SQL_FetchString(hndl, 2, name, sizeof(name));
 		
 #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
 		
 		/* 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")) {
 			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.
-	 */
-	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.
+	 * It's time to get the group override list.
 	 */
 	decl String:query[255];
 	Format(query, 
@@ -759,7 +765,7 @@ FetchGroups(Handle:db, sequence)
 	decl String:query[255];
 	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();
 	WritePackCell(pk, sequence);
diff --git a/plugins/sql-admin-manager.sp b/plugins/sql-admin-manager.sp
index 6e4ebcc9..9f6ea876 100644
--- a/plugins/sql-admin-manager.sp
+++ b/plugins/sql-admin-manager.sp
@@ -227,39 +227,54 @@ public Action:Command_DelGroup(client, args)
 	
 	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 */
-	Format(query, 
-		sizeof(query),
-		"DELETE FROM sm_admins_groups WHERE group_id IN (SELECT id FROM sm_groups WHERE name = '%s')",
-		safe_name);
+	Format(query, sizeof(query), "DELETE FROM sm_admins_groups WHERE group_id = %d", id);
 	if (!SQL_FastQuery(db, query))
 	{
 		return DoError(client, db, query, "Admin group deletion query failed");
 	}
 	
 	/* Delete group overrides */
-	Format(query, 
-		sizeof(query),
-		"DELETE FROM sm_group_overrides WHERE group_id IN (SELECT id FROM sm_groups WHERE name = '%s')",
-		safe_name);
+	Format(query, sizeof(query), "DELETE FROM sm_group_overrides WHERE group_id = %d", id);
 	if (!SQL_FastQuery(db, query))
 	{
 		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 */
-	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))
 	{
 		return DoError(client, db, query, "Group deletion query failed");
 	}
 	
-	if (SQL_GetAffectedRows(db))
-	{
-		ReplyToCommand(client, "[SM] %t", "SQL Group deleted");
-	} else {
-		ReplyToCommand(client, "[SM] %t", "SQL Group not found");
-	}
+	ReplyToCommand(client, "[SM] %t", "SQL Group deleted");
 	
 	CloseHandle(db);
 	
diff --git a/translations/sqladmins.phrases.txt b/translations/sqladmins.phrases.txt
index 4859b6f5..67b78336 100644
--- a/translations/sqladmins.phrases.txt
+++ b/translations/sqladmins.phrases.txt
@@ -5,6 +5,11 @@
 		"en"		"Auth type must be either 'steam', 'name', or 'ip'."
 	}
 
+	"Invalid immunity"
+	{
+		"en"		"Immunity must be 'none', 'default', or 'global'."
+	}
+
 	"SQL Admin already exists"
 	{
 		"en"		"An administrator with the given credentials already exists."