From eda39975a92bc95652c7116a7f0fda61a9df7fe4 Mon Sep 17 00:00:00 2001
From: Danny Auble <da@llnl.gov>
Date: Wed, 10 Feb 2010 20:33:25 +0000
Subject: [PATCH] ok got (hopefully) up to association mod

---
 .../mysql/accounting_storage_mysql.c          |   31 +-
 .../mysql/accounting_storage_mysql.h          |    3 +-
 .../accounting_storage/mysql/mysql_acct.c     |   40 +-
 .../accounting_storage/mysql/mysql_archive.c  |  152 +-
 .../accounting_storage/mysql/mysql_assoc.c    | 1354 +++++++++--------
 .../accounting_storage/mysql/mysql_cluster.c  |    3 +-
 .../accounting_storage/mysql/mysql_qos.c      |    2 +-
 .../accounting_storage/mysql/mysql_user.c     |    2 +-
 8 files changed, 823 insertions(+), 764 deletions(-)

diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
index abc2b328e35..5996a8e6123 100644
--- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
+++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.c
@@ -627,8 +627,8 @@ static int _mysql_acct_check_tables(MYSQL *db_conn)
 		"@delta_qos := CONCAT(delta_qos, @delta_qos), '); "
 		"end if; "
 		"set @s = concat(@s, ' @my_acct := parent_acct from ', "
-		"my_table, ' where acct = \"', @my_acct, '\" && "
-		"cluster = \"', cluster, '\" && user=\"\"'); "
+		"cluster, '_', my_table, ' where "
+		"acct = \"', @my_acct, '\" && user=\"\"'); "
 		"prepare query from @s; "
 		"execute query; "
 		"deallocate prepare query; "
@@ -1208,21 +1208,34 @@ extern int modify_common(mysql_conn_t *mysql_conn,
 			 char *user_name,
 			 char *table,
 			 char *cond_char,
-			 char *vals)
+			 char *vals,
+			 char *cluster_name)
 {
 	char *query = NULL;
 	int rc = SLURM_SUCCESS;
 	char *tmp_cond_char = fix_double_quotes(cond_char);
 	char *tmp_vals = NULL;
+	bool cluster_centric = true;
+
+	/* figure out which tables we need to append the cluster name to */
+	if((table == cluster_table) || (table == acct_coord_table)
+	   || (table == acct_table) || (table == qos_table)
+	   || (table == txn_table) || (table == user_table))
+		cluster_centric = false;
 
 	if(vals[1])
 		tmp_vals = fix_double_quotes(vals+2);
-
-	xstrfmtcat(query,
-		   "update %s set mod_time=%d%s "
-		   "where deleted=0 && %s;",
-		   table, now, vals,
-		   cond_char);
+	if(cluster_centric) {
+		xassert(cluster_name);
+		xstrfmtcat(query,
+			   "update %s_%s set mod_time=%d%s "
+			   "where deleted=0 && %s;",
+			   cluster_name, table, now, vals, cond_char);
+	} else
+		xstrfmtcat(query,
+			   "update %s set mod_time=%d%s "
+			   "where deleted=0 && %s;",
+			   table, now, vals, cond_char);
 	xstrfmtcat(query,
 		   "insert into %s "
 		   "(timestamp, action, name, actor, info) "
diff --git a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.h b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.h
index 0debd71eb74..4db9f5769d4 100644
--- a/src/plugins/accounting_storage/mysql/accounting_storage_mysql.h
+++ b/src/plugins/accounting_storage/mysql/accounting_storage_mysql.h
@@ -106,7 +106,8 @@ extern int modify_common(mysql_conn_t *mysql_conn,
 			 char *user_name,
 			 char *table,
 			 char *cond_char,
-			 char *vals);
+			 char *vals,
+			 char *cluster_name);
 extern int remove_common(mysql_conn_t *mysql_conn,
 			 uint16_t type,
 			 time_t now,
diff --git a/src/plugins/accounting_storage/mysql/mysql_acct.c b/src/plugins/accounting_storage/mysql/mysql_acct.c
index 01fafa9a2fc..2b8a1e4ab94 100644
--- a/src/plugins/accounting_storage/mysql/mysql_acct.c
+++ b/src/plugins/accounting_storage/mysql/mysql_acct.c
@@ -47,10 +47,11 @@
 static int _get_account_coords(mysql_conn_t *mysql_conn,
 			       acct_account_rec_t *acct)
 {
-	char *query = NULL;
+	char *query = NULL, *cluster_name = NULL;
 	acct_coord_rec_t *coord = NULL;
 	MYSQL_RES *result = NULL;
 	MYSQL_ROW row;
+	ListIterator itr;
 
 	if(!acct) {
 		error("We need a account to fill in.");
@@ -78,15 +79,32 @@ static int _get_account_coords(mysql_conn_t *mysql_conn,
 	}
 	mysql_free_result(result);
 
-	query = xstrdup_printf("select distinct t0.user from %s as t0, "
-			       "%s as t1, %s as t2 where t0.acct=t1.acct && "
-			       "t1.lft<t2.lft && t1.rgt>t2.lft && "
-			       "t1.user='' && t2.acct=\"%s\" "
-			       "&& t1.acct!=\"%s\" && !t0.deleted;",
-			       acct_coord_table, assoc_table, assoc_table,
-			       acct->name, acct->name);
-	if(!(result =
-	     mysql_db_query_ret(mysql_conn->db_conn, query, 0))) {
+	slurm_mutex_lock(&mysql_cluster_list_lock);
+	itr = list_iterator_create(mysql_cluster_list);
+	while((cluster_name = list_next(itr))) {
+		if(query)
+			xstrcat(query, " union ");
+		xstrfmtcat(query,
+			   "select distinct t0.user from %s as t0, "
+			   "%s_%s as t1, %s_%s as t2 "
+			   "where t0.acct=t1.acct && "
+			   "t1.lft<t2.lft && t1.rgt>t2.lft && "
+			   "t1.user='' && t2.acct=\"%s\" "
+			   "&& t1.acct!=\"%s\" && !t0.deleted",
+			   acct_coord_table, cluster_name, assoc_table,
+			   cluster_name, assoc_table,
+			   acct->name, acct->name);
+	}
+	list_iterator_destroy(itr);
+	slurm_mutex_unlock(&mysql_cluster_list_lock);
+
+	if(!query) {
+		error("No clusters defined?  How could there be accts?");
+		return SLURM_SUCCESS;
+	}
+	xstrcat(query, ";");
+
+	if(!(result =  mysql_db_query_ret(mysql_conn->db_conn, query, 0))) {
 		xfree(query);
 		return SLURM_ERROR;
 	}
@@ -335,7 +353,7 @@ extern List mysql_modify_accts(mysql_conn_t *mysql_conn, uint32_t uid,
 
 	user_name = uid_to_string((uid_t) uid);
 	rc = modify_common(mysql_conn, DBD_MODIFY_ACCOUNTS, now,
-			    user_name, acct_table, name_char, vals);
+			   user_name, acct_table, name_char, vals, NULL);
 	xfree(user_name);
 	if (rc == SLURM_ERROR) {
 		error("Couldn't modify accounts");
diff --git a/src/plugins/accounting_storage/mysql/mysql_archive.c b/src/plugins/accounting_storage/mysql/mysql_archive.c
index c284487899e..cf8d41e5d43 100644
--- a/src/plugins/accounting_storage/mysql/mysql_archive.c
+++ b/src/plugins/accounting_storage/mysql/mysql_archive.c
@@ -135,26 +135,26 @@ typedef struct {
 
 /* if this changes you will need to edit the corresponding
  * enum below */
-static char *event_req_inx[] = {
+char *event_req_inx[] = {
+	"time_start",
+	"time_end",
 	"node_name",
+	"cluster_nodes",
 	"cpu_count",
-	"state",
-	"period_start",
-	"period_end",
 	"reason",
 	"reason_uid",
-	"cluster_nodes",
+	"state",
 };
 
 enum {
-	EVENT_REQ_NODE,
-	EVENT_REQ_CPU,
-	EVENT_REQ_STATE,
 	EVENT_REQ_START,
 	EVENT_REQ_END,
+	EVENT_REQ_NODE,
+	EVENT_REQ_CNODES,
+	EVENT_REQ_CPU,
 	EVENT_REQ_REASON,
 	EVENT_REQ_REASON_UID,
-	EVENT_REQ_CNODES,
+	EVENT_REQ_STATE,
 	EVENT_REQ_COUNT
 };
 
@@ -162,33 +162,33 @@ enum {
  * enum below */
 static char *job_req_inx[] = {
 	"account",
-	"alloc_cpus",
-	"alloc_nodes",
-	"associd",
-	"blockid",
-	"comp_code",
-	"eligible",
-	"end",
-	"gid",
-	"id",
-	"jobid",
+	"cpus_alloc",
+	"nodes_alloc",
+	"id_assoc",
+	"id_block",
+	"exit_code",
+	"time_eligible",
+	"time_end",
+	"id_group",
+	"job_db_inx",
+	"id_job",
 	"kill_requid",
-	"name",
+	"job_name",
 	"nodelist",
 	"node_inx",
 	"partition",
 	"priority",
 	"qos",
-	"req_cpus",
-	"resvid",
-	"start",
+	"cpus_req",
+	"id_resv",
+	"time_start",
 	"state",
-	"submit",
-	"suspended",
+	"time_submit",
+	"time_suspended",
 	"track_steps",
-	"uid",
+	"id_user",
 	"wckey",
-	"wckeyid",
+	"id_wckey",
 };
 
 enum {
@@ -226,20 +226,20 @@ enum {
 /* if this changes you will need to edit the corresponding
  * enum below */
 static char *step_req_inx[] = {
-	"id",
-	"stepid",
-	"start",
-	"end",
-	"suspended",
-	"name",
+	"job_db_inx",
+	"id_step",
+	"time_start",
+	"time_end",
+	"time_suspended",
+	"step_name",
 	"nodelist",
 	"node_inx",
 	"state",
 	"kill_requid",
-	"comp_code",
-	"nodes",
-	"cpus",
-	"tasks",
+	"exit_code",
+	"nodes_alloc",
+	"cpus_alloc",
+	"task_cnt",
 	"task_dist",
 	"user_sec",
 	"user_usec",
@@ -306,10 +306,10 @@ enum {
 /* if this changes you will need to edit the corresponding
  * enum below */
 static char *suspend_req_inx[] = {
-	"id",
-	"associd",
-	"start",
-	"end",
+	"job_db_inx",
+	"id_assoc",
+	"time_start",
+	"time_end",
 };
 
 enum {
@@ -653,31 +653,6 @@ static uint32_t _archive_events(mysql_conn_t *mysql_conn, char *cluster_name,
 	Buf buffer;
 	int error_code = 0, i = 0;
 
-	/* if this changes you will need to edit the corresponding
-	 * enum below */
-	char *event_req_inx[] = {
-		"node_name",
-		"cpu_count",
-		"state",
-		"period_start",
-		"period_end",
-		"reason",
-		"reason_uid",
-		"cluster_nodes",
-	};
-
-	enum {
-		EVENT_REQ_NODE,
-		EVENT_REQ_CPU,
-		EVENT_REQ_STATE,
-		EVENT_REQ_START,
-		EVENT_REQ_END,
-		EVENT_REQ_REASON,
-		EVENT_REQ_REASON_UID,
-		EVENT_REQ_CNODES,
-		EVENT_REQ_COUNT
-	};
-
 	xfree(tmp);
 	xstrfmtcat(tmp, "%s", event_req_inx[0]);
 	for(i=1; i<EVENT_REQ_COUNT; i++) {
@@ -685,9 +660,9 @@ static uint32_t _archive_events(mysql_conn_t *mysql_conn, char *cluster_name,
 	}
 
 	/* get all the events started before this time listed */
-	query = xstrdup_printf("select %s from %s where period_start <= %d "
+	query = xstrdup_printf("select %s from %s_%s where period_start <= %d "
 			       "&& period_end != 0 order by period_start asc",
-			       tmp, event_table, period_end);
+			       tmp, cluster_name, event_table, period_end);
 	xfree(tmp);
 
 //	START_TIMER;
@@ -752,7 +727,8 @@ static char *_load_events(uint16_t rpc_version, Buf buffer,
 	local_event_t object;
 	int i = 0;
 
-	xstrfmtcat(insert, "insert into %s (%s", event_table, event_req_inx[0]);
+	xstrfmtcat(insert, "insert into %s_%s (%s",
+		   cluster_name, event_table, event_req_inx[0]);
 	xstrcat(format, "('%s'");
 	for(i=1; i<EVENT_REQ_COUNT; i++) {
 		xstrfmtcat(insert, ", %s", event_req_inx[i]);
@@ -810,10 +786,10 @@ static uint32_t _archive_jobs(mysql_conn_t *mysql_conn, char *cluster_name,
 	}
 
 	/* get all the events started before this time listed */
-	query = xstrdup_printf("select %s from %s where "
+	query = xstrdup_printf("select %s from %s_%s where "
 			       "submit < %d && end != 0 && !deleted "
 			       "order by submit asc",
-			       tmp, job_table, period_end);
+			       tmp, cluster_name, job_table, period_end);
 	xfree(tmp);
 
 //	START_TIMER;
@@ -898,7 +874,8 @@ static char *_load_jobs(uint16_t rpc_version, Buf buffer,
 	local_job_t object;
 	int i = 0;
 
-	xstrfmtcat(insert, "insert into %s (%s", job_table, job_req_inx[0]);
+	xstrfmtcat(insert, "insert into %s_%s (%s",
+		   cluster_name, job_table, job_req_inx[0]);
 	xstrcat(format, "('%s'");
 	for(i=1; i<JOB_REQ_COUNT; i++) {
 		xstrfmtcat(insert, ", %s", job_req_inx[i]);
@@ -976,10 +953,10 @@ static uint32_t _archive_steps(mysql_conn_t *mysql_conn, char *cluster_name,
 	}
 
 	/* get all the events started before this time listed */
-	query = xstrdup_printf("select %s from %s where "
+	query = xstrdup_printf("select %s from %s_%s where "
 			       "start <= %d && end != 0 "
 			       "&& !deleted order by start asc",
-			       tmp, step_table, period_end);
+			       tmp, cluster_name, step_table, period_end);
 	xfree(tmp);
 
 //	START_TIMER;
@@ -1071,7 +1048,8 @@ static char *_load_steps(uint16_t rpc_version, Buf buffer,
 	local_step_t object;
 	int i = 0;
 
-	xstrfmtcat(insert, "insert into %s (%s", step_table, step_req_inx[0]);
+	xstrfmtcat(insert, "insert into %s_%s (%s",
+		   cluster_name, step_table, step_req_inx[0]);
 	xstrcat(format, "('%s'");
 	for(i=1; i<STEP_REQ_COUNT; i++) {
 		xstrfmtcat(insert, ", %s", step_req_inx[i]);
@@ -1156,10 +1134,10 @@ static uint32_t _archive_suspend(mysql_conn_t *mysql_conn, char *cluster_name,
 	}
 
 	/* get all the events started before this time listed */
-	query = xstrdup_printf("select %s from %s where "
+	query = xstrdup_printf("select %s from %s_%s where "
 			       "start <= %d && end != 0 "
 			       "order by start asc",
-			       tmp, suspend_table, period_end);
+			       tmp, cluster_name, suspend_table, period_end);
 	xfree(tmp);
 
 //	START_TIMER;
@@ -1220,8 +1198,8 @@ static char *_load_suspend(uint16_t rpc_version, Buf buffer,
 	local_suspend_t object;
 	int i = 0;
 
-	xstrfmtcat(insert, "insert into %s (%s",
-		   suspend_table, suspend_req_inx[0]);
+	xstrfmtcat(insert, "insert into %s_%s (%s",
+		   cluster_name, suspend_table, suspend_req_inx[0]);
 	xstrcat(format, "('%s'");
 	for(i=1; i<SUSPEND_REQ_COUNT; i++) {
 		xstrfmtcat(insert, ", %s", suspend_req_inx[i]);
@@ -1420,9 +1398,9 @@ static int _execute_archive(mysql_conn_t *mysql_conn, time_t last_submit,
 			else if(rc == SLURM_ERROR)
 				return rc;
 		}
-		query = xstrdup_printf("delete from %s where "
+		query = xstrdup_printf("delete from %s_%s where "
 				       "period_start <= %d && period_end != 0",
-				       event_table, curr_end);
+				       cluster_name, event_table, curr_end);
 		debug3("%d(%s:%d) query\n%s",
 		       mysql_conn->conn, __FILE__, __LINE__, query);
 		rc = mysql_db_query(mysql_conn->db_conn, query);
@@ -1465,9 +1443,9 @@ exit_events:
 			else if(rc == SLURM_ERROR)
 				return rc;
 		}
-		query = xstrdup_printf("delete from %s where start <= %d "
+		query = xstrdup_printf("delete from %s_%s where start <= %d "
 				       "&& end != 0",
-				       suspend_table, curr_end);
+				       cluster_name, suspend_table, curr_end);
 		debug3("%d(%s:%d) query\n%s",
 		       mysql_conn->conn, __FILE__, __LINE__, query);
 		rc = mysql_db_query(mysql_conn->db_conn, query);
@@ -1511,9 +1489,9 @@ exit_suspend:
 				return rc;
 		}
 
-		query = xstrdup_printf("delete from %s where start <= %d "
+		query = xstrdup_printf("delete from %s_%s where start <= %d "
 				       "&& end != 0",
-				       step_table, curr_end);
+				       cluster_name, step_table, curr_end);
 		debug3("%d(%s:%d) query\n%s",
 		       mysql_conn->conn, __FILE__, __LINE__, query);
 		rc = mysql_db_query(mysql_conn->db_conn, query);
@@ -1556,9 +1534,9 @@ exit_steps:
 				return rc;
 		}
 
-		query = xstrdup_printf("delete from %s where submit <= %d "
+		query = xstrdup_printf("delete from %s_%s where submit <= %d "
 				       "&& end != 0",
-				       job_table, curr_end);
+				       cluster_name, job_table, curr_end);
 		debug3("%d(%s:%d) query\n%s",
 		       mysql_conn->conn, __FILE__, __LINE__, query);
 		rc = mysql_db_query(mysql_conn->db_conn, query);
diff --git a/src/plugins/accounting_storage/mysql/mysql_assoc.c b/src/plugins/accounting_storage/mysql/mysql_assoc.c
index e53b862a25a..319af24084b 100644
--- a/src/plugins/accounting_storage/mysql/mysql_assoc.c
+++ b/src/plugins/accounting_storage/mysql/mysql_assoc.c
@@ -40,6 +40,67 @@
 #include "mysql_assoc.h"
 #include "mysql_usage.h"
 
+static char *aassoc_req_inx[] = {
+	"id_assoc",
+	"parent_acct",
+	"lft",
+	"rgt",
+	"deleted"
+};
+
+enum {
+	AASSOC_ID,
+	AASSOC_PACCT,
+	AASSOC_LFT,
+	AASSOC_RGT,
+	AASSOC_DELETED,
+	AASSOC_COUNT
+};
+
+static char *massoc_req_inx[] = {
+	"id_assoc",
+	"acct",
+	"parent_acct",
+	"user",
+	"partition",
+	"lft",
+	"rgt",
+	"qos",
+};
+
+enum {
+	MASSOC_ID,
+	MASSOC_ACCT,
+	MASSOC_PACCT,
+	MASSOC_USER,
+	MASSOC_PART,
+	MASSOC_LFT,
+	MASSOC_RGT,
+	MASSOC_QOS,
+	MASSOC_COUNT
+};
+
+/* if this changes you will need to edit the corresponding
+ * enum below also t1 is step_table */
+static char *rassoc_req_inx[] = {
+	"id_assoc",
+	"acct",
+	"parent_acct",
+	"cluster",
+	"user",
+	"partition"
+};
+
+enum {
+	RASSOC_ID,
+	RASSOC_ACCT,
+	RASSOC_PACCT,
+	RASSOC_CLUSTER,
+	RASSOC_USER,
+	RASSOC_PART,
+	RASSOC_COUNT
+};
+
 /* This should take care of all the lft and rgts when you move an
  * account.  This handles deleted associations also.
  */
@@ -53,10 +114,8 @@ static int _move_account(mysql_conn_t *mysql_conn, uint32_t *lft, uint32_t *rgt,
 	int diff = 0;
 	int width = 0;
 	char *query = xstrdup_printf(
-		"SELECT lft from %s "
-		"where cluster=\"%s\" && acct=\"%s\" && user='';",
-		assoc_table,
-		cluster, parent);
+		"SELECT lft from %s_%s where acct=\"%s\" && user='';",
+		cluster, assoc_table, parent);
 	debug3("%d(%s:%d) query\n%s",
 	       mysql_conn->conn, __FILE__, __LINE__, query);
 	if(!(result = mysql_db_query_ret(
@@ -86,47 +145,47 @@ static int _move_account(mysql_conn_t *mysql_conn, uint32_t *lft, uint32_t *rgt,
 	/* every thing below needs to be a %d not a %u because we are
 	   looking for -1 */
 	xstrfmtcat(query,
-		   "update %s set mod_time=%d, deleted = deleted + 2, "
+		   "update %s_%s set mod_time=%d, deleted = deleted + 2, "
 		   "lft = lft + %d, rgt = rgt + %d "
 		   "WHERE lft BETWEEN %d AND %d;",
-		   assoc_table, now, diff, diff, *lft, *rgt);
+		   cluster, assoc_table, now, diff, diff, *lft, *rgt);
 
 	xstrfmtcat(query,
-		   "UPDATE %s SET mod_time=%d, rgt = rgt + %d WHERE "
+		   "UPDATE %s_%s SET mod_time=%d, rgt = rgt + %d WHERE "
 		   "rgt > %d && deleted < 2;"
-		   "UPDATE %s SET mod_time=%d, lft = lft + %d WHERE "
+		   "UPDATE %s_%s SET mod_time=%d, lft = lft + %d WHERE "
 		   "lft > %d && deleted < 2;",
-		   assoc_table, now, width,
+		   cluster, assoc_table, now, width,
 		   par_left,
-		   assoc_table, now, width,
+		   cluster, assoc_table, now, width,
 		   par_left);
 
 	xstrfmtcat(query,
-		   "UPDATE %s SET mod_time=%d, rgt = rgt - %d WHERE "
+		   "UPDATE %s_%s SET mod_time=%d, rgt = rgt - %d WHERE "
 		   "(%d < 0 && rgt > %d && deleted < 2) "
 		   "|| (%d > 0 && rgt > %d);"
-		   "UPDATE %s SET mod_time=%d, lft = lft - %d WHERE "
+		   "UPDATE %s_%s SET mod_time=%d, lft = lft - %d WHERE "
 		   "(%d < 0 && lft > %d && deleted < 2) "
 		   "|| (%d > 0 && lft > %d);",
-		   assoc_table, now, width,
+		   cluster, assoc_table, now, width,
 		   diff, *rgt,
 		   diff, *lft,
-		   assoc_table, now, width,
+		   cluster, assoc_table, now, width,
 		   diff, *rgt,
 		   diff, *lft);
 
 	xstrfmtcat(query,
-		   "update %s set mod_time=%d, "
+		   "update %s_%s set mod_time=%d, "
 		   "deleted = deleted - 2 WHERE deleted > 1;",
-		   assoc_table, now);
+		   cluster, assoc_table, now);
 	xstrfmtcat(query,
-		   "update %s set mod_time=%d, "
-		   "parent_acct=\"%s\" where id = %s;",
-		   assoc_table, now, parent, id);
+		   "update %s_%s set mod_time=%d, "
+		   "parent_acct=\"%s\" where id_assoc = %s;",
+		   cluster, assoc_table, now, parent, id);
 	/* get the new lft and rgt if changed */
 	xstrfmtcat(query,
-		   "select lft, rgt from %s where id = %s",
-		   assoc_table, id);
+		   "select lft, rgt from %s_%s where id_assoc = %s",
+		   cluster, assoc_table, id);
 	debug3("%d(%s:%d) query\n%s",
 	       mysql_conn->conn, __FILE__, __LINE__, query);
 	if(!(result = mysql_db_query_ret(mysql_conn->db_conn, query, 1))) {
@@ -166,9 +225,10 @@ static int _move_parent(mysql_conn_t *mysql_conn, uid_t uid,
 	 * accounts parent and then do the move.
 	 */
 	query = xstrdup_printf(
-		"select id, lft, rgt from %s where lft between %d and %d "
+		"select id_assoc, lft, rgt from %s_%s "
+		"where lft between %d and %d "
 		"&& acct=\"%s\" && user='' order by lft;",
-		assoc_table, *lft, *rgt,
+		cluster, assoc_table, *lft, *rgt,
 		new_parent);
 	debug3("%d(%s:%d) query\n%s",
 	       mysql_conn->conn, __FILE__, __LINE__, query);
@@ -198,8 +258,8 @@ static int _move_parent(mysql_conn_t *mysql_conn, uid_t uid,
 	 * have changed.
 	 */
 	query = xstrdup_printf(
-		"select lft, rgt from %s where id=%s;",
-		assoc_table, id);
+		"select lft, rgt from %s_%s where id_assoc=%s;",
+		cluster, assoc_table, id);
 	debug3("%d(%s:%d) query\n%s",
 	       mysql_conn->conn, __FILE__, __LINE__, query);
 	if(!(result =
@@ -234,10 +294,9 @@ static uint32_t _get_parent_id(
 	xassert(parent);
 	xassert(cluster);
 
-	query = xstrdup_printf("select id from %s where user='' "
-			       "and deleted = 0 and acct=\"%s\" "
-			       "and cluster=\"%s\";",
-			       assoc_table, parent, cluster);
+	query = xstrdup_printf("select id_assoc from %s_%s where user='' "
+			       "and deleted = 0 and acct=\"%s\";",
+			       cluster, assoc_table, parent);
 	debug4("%d(%s:%d) query\n%s",
 	       mysql_conn->conn, __FILE__, __LINE__, query);
 
@@ -266,10 +325,11 @@ static int _set_assoc_lft_rgt(
 	char *query = NULL;
 	int rc = SLURM_ERROR;
 
+	xassert(assoc->cluster);
 	xassert(assoc->id);
 
-	query = xstrdup_printf("select lft, rgt from %s where id=%u;",
-			       assoc_table, assoc->id);
+	query = xstrdup_printf("select lft, rgt from %s_%s where id_assoc=%u;",
+			       assoc->cluster, assoc_table, assoc->id);
 	debug4("%d(%s:%d) query\n%s",
 	       mysql_conn->conn, __FILE__, __LINE__, query);
 
@@ -411,10 +471,9 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn,
 	int i;
 
 	char *assoc_req_inx[] = {
-		"id",
+		"id_assoc",
 		"user",
 		"acct",
-		"cluster",
 		"partition",
 		"max_jobs",
 		"max_submit_jobs",
@@ -432,7 +491,6 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn,
 		ASSOC_ID,
 		ASSOC_USER,
 		ASSOC_ACCT,
-		ASSOC_CLUSTER,
 		ASSOC_PART,
 		ASSOC_MJ,
 		ASSOC_MSJ,
@@ -447,6 +505,9 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn,
 		ASSOC_COUNT
 	};
 
+	xassert(assoc);
+	xassert(assoc->cluster);
+
 	if(!ret_list || !acct)
 		return SLURM_ERROR;
 
@@ -457,12 +518,13 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn,
 	}
 
 	/* We want all the sub accounts and user accounts */
-	query = xstrdup_printf("select distinct %s from %s where deleted=0 "
+	query = xstrdup_printf("select distinct %s from %s_%s where deleted=0 "
 			       "&& lft between %d and %d && "
 			       "((user = '' && parent_acct = \"%s\") || "
 			       "(user != '' && acct = \"%s\")) "
 			       "order by lft;",
-			       object, assoc_table, lft, rgt, acct, acct);
+			       object, assoc->cluster, assoc_table,
+			       lft, rgt, acct, acct);
 	xfree(object);
 	debug3("%d(%s:%d) query\n%s",
 	       mysql_conn->conn, __FILE__, __LINE__, query);
@@ -480,6 +542,7 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn,
 		mod_assoc = xmalloc(sizeof(acct_association_rec_t));
 		init_acct_association_rec(mod_assoc);
 		mod_assoc->id = atoi(row[ASSOC_ID]);
+		mod_assoc->cluster = xstrdup(assoc->cluster);
 
 		if(!row[ASSOC_MJ] && assoc->max_jobs != NO_VAL) {
 			mod_assoc->max_jobs = assoc->max_jobs;
@@ -585,12 +648,12 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn,
 				// see if there is a partition name
 				object = xstrdup_printf(
 					"C = %-10s A = %-20s U = %-9s P = %s",
-					row[ASSOC_CLUSTER], row[ASSOC_ACCT],
+					assoc->cluster, row[ASSOC_ACCT],
 					row[ASSOC_USER], row[ASSOC_PART]);
 			} else {
 				object = xstrdup_printf(
 					"C = %-10s A = %-20s U = %-9s",
-					row[ASSOC_CLUSTER],
+					assoc->cluster,
 					row[ASSOC_ACCT],
 					row[ASSOC_USER]);
 			}
@@ -601,8 +664,8 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn,
 				destroy_acct_association_rec(mod_assoc);
 			else
 				if(addto_update_list(mysql_conn->update_list,
-						      ACCT_MODIFY_ASSOC,
-						      mod_assoc)
+						     ACCT_MODIFY_ASSOC,
+						     mod_assoc)
 				   != SLURM_SUCCESS)
 					error("couldn't add to "
 					      "the update list");
@@ -616,17 +679,18 @@ static int _modify_unset_users(mysql_conn_t *mysql_conn,
 }
 
 /* when doing a select on this all the select should have a prefix of
- * t1. */
-static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond,
-					  char **extra)
+ * t1. Returns "where" clause which needs to be xfreed. */
+static char *_setup_association_cond_qos(acct_association_cond_t *assoc_cond,
+					 char *cluster_name)
 {
 	int set = 0;
 	ListIterator itr = NULL;
 	char *object = NULL;
 	char *prefix = "t1";
+	char *extra = NULL;
 
 	if(!assoc_cond)
-		return 0;
+		return NULL;
 
 	/* we need to check this first so we can update the
 	   with_sub_accts if needed since this the qos_list is a
@@ -638,15 +702,15 @@ static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond,
 		   really most likely a parent thing */
 		assoc_cond->with_sub_accts = 1;
 		prefix = "t2";
-		xstrfmtcat(*extra, ", %s as t2 where "
+		xstrfmtcat(extra, ", %s_%s as t2 where "
 			   "(t1.lft between t2.lft and t2.rgt) && (",
-			   assoc_table);
+			   cluster_name, assoc_table);
 		set = 0;
 		itr = list_iterator_create(assoc_cond->qos_list);
 		while((object = list_next(itr))) {
 			if(set)
-				xstrcat(*extra, " || ");
-			xstrfmtcat(*extra,
+				xstrcat(extra, " || ");
+			xstrfmtcat(extra,
 				   "(%s.qos like '%%,%s' "
 				   "|| %s.qos like '%%,%s,%%' "
 				   "|| %s.delta_qos like '%%,+%s' "
@@ -656,14 +720,27 @@ static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond,
 			set = 1;
 		}
 		list_iterator_destroy(itr);
-		xstrcat(*extra, ") &&");
+		xstrcat(extra, ") &&");
 	} else if(assoc_cond->with_sub_accts) {
 		prefix = "t2";
-		xstrfmtcat(*extra, ", %s as t2 where "
+		xstrfmtcat(extra, ", %s as t2 where "
 			   "(t1.lft between t2.lft and t2.rgt) &&",
 			   assoc_table);
 	} else
-		xstrcat(*extra, " where");
+		xstrcat(extra, " where");
+	return extra;
+}
+
+/* When doing a select on this all the select should have a prefix of t1. */
+static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond,
+					  const char *prefix, char **extra)
+{
+	int set = 0;
+	ListIterator itr = NULL;
+	char *object = NULL;
+
+	if(!assoc_cond)
+		return 0;
 
 	if(assoc_cond->with_deleted)
 		xstrfmtcat(*extra, " (%s.deleted=0 || %s.deleted=1)",
@@ -685,20 +762,6 @@ static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond,
 		xstrcat(*extra, ")");
 	}
 
-	if(assoc_cond->cluster_list && list_count(assoc_cond->cluster_list)) {
-		set = 0;
-		xstrcat(*extra, " && (");
-		itr = list_iterator_create(assoc_cond->cluster_list);
-		while((object = list_next(itr))) {
-			if(set)
-				xstrcat(*extra, " || ");
-			xstrfmtcat(*extra, "%s.cluster=\"%s\"", prefix, object);
-			set = 1;
-		}
-		list_iterator_destroy(itr);
-		xstrcat(*extra, ")");
-	}
-
 	if(assoc_cond->fairshare_list
 	   && list_count(assoc_cond->fairshare_list)) {
 		set = 0;
@@ -974,161 +1037,467 @@ static int _setup_association_cond_limits(acct_association_cond_t *assoc_cond,
 	return set;
 }
 
-extern int mysql_add_assocs(mysql_conn_t *mysql_conn, uint32_t uid,
-			    List association_list)
+static int _process_modify_assoc_results(mysql_conn_t *mysql_conn,
+					 MYSQL_RES *result,
+					 acct_association_rec_t *assoc,
+					 acct_user_rec_t *user,
+					 char *cluster_name,
+					 bool is_admin, List ret_list)
 {
 	ListIterator itr = NULL;
+	MYSQL_ROW row;
+	int added = 0;
 	int rc = SLURM_SUCCESS;
-	int i=0;
-	acct_association_rec_t *object = NULL;
-	char *cols = NULL, *vals = NULL, *txn_query = NULL,
-		*extra = NULL, *query = NULL, *update = NULL, *tmp_extra = NULL;
-	char *parent = NULL;
-	time_t now = time(NULL);
-	char *user_name = NULL;
-	char *tmp_char = NULL;
-	int assoc_id = 0;
-	int incr = 0, my_left = 0, my_par_id = 0;
-	int affect_rows = 0;
+	int set_qos_vals = 0;
 	int moved_parent = 0;
-	MYSQL_RES *result = NULL;
-	MYSQL_ROW row;
-	char *old_parent = NULL, *old_cluster = NULL;
-	char *last_parent = NULL, *last_cluster = NULL;
-	char *massoc_req_inx[] = {
-		"id",
-		"parent_acct",
-		"lft",
-		"rgt",
-		"deleted"
-	};
+	char *vals = NULL, *object = NULL, *name_char = NULL;
+	time_t now = time(NULL);
 
-	enum {
-		MASSOC_ID,
-		MASSOC_PACCT,
-		MASSOC_LFT,
-		MASSOC_RGT,
-		MASSOC_DELETED,
-		MASSOC_COUNT
-	};
+	xassert(result);
 
-	if(!association_list) {
-		error("No association list given");
-		return SLURM_ERROR;
-	}
+	if(!mysql_num_rows(result))
+		return SLURM_SUCCESS;
 
-	if(check_connection(mysql_conn) != SLURM_SUCCESS)
-		return ESLURM_DB_CONNECTION;
+	while((row = mysql_fetch_row(result))) {
+		acct_association_rec_t *mod_assoc = NULL;
+		int account_type=0;
+		/* If parent changes these also could change
+		   so we need to keep track of the latest
+		   ones.
+		*/
+		uint32_t lft = atoi(row[MASSOC_LFT]);
+		uint32_t rgt = atoi(row[MASSOC_RGT]);
 
-	user_name = uid_to_string((uid_t) uid);
-	itr = list_iterator_create(association_list);
-	while((object = list_next(itr))) {
-		if(!object->cluster || !object->cluster[0]
-		   || !object->acct || !object->acct[0]) {
-			error("We need a association cluster and "
-			      "acct to add one.");
-			rc = SLURM_ERROR;
-			continue;
-		}
+		if(!is_admin) {
+			acct_coord_rec_t *coord = NULL;
+			char *account = row[MASSOC_ACCT];
 
-		if(object->parent_acct) {
-			parent = object->parent_acct;
-		} else if(object->user) {
-			parent = object->acct;
-		} else {
-			parent = "root";
-		}
+			/* Here we want to see if the person
+			 * is a coord of the parent account
+			 * since we don't want him to be able
+			 * to alter the limits of the account
+			 * he is directly coord of.  They
+			 * should be able to alter the
+			 * sub-accounts though. If no parent account
+			 * that means we are talking about a user
+			 * association so account is really the parent
+			 * of the user a coord can change that all day long.
+			 */
+			if(row[MASSOC_PACCT][0])
+				account = row[MASSOC_PACCT];
 
-		xstrcat(cols, "creation_time, mod_time, cluster, acct");
-		xstrfmtcat(vals, "%d, %d, \"%s\", \"%s\"",
-			   now, now, object->cluster, object->acct);
-		xstrfmtcat(update,
-			   "where cluster=\"%s\" && acct=\"%s\"",
-			   object->cluster, object->acct);
+			if(!user->coord_accts) { // This should never
+				// happen
+				error("We are here with no coord accts.");
+				rc = ESLURM_ACCESS_DENIED;
+				goto end_it;
+			}
+			itr = list_iterator_create(user->coord_accts);
+			while((coord = list_next(itr))) {
+				if(!strcasecmp(coord->name, account))
+					break;
+			}
+			list_iterator_destroy(itr);
 
-		xstrfmtcat(extra, ", mod_time=%d, cluster=\"%s\", "
-			   "acct=\"%s\"", now, object->cluster, object->acct);
-		if(!object->user) {
-			xstrcat(cols, ", parent_acct");
-			xstrfmtcat(vals, ", \"%s\"", parent);
-			xstrfmtcat(extra, ", parent_acct=\"%s\", user=\"\"",
-				   parent);
-			xstrfmtcat(update, " && user=\"\"");
-		} else {
-			char *part = object->partition;
-			xstrcat(cols, ", user");
-			xstrfmtcat(vals, ", \"%s\"", object->user);
-			xstrfmtcat(update, " && user=\"%s\"", object->user);
-			xstrfmtcat(extra, ", user=\"%s\"", object->user);
+			if(!coord) {
+				if(row[MASSOC_PACCT][0])
+					error("User %s(%d) can not modify "
+					      "account (%s) because they "
+					      "are not coordinators of "
+					      "parent account \"%s\".",
+					      user->name, user->uid,
+					      row[MASSOC_ACCT],
+					      row[MASSOC_PACCT]);
+				else
+					error("User %s(%d) does not have the "
+					      "ability to modify the account "
+					      "(%s).",
+					      user->name, user->uid,
+					      row[MASSOC_ACCT]);
 
-			/* We need to give a partition whether it be
-			 * '' or the actual partition name given
-			 */
-			if(!part)
-				part = "";
-			xstrcat(cols, ", partition");
-			xstrfmtcat(vals, ", \"%s\"", part);
-			xstrfmtcat(update, " && partition=\"%s\"", part);
-			xstrfmtcat(extra, ", partition=\"%s\"", part);
+				rc = ESLURM_ACCESS_DENIED;
+				goto end_it;
+			}
 		}
 
-		setup_association_limits(object, &cols, &vals, &extra,
-					  QOS_LEVEL_NONE, 1);
+		if(row[MASSOC_PART][0]) {
+			// see if there is a partition name
+			object = xstrdup_printf(
+				"C = %-10s A = %-20s U = %-9s P = %s",
+				row[MASSOC_COUNT], row[MASSOC_ACCT],
+				row[MASSOC_USER], row[MASSOC_PART]);
+		} else if(row[MASSOC_USER][0]){
+			object = xstrdup_printf(
+				"C = %-10s A = %-20s U = %-9s",
+				row[MASSOC_COUNT], row[MASSOC_ACCT],
+				row[MASSOC_USER]);
+		} else {
+			if(assoc->parent_acct) {
+				if(!strcasecmp(row[MASSOC_ACCT],
+					       assoc->parent_acct)) {
+					error("You can't make an account be a "
+					      "child of it's self");
+					xfree(object);
+					continue;
+				}
+				rc = _move_parent(mysql_conn, user->uid,
+						  &lft, &rgt,
+						  row[MASSOC_COUNT],
+						  row[MASSOC_ID],
+						  row[MASSOC_PACCT],
+						  assoc->parent_acct,
+						  now);
+				if((rc == ESLURM_INVALID_PARENT_ACCOUNT)
+				   || (rc == ESLURM_SAME_PARENT_ACCOUNT)) {
+					continue;
+				} else if(rc != SLURM_SUCCESS)
+					break;
 
-		for(i=0; i<MASSOC_COUNT; i++) {
-			if(i)
-				xstrcat(tmp_char, ", ");
-			xstrcat(tmp_char, massoc_req_inx[i]);
+				moved_parent = 1;
+			}
+			if(row[MASSOC_PACCT][0]) {
+				object = xstrdup_printf(
+					"C = %-10s A = %s of %s",
+					row[MASSOC_COUNT], row[MASSOC_ACCT],
+					row[MASSOC_PACCT]);
+			} else {
+				object = xstrdup_printf(
+					"C = %-10s A = %s",
+					row[MASSOC_COUNT], row[MASSOC_ACCT]);
+			}
+			account_type = 1;
 		}
+		list_append(ret_list, object);
+		added++;
 
-		xstrfmtcat(query,
-			   "select distinct %s from %s %s order by lft "
-			   "FOR UPDATE;",
-			   tmp_char, assoc_table, update);
-		xfree(tmp_char);
-		debug3("%d(%s:%d) query\n%s",
-		       mysql_conn->conn, __FILE__, __LINE__, query);
-		if(!(result = mysql_db_query_ret(
-			     mysql_conn->db_conn, query, 0))) {
-			xfree(query);
-			xfree(cols);
-			xfree(vals);
-			xfree(extra);
-			xfree(update);
-			error("couldn't query the database");
-			rc = SLURM_ERROR;
-			break;
-		}
-		xfree(query);
+		if(name_char)
+			xstrfmtcat(name_char, " || id_assoc=%s",
+				   row[MASSOC_ID]);
+		else
+			xstrfmtcat(name_char, "(id_assoc=%s", row[MASSOC_ID]);
 
-		assoc_id = 0;
-		if(!(row = mysql_fetch_row(result))) {
-			/* This code speeds up the add process quite a bit
-			 * here we are only doing an update when we are done
-			 * adding to a specific group (cluster/account) other
-			 * than that we are adding right behind what we were
-			 * so just total them up and then do one update
-			 * instead of the slow ones that require an update
-			 * every time.  There is a incr check outside of the
-			 * loop to catch everything on the last spin of the
-			 * while.
-			 */
-			if(!old_parent || !old_cluster
-			   || strcasecmp(parent, old_parent)
-			   || strcasecmp(object->cluster, old_cluster)) {
-				char *sel_query = xstrdup_printf(
-					"SELECT lft FROM %s WHERE "
-					"acct = \"%s\" and cluster = \"%s\" "
-					"and user = '' order by lft;",
-					assoc_table,
-					parent, object->cluster);
-				MYSQL_RES *sel_result = NULL;
+		mod_assoc = xmalloc(sizeof(acct_association_rec_t));
+		init_acct_association_rec(mod_assoc);
+		mod_assoc->id = atoi(row[MASSOC_ID]);
+		mod_assoc->cluster = xstrdup(cluster_name);
 
-				if(incr) {
-					char *up_query = xstrdup_printf(
-						"UPDATE %s SET rgt = rgt+%d "
-						"WHERE rgt > %d && deleted < 2;"
-						"UPDATE %s SET lft = lft+%d "
+		mod_assoc->shares_raw = assoc->shares_raw;
+
+		mod_assoc->grp_cpus = assoc->grp_cpus;
+		mod_assoc->grp_cpu_mins = assoc->grp_cpu_mins;
+		mod_assoc->grp_jobs = assoc->grp_jobs;
+		mod_assoc->grp_nodes = assoc->grp_nodes;
+		mod_assoc->grp_submit_jobs = assoc->grp_submit_jobs;
+		mod_assoc->grp_wall = assoc->grp_wall;
+
+		mod_assoc->max_cpus_pj = assoc->max_cpus_pj;
+		mod_assoc->max_cpu_mins_pj = assoc->max_cpu_mins_pj;
+		mod_assoc->max_jobs = assoc->max_jobs;
+		mod_assoc->max_nodes_pj = assoc->max_nodes_pj;
+		mod_assoc->max_submit_jobs = assoc->max_submit_jobs;
+		mod_assoc->max_wall_pj = assoc->max_wall_pj;
+
+		/* no need to get the parent id since if we moved
+		 * parent id's we will get it when we send the total list */
+
+		if(!row[MASSOC_USER][0])
+			mod_assoc->parent_acct = xstrdup(assoc->parent_acct);
+		if(assoc->qos_list && list_count(assoc->qos_list)) {
+			ListIterator new_qos_itr =
+				list_iterator_create(assoc->qos_list);
+			char *new_qos = NULL, *tmp_qos = NULL;
+
+			mod_assoc->qos_list = list_create(slurm_destroy_char);
+
+			while((new_qos = list_next(new_qos_itr))) {
+				if(new_qos[0] == '-' || new_qos[0] == '+') {
+					list_append(mod_assoc->qos_list,
+						    xstrdup(new_qos));
+				} else if(new_qos[0]) {
+					list_append(mod_assoc->qos_list,
+						    xstrdup_printf("=%s",
+								   new_qos));
+				}
+
+				if(set_qos_vals)
+					continue;
+				/* Now we can set up the values and
+				   make sure we aren't over writing
+				   things that are really from the
+				   parent
+				*/
+				if(new_qos[0] == '-') {
+					xstrfmtcat(vals,
+						   ", qos=if(qos='', '', "
+						   "replace(qos, ',%s', ''))"
+						   ", delta_qos=if(qos='', "
+						   "concat(replace(replace("
+						   "delta_qos, ',+%s', ''), "
+						   "',-%s', ''), ',%s'), '')",
+						   new_qos+1, new_qos+1,
+						   new_qos+1, new_qos);
+				} else if(new_qos[0] == '+') {
+					xstrfmtcat(vals,
+						   ", qos=if(qos='', '', "
+						   "concat_ws(',', "
+						   "replace(qos, ',%s', ''), "
+						   "\"%s\")), delta_qos=if("
+						   "qos='', concat("
+						   "replace(replace("
+						   "delta_qos, ',+%s', ''), "
+						   "',-%s', ''), ',%s'), '')",
+						   new_qos+1, new_qos+1,
+						   new_qos+1, new_qos+1,
+						   new_qos);
+				} else if(new_qos[0])
+					xstrfmtcat(tmp_qos, ",%s", new_qos);
+				else
+					xstrcat(tmp_qos, "");
+
+			}
+			list_iterator_destroy(new_qos_itr);
+
+			if(!set_qos_vals && tmp_qos)
+				xstrfmtcat(vals, ", qos='%s', delta_qos=''",
+					   tmp_qos);
+			xfree(tmp_qos);
+
+			set_qos_vals=1;
+		}
+
+		if(addto_update_list(mysql_conn->update_list,
+				     ACCT_MODIFY_ASSOC,
+				     mod_assoc) != SLURM_SUCCESS)
+			error("couldn't add to the update list");
+		if(account_type) {
+			_modify_unset_users(mysql_conn,
+					    mod_assoc,
+					    row[MASSOC_ACCT],
+					    lft, rgt,
+					    ret_list,
+					    moved_parent);
+		}
+	}
+
+	xstrcat(name_char, ")");
+
+	if(assoc->parent_acct) {
+		if(((rc == ESLURM_INVALID_PARENT_ACCOUNT)
+		    || (rc == ESLURM_SAME_PARENT_ACCOUNT))
+		   && added)
+			rc = SLURM_SUCCESS;
+	}
+
+	if(rc != SLURM_SUCCESS)
+		goto end_it;
+
+	if(vals) {
+		char *user_name = uid_to_string((uid_t) user->uid);
+		rc = modify_common(mysql_conn, DBD_MODIFY_ASSOCS, now,
+				   user_name, assoc_table, name_char, vals,
+				   cluster_name);
+		xfree(user_name);
+		if (rc == SLURM_ERROR) {
+			if(mysql_conn->rollback) {
+				mysql_db_rollback(mysql_conn->db_conn);
+			}
+			list_flush(mysql_conn->update_list);
+			error("Couldn't modify associations");
+			list_destroy(ret_list);
+			ret_list = NULL;
+			goto end_it;
+		}
+	}
+
+	if(moved_parent) {
+		List local_assoc_list = NULL;
+		ListIterator local_itr = NULL;
+		acct_association_rec_t *local_assoc = NULL;
+		acct_association_cond_t local_assoc_cond;
+		/* now we need to send the update of the new parents and
+		 * limits, so just to be safe, send the whole
+		 * tree because we could have some limits that
+		 * were affected but not noticed.
+		 */
+		/* we can probably just look at the mod time now but
+		 * we will have to wait for the next revision number
+		 * since you can't query on mod time here and I don't
+		 * want to rewrite code to make it happen
+		 */
+
+		memset(&local_assoc_cond, 0, sizeof(acct_association_cond_t));
+		local_assoc_cond.cluster_list = list_create(NULL);
+		list_append(local_assoc_cond.cluster_list, cluster_name);
+		local_assoc_list = mysql_get_assocs(
+			mysql_conn, user->uid, &local_assoc_cond);
+		list_destroy(local_assoc_cond.cluster_list);
+		if(!local_assoc_list)
+			   goto end_it;
+		/* NOTE: you can not use list_pop, or list_push
+		   anywhere either, since mysql is
+		   exporting something of the same type as a macro,
+		   which messes everything up (my_list.h is
+		   the bad boy).
+		   So we are just going to delete each item as it
+		   comes out since we are moving it to the update_list.
+		*/
+		local_itr = list_iterator_create(local_assoc_list);
+		while((local_assoc = list_next(local_itr))) {
+			if(addto_update_list(mysql_conn->update_list,
+					     ACCT_MODIFY_ASSOC,
+					     local_assoc) == SLURM_SUCCESS)
+				list_remove(local_itr);
+		}
+		list_iterator_destroy(local_itr);
+		list_destroy(local_assoc_list);
+	}
+
+end_it:
+	xfree(name_char);
+	xfree(vals);
+
+	return rc;
+}
+
+extern int mysql_add_assocs(mysql_conn_t *mysql_conn, uint32_t uid,
+			    List association_list)
+{
+	ListIterator itr = NULL;
+	int rc = SLURM_SUCCESS;
+	int i=0;
+	acct_association_rec_t *object = NULL;
+	char *cols = NULL, *vals = NULL, *txn_query = NULL,
+		*extra = NULL, *query = NULL, *update = NULL, *tmp_extra = NULL;
+	char *parent = NULL;
+	time_t now = time(NULL);
+	char *user_name = NULL;
+	char *tmp_char = NULL;
+	int assoc_id = 0;
+	int incr = 0, my_left = 0, my_par_id = 0;
+	int affect_rows = 0;
+	int moved_parent = 0;
+	MYSQL_RES *result = NULL;
+	MYSQL_ROW row;
+	char *old_parent = NULL, *old_cluster = NULL;
+	char *last_parent = NULL, *last_cluster = NULL;
+
+	if(!association_list) {
+		error("No association list given");
+		return SLURM_ERROR;
+	}
+
+	if(check_connection(mysql_conn) != SLURM_SUCCESS)
+		return ESLURM_DB_CONNECTION;
+
+	user_name = uid_to_string((uid_t) uid);
+	itr = list_iterator_create(association_list);
+	while((object = list_next(itr))) {
+		if(!object->cluster || !object->cluster[0]
+		   || !object->acct || !object->acct[0]) {
+			error("We need a association cluster and "
+			      "acct to add one.");
+			rc = SLURM_ERROR;
+			continue;
+		}
+
+		if(object->parent_acct) {
+			parent = object->parent_acct;
+		} else if(object->user) {
+			parent = object->acct;
+		} else {
+			parent = "root";
+		}
+
+		xstrcat(cols, "creation_time, mod_time, cluster, acct");
+		xstrfmtcat(vals, "%d, %d, \"%s\", \"%s\"",
+			   now, now, object->cluster, object->acct);
+		xstrfmtcat(update,
+			   "where cluster=\"%s\" && acct=\"%s\"",
+			   object->cluster, object->acct);
+
+		xstrfmtcat(extra, ", mod_time=%d, cluster=\"%s\", "
+			   "acct=\"%s\"", now, object->cluster, object->acct);
+		if(!object->user) {
+			xstrcat(cols, ", parent_acct");
+			xstrfmtcat(vals, ", \"%s\"", parent);
+			xstrfmtcat(extra, ", parent_acct=\"%s\", user=\"\"",
+				   parent);
+			xstrfmtcat(update, " && user=\"\"");
+		} else {
+			char *part = object->partition;
+			xstrcat(cols, ", user");
+			xstrfmtcat(vals, ", \"%s\"", object->user);
+			xstrfmtcat(update, " && user=\"%s\"", object->user);
+			xstrfmtcat(extra, ", user=\"%s\"", object->user);
+
+			/* We need to give a partition whether it be
+			 * '' or the actual partition name given
+			 */
+			if(!part)
+				part = "";
+			xstrcat(cols, ", partition");
+			xstrfmtcat(vals, ", \"%s\"", part);
+			xstrfmtcat(update, " && partition=\"%s\"", part);
+			xstrfmtcat(extra, ", partition=\"%s\"", part);
+		}
+
+		setup_association_limits(object, &cols, &vals, &extra,
+					  QOS_LEVEL_NONE, 1);
+
+		for(i=0; i<AASSOC_COUNT; i++) {
+			if(i)
+				xstrcat(tmp_char, ", ");
+			xstrcat(tmp_char, aassoc_req_inx[i]);
+		}
+
+		xstrfmtcat(query,
+			   "select distinct %s from %s %s order by lft "
+			   "FOR UPDATE;",
+			   tmp_char, assoc_table, update);
+		xfree(tmp_char);
+		debug3("%d(%s:%d) query\n%s",
+		       mysql_conn->conn, __FILE__, __LINE__, query);
+		if(!(result = mysql_db_query_ret(
+			     mysql_conn->db_conn, query, 0))) {
+			xfree(query);
+			xfree(cols);
+			xfree(vals);
+			xfree(extra);
+			xfree(update);
+			error("couldn't query the database");
+			rc = SLURM_ERROR;
+			break;
+		}
+		xfree(query);
+
+		assoc_id = 0;
+		if(!(row = mysql_fetch_row(result))) {
+			/* This code speeds up the add process quite a bit
+			 * here we are only doing an update when we are done
+			 * adding to a specific group (cluster/account) other
+			 * than that we are adding right behind what we were
+			 * so just total them up and then do one update
+			 * instead of the slow ones that require an update
+			 * every time.  There is a incr check outside of the
+			 * loop to catch everything on the last spin of the
+			 * while.
+			 */
+			if(!old_parent || !old_cluster
+			   || strcasecmp(parent, old_parent)
+			   || strcasecmp(object->cluster, old_cluster)) {
+				char *sel_query = xstrdup_printf(
+					"SELECT lft FROM %s WHERE "
+					"acct = \"%s\" and cluster = \"%s\" "
+					"and user = '' order by lft;",
+					assoc_table,
+					parent, object->cluster);
+				MYSQL_RES *sel_result = NULL;
+
+				if(incr) {
+					char *up_query = xstrdup_printf(
+						"UPDATE %s SET rgt = rgt+%d "
+						"WHERE rgt > %d && deleted < 2;"
+						"UPDATE %s SET lft = lft+%d "
 						"WHERE lft > %d "
 						"&& deleted < 2;"
 						"UPDATE %s SET deleted = 0 "
@@ -1218,7 +1587,7 @@ extern int mysql_add_assocs(mysql_conn_t *mysql_conn, uint32_t uid,
 /* 				   "values (%s, @myLeft+1, @myLeft+2);", */
 /* 				   assoc_table, cols, */
 /* 				   vals); */
-		} else if(!atoi(row[MASSOC_DELETED])) {
+		} else if(!atoi(row[AASSOC_DELETED])) {
 			/* We don't need to do anything here */
 			debug("This account was added already");
 			xfree(cols);
@@ -1228,25 +1597,25 @@ extern int mysql_add_assocs(mysql_conn_t *mysql_conn, uint32_t uid,
 			xfree(extra);
 			continue;
 		} else {
-			uint32_t lft = atoi(row[MASSOC_LFT]);
-			uint32_t rgt = atoi(row[MASSOC_RGT]);
+			uint32_t lft = atoi(row[AASSOC_LFT]);
+			uint32_t rgt = atoi(row[AASSOC_RGT]);
 
 			/* If it was once deleted we have kept the lft
 			 * and rgt's consant while it was deleted and
 			 * so we can just unset the deleted flag,
 			 * check for the parent and move if needed.
 			 */
-			assoc_id = atoi(row[MASSOC_ID]);
+			assoc_id = atoi(row[AASSOC_ID]);
 			if(object->parent_acct
 			   && strcasecmp(object->parent_acct,
-					 row[MASSOC_PACCT])) {
+					 row[AASSOC_PACCT])) {
 
 				/* We need to move the parent! */
 				if(_move_parent(mysql_conn, uid,
 						&lft, &rgt,
 						object->cluster,
-						row[MASSOC_ID],
-						row[MASSOC_PACCT],
+						row[AASSOC_ID],
+						row[AASSOC_PACCT],
 						object->parent_acct, now)
 				   == SLURM_ERROR)
 					continue;
@@ -1419,456 +1788,146 @@ end_it:
 			list_iterator_destroy(itr);
 			list_destroy(assoc_list);
 		}
-	} else {
-		xfree(txn_query);
-		if(mysql_conn->rollback) {
-			mysql_db_rollback(mysql_conn->db_conn);
-		}
-		list_flush(mysql_conn->update_list);
-	}
-
-	return rc;
-}
-
-extern List mysql_modify_assocs(mysql_conn_t *mysql_conn, uint32_t uid,
-				acct_association_cond_t *assoc_cond,
-				acct_association_rec_t *assoc)
-{
-	ListIterator itr = NULL;
-	List ret_list = NULL;
-	int rc = SLURM_SUCCESS;
-	char *object = NULL;
-	char *vals = NULL, *extra = NULL, *query = NULL, *name_char = NULL;
-	time_t now = time(NULL);
-	char *user_name = NULL;
-	int set = 0, i = 0, is_admin=0;
-	MYSQL_RES *result = NULL;
-	MYSQL_ROW row;
-	acct_user_rec_t user;
-	char *tmp_char1=NULL, *tmp_char2=NULL;
-	int set_qos_vals = 0;
-	int moved_parent = 0;
-
-	char *massoc_req_inx[] = {
-		"id",
-		"acct",
-		"parent_acct",
-		"cluster",
-		"user",
-		"partition",
-		"lft",
-		"rgt",
-		"qos",
-	};
-
-	enum {
-		MASSOC_ID,
-		MASSOC_ACCT,
-		MASSOC_PACCT,
-		MASSOC_CLUSTER,
-		MASSOC_USER,
-		MASSOC_PART,
-		MASSOC_LFT,
-		MASSOC_RGT,
-		MASSOC_QOS,
-		MASSOC_COUNT
-	};
-
-	if(!assoc_cond || !assoc) {
-		error("we need something to change");
-		return NULL;
-	}
-
-	if(check_connection(mysql_conn) != SLURM_SUCCESS)
-		return NULL;
-
-	memset(&user, 0, sizeof(acct_user_rec_t));
-	user.uid = uid;
-
-	if(!(is_admin = is_user_min_admin_level(
-		     mysql_conn, uid, ACCT_ADMIN_OPERATOR))) {
-		if(!is_user_any_coord(mysql_conn, &user)) {
-			error("Only admins/coordinators can "
-			      "modify associations");
-			errno = ESLURM_ACCESS_DENIED;
-			return NULL;
-		}
-	}
-
-	set = _setup_association_cond_limits(assoc_cond, &extra);
-
-	/* This needs to be here to make sure we only modify the
-	   correct set of associations The first clause was already
-	   taken care of above. */
-	if (assoc_cond->user_list && !list_count(assoc_cond->user_list)) {
-		debug4("no user specified looking at users");
-		xstrcat(extra, " && user != '' ");
-	} else if (!assoc_cond->user_list) {
-		debug4("no user specified looking at accounts");
-		xstrcat(extra, " && user = '' ");
-	}
-
-	setup_association_limits(assoc, &tmp_char1, &tmp_char2,
-				 &vals, QOS_LEVEL_MODIFY, 0);
-	xfree(tmp_char1);
-	xfree(tmp_char2);
-
-	if(!extra || (!vals && !assoc->parent_acct
-		      && (!assoc->qos_list || !list_count(assoc->qos_list)))) {
-		errno = SLURM_NO_CHANGE_IN_DATA;
-		error("Nothing to change");
-		return NULL;
-	}
-
-	for(i=0; i<MASSOC_COUNT; i++) {
-		if(i)
-			xstrcat(object, ", ");
-		xstrfmtcat(object, "t1.%s", massoc_req_inx[i]);
-	}
-
-	query = xstrdup_printf("select distinct %s from %s as t1%s "
-			       "order by lft FOR UPDATE;",
-			       object, assoc_table, extra);
-	xfree(object);
-	xfree(extra);
-
-	debug3("%d(%s:%d) query\n%s",
-	       mysql_conn->conn, __FILE__, __LINE__, query);
-	if(!(result = mysql_db_query_ret(
-		     mysql_conn->db_conn, query, 0))) {
-		xfree(query);
-		return NULL;
-	}
-	xfree(query);
-
-	rc = SLURM_SUCCESS;
-	set = 0;
-	extra = NULL;
-	ret_list = list_create(slurm_destroy_char);
-	while((row = mysql_fetch_row(result))) {
-		acct_association_rec_t *mod_assoc = NULL;
-		int account_type=0;
-		/* If parent changes these also could change
-		   so we need to keep track of the latest
-		   ones.
-		*/
-		uint32_t lft = atoi(row[MASSOC_LFT]);
-		uint32_t rgt = atoi(row[MASSOC_RGT]);
-
-		if(!is_admin) {
-			acct_coord_rec_t *coord = NULL;
-			char *account = row[MASSOC_ACCT];
-
-			/* Here we want to see if the person
-			 * is a coord of the parent account
-			 * since we don't want him to be able
-			 * to alter the limits of the account
-			 * he is directly coord of.  They
-			 * should be able to alter the
-			 * sub-accounts though. If no parent account
-			 * that means we are talking about a user
-			 * association so account is really the parent
-			 * of the user a coord can change that all day long.
-			 */
-			if(row[MASSOC_PACCT][0])
-				account = row[MASSOC_PACCT];
-
-			if(!user.coord_accts) { // This should never
-						// happen
-				error("We are here with no coord accts.");
-				if(mysql_conn->rollback) {
-					mysql_db_rollback(
-						mysql_conn->db_conn);
-				}
-				errno = ESLURM_ACCESS_DENIED;
-				mysql_free_result(result);
-				xfree(vals);
-				list_destroy(ret_list);
-				return NULL;
-			}
-			itr = list_iterator_create(user.coord_accts);
-			while((coord = list_next(itr))) {
-				if(!strcasecmp(coord->name, account))
-					break;
-			}
-			list_iterator_destroy(itr);
-
-			if(!coord) {
-				if(row[MASSOC_PACCT][0])
-					error("User %s(%d) can not modify "
-					      "account (%s) because they "
-					      "are not coordinators of "
-					      "parent account \"%s\".",
-					      user.name, user.uid,
-					      row[MASSOC_ACCT],
-					      row[MASSOC_PACCT]);
-				else
-					error("User %s(%d) does not have the "
-					      "ability to modify the account "
-					      "(%s).",
-					      user.name, user.uid,
-					      row[MASSOC_ACCT]);
-
-				if(mysql_conn->rollback) {
-					mysql_db_rollback(
-						mysql_conn->db_conn);
-				}
-				errno = ESLURM_ACCESS_DENIED;
-				mysql_free_result(result);
-				xfree(vals);
-				list_destroy(ret_list);
-				return NULL;
-			}
-		}
-
-		if(row[MASSOC_PART][0]) {
-			// see if there is a partition name
-			object = xstrdup_printf(
-				"C = %-10s A = %-20s U = %-9s P = %s",
-				row[MASSOC_CLUSTER], row[MASSOC_ACCT],
-				row[MASSOC_USER], row[MASSOC_PART]);
-		} else if(row[MASSOC_USER][0]){
-			object = xstrdup_printf(
-				"C = %-10s A = %-20s U = %-9s",
-				row[MASSOC_CLUSTER], row[MASSOC_ACCT],
-				row[MASSOC_USER]);
-		} else {
-			if(assoc->parent_acct) {
-				if(!strcasecmp(row[MASSOC_ACCT],
-					       assoc->parent_acct)) {
-					error("You can't make an account be a "
-					      "child of it's self");
-					xfree(object);
-					continue;
-				}
-				rc = _move_parent(mysql_conn, uid,
-						  &lft, &rgt,
-						  row[MASSOC_CLUSTER],
-						  row[MASSOC_ID],
-						  row[MASSOC_PACCT],
-						  assoc->parent_acct,
-						  now);
-				if((rc == ESLURM_INVALID_PARENT_ACCOUNT)
-				   || (rc == ESLURM_SAME_PARENT_ACCOUNT)) {
-					continue;
-				} else if(rc != SLURM_SUCCESS)
-					break;
-
-				moved_parent = 1;
-			}
-			if(row[MASSOC_PACCT][0]) {
-				object = xstrdup_printf(
-					"C = %-10s A = %s of %s",
-					row[MASSOC_CLUSTER], row[MASSOC_ACCT],
-					row[MASSOC_PACCT]);
-			} else {
-				object = xstrdup_printf(
-					"C = %-10s A = %s",
-					row[MASSOC_CLUSTER], row[MASSOC_ACCT]);
-			}
-			account_type = 1;
-		}
-		list_append(ret_list, object);
-
-		if(!set) {
-			xstrfmtcat(name_char, "(id=%s", row[MASSOC_ID]);
-			set = 1;
-		} else {
-			xstrfmtcat(name_char, " || id=%s", row[MASSOC_ID]);
+	} else {
+		xfree(txn_query);
+		if(mysql_conn->rollback) {
+			mysql_db_rollback(mysql_conn->db_conn);
 		}
+		list_flush(mysql_conn->update_list);
+	}
 
-		mod_assoc = xmalloc(sizeof(acct_association_rec_t));
-		init_acct_association_rec(mod_assoc);
-		mod_assoc->id = atoi(row[MASSOC_ID]);
-
-		mod_assoc->shares_raw = assoc->shares_raw;
+	return rc;
+}
 
-		mod_assoc->grp_cpus = assoc->grp_cpus;
-		mod_assoc->grp_cpu_mins = assoc->grp_cpu_mins;
-		mod_assoc->grp_jobs = assoc->grp_jobs;
-		mod_assoc->grp_nodes = assoc->grp_nodes;
-		mod_assoc->grp_submit_jobs = assoc->grp_submit_jobs;
-		mod_assoc->grp_wall = assoc->grp_wall;
+extern List mysql_modify_assocs(mysql_conn_t *mysql_conn, uint32_t uid,
+				acct_association_cond_t *assoc_cond,
+				acct_association_rec_t *assoc)
+{
+	ListIterator itr = NULL;
+	List ret_list = NULL;
+	int rc = SLURM_SUCCESS;
+	char *object = NULL;
+	char *vals = NULL, *extra = NULL, *query = NULL;
+	int set = 0, i = 0, is_admin=0;
+	MYSQL_RES *result = NULL;
+	acct_user_rec_t user;
+	char *tmp_char1=NULL, *tmp_char2=NULL;
+	char *cluster_name = NULL;
+	char *prefix = "t1";
+	List use_cluster_list = mysql_cluster_list;
 
-		mod_assoc->max_cpus_pj = assoc->max_cpus_pj;
-		mod_assoc->max_cpu_mins_pj = assoc->max_cpu_mins_pj;
-		mod_assoc->max_jobs = assoc->max_jobs;
-		mod_assoc->max_nodes_pj = assoc->max_nodes_pj;
-		mod_assoc->max_submit_jobs = assoc->max_submit_jobs;
-		mod_assoc->max_wall_pj = assoc->max_wall_pj;
+	if(!assoc_cond || !assoc) {
+		error("we need something to change");
+		return NULL;
+	}
 
-		/* no need to get the parent id since if we moved
-		 * parent id's we will get it when we send the total list */
+	if(check_connection(mysql_conn) != SLURM_SUCCESS)
+		return NULL;
 
-		if(!row[MASSOC_USER][0])
-			mod_assoc->parent_acct = xstrdup(assoc->parent_acct);
-		if(assoc->qos_list && list_count(assoc->qos_list)) {
-			ListIterator new_qos_itr =
-				list_iterator_create(assoc->qos_list);
-			char *new_qos = NULL, *tmp_qos = NULL;
+	memset(&user, 0, sizeof(acct_user_rec_t));
+	user.uid = uid;
 
-			mod_assoc->qos_list = list_create(slurm_destroy_char);
+	if(!(is_admin = is_user_min_admin_level(
+		     mysql_conn, uid, ACCT_ADMIN_OPERATOR))) {
+		if(!is_user_any_coord(mysql_conn, &user)) {
+			error("Only admins/coordinators can "
+			      "modify associations");
+			errno = ESLURM_ACCESS_DENIED;
+			return NULL;
+		}
+	}
 
-			while((new_qos = list_next(new_qos_itr))) {
-				if(new_qos[0] == '-' || new_qos[0] == '+') {
-					list_append(mod_assoc->qos_list,
-						    xstrdup(new_qos));
-				} else if(new_qos[0]) {
-					list_append(mod_assoc->qos_list,
-						    xstrdup_printf("=%s",
-								   new_qos));
-				}
+	if((assoc_cond->qos_list && list_count(assoc_cond->qos_list))
+	   || assoc_cond->with_sub_accts)
+		prefix = "t2";
 
-				if(set_qos_vals)
-					continue;
-				/* Now we can set up the values and
-				   make sure we aren't over writing
-				   things that are really from the
-				   parent
-				*/
-				if(new_qos[0] == '-') {
-					xstrfmtcat(vals,
-						   ", qos=if(qos='', '', "
-						   "replace(qos, ',%s', ''))"
-						   ", delta_qos=if(qos='', "
-						   "concat(replace(replace("
-						   "delta_qos, ',+%s', ''), "
-						   "',-%s', ''), ',%s'), '')",
-						   new_qos+1, new_qos+1,
-						   new_qos+1, new_qos);
-				} else if(new_qos[0] == '+') {
-					xstrfmtcat(vals,
-						   ", qos=if(qos='', '', "
-						   "concat_ws(',', "
-						   "replace(qos, ',%s', ''), "
-						   "\"%s\")), delta_qos=if("
-						   "qos='', concat("
-						   "replace(replace("
-						   "delta_qos, ',+%s', ''), "
-						   "',-%s', ''), ',%s'), '')",
-						   new_qos+1, new_qos+1,
-						   new_qos+1, new_qos+1,
-						   new_qos);
-				} else if(new_qos[0])
-					xstrfmtcat(tmp_qos, ",%s", new_qos);
-				else
-					xstrcat(tmp_qos, "");
+	set = _setup_association_cond_limits(assoc_cond, prefix, &extra);
 
-			}
-			list_iterator_destroy(new_qos_itr);
+	/* This needs to be here to make sure we only modify the
+	   correct set of associations The first clause was already
+	   taken care of above. */
+	if (assoc_cond->user_list && !list_count(assoc_cond->user_list)) {
+		debug4("no user specified looking at users");
+		xstrcat(extra, " && user != '' ");
+	} else if (!assoc_cond->user_list) {
+		debug4("no user specified looking at accounts");
+		xstrcat(extra, " && user = '' ");
+	}
 
-			if(!set_qos_vals && tmp_qos)
-				xstrfmtcat(vals, ", qos='%s', delta_qos=''",
-					   tmp_qos);
-			xfree(tmp_qos);
+	setup_association_limits(assoc, &tmp_char1, &tmp_char2,
+				 &vals, QOS_LEVEL_MODIFY, 0);
+	xfree(tmp_char1);
+	xfree(tmp_char2);
 
-			set_qos_vals=1;
-		}
+	if(!extra || (!vals && !assoc->parent_acct
+		      && (!assoc->qos_list || !list_count(assoc->qos_list)))) {
+		errno = SLURM_NO_CHANGE_IN_DATA;
+		error("Nothing to change");
+		return NULL;
+	}
 
-		if(addto_update_list(mysql_conn->update_list,
-				      ACCT_MODIFY_ASSOC,
-				      mod_assoc) != SLURM_SUCCESS)
-			error("couldn't add to the update list");
-		if(account_type) {
-			_modify_unset_users(mysql_conn,
-					    mod_assoc,
-					    row[MASSOC_ACCT],
-					    lft, rgt,
-					    ret_list,
-					    moved_parent);
-		}
+	for(i=0; i<MASSOC_COUNT; i++) {
+		if(i)
+			xstrcat(object, ", ");
+		xstrfmtcat(object, "t1.%s", massoc_req_inx[i]);
 	}
-	mysql_free_result(result);
 
-	if(assoc->parent_acct) {
-		if(((rc == ESLURM_INVALID_PARENT_ACCOUNT)
-		    || (rc == ESLURM_SAME_PARENT_ACCOUNT))
-		   && list_count(ret_list))
-			rc = SLURM_SUCCESS;
+
+	ret_list = list_create(slurm_destroy_char);
+
+	if(assoc_cond->cluster_list && list_count(assoc_cond->cluster_list))
+		use_cluster_list = assoc_cond->cluster_list;
+	else
+		slurm_mutex_lock(&mysql_cluster_list_lock);
+
+	itr = list_iterator_create(use_cluster_list);
+	while((cluster_name = list_next(itr))) {
+		char *qos_extra = _setup_association_cond_qos(
+			assoc_cond, cluster_name);
+
+		xstrfmtcat(query, "select distinct %s,'%s' "
+			   "from %s_%s as t1%s%s "
+			   "order by lft FOR UPDATE;",
+			   object, cluster_name,
+			   assoc_table, qos_extra, extra);
+		xfree(qos_extra);
+		debug3("%d(%s:%d) query\n%s",
+		       mysql_conn->conn, __FILE__, __LINE__, query);
+		if(!(result = mysql_db_query_ret(
+			     mysql_conn->db_conn, query, 0))) {
+			xfree(query);
+			list_destroy(ret_list);
+			ret_list = NULL;
+			break;
+		}
+		xfree(query);
+		rc = _process_modify_assoc_results(mysql_conn, result, assoc,
+						   &user, cluster_name,
+						   is_admin, ret_list);
+		mysql_free_result(result);
 
 		if(rc != SLURM_SUCCESS) {
-			if(mysql_conn->rollback) {
-				mysql_db_rollback(mysql_conn->db_conn);
-			}
-			list_flush(mysql_conn->update_list);
 			list_destroy(ret_list);
-			xfree(vals);
-			errno = rc;
-			return NULL;
+			ret_list = NULL;
+			break;
 		}
 	}
+	list_iterator_destroy(itr);
+	if(use_cluster_list == mysql_cluster_list)
+		slurm_mutex_unlock(&mysql_cluster_list_lock);
+	xfree(object);
+	xfree(extra);
 
-
-	if(!list_count(ret_list)) {
+	if(!ret_list)
+		return NULL;
+	else if(!list_count(ret_list)) {
 		if(mysql_conn->rollback) {
 			mysql_db_rollback(mysql_conn->db_conn);
 		}
 		errno = SLURM_NO_CHANGE_IN_DATA;
 		debug3("didn't effect anything");
-		xfree(vals);
 		return ret_list;
 	}
-	xstrcat(name_char, ")");
-
-	if(vals) {
-		user_name = uid_to_string((uid_t) uid);
-		rc = modify_common(mysql_conn, DBD_MODIFY_ASSOCS, now,
-				   user_name, assoc_table, name_char, vals);
-		xfree(user_name);
-		if (rc == SLURM_ERROR) {
-			if(mysql_conn->rollback) {
-				mysql_db_rollback(mysql_conn->db_conn);
-			}
-			list_flush(mysql_conn->update_list);
-			error("Couldn't modify associations");
-			list_destroy(ret_list);
-			ret_list = NULL;
-			goto end_it;
-		}
-	}
-	if(moved_parent) {
-		List local_assoc_list = NULL;
-		ListIterator local_itr = NULL;
-		acct_association_rec_t *local_assoc = NULL;
-		//acct_association_cond_t local_assoc_cond;
-		/* now we need to send the update of the new parents and
-		 * limits, so just to be safe, send the whole
-		 * tree because we could have some limits that
-		 * were affected but not noticed.
-		 */
-		/* we can probably just look at the mod time now but
-		 * we will have to wait for the next revision number
-		 * since you can't query on mod time here and I don't
-		 * want to rewrite code to make it happen
-		 */
-
-		//memset(&local_assoc_cond, 0, sizeof(acct_association_cond_t));
-
-		if(!(local_assoc_list =
-		     mysql_get_assocs(mysql_conn, uid, NULL)))
-			return ret_list;
-		/* NOTE: you can not use list_pop, or list_push
-		   anywhere either, since mysql is
-		   exporting something of the same type as a macro,
-		   which messes everything up (my_list.h is
-		   the bad boy).
-		   So we are just going to delete each item as it
-		   comes out since we are moving it to the update_list.
-		*/
-		local_itr = list_iterator_create(local_assoc_list);
-		while((local_assoc = list_next(local_itr))) {
-			if(addto_update_list(mysql_conn->update_list,
-					      ACCT_MODIFY_ASSOC,
-					      local_assoc) == SLURM_SUCCESS)
-				list_remove(local_itr);
-		}
-		list_iterator_destroy(local_itr);
-		list_destroy(local_assoc_list);
-	}
-
-end_it:
-	xfree(name_char);
-	xfree(vals);
 
 	return ret_list;
 }
@@ -1888,27 +1947,7 @@ extern List mysql_remove_assocs(mysql_conn_t *mysql_conn, uint32_t uid,
 	MYSQL_RES *result = NULL;
 	MYSQL_ROW row;
 	acct_user_rec_t user;
-
-	/* if this changes you will need to edit the corresponding
-	 * enum below also t1 is step_table */
-	char *rassoc_req_inx[] = {
-		"id",
-		"acct",
-		"parent_acct",
-		"cluster",
-		"user",
-		"partition"
-	};
-
-	enum {
-		RASSOC_ID,
-		RASSOC_ACCT,
-		RASSOC_PACCT,
-		RASSOC_CLUSTER,
-		RASSOC_USER,
-		RASSOC_PART,
-		RASSOC_COUNT
-	};
+	char *prefix = "t1";
 
 	if(!assoc_cond) {
 		error("we need something to change");
@@ -1931,7 +1970,11 @@ extern List mysql_remove_assocs(mysql_conn_t *mysql_conn, uint32_t uid,
 		}
 	}
 
-	set = _setup_association_cond_limits(assoc_cond, &extra);
+	if((assoc_cond->qos_list && list_count(assoc_cond->qos_list))
+	   || assoc_cond->with_sub_accts)
+		prefix = "t2";
+
+	set = _setup_association_cond_limits(assoc_cond, prefix, &extra);
 
 	for(i=0; i<RASSOC_COUNT; i++) {
 		if(i)
@@ -2128,6 +2171,7 @@ extern List mysql_get_assocs(mysql_conn_t *mysql_conn, uid_t uid,
 	uint32_t parent_id = 0;
 	uint16_t private_data = 0;
 	acct_user_rec_t user;
+	char *prefix = "t1";
 
 	/* needed if we don't have an assoc_cond */
 	uint16_t without_parent_info = 0;
@@ -2218,7 +2262,11 @@ extern List mysql_get_assocs(mysql_conn_t *mysql_conn, uid_t uid,
 			is_user_any_coord(mysql_conn, &user);
 	}
 
-	set = _setup_association_cond_limits(assoc_cond, &extra);
+	if((assoc_cond->qos_list && list_count(assoc_cond->qos_list))
+	   || assoc_cond->with_sub_accts)
+		prefix = "t2";
+
+	set = _setup_association_cond_limits(assoc_cond, prefix, &extra);
 
 	with_raw_qos = assoc_cond->with_raw_qos;
 	with_usage = assoc_cond->with_usage;
diff --git a/src/plugins/accounting_storage/mysql/mysql_cluster.c b/src/plugins/accounting_storage/mysql/mysql_cluster.c
index bde4b6426cc..335f94ece7f 100644
--- a/src/plugins/accounting_storage/mysql/mysql_cluster.c
+++ b/src/plugins/accounting_storage/mysql/mysql_cluster.c
@@ -325,7 +325,8 @@ extern List mysql_modify_clusters(mysql_conn_t *mysql_conn, uint32_t uid,
 		send_char = xstrdup_printf("(%s)", name_char);
 		user_name = uid_to_string((uid_t) uid);
 		rc = modify_common(mysql_conn, DBD_MODIFY_CLUSTERS, now,
-				   user_name, cluster_table, send_char, vals);
+				   user_name, cluster_table,
+				   send_char, vals, NULL);
 		xfree(user_name);
 		if (rc == SLURM_ERROR) {
 			error("Couldn't modify cluster 1");
diff --git a/src/plugins/accounting_storage/mysql/mysql_qos.c b/src/plugins/accounting_storage/mysql/mysql_qos.c
index 5bfcb601091..7817a70b2b8 100644
--- a/src/plugins/accounting_storage/mysql/mysql_qos.c
+++ b/src/plugins/accounting_storage/mysql/mysql_qos.c
@@ -590,7 +590,7 @@ extern List mysql_modify_qos(mysql_conn_t *mysql_conn, uint32_t uid,
 
 	user_name = uid_to_string((uid_t) uid);
 	rc = modify_common(mysql_conn, DBD_MODIFY_QOS, now,
-			    user_name, qos_table, name_char, vals);
+			   user_name, qos_table, name_char, vals, NULL);
 	xfree(user_name);
 	xfree(name_char);
 	xfree(vals);
diff --git a/src/plugins/accounting_storage/mysql/mysql_user.c b/src/plugins/accounting_storage/mysql/mysql_user.c
index 2d8f194ac19..46d169576ee 100644
--- a/src/plugins/accounting_storage/mysql/mysql_user.c
+++ b/src/plugins/accounting_storage/mysql/mysql_user.c
@@ -482,7 +482,7 @@ extern List mysql_modify_users(mysql_conn_t *mysql_conn, uint32_t uid,
 
 	user_name = uid_to_string((uid_t) uid);
 	rc = modify_common(mysql_conn, DBD_MODIFY_USERS, now,
-			    user_name, user_table, name_char, vals);
+			   user_name, user_table, name_char, vals, NULL);
 	xfree(user_name);
 	xfree(name_char);
 	xfree(vals);
-- 
GitLab