| /*****************************************************************************\ |
| * as_mysql_txn.c - functions dealing with transactions. |
| ***************************************************************************** |
| * Copyright (C) 2004-2007 The Regents of the University of California. |
| * Copyright (C) 2008-2010 Lawrence Livermore National Security. |
| * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). |
| * Written by Danny Auble <da@llnl.gov> |
| * |
| * This file is part of Slurm, a resource management program. |
| * For details, see <https://slurm.schedmd.com/>. |
| * Please also read the included file: DISCLAIMER. |
| * |
| * Slurm is free software; you can redistribute it and/or modify it under |
| * the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * In addition, as a special exception, the copyright holders give permission |
| * to link the code of portions of this program with the OpenSSL library under |
| * certain conditions as described in each individual source file, and |
| * distribute linked combinations including the two. You must obey the GNU |
| * General Public License in all respects for all of the code used other than |
| * OpenSSL. If you modify file(s) with this exception, you may extend this |
| * exception to your version of the file(s), but you are not obligated to do |
| * so. If you do not wish to do so, delete this exception statement from your |
| * version. If you delete this exception statement from all source files in |
| * the program, then also delete it here. |
| * |
| * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY |
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| * details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with Slurm; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| \*****************************************************************************/ |
| |
| #include "as_mysql_txn.h" |
| |
| extern list_t *as_mysql_get_txn(mysql_conn_t *mysql_conn, uid_t uid, |
| slurmdb_txn_cond_t *txn_cond) |
| { |
| char *query = NULL; |
| char *assoc_extra = NULL; |
| char *name_extra = NULL; |
| char *extra = NULL; |
| char *tmp = NULL; |
| list_t *txn_list = NULL; |
| list_itr_t *itr = NULL; |
| char *object = NULL; |
| int set = 0; |
| int i=0; |
| MYSQL_RES *result = NULL; |
| MYSQL_ROW row; |
| list_t *use_cluster_list = NULL; |
| bool locked = 0; |
| |
| /* if this changes you will need to edit the corresponding enum */ |
| char *txn_req_inx[] = { |
| "id", |
| "timestamp", |
| "action", |
| "name", |
| "actor", |
| "info", |
| "cluster" |
| }; |
| enum { |
| TXN_REQ_ID, |
| TXN_REQ_TS, |
| TXN_REQ_ACTION, |
| TXN_REQ_NAME, |
| TXN_REQ_ACTOR, |
| TXN_REQ_INFO, |
| TXN_REQ_CLUSTER, |
| TXN_REQ_COUNT |
| }; |
| |
| if (check_connection(mysql_conn) != SLURM_SUCCESS) |
| return NULL; |
| |
| if (!txn_cond) |
| goto empty; |
| |
| /* handle query for associations first */ |
| if (txn_cond->acct_list && list_count(txn_cond->acct_list)) { |
| set = 0; |
| if (assoc_extra) |
| xstrcat(assoc_extra, " && ("); |
| else |
| xstrcat(assoc_extra, " where ("); |
| |
| if (name_extra) |
| xstrcat(name_extra, " && ("); |
| else |
| xstrcat(name_extra, " ("); |
| itr = list_iterator_create(txn_cond->acct_list); |
| while ((object = list_next(itr))) { |
| if (set) { |
| xstrcat(assoc_extra, " || "); |
| xstrcat(name_extra, " || "); |
| } |
| |
| xstrfmtcat(assoc_extra, "acct='%s'", object); |
| |
| xstrfmtcat(name_extra, "(name like '%%\\'%s\\'%%'" |
| " || name='%s')" |
| " || (info like '%%acct=\\'%s\\'%%')", |
| object, object, object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(assoc_extra, ")"); |
| xstrcat(name_extra, ")"); |
| } |
| |
| if (txn_cond->cluster_list && list_count(txn_cond->cluster_list)) { |
| set = 0; |
| if (name_extra) |
| xstrcat(name_extra, " && ("); |
| else |
| xstrcat(name_extra, "("); |
| |
| itr = list_iterator_create(txn_cond->cluster_list); |
| while ((object = list_next(itr))) { |
| if (set) { |
| xstrcat(name_extra, " || "); |
| } |
| xstrfmtcat(name_extra, "(cluster='%s' || " |
| "name like '%%\\'%s\\'%%' || name='%s')" |
| " || (info like '%%cluster=\\'%s\\'%%')", |
| object, object, object, object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(name_extra, ")"); |
| use_cluster_list = txn_cond->cluster_list; |
| } |
| |
| if (txn_cond->user_list && list_count(txn_cond->user_list)) { |
| set = 0; |
| if (assoc_extra) |
| xstrcat(assoc_extra, " && ("); |
| else |
| xstrcat(assoc_extra, " where ("); |
| |
| if (name_extra) |
| xstrcat(name_extra, " && ("); |
| else |
| xstrcat(name_extra, "("); |
| |
| itr = list_iterator_create(txn_cond->user_list); |
| while ((object = list_next(itr))) { |
| if (set) { |
| xstrcat(assoc_extra, " || "); |
| xstrcat(name_extra, " || "); |
| } |
| xstrfmtcat(assoc_extra, "user='%s'", object); |
| |
| xstrfmtcat(name_extra, "(name like '%%\\'%s\\'%%'" |
| " || name='%s')" |
| " || (info like '%%user=\\'%s\\'%%')", |
| object, object, object); |
| |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(assoc_extra, ")"); |
| xstrcat(name_extra, ")"); |
| } |
| |
| if (assoc_extra) { |
| if (!locked && !use_cluster_list) { |
| slurm_rwlock_rdlock(&as_mysql_cluster_list_lock); |
| use_cluster_list = list_shallow_copy( |
| as_mysql_cluster_list); |
| locked = 1; |
| } |
| |
| itr = list_iterator_create(use_cluster_list); |
| while ((object = list_next(itr))) { |
| xstrfmtcat(query, "select id_assoc from \"%s_%s\"%s", |
| object, assoc_table, assoc_extra); |
| DB_DEBUG(DB_QUERY, mysql_conn->conn, "query\n%s", |
| query); |
| if (!(result = mysql_db_query_ret( |
| mysql_conn, query, 0))) { |
| xfree(query); |
| break; |
| } |
| xfree(query); |
| |
| if (mysql_num_rows(result)) { |
| if (extra) |
| xstrfmtcat(extra, |
| " || (cluster='%s' && (", |
| object); |
| else |
| xstrfmtcat(extra, |
| " where (cluster='%s' && (", |
| object); |
| |
| set = 0; |
| |
| while ((row = mysql_fetch_row(result))) { |
| if (set) |
| xstrcat(extra, " || "); |
| |
| xstrfmtcat(extra, |
| "(name like " |
| "'%%id_assoc=%s %%' " |
| "|| name like " |
| "'%%id_assoc=%s)')", |
| row[0], row[0]); |
| set = 1; |
| } |
| xstrcat(extra, "))"); |
| } |
| mysql_free_result(result); |
| } |
| list_iterator_destroy(itr); |
| |
| xfree(assoc_extra); |
| } |
| |
| if (name_extra) { |
| if (extra) |
| xstrfmtcat(extra, " || (%s)", name_extra); |
| else |
| xstrfmtcat(extra, " where (%s)", name_extra); |
| xfree(name_extra); |
| } |
| /*******************************************/ |
| |
| if (txn_cond->action_list && list_count(txn_cond->action_list)) { |
| set = 0; |
| if (extra) |
| xstrcat(extra, " && ("); |
| else |
| xstrcat(extra, " where ("); |
| itr = list_iterator_create(txn_cond->action_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(extra, " || "); |
| xstrfmtcat(extra, "action='%s'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(extra, ")"); |
| } |
| |
| if (txn_cond->actor_list && list_count(txn_cond->actor_list)) { |
| set = 0; |
| if (extra) |
| xstrcat(extra, " && ("); |
| else |
| xstrcat(extra, " where ("); |
| itr = list_iterator_create(txn_cond->actor_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(extra, " || "); |
| xstrfmtcat(extra, "actor='%s'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(extra, ")"); |
| } |
| |
| if (txn_cond->id_list && list_count(txn_cond->id_list)) { |
| set = 0; |
| if (extra) |
| xstrcat(extra, " && ("); |
| else |
| xstrcat(extra, " where ("); |
| itr = list_iterator_create(txn_cond->id_list); |
| while ((object = list_next(itr))) { |
| char *ptr = NULL; |
| long num = strtol(object, &ptr, 10); |
| if ((num == 0) && ptr && ptr[0]) { |
| error("Invalid value for txn id (%s)", |
| object); |
| xfree(extra); |
| list_iterator_destroy(itr); |
| goto end_it; |
| } |
| |
| if (set) |
| xstrcat(extra, " || "); |
| xstrfmtcat(extra, "id=%s", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(extra, ")"); |
| } |
| |
| if (txn_cond->info_list && list_count(txn_cond->info_list)) { |
| set = 0; |
| if (extra) |
| xstrcat(extra, " && ("); |
| else |
| xstrcat(extra, " where ("); |
| itr = list_iterator_create(txn_cond->info_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(extra, " || "); |
| xstrfmtcat(extra, "info like '%%%s%%'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(extra, ")"); |
| } |
| |
| if (txn_cond->name_list && list_count(txn_cond->name_list)) { |
| set = 0; |
| if (extra) |
| xstrcat(extra, " && ("); |
| else |
| xstrcat(extra, " where ("); |
| itr = list_iterator_create(txn_cond->name_list); |
| while ((object = list_next(itr))) { |
| if (set) |
| xstrcat(extra, " || "); |
| xstrfmtcat(extra, "name like '%%%s%%'", object); |
| set = 1; |
| } |
| list_iterator_destroy(itr); |
| xstrcat(extra, ")"); |
| } |
| |
| if (txn_cond->time_start && txn_cond->time_end) { |
| if (extra) |
| xstrcat(extra, " && ("); |
| else |
| xstrcat(extra, " where ("); |
| xstrfmtcat(extra, "timestamp < %ld && timestamp >= %ld)", |
| txn_cond->time_end, txn_cond->time_start); |
| } else if (txn_cond->time_start) { |
| if (extra) |
| xstrcat(extra, " && ("); |
| else |
| xstrcat(extra, " where ("); |
| xstrfmtcat(extra, "timestamp >= %ld)", txn_cond->time_start); |
| |
| } else if (txn_cond->time_end) { |
| if (extra) |
| xstrcat(extra, " && ("); |
| else |
| xstrcat(extra, " where ("); |
| xstrfmtcat(extra, "timestamp < %ld)", txn_cond->time_end); |
| } |
| |
| /* make sure we can get the max length out of the database |
| * when grouping the names |
| */ |
| if (txn_cond->with_assoc_info) |
| (void) mysql_db_query(mysql_conn, |
| "set session group_concat_max_len=65536;"); |
| |
| empty: |
| if (!locked && !use_cluster_list) { |
| slurm_rwlock_rdlock(&as_mysql_cluster_list_lock); |
| use_cluster_list = list_shallow_copy(as_mysql_cluster_list); |
| locked = 1; |
| } |
| |
| xfree(tmp); |
| xstrfmtcat(tmp, "%s", txn_req_inx[i]); |
| for(i=1; i<TXN_REQ_COUNT; i++) { |
| xstrfmtcat(tmp, ", %s", txn_req_inx[i]); |
| } |
| |
| query = xstrdup_printf("select %s from %s", tmp, txn_table); |
| |
| if (extra) { |
| xstrfmtcat(query, "%s", extra); |
| xfree(extra); |
| } |
| xstrcat(query, " order by timestamp;"); |
| |
| xfree(tmp); |
| |
| DB_DEBUG(DB_QUERY, mysql_conn->conn, "query\n%s", query); |
| if (!(result = mysql_db_query_ret( |
| mysql_conn, query, 0))) { |
| xfree(query); |
| goto end_it; |
| } |
| xfree(query); |
| |
| txn_list = list_create(slurmdb_destroy_txn_rec); |
| |
| while ((row = mysql_fetch_row(result))) { |
| slurmdb_txn_rec_t *txn = xmalloc(sizeof(slurmdb_txn_rec_t)); |
| |
| list_append(txn_list, txn); |
| |
| txn->action = slurm_atoul(row[TXN_REQ_ACTION]); |
| txn->actor_name = xstrdup(row[TXN_REQ_ACTOR]); |
| txn->id = slurm_atoul(row[TXN_REQ_ID]); |
| txn->set_info = xstrdup(row[TXN_REQ_INFO]); |
| txn->timestamp = slurm_atoul(row[TXN_REQ_TS]); |
| txn->where_query = xstrdup(row[TXN_REQ_NAME]); |
| txn->clusters = xstrdup(row[TXN_REQ_CLUSTER]); |
| |
| if (txn_cond && txn_cond->with_assoc_info |
| && (txn->action == DBD_ADD_ASSOCS |
| || txn->action == DBD_MODIFY_ASSOCS |
| || txn->action == DBD_REMOVE_ASSOCS)) { |
| MYSQL_RES *result2 = NULL; |
| MYSQL_ROW row2; |
| if (txn->clusters) { |
| query = xstrdup_printf( |
| "select " |
| "group_concat(distinct user " |
| "order by user), " |
| "group_concat(distinct acct " |
| "order by acct) " |
| "from \"%s_%s\" where %s", |
| txn->clusters, assoc_table, |
| row[TXN_REQ_NAME]); |
| debug4("%d(%s:%d) query\n%s", mysql_conn->conn, |
| THIS_FILE, __LINE__, query); |
| if (!(result2 = mysql_db_query_ret( |
| mysql_conn, query, 0))) { |
| xfree(query); |
| continue; |
| } |
| xfree(query); |
| |
| if ((row2 = mysql_fetch_row(result2))) { |
| if (row2[0] && row2[0][0]) |
| txn->users = xstrdup(row2[0]); |
| if (row2[1] && row2[1][0]) |
| txn->accts = xstrdup(row2[1]); |
| } |
| mysql_free_result(result2); |
| } else { |
| error("We can't handle associations " |
| "from action %s yet.", |
| slurmdbd_msg_type_2_str(txn->action, 1)); |
| } |
| } |
| } |
| mysql_free_result(result); |
| |
| end_it: |
| if (locked) { |
| FREE_NULL_LIST(use_cluster_list); |
| slurm_rwlock_unlock(&as_mysql_cluster_list_lock); |
| } |
| |
| return txn_list; |
| } |