diff --git a/SQL/feedback_schema.sql b/SQL/feedback_schema.sql index a1071363728..bdc1f2c33a6 100644 --- a/SQL/feedback_schema.sql +++ b/SQL/feedback_schema.sql @@ -1,3 +1,4 @@ +-- Table structure for table `erro_admin` CREATE TABLE `erro_admin` ( `id` int(11) NOT NULL AUTO_INCREMENT, `ckey` varchar(32) NOT NULL, @@ -7,6 +8,7 @@ CREATE TABLE `erro_admin` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; +-- Table structure for table `erro_admin_log` CREATE TABLE `erro_admin_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, @@ -16,6 +18,7 @@ CREATE TABLE `erro_admin_log` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; +-- Table structure for table `erro_ban` CREATE TABLE `erro_ban` ( `id` int(11) NOT NULL AUTO_INCREMENT, `bantime` datetime NOT NULL, @@ -43,6 +46,18 @@ CREATE TABLE `erro_ban` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; +-- Table structure for table `erro_connection_log` +CREATE TABLE `erro_connection_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `datetime` datetime NOT NULL, + `serverip` varchar(32) NOT NULL, + `ckey` varchar(32) NOT NULL, + `ip` varchar(32) NOT NULL, + `computerid` varchar(32) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; + +-- Table structure for table `erro_feedback` CREATE TABLE `erro_feedback` ( `id` int(11) NOT NULL AUTO_INCREMENT, `time` datetime NOT NULL, @@ -53,6 +68,7 @@ CREATE TABLE `erro_feedback` ( PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; +-- Table structure for table `erro_player` CREATE TABLE `erro_player` ( `id` int(11) NOT NULL AUTO_INCREMENT, `ckey` varchar(32) NOT NULL, @@ -67,6 +83,7 @@ CREATE TABLE `erro_player` ( KEY `discord_id` (`discord_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; +-- Table structure for table `erro_poll_option` CREATE TABLE `erro_poll_option` ( `id` int(11) NOT NULL AUTO_INCREMENT, `pollid` int(11) NOT NULL, @@ -80,6 +97,7 @@ CREATE TABLE `erro_poll_option` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; +-- Table structure for table `erro_poll_question` CREATE TABLE `erro_poll_question` ( `id` int(11) NOT NULL AUTO_INCREMENT, `polltype` varchar(16) NOT NULL DEFAULT 'OPTION', @@ -90,6 +108,7 @@ CREATE TABLE `erro_poll_question` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; +-- Table structure for table `erro_poll_textreply` CREATE TABLE `erro_poll_textreply` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, @@ -101,6 +120,7 @@ CREATE TABLE `erro_poll_textreply` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; +-- Table structure for table `erro_poll_vote` CREATE TABLE `erro_poll_vote` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, @@ -113,6 +133,7 @@ CREATE TABLE `erro_poll_vote` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; +-- Table structure for table `erro_privacy` CREATE TABLE `erro_privacy` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, @@ -121,10 +142,92 @@ CREATE TABLE `erro_privacy` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; +-- Table structure for table `death` +CREATE TABLE `death` ( + `id` INT(11) NOT NULL AUTO_INCREMENT , + `pod` TEXT NOT NULL COMMENT 'Place of death' , + `coord` TEXT NOT NULL COMMENT 'X, Y, Z POD' , + `tod` DATETIME NOT NULL COMMENT 'Time of death' , + `job` TEXT NOT NULL , + `special` TEXT NOT NULL , + `name` TEXT NOT NULL , + `byondkey` TEXT NOT NULL , + `laname` TEXT NOT NULL COMMENT 'Last attacker name' , + `lakey` TEXT NOT NULL COMMENT 'Last attacker key' , + `gender` TEXT NOT NULL , + `bruteloss` INT(11) NOT NULL , + `brainloss` INT(11) NOT NULL , + `fireloss` INT(11) NOT NULL , + `oxyloss` INT(11) NOT NULL , + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; + + +-- Table structure for table `karma` +CREATE TABLE `karma` ( + `id` INT(11) NOT NULL AUTO_INCREMENT , + `spendername` TEXT NOT NULL , + `spenderkey` TEXT NOT NULL , + `receivername` TEXT NOT NULL , + `receiverkey` TEXT NOT NULL , + `receiverrole` TEXT NOT NULL , + `receiverspecial` TEXT NOT NULL , + `isnegative` TINYINT(1) NOT NULL , + `spenderip` TEXT NOT NULL , + `time` DATETIME NOT NULL , + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; + +-- Table structure for table `karmatotals` +CREATE TABLE `karmatotals` ( + `id` INT(11) NOT NULL AUTO_INCREMENT , + `byondkey` TEXT NOT NULL , + `karma` INT(11) NOT NULL , + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; + +-- Table structure for table `library` +CREATE TABLE `library` ( + `id` INT(11) NOT NULL AUTO_INCREMENT , + `author` TEXT NOT NULL , + `title` TEXT NOT NULL , + `content` TEXT NOT NULL , + `category` TEXT NOT NULL , + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; + +-- Table structure for table `population` +CREATE TABLE `population` ( + `id` INT(11) NOT NULL AUTO_INCREMENT , + `playercount` INT(11) NULL DEFAULT NULL , + `admincount` INT(11) NULL DEFAULT NULL , + `time` DATETIME NOT NULL , + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; + +-- Table structure for table `vr_player_hours` CREATE TABLE `vr_player_hours` ( `ckey` varchar(32) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, `department` varchar(64) CHARACTER SET latin1 COLLATE latin1_general_ci NOT NULL, `hours` double NOT NULL, `total_hours` double NOT NULL DEFAULT '0', PRIMARY KEY (`ckey`,`department`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +CREATE TABLE IF NOT EXISTS `round` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `initialize_datetime` DATETIME NOT NULL, + `start_datetime` DATETIME NULL, + `shutdown_datetime` DATETIME NULL, + `end_datetime` DATETIME NULL, + `server_ip` INT(10) UNSIGNED NOT NULL, + `server_port` SMALLINT(5) UNSIGNED NOT NULL, + `commit_hash` CHAR(40) NULL, + `game_mode` VARCHAR(32) NULL, + `game_mode_result` VARCHAR(64) NULL, + `end_state` VARCHAR(64) NULL, + `shuttle_name` VARCHAR(64) NULL, + `map_name` VARCHAR(32) NULL, + `station_name` VARCHAR(80) NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql deleted file mode 100644 index b7e2e501ce1..00000000000 --- a/SQL/tgstation_schema.sql +++ /dev/null @@ -1,100 +0,0 @@ -SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; -SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; -SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL'; - -CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ; -CREATE SCHEMA IF NOT EXISTS `tgstation` DEFAULT CHARACTER SET latin1 ; -USE `mydb` ; -USE `tgstation` ; - --- ----------------------------------------------------- --- Table `tgstation`.`death` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `tgstation`.`death` ( - `id` INT(11) NOT NULL AUTO_INCREMENT , - `pod` TEXT NOT NULL COMMENT 'Place of death' , - `coord` TEXT NOT NULL COMMENT 'X, Y, Z POD' , - `tod` DATETIME NOT NULL COMMENT 'Time of death' , - `job` TEXT NOT NULL , - `special` TEXT NOT NULL , - `name` TEXT NOT NULL , - `byondkey` TEXT NOT NULL , - `laname` TEXT NOT NULL COMMENT 'Last attacker name' , - `lakey` TEXT NOT NULL COMMENT 'Last attacker key' , - `gender` TEXT NOT NULL , - `bruteloss` INT(11) NOT NULL , - `brainloss` INT(11) NOT NULL , - `fireloss` INT(11) NOT NULL , - `oxyloss` INT(11) NOT NULL , - PRIMARY KEY (`id`) ) -ENGINE = MyISAM -AUTO_INCREMENT = 3409 -DEFAULT CHARACTER SET = latin1; - - --- ----------------------------------------------------- --- Table `tgstation`.`karma` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `tgstation`.`karma` ( - `id` INT(11) NOT NULL AUTO_INCREMENT , - `spendername` TEXT NOT NULL , - `spenderkey` TEXT NOT NULL , - `receivername` TEXT NOT NULL , - `receiverkey` TEXT NOT NULL , - `receiverrole` TEXT NOT NULL , - `receiverspecial` TEXT NOT NULL , - `isnegative` TINYINT(1) NOT NULL , - `spenderip` TEXT NOT NULL , - `time` DATETIME NOT NULL , - PRIMARY KEY (`id`) ) -ENGINE = MyISAM -AUTO_INCREMENT = 943 -DEFAULT CHARACTER SET = latin1; - - --- ----------------------------------------------------- --- Table `tgstation`.`karmatotals` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `tgstation`.`karmatotals` ( - `id` INT(11) NOT NULL AUTO_INCREMENT , - `byondkey` TEXT NOT NULL , - `karma` INT(11) NOT NULL , - PRIMARY KEY (`id`) ) -ENGINE = MyISAM -AUTO_INCREMENT = 244 -DEFAULT CHARACTER SET = latin1; - - --- ----------------------------------------------------- --- Table `tgstation`.`library` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `tgstation`.`library` ( - `id` INT(11) NOT NULL AUTO_INCREMENT , - `author` TEXT NOT NULL , - `title` TEXT NOT NULL , - `content` TEXT NOT NULL , - `category` TEXT NOT NULL , - PRIMARY KEY (`id`) ) -ENGINE = MyISAM -AUTO_INCREMENT = 184 -DEFAULT CHARACTER SET = latin1; - - --- ----------------------------------------------------- --- Table `tgstation`.`population` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `tgstation`.`population` ( - `id` INT(11) NOT NULL AUTO_INCREMENT , - `playercount` INT(11) NULL DEFAULT NULL , - `admincount` INT(11) NULL DEFAULT NULL , - `time` DATETIME NOT NULL , - PRIMARY KEY (`id`) ) -ENGINE = MyISAM -AUTO_INCREMENT = 2544 -DEFAULT CHARACTER SET = latin1; - - - -SET SQL_MODE=@OLD_SQL_MODE; -SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; -SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; diff --git a/code/__defines/database.dm b/code/__defines/database.dm new file mode 100644 index 00000000000..3d20b3b9a3c --- /dev/null +++ b/code/__defines/database.dm @@ -0,0 +1,6 @@ +/// When a query has been queued up for execution/is being executed +#define DB_QUERY_STARTED 0 +/// When a query is finished executing +#define DB_QUERY_FINISHED 1 +/// When there was a problem with the execution of a query. +#define DB_QUERY_BROKEN 2 diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 8043562a579..0a5b9428e09 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -118,8 +118,9 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G // The numbers just define the ordering, they are meaningless otherwise. #define INIT_ORDER_SERVER_MAINT 93 #define INIT_ORDER_WEBHOOKS 50 -#define INIT_ORDER_SQLITE 40 -#define INIT_ORDER_GARBAGE 39 +#define INIT_ORDER_SQLITE 41 +#define INIT_ORDER_GARBAGE 40 +#define INIT_ORDER_DBCORE 39 #define INIT_ORDER_MEDIA_TRACKS 38 // Gotta get that lobby music up, yo #define INIT_ORDER_INPUT 37 #define INIT_ORDER_CHEMISTRY 35 diff --git a/code/_global_vars/logging.dm b/code/_global_vars/logging.dm new file mode 100644 index 00000000000..06a240822d9 --- /dev/null +++ b/code/_global_vars/logging.dm @@ -0,0 +1,2 @@ +GLOBAL_VAR(round_id) +GLOBAL_PROTECT(round_id) diff --git a/code/_helpers/logging.dm b/code/_helpers/logging.dm index 05b6ff61582..2157cf4e6da 100644 --- a/code/_helpers/logging.dm +++ b/code/_helpers/logging.dm @@ -30,6 +30,11 @@ if (CONFIG_GET(flag/log_admin)) WRITE_LOG(diary, "ADMIN: [text]") +/proc/log_admin_private(text) + admin_log.Add(text) + if (CONFIG_GET(flag/log_admin)) + WRITE_LOG(diary, "ADMINPRIVATE: [text]") + /proc/log_adminpm(text, client/source, client/dest) admin_log.Add(text) if (CONFIG_GET(flag/log_admin)) @@ -161,6 +166,12 @@ /proc/log_misc(text) WRITE_LOG(diary, "MISC: [text]") +/proc/log_sql(text) + WRITE_LOG(sql_error_log, "SQL: [text]") + +/proc/log_query_debug(text) + WRITE_LOG(query_debug_log, "SQL: [text]") + /proc/log_topic(text) if(Debug2) WRITE_LOG(diary, "TOPIC: [text]") diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm index 910644d63fa..077e4702e4e 100644 --- a/code/_helpers/text.dm +++ b/code/_helpers/text.dm @@ -15,8 +15,13 @@ // Run all strings to be used in an SQL query through this proc first to properly escape out injection attempts. /proc/sanitizeSQL(var/t as text) - var/sqltext = dbcon.Quote(t); - return copytext(sqltext, 2, length(sqltext));//Quote() adds quotes around input, we already do that + //var/sqltext = dbcon.Quote(t); + //return copytext(sqltext, 2, length(sqltext));//Quote() adds quotes around input, we already do that + return t + +/proc/format_table_name(table as text) + //return CONFIG_GET(string/feedback_tableprefix) + table + return table // We don't implement tableprefix /* * Text sanitization diff --git a/code/controllers/configuration/entries/dbconfig.dm b/code/controllers/configuration/entries/dbconfig.dm index d14ca42e68b..2dbc1fb075b 100644 --- a/code/controllers/configuration/entries/dbconfig.dm +++ b/code/controllers/configuration/entries/dbconfig.dm @@ -46,8 +46,8 @@ /datum/config_entry/number/max_concurrent_queries/ValidateAndSet(str_val) . = ..() - //if (.) TODO: ENABLE THIS IN FUTURE DB PRs - //SSdbcore.max_concurrent_queries = config_entry_value TODO: ENABLE THIS IN FUTURE DB PRs + if (.) + SSdbcore.max_concurrent_queries = config_entry_value /// The exe for mariadbd.exe. /// Shouldn't really be set on production servers, primarily for EZDB. diff --git a/code/controllers/subsystems/dbcore.dm b/code/controllers/subsystems/dbcore.dm new file mode 100644 index 00000000000..e800b4aaca3 --- /dev/null +++ b/code/controllers/subsystems/dbcore.dm @@ -0,0 +1,599 @@ +SUBSYSTEM_DEF(dbcore) + name = "Database" + flags = SS_TICKER + wait = 10 // Not seconds because we're running on SS_TICKER + init_order = INIT_ORDER_DBCORE + + var/failed_connection_timeout = 0 + + var/schema_mismatch = 0 + var/db_minor = 0 + var/db_major = 0 + var/failed_connections = 0 + + var/last_error + + var/max_concurrent_queries = 25 + + /// Number of all queries, reset to 0 when logged in SStime_track. Used by SStime_track + var/all_queries_num = 0 + /// Number of active queries, reset to 0 when logged in SStime_track. Used by SStime_track + var/queries_active_num = 0 + /// Number of standby queries, reset to 0 when logged in SStime_track. Used by SStime_track + var/queries_standby_num = 0 + + /// All the current queries that exist. + var/list/all_queries = list() + /// Queries being checked for timeouts. + var/list/processing_queries + + /// Queries currently being handled by database driver + var/list/datum/db_query/queries_active = list() + /// Queries pending execution, mapped to complete arguments + var/list/datum/db_query/queries_standby = list() + + /// We are in the process of shutting down and should not allow more DB connections + var/shutting_down = FALSE + + + var/connection // Arbitrary handle returned from rust_g. + + //var/db_daemon_started = FALSE + +/datum/controller/subsystem/dbcore/Initialize() + return SS_INIT_SUCCESS + +/datum/controller/subsystem/dbcore/stat_entry(msg) + msg = "P:[length(all_queries)]|Active:[length(queries_active)]|Standby:[length(queries_standby)]" + return ..() + +/// Resets the tracking numbers on the subsystem. Used by SStime_track. +/datum/controller/subsystem/dbcore/proc/reset_tracking() + all_queries_num = 0 + queries_active_num = 0 + queries_standby_num = 0 + +/datum/controller/subsystem/dbcore/fire(resumed = FALSE) + if(!IsConnected()) + return + + if(!resumed) + if(!length(queries_active) && !length(queries_standby) && !length(all_queries)) + processing_queries = null + return + processing_queries = all_queries.Copy() + + // First handle the already running queries + for (var/datum/db_query/query in queries_active) + if(!process_query(query)) + queries_active -= query + + // Now lets pull in standby queries if we have room. + if (length(queries_standby) > 0 && length(queries_active) < max_concurrent_queries) + var/list/queries_to_activate = queries_standby.Copy(1, min(length(queries_standby), max_concurrent_queries) + 1) + + for (var/datum/db_query/query in queries_to_activate) + queries_standby.Remove(query) + create_active_query(query) + + // And finally, let check queries for undeleted queries, check ticking if there is a lot of work to do. + while(length(processing_queries)) + var/datum/db_query/query = popleft(processing_queries) + if(world.time - query.last_activity_time > (5 MINUTES)) + stack_trace("Found undeleted query, check the sql.log for the undeleted query and add a delete call to the query datum.") + log_debug("Undeleted query: \"[query.sql]\" LA: [query.last_activity] LAT: [query.last_activity_time]") + qdel(query) + if(MC_TICK_CHECK) + return + + +/// Helper proc for handling activating queued queries +/datum/controller/subsystem/dbcore/proc/create_active_query(datum/db_query/query) + PRIVATE_PROC(TRUE) + SHOULD_NOT_SLEEP(TRUE) + if(IsAdminAdvancedProcCall()) + return FALSE + run_query(query) + queries_active_num++ + queries_active += query + return query + +/datum/controller/subsystem/dbcore/proc/process_query(datum/db_query/query) + PRIVATE_PROC(TRUE) + SHOULD_NOT_SLEEP(TRUE) + if(IsAdminAdvancedProcCall()) + return FALSE + if(QDELETED(query)) + return FALSE + if(query.process((TICKS2DS(wait)) / 10)) + queries_active -= query + return FALSE + return TRUE + +/datum/controller/subsystem/dbcore/proc/run_query_sync(datum/db_query/query) + if(IsAdminAdvancedProcCall()) + return + run_query(query) + UNTIL(query.process()) + return query + +/datum/controller/subsystem/dbcore/proc/run_query(datum/db_query/query) + if(IsAdminAdvancedProcCall()) + return + query.job_id = rustg_sql_query_async(connection, query.sql, json_encode(query.arguments)) + +/datum/controller/subsystem/dbcore/proc/queue_query(datum/db_query/query) + if(IsAdminAdvancedProcCall()) + return + + if (!length(queries_standby) && length(queries_active) < max_concurrent_queries) + create_active_query(query) + return + + queries_standby_num++ + queries_standby |= query + +/datum/controller/subsystem/dbcore/Recover() + connection = SSdbcore.connection + +/datum/controller/subsystem/dbcore/Shutdown() + shutting_down = TRUE + log_debug("Clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]") + //This is as close as we can get to the true round end before Disconnect() without changing where it's called, defeating the reason this is a subsystem + if(SSdbcore.Connect()) + //Execute all waiting queries + for(var/datum/db_query/query in queries_standby) + run_query_sync(query) + queries_standby -= query + for(var/datum/db_query/query in queries_active) + //Finish any remaining active qeries + UNTIL(query.process()) + queries_active -= query + + var/datum/db_query/query_round_shutdown = SSdbcore.NewQuery( + "UPDATE [format_table_name("round")] SET shutdown_datetime = Now(), end_state = :end_state WHERE id = :round_id", + //list("end_state" = SSticker.end_state, "round_id" = GLOB.round_id), + list("end_state" = "undefined", "round_id" = GLOB.round_id), // FIXME: end_state does not exist on ticker + TRUE + ) + query_round_shutdown.Execute(FALSE) + qdel(query_round_shutdown) + + log_debug("Done clearing DB queries standby:[length(queries_standby)] active: [length(queries_active)] all: [length(all_queries)]") + if(IsConnected()) + Disconnect() + //stop_db_daemon() + +//nu +/datum/controller/subsystem/dbcore/can_vv_get(var_name) + if(var_name == NAMEOF(src, connection)) + return FALSE + if(var_name == NAMEOF(src, all_queries)) + return FALSE + if(var_name == NAMEOF(src, queries_active)) + return FALSE + if(var_name == NAMEOF(src, queries_standby)) + return FALSE + if(var_name == NAMEOF(src, processing_queries)) + return FALSE + + return ..() + +/datum/controller/subsystem/dbcore/vv_edit_var(var_name, var_value) + if(var_name == NAMEOF(src, connection)) + return FALSE + if(var_name == NAMEOF(src, all_queries)) + return FALSE + if(var_name == NAMEOF(src, queries_active)) + return FALSE + if(var_name == NAMEOF(src, queries_standby)) + return FALSE + if(var_name == NAMEOF(src, processing_queries)) + return FALSE + return ..() + +/datum/controller/subsystem/dbcore/proc/Connect() + if(IsConnected()) + return TRUE + + if(failed_connection_timeout <= world.time) //it's been more than 5 seconds since we failed to connect, reset the counter + failed_connections = 0 + + if(failed_connections > 5) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to connect for 5 seconds. + failed_connection_timeout = world.time + 50 + return FALSE + + if(!CONFIG_GET(flag/sql_enabled)) + return FALSE + + //start_db_daemon() + + var/user = CONFIG_GET(string/feedback_login) + var/pass = CONFIG_GET(string/feedback_password) + var/db = CONFIG_GET(string/feedback_database) + var/address = CONFIG_GET(string/address) + var/port = CONFIG_GET(number/port) + var/timeout = max(CONFIG_GET(number/async_query_timeout), CONFIG_GET(number/blocking_query_timeout)) + var/min_sql_connections = CONFIG_GET(number/pooling_min_sql_connections) + var/max_sql_connections = CONFIG_GET(number/pooling_max_sql_connections) + + var/result = json_decode(rustg_sql_connect_pool(json_encode(list( + "host" = address, + "port" = port, + "user" = user, + "pass" = pass, + "db_name" = db, + "read_timeout" = timeout, + "write_timeout" = timeout, + "min_threads" = min_sql_connections, + "max_threads" = max_sql_connections, + )))) + . = (result["status"] == "ok") + if (.) + connection = result["handle"] + else + connection = null + last_error = result["data"] + log_debug("Connect() failed | [last_error]") + ++failed_connections + +/datum/controller/subsystem/dbcore/proc/CheckSchemaVersion() + if(CONFIG_GET(flag/sql_enabled)) + if(Connect()) + log_world("Database connection established.") + else + log_debug("Your server failed to establish a connection with the database.") + else + log_debug("Database is not enabled in configuration.") + +/datum/controller/subsystem/dbcore/proc/InitializeRound() + if(!Connect()) + return + var/datum/db_query/query_round_initialize = SSdbcore.NewQuery( + "INSERT INTO [format_table_name("round")] (initialize_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(:internet_address), :port)", + list("internet_address" = world.internet_address || "0", "port" = "[world.port]") + ) + query_round_initialize.Execute(async = FALSE) + GLOB.round_id = "[query_round_initialize.last_insert_id]" + qdel(query_round_initialize) + +/datum/controller/subsystem/dbcore/proc/SetRoundStart() + if(!Connect()) + return + var/datum/db_query/query_round_start = SSdbcore.NewQuery( + "UPDATE [format_table_name("round")] SET start_datetime = Now() WHERE id = :round_id", + list("round_id" = GLOB.round_id) + ) + query_round_start.Execute() + qdel(query_round_start) + +/datum/controller/subsystem/dbcore/proc/SetRoundEnd() + if(!Connect()) + return + var/datum/db_query/query_round_end = SSdbcore.NewQuery( + "UPDATE [format_table_name("round")] SET end_datetime = Now(), game_mode_result = :game_mode_result, station_name = :station_name WHERE id = :round_id", + //list("game_mode_result" = SSticker.mode_result, "station_name" = station_name(), "round_id" = GLOB.round_id) + list("game_mode_result" = "extended", "station_name" = station_name(), "round_id" = GLOB.round_id) // FIXME: temporary solution as we only use extended so far + ) + query_round_end.Execute() + qdel(query_round_end) + +/datum/controller/subsystem/dbcore/proc/Disconnect() + failed_connections = 0 + if (connection) + rustg_sql_disconnect_pool(connection) + connection = null + +/datum/controller/subsystem/dbcore/proc/IsConnected() + if (!CONFIG_GET(flag/sql_enabled)) + return FALSE + if (!connection) + return FALSE + return json_decode(rustg_sql_connected(connection))["status"] == "online" + +/datum/controller/subsystem/dbcore/proc/ErrorMsg() + if(!CONFIG_GET(flag/sql_enabled)) + return "Database disabled by configuration" + return last_error + +/datum/controller/subsystem/dbcore/proc/ReportError(error) + last_error = error + +/datum/controller/subsystem/dbcore/proc/NewQuery(sql_query, arguments, allow_during_shutdown=FALSE) + //If the subsystem is shutting down, disallow new queries + if(!allow_during_shutdown && shutting_down) + CRASH("Attempting to create a new db query during the world shutdown") + + if(IsAdminAdvancedProcCall()) + log_admin("ERROR: Advanced admin proc call led to sql query: [sql_query]. Query has been blocked") + message_admins("ERROR: Advanced admin proc call led to sql query. Query has been blocked") + return FALSE + return new /datum/db_query(connection, sql_query, arguments) + +/** QuerySelect + Run a list of query datums in parallel, blocking until they all complete. + * queries - List of queries or single query datum to run. + * warn - Controls rather warn_execute() or Execute() is called. + * qdel - If you don't care about the result or checking for errors, you can have the queries be deleted afterwards. + This can be combined with invoke_async as a way of running queries async without having to care about waiting for them to finish so they can be deleted. +*/ +/datum/controller/subsystem/dbcore/proc/QuerySelect(list/queries, warn = FALSE, qdel = FALSE) + if (!islist(queries)) + if (!istype(queries, /datum/db_query)) + CRASH("Invalid query passed to QuerySelect: [queries]") + queries = list(queries) + else + queries = queries.Copy() //we don't want to hide bugs in the parent caller by removing invalid values from this list. + + for (var/datum/db_query/query as anything in queries) + if (!istype(query)) + queries -= query + stack_trace("Invalid query passed to QuerySelect: `[query]` [REF(query)]") + continue + + if (warn) + INVOKE_ASYNC(query, TYPE_PROC_REF(/datum/db_query, warn_execute)) + else + INVOKE_ASYNC(query, TYPE_PROC_REF(/datum/db_query, Execute)) + + for (var/datum/db_query/query as anything in queries) + query.sync() + if (qdel) + qdel(query) + + + +/* +Takes a list of rows (each row being an associated list of column => value) and inserts them via a single mass query. +Rows missing columns present in other rows will resolve to SQL NULL +You are expected to do your own escaping of the data, and expected to provide your own quotes for strings. +The duplicate_key arg can be true to automatically generate this part of the query + or set to a string that is appended to the end of the query +Ignore_errors instructes mysql to continue inserting rows if some of them have errors. + the erroneous row(s) aren't inserted and there isn't really any way to know why or why errored +*/ +/datum/controller/subsystem/dbcore/proc/MassInsert(table, list/rows, duplicate_key = FALSE, ignore_errors = FALSE, warn = FALSE, async = TRUE, special_columns = null) + if (!table || !rows || !istype(rows)) + return + + // Prepare column list + var/list/columns = list() + var/list/has_question_mark = list() + for (var/list/row in rows) + for (var/column in row) + columns[column] = "?" + has_question_mark[column] = TRUE + for (var/column in special_columns) + columns[column] = special_columns[column] + has_question_mark[column] = findtext(special_columns[column], "?") + + // Prepare SQL query full of placeholders + var/list/query_parts = list("INSERT") + if (ignore_errors) + query_parts += " IGNORE" + query_parts += " INTO " + query_parts += table + query_parts += "\n([columns.Join(", ")])\nVALUES" + + var/list/arguments = list() + var/has_row = FALSE + for (var/list/row in rows) + if (has_row) + query_parts += "," + query_parts += "\n (" + var/has_col = FALSE + for (var/column in columns) + if (has_col) + query_parts += ", " + if (has_question_mark[column]) + var/name = "p[arguments.len]" + query_parts += replacetext(columns[column], "?", ":[name]") + arguments[name] = row[column] + else + query_parts += columns[column] + has_col = TRUE + query_parts += ")" + has_row = TRUE + + if (duplicate_key == TRUE) + var/list/column_list = list() + for (var/column in columns) + column_list += "[column] = VALUES([column])" + query_parts += "\nON DUPLICATE KEY UPDATE [column_list.Join(", ")]" + else if (duplicate_key != FALSE) + query_parts += duplicate_key + + var/datum/db_query/Query = NewQuery(query_parts.Join(), arguments) + if (warn) + . = Query.warn_execute(async) + else + . = Query.Execute(async) + qdel(Query) + +/* +/datum/controller/subsystem/dbcore/proc/start_db_daemon() + set waitfor = FALSE + + if (db_daemon_started) + return + + db_daemon_started = TRUE + + var/daemon = CONFIG_GET(string/db_daemon) + if (!daemon) + return + + ASSERT(fexists(daemon)) + + var/list/result = world.shelleo("echo \"Starting ezdb daemon, do not close this window\" && [daemon]") + var/result_code = result[1] + if (!result_code || result_code == 1) + return + + stack_trace("Failed to start DB daemon: [result_code]\n[result[3]]") + +/datum/controller/subsystem/dbcore/proc/stop_db_daemon() + set waitfor = FALSE + + if (!db_daemon_started) + return + + db_daemon_started = FALSE + + var/daemon = CONFIG_GET(string/db_daemon) + if (!daemon) + return + + switch (world.system_type) + if (MS_WINDOWS) + var/list/result = world.shelleo("Get-Process | ? { $_.Path -eq '[daemon]' } | Stop-Process") + ASSERT(result[1]) + if (UNIX) + var/list/result = world.shelleo("kill $(pgrep -f '[daemon]')") + ASSERT(result[1]) +*/ + +/datum/db_query + // Inputs + var/connection + var/sql + var/arguments + + var/datum/callback/success_callback + var/datum/callback/fail_callback + + // Status information + /// Current status of the query. + var/status + /// Job ID of the query passed by rustg. + var/job_id + var/last_error + var/last_activity + var/last_activity_time + + // Output + var/list/list/rows + var/next_row_to_take = 1 + var/affected + var/last_insert_id + + var/list/item //list of data values populated by NextRow() + +/datum/db_query/New(connection, sql, arguments) + SSdbcore.all_queries += src + SSdbcore.all_queries_num++ + Activity("Created") + item = list() + + src.connection = connection + src.sql = sql + src.arguments = arguments + +/datum/db_query/Destroy() + Close() + SSdbcore.all_queries -= src + SSdbcore.queries_standby -= src + SSdbcore.queries_active -= src + return ..() + +/datum/db_query/CanProcCall(proc_name) + return FALSE + +/datum/db_query/proc/Activity(activity) + last_activity = activity + last_activity_time = world.time + +/datum/db_query/proc/warn_execute(async = TRUE) + . = Execute(async) + if(!.) + to_chat(usr, span_danger("A SQL error occurred during this operation, check the server logs.")) + +/datum/db_query/proc/Execute(async = TRUE, log_error = TRUE) + Activity("Execute") + if(status == DB_QUERY_STARTED) + CRASH("Attempted to start a new query while waiting on the old one") + + if(!SSdbcore.IsConnected()) + last_error = "No connection!" + return FALSE + + var/start_time + if(!async) + start_time = REALTIMEOFDAY + Close() + status = DB_QUERY_STARTED + if(async) + /*if(!MC_RUNNING(SSdbcore.init_stage)) + SSdbcore.run_query_sync(src) + else + SSdbcore.queue_query(src)*/ + SSdbcore.run_query_sync(src) + sync() + else + var/job_result_str = rustg_sql_query_blocking(connection, sql, json_encode(arguments)) + store_data(json_decode(job_result_str)) + + . = (status != DB_QUERY_BROKEN) + var/timed_out = !. && findtext(last_error, "Operation timed out") + if(!. && log_error) + log_debug("[last_error] | Query used: [sql] | Arguments: [json_encode(arguments)]") + if(!async && timed_out) + log_debug("Query execution started at [start_time]") + log_debug("Query execution ended at [REALTIMEOFDAY]") + log_debug("Slow query timeout detected.") + log_debug("Query used: [sql]") + slow_query_check() + +/// Sleeps until execution of the query has finished. +/datum/db_query/proc/sync() + while(status < DB_QUERY_FINISHED) + stoplag() + +/datum/db_query/process(seconds_per_tick) + if(status >= DB_QUERY_FINISHED) + return TRUE // we are done processing after all + + status = DB_QUERY_STARTED + var/job_result = rustg_sql_check_query(job_id) + if(job_result == RUSTG_JOB_NO_RESULTS_YET) + return FALSE //no results yet + + store_data(json_decode(job_result)) + return TRUE + +/datum/db_query/proc/store_data(result) + switch(result["status"]) + if("ok") + rows = result["rows"] + affected = result["affected"] + last_insert_id = result["last_insert_id"] + status = DB_QUERY_FINISHED + return + if("err") + last_error = result["data"] + status = DB_QUERY_BROKEN + return + if("offline") + last_error = "CONNECTION OFFLINE" + status = DB_QUERY_BROKEN + return + +/datum/db_query/proc/slow_query_check() + message_admins("HEY! A database query timed out. Did the server just hang? \[YES\]|\[NO\]") + +/datum/db_query/proc/NextRow(async = TRUE) + Activity("NextRow") + + if (rows && next_row_to_take <= rows.len) + item = rows[next_row_to_take] + next_row_to_take++ + return !!item + else + return FALSE + +/datum/db_query/proc/ErrorMsg() + return last_error + +/datum/db_query/proc/Close() + rows = null + item = null diff --git a/code/controllers/subsystems/persist_vr.dm b/code/controllers/subsystems/persist_vr.dm index d74b96f9603..c6eda65ef46 100644 --- a/code/controllers/subsystems/persist_vr.dm +++ b/code/controllers/subsystems/persist_vr.dm @@ -10,6 +10,7 @@ SUBSYSTEM_DEF(persist) flags = SS_BACKGROUND|SS_NO_INIT|SS_KEEP_TIMING runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME var/list/currentrun = list() + var/list/query_stack = list() /datum/controller/subsystem/persist/fire(var/resumed = FALSE) update_department_hours(resumed) @@ -20,7 +21,7 @@ SUBSYSTEM_DEF(persist) return establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) src.currentrun.Cut() return if(!resumed) @@ -29,6 +30,7 @@ SUBSYSTEM_DEF(persist) //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun + var/list/query_stack = src.query_stack while (currentrun.len) var/mob/M = currentrun[currentrun.len] currentrun.len-- @@ -85,12 +87,21 @@ SUBSYSTEM_DEF(persist) var/sql_dpt = sql_sanitize_text(department_earning) var/sql_bal = text2num("[C.department_hours[department_earning]]") var/sql_total = text2num("[C.play_hours[department_earning]]") - var/DBQuery/query = dbcon.NewQuery("INSERT INTO vr_player_hours (ckey, department, hours, total_hours) VALUES ('[sql_ckey]', '[sql_dpt]', [sql_bal], [sql_total]) ON DUPLICATE KEY UPDATE hours = VALUES(hours), total_hours = VALUES(total_hours)") - query.Execute() + var/list/entry = list( + "ckey" = sql_ckey, + "department" = sql_dpt, + "hours" = sql_bal, + "total_hours" = sql_total + ) + query_stack += list(entry) if (MC_TICK_CHECK) return + if(query_stack.len) + SSdbcore.MassInsert(format_table_name("vr_player_hours"), query_stack, duplicate_key = "ON DUPLICATE KEY UPDATE hours = VALUES(hours), total_hours = VALUES(total_hours)") + query_stack.Cut() + // This proc tries to find the job datum of an arbitrary mob. /datum/controller/subsystem/persist/proc/detect_job(var/mob/M) // Records are usually the most reliable way to get what job someone is. diff --git a/code/controllers/subsystems/statpanel.dm b/code/controllers/subsystems/statpanel.dm index 8383f0a3d7d..fa045838ee7 100644 --- a/code/controllers/subsystems/statpanel.dm +++ b/code/controllers/subsystems/statpanel.dm @@ -31,7 +31,7 @@ SUBSYSTEM_DEF(statpanels) "Map: [using_map.name]", //cached ? "Next Map: [cached.map_name]" : null, //"Next Map: -- Not Available --", - // "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]", + "Round ID: [GLOB.round_id ? GLOB.round_id : "NULL"]", "Server Time: [time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")]", "Round Time: [roundduration2text()]", "Station Date: [stationdate2text()]", // [capitalize(GLOB.world_time_season)]", diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm index 8a8e35d73d3..9df8da605f9 100644 --- a/code/controllers/subsystems/ticker.dm +++ b/code/controllers/subsystems/ticker.dm @@ -546,6 +546,8 @@ var/global/datum/controller/subsystem/ticker/ticker for(var/i in total_antagonists) log_game("[i]s[total_antagonists[i]].") + SSdbcore.SetRoundEnd() + return 1 /datum/controller/subsystem/ticker/stat_entry(msg) diff --git a/code/defines/procs/dbcore.dm b/code/defines/procs/dbcore.dm deleted file mode 100644 index 9367b269643..00000000000 --- a/code/defines/procs/dbcore.dm +++ /dev/null @@ -1,208 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - -//cursors -#define Default_Cursor 0 -#define Client_Cursor 1 -#define Server_Cursor 2 -//conversions -#define TEXT_CONV 1 -#define RSC_FILE_CONV 2 -#define NUMBER_CONV 3 -//column flag values: -#define IS_NUMERIC 1 -#define IS_BINARY 2 -#define IS_NOT_NULL 4 -#define IS_PRIMARY_KEY 8 -#define IS_UNSIGNED 16 -//types -#define TINYINT 1 -#define SMALLINT 2 -#define MEDIUMINT 3 -#define INTEGER 4 -#define BIGINT 5 -#define DECIMAL 6 -#define FLOAT 7 -#define DOUBLE 8 -#define DATE 9 -#define DATETIME 10 -#define TIMESTAMP 11 -#define TIME 12 -#define STRING 13 -#define BLOB 14 -// TODO: Investigate more recent type additions and see if I can handle them. - Nadrew - - -// Deprecated! See global.dm for new configuration vars -/* -var/DB_SERVER = "" // This is the location of your MySQL server (localhost is USUALLY fine) -var/DB_PORT = 3306 // This is the port your MySQL server is running on (3306 is the default) -*/ - -/DBConnection - var/_db_con // This variable contains a reference to the actual database connection. - var/dbi // This variable is a string containing the DBI MySQL requires. - var/user // This variable contains the username data. - var/password // This variable contains the password data. - var/default_cursor // This contains the default database cursor data. - // - var/server = "" - var/port = 3306 - -/DBConnection/New(dbi_handler,username,password_handler,cursor_handler) - src.dbi = dbi_handler - src.user = username - src.password = password_handler - src.default_cursor = cursor_handler - _db_con = _dm_db_new_con() - -/DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_handler=src.password,cursor_handler) - if(!CONFIG_GET(flag/sql_enabled)) - return 0 - if(!src) return 0 - cursor_handler = src.default_cursor - if(!cursor_handler) cursor_handler = Default_Cursor - return _dm_db_connect(_db_con,dbi_handler,user_handler,password_handler,cursor_handler,null) - -/DBConnection/proc/Disconnect() return _dm_db_close(_db_con) - -/DBConnection/proc/IsConnected() - if(!CONFIG_GET(flag/sql_enabled)) return 0 - var/success = _dm_db_is_connected(_db_con) - return success - -/DBConnection/proc/Quote(str) return _dm_db_quote(_db_con,str) - -/DBConnection/proc/ErrorMsg() return _dm_db_error_msg(_db_con) -/DBConnection/proc/SelectDB(database_name,dbi) - if(IsConnected()) Disconnect() - //return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[DB_SERVER]:[DB_PORT]"]",user,password) - return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[CONFIG_GET(string/address)]:[CONFIG_GET(number/port)]"]",user,password) -/DBConnection/proc/NewQuery(sql_query,cursor_handler=src.default_cursor) return new/DBQuery(sql_query,src,cursor_handler) - - -/DBQuery/New(sql_query,DBConnection/connection_handler,cursor_handler) - if(sql_query) src.sql = sql_query - if(connection_handler) src.db_connection = connection_handler - if(cursor_handler) src.default_cursor = cursor_handler - _db_query = _dm_db_new_query() - return ..() - - -/DBQuery - var/sql // The sql query being executed. - var/default_cursor - var/list/columns //list of DB Columns populated by Columns() - var/list/conversions - var/list/item[0] //list of data values populated by NextRow() - - var/DBConnection/db_connection - var/_db_query - -/DBQuery/proc/Connect(DBConnection/connection_handler) src.db_connection = connection_handler - -/DBQuery/proc/Execute(sql_query=src.sql,cursor_handler=default_cursor) - Close() - return _dm_db_execute(_db_query,sql_query,db_connection._db_con,cursor_handler,null) - -/DBQuery/proc/NextRow() return _dm_db_next_row(_db_query,item,conversions) - -/DBQuery/proc/RowsAffected() return _dm_db_rows_affected(_db_query) - -/DBQuery/proc/RowCount() return _dm_db_row_count(_db_query) - -/DBQuery/proc/ErrorMsg() return _dm_db_error_msg(_db_query) - -/DBQuery/proc/Columns() - if(!columns) - columns = _dm_db_columns(_db_query,/DBColumn) - return columns - -/DBQuery/proc/GetRowData() - var/list/columns = Columns() - var/list/results - if(columns.len) - results = list() - for(var/C in columns) - results+=C - var/DBColumn/cur_col = columns[C] - results[C] = src.item[(cur_col.position+1)] - return results - -/DBQuery/proc/Close() - item.len = 0 - columns = null - conversions = null - return _dm_db_close(_db_query) - -/DBQuery/proc/Quote(str) - return db_connection.Quote(str) - -/DBQuery/proc/SetConversion(column,conversion) - if(istext(column)) column = columns.Find(column) - if(!conversions) conversions = new/list(column) - else if(conversions.len < column) conversions.len = column - conversions[column] = conversion - - -/DBColumn - var/name - var/table - var/position //1-based index into item data - var/sql_type - var/flags - var/length - var/max_length - -/DBColumn/New(name_handler,table_handler,position_handler,type_handler,flag_handler,length_handler,max_length_handler) - src.name = name_handler - src.table = table_handler - src.position = position_handler - src.sql_type = type_handler - src.flags = flag_handler - src.length = length_handler - src.max_length = max_length_handler - return ..() - - -/DBColumn/proc/SqlTypeName(type_handler=src.sql_type) - switch(type_handler) - if(TINYINT) return "TINYINT" - if(SMALLINT) return "SMALLINT" - if(MEDIUMINT) return "MEDIUMINT" - if(INTEGER) return "INTEGER" - if(BIGINT) return "BIGINT" - if(FLOAT) return "FLOAT" - if(DOUBLE) return "DOUBLE" - if(DATE) return "DATE" - if(DATETIME) return "DATETIME" - if(TIMESTAMP) return "TIMESTAMP" - if(TIME) return "TIME" - if(STRING) return "STRING" - if(BLOB) return "BLOB" - - -#undef Default_Cursor -#undef Client_Cursor -#undef Server_Cursor -#undef TEXT_CONV -#undef RSC_FILE_CONV -#undef NUMBER_CONV -#undef IS_NUMERIC -#undef IS_BINARY -#undef IS_NOT_NULL -#undef IS_PRIMARY_KEY -#undef IS_UNSIGNED -#undef TINYINT -#undef SMALLINT -#undef MEDIUMINT -#undef INTEGER -#undef BIGINT -#undef DECIMAL -#undef FLOAT -#undef DOUBLE -#undef DATE -#undef DATETIME -#undef TIMESTAMP -#undef TIME -#undef STRING -#undef BLOB diff --git a/code/defines/procs/statistics.dm b/code/defines/procs/statistics.dm index d11864fc755..0f1278ee302 100644 --- a/code/defines/procs/statistics.dm +++ b/code/defines/procs/statistics.dm @@ -7,14 +7,15 @@ if(M.client) playercount += 1 establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) log_game("SQL ERROR during population polling. Failed to connect.") else var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") - var/DBQuery/query = dbcon_old.NewQuery("INSERT INTO `tgstation`.`population` (`playercount`, `admincount`, `time`) VALUES ([playercount], [admincount], '[sqltime]')") + var/datum/db_query/query = SSdbcore.NewQuery("INSERT INTO population ('playercount', 'admincount', 'time') VALUES ([playercount], [admincount], '[sqltime]')") if(!query.Execute()) var/err = query.ErrorMsg() log_game("SQL ERROR during population polling. Error : \[[err]\]\n") + qdel(query) /proc/sql_report_round_start() // TODO @@ -50,13 +51,14 @@ var/coord = "[H.x], [H.y], [H.z]" //to_world("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()])") establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) log_game("SQL ERROR during death reporting. Failed to connect.") else - var/DBQuery/query = dbcon.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()], '[coord]')") + var/datum/db_query/query = SSdbcore.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()], '[coord]')") if(!query.Execute()) var/err = query.ErrorMsg() log_game("SQL ERROR during death reporting. Error : \[[err]\]\n") + qdel(query) /proc/sql_report_cyborg_death(var/mob/living/silicon/robot/H) @@ -84,13 +86,14 @@ var/coord = "[H.x], [H.y], [H.z]" //to_world("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.bruteloss], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()])") establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) log_game("SQL ERROR during death reporting. Failed to connect.") else - var/DBQuery/query = dbcon.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()], '[coord]')") + var/datum/db_query/query = SSdbcore.NewQuery("INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord) VALUES ('[sqlname]', '[sqlkey]', '[sqljob]', '[sqlspecial]', '[sqlpod]', '[sqltime]', '[laname]', '[lakey]', '[H.gender]', [H.getBruteLoss()], [H.getFireLoss()], [H.brainloss], [H.getOxyLoss()], '[coord]')") if(!query.Execute()) var/err = query.ErrorMsg() log_game("SQL ERROR during death reporting. Error : \[[err]\]\n") + qdel(query) /proc/statistic_cycle() @@ -115,11 +118,11 @@ return establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) log_game("SQL ERROR during feedback reporting. Failed to connect.") else - var/DBQuery/max_query = dbcon.NewQuery("SELECT MAX(roundid) AS max_round_id FROM erro_feedback") + var/datum/db_query/max_query = SSdbcore.NewQuery("SELECT MAX(roundid) AS max_round_id FROM erro_feedback") max_query.Execute() var/newroundid @@ -139,7 +142,7 @@ var/variable = item.get_variable() var/value = item.get_value() - var/DBQuery/query = dbcon.NewQuery("INSERT INTO erro_feedback (id, roundid, time, variable, value) VALUES (null, [newroundid], Now(), '[variable]', '[value]')") + var/datum/db_query/query = SSdbcore.NewQuery("INSERT INTO erro_feedback (id, roundid, time, variable, value) VALUES (null, [newroundid], Now(), '[variable]', '[value]')") if(!query.Execute()) var/err = query.ErrorMsg() log_game("SQL ERROR during death reporting. Error : \[[err]\]\n") diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 937cbb0777d..e67d622167d 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -218,6 +218,7 @@ var/global/list/additional_antag_types = list() emergency_shuttle.auto_recall = 1 feedback_set_details("round_start","[time2text(world.realtime)]") + INVOKE_ASYNC(SSdbcore, TYPE_PROC_REF(/datum/controller/subsystem/dbcore, SetRoundStart)) if(ticker && ticker.mode) feedback_set_details("game_mode","[ticker.mode]") feedback_set_details("server_ip","[world.internet_address]:[world.port]") diff --git a/code/game/machinery/records_scanner.dm b/code/game/machinery/records_scanner.dm index e6aeb521e5d..3ff97f160e5 100644 --- a/code/game/machinery/records_scanner.dm +++ b/code/game/machinery/records_scanner.dm @@ -51,7 +51,7 @@ var/age = user.age var/gender = user.gender /* no dbstuff yet - var/DBQuery/cquery = dbcon.NewQuery("SELECT * from jobban WHERE ckey='[user.ckey]'") + var/datum/DBQuery/cquery = SSdbcore.NewQuery("SELECT * from jobban WHERE ckey='[user.ckey]'") if(!cquery.Execute()) return else while(cquery.NextRow()) diff --git a/code/game/magic/archived_book.dm b/code/game/magic/archived_book.dm index 958c96e9224..86a9620c224 100644 --- a/code/game/magic/archived_book.dm +++ b/code/game/magic/archived_book.dm @@ -53,13 +53,13 @@ var/global/datum/book_manager/book_mgr = new() dat += "

ADMINISTRATIVE MANAGEMENT

" establish_old_db_connection() - if(!dbcon_old.IsConnected()) + if(!SSdbcore.IsConnected()) dat += "ERROR: Unable to contact External Archive. Please contact your system administrator for assistance." else dat += {"(Order book by SS13BN)

" dat += "
TITLE\[Del\]" dat += "
" + qdel(query) usr << browse("[dat]", "window=library") onclose(usr, "library") diff --git a/code/game/world.dm b/code/game/world.dm index ceccdb9660c..67384cfe35b 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -9,6 +9,8 @@ diary = start_log("[log_path].log") href_logfile = start_log("[log_path]-hrefs.htm") error_log = start_log("[log_path]-error.log") + sql_error_log = start_log("[log_path]-sql-error.log") + query_debug_log = start_log("[log_path]-query-debug.log") debug_log = start_log("[log_path]-debug.log") //VOREStation Edit End @@ -93,7 +95,7 @@ // (i.e. basically nothing should be added before load_admins() in here) // Try to set round ID - //SSdbcore.InitializeRound() TODO: Implement roundid on database subsystem and uncomment + SSdbcore.InitializeRound() //apply a default value to config.python_path, if needed if (!CONFIG_GET(string/python_path)) @@ -602,8 +604,8 @@ var/failed_old_db_connections = 0 if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore. return 0 - if(!dbcon) - dbcon = new() + if(!SSdbcore) + SSdbcore = new() var/user = CONFIG_GET(string/feedback_login) var/pass = CONFIG_GET(string/feedback_password) @@ -611,13 +613,13 @@ var/failed_old_db_connections = 0 var/address = CONFIG_GET(string/address) var/port = CONFIG_GET(number/port) - dbcon.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]") - . = dbcon.IsConnected() + SSdbcore.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]") + . = SSdbcore.IsConnected() if ( . ) failed_db_connections = 0 //If this connection succeeded, reset the failed connections counter. else failed_db_connections++ //If it failed, increase the failed connections counter. - to_world_log(dbcon.ErrorMsg()) + to_world_log(SSdbcore.ErrorMsg()) return . @@ -626,7 +628,7 @@ var/failed_old_db_connections = 0 if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) return 0 - if(!dbcon || !dbcon.IsConnected()) + if(!SSdbcore || !SSdbcore.IsConnected()) return setup_database_connection() else return 1 @@ -636,14 +638,11 @@ var/failed_old_db_connections = 0 var/list/results = list("-- Resetting DB connections --") failed_db_connections = 0 - if(dbcon?.IsConnected()) - dbcon.Disconnect() - results += "dbcon was connected and asked to disconnect" + if(SSdbcore?.IsConnected()) + SSdbcore.Disconnect() + results += "SSdbcore was connected and asked to disconnect" else - results += "dbcon was not connected" - - if(dbcon_old?.IsConnected()) - results += "WARNING: dbcon_old is connected, not touching it, but is this intentional?" + results += "SSdbcore was not connected" if(!CONFIG_GET(flag/sql_enabled)) results += "stopping because config.sql_enabled = false" diff --git a/code/global.dm b/code/global.dm index 3626077f064..8fe0183d92c 100644 --- a/code/global.dm +++ b/code/global.dm @@ -17,6 +17,8 @@ var/list/hit_appends = list("-OOF", "-ACK", "-UGH", "-HRNK", "-HURGH", "-GLORF") var/log_path = "data/logs/" //See world.dm for the full calculated path var/diary = null var/error_log = null +var/sql_error_log = null +var/query_debug_log = null var/debug_log = null var/href_logfile = null // var/station_name = "Northern Star" @@ -116,11 +118,6 @@ var/forum_authenticated_group = "10" var/fileaccess_timer = 0 var/custom_event_msg = null -// Database connections. A connection is established on world creation. -// Ideally, the connection dies when the server restarts (After feedback logging.). -var/DBConnection/dbcon = new() // Feedback database (New database) -var/DBConnection/dbcon_old = new() // /tg/station database (Old database) -- see the files in the SQL folder for information on what goes where. - // Added for Xenoarchaeology, might be useful for other stuff. var/global/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z") diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index 5278f07991f..aff45f3b52e 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -5,7 +5,7 @@ if(!check_rights(R_MOD,0) && !check_rights(R_BAN)) return establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) return var/serverip = "[world.internet_address]:[world.port]" @@ -44,7 +44,7 @@ computerid = bancid ip = banip - var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_player WHERE ckey = '[ckey]'") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT id FROM erro_player WHERE ckey = '[ckey]'") query.Execute() var/validckey = 0 if(query.NextRow()) @@ -81,7 +81,7 @@ reason = sql_sanitize_text(reason) var/sql = "INSERT INTO erro_ban (`id`,`bantime`,`serverip`,`bantype`,`reason`,`job`,`duration`,`rounds`,`expiration_time`,`ckey`,`computerid`,`ip`,`a_ckey`,`a_computerid`,`a_ip`,`who`,`adminwho`,`edits`,`unbanned`,`unbanned_datetime`,`unbanned_ckey`,`unbanned_computerid`,`unbanned_ip`) VALUES (null, Now(), '[serverip]', '[bantype_str]', '[reason]', '[job]', [(duration)?"[duration]":"0"], [(rounds)?"[rounds]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[ckey]', '[computerid]', '[ip]', '[a_ckey]', '[a_computerid]', '[a_ip]', '[who]', '[adminwho]', '', null, null, null, null, null)" - var/DBQuery/query_insert = dbcon.NewQuery(sql) + var/datum/db_query/query_insert = SSdbcore.NewQuery(sql) query_insert.Execute() to_chat(usr, span_filter_adminlog("[span_blue("Ban saved to database.")]")) message_admins("[key_name_admin(usr)] has added a [bantype_str] for [ckey] [(job)?"([job])":""] [(duration > 0)?"([duration] minutes)":""] with the reason: \"[reason]\" to the ban database.",1) @@ -124,13 +124,13 @@ sql += " AND job = '[job]'" establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) return var/ban_id var/ban_number = 0 //failsafe - var/DBQuery/query = dbcon.NewQuery(sql) + var/datum/db_query/query = SSdbcore.NewQuery(sql) query.Execute() while(query.NextRow()) ban_id = query.item[1] @@ -160,7 +160,7 @@ to_chat(usr, "Cancelled") return - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, duration, reason FROM erro_ban WHERE id = [banid]") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, duration, reason FROM erro_ban WHERE id = [banid]") query.Execute() var/eckey = usr.ckey //Editing admin ckey @@ -174,8 +174,10 @@ reason = query.item[3] else to_chat(usr, span_filter_adminlog("Invalid ban id. Contact the database admin")) + qdel(query) return + qdel(query) reason = sql_sanitize_text(reason) var/value @@ -188,7 +190,7 @@ to_chat(usr, "Cancelled") return - var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from \\\"[reason]\\\" to \\\"[value]\\\"
') WHERE id = [banid]") + var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE erro_ban SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from \\\"[reason]\\\" to \\\"[value]\\\"
') WHERE id = [banid]") update_query.Execute() message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s reason from [reason] to [value]",1) if("duration") @@ -198,7 +200,7 @@ to_chat(usr, "Cancelled") return - var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]
'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]") + var/datum/db_query/update_query = SSdbcore.NewQuery("UPDATE erro_ban SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]
'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]") message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s duration from [duration] to [value]",1) update_query.Execute() if("unban") @@ -215,13 +217,13 @@ var/sql = "SELECT ckey FROM erro_ban WHERE id = [id]" establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) return var/ban_number = 0 //failsafe var/pckey - var/DBQuery/query = dbcon.NewQuery(sql) + var/datum/db_query/query = SSdbcore.NewQuery(sql) query.Execute() while(query.NextRow()) pckey = query.item[1] @@ -245,7 +247,7 @@ var/sql_update = "UPDATE erro_ban SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = '[unban_ckey]', unbanned_computerid = '[unban_computerid]', unbanned_ip = '[unban_ip]' WHERE id = [id]" message_admins("[key_name_admin(usr)] has lifted [pckey]'s ban.",1) - var/DBQuery/query_update = dbcon.NewQuery(sql_update) + var/datum/db_query/query_update = SSdbcore.NewQuery(sql_update) query_update.Execute() @@ -267,7 +269,7 @@ if(!check_rights(R_BAN)) return establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection")]")) return @@ -398,7 +400,7 @@ else bantypesearch += "'PERMABAN' " - var/DBQuery/select_query = dbcon.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM erro_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100") + var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits, ip, computerid FROM erro_ban WHERE 1 [playersearch] [adminsearch] [ipsearch] [cidsearch] [bantypesearch] ORDER BY bantime DESC LIMIT 100") select_query.Execute() var/now = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss") // MUST BE the same format as SQL gives us the dates in, and MUST be least to most specific (i.e. year, month, day not day, month, year) diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index af128e5722f..2334f72e8e3 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -56,7 +56,7 @@ log_misc("Key [ckeytext] cid not checked. Non-Numeric: [computer_id]") failedcid = 1 - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM erro_ban WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM erro_ban WHERE (ckey = '[ckeytext]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)") query.Execute() diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index 1105ebcf092..a66d2689775 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -106,14 +106,14 @@ var/list/admin_ranks = list() //list of all ranks with associated rights //The current admin system uses SQL establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) error("Failed to connect to database in load_admins(). Reverting to legacy system.") log_misc("Failed to connect to database in load_admins(). Reverting to legacy system.") CONFIG_SET(flag/admin_legacy_system, TRUE) load_admins() return - var/DBQuery/query = dbcon.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, rank, level, flags FROM erro_admin") query.Execute() while(query.NextRow()) var/ckey = query.item[1] diff --git a/code/modules/admin/admin_verbs_vr.dm b/code/modules/admin/admin_verbs_vr.dm index 1d017794505..149eed75a52 100644 --- a/code/modules/admin/admin_verbs_vr.dm +++ b/code/modules/admin/admin_verbs_vr.dm @@ -96,13 +96,13 @@ dat += "

ADMINISTRATIVE MANAGEMENT

" establish_db_connection() - if(!dbcon_old.IsConnected()) + if(!SSdbcore.IsConnected()) dat += "ERROR: Unable to contact External Archive. Please contact your system administrator for assistance." else dat += {"(Order book by SS13BN)

TITLE Now()") + var/datum/db_query/query1 = SSdbcore.NewQuery("SELECT ckey, job FROM erro_ban WHERE bantype = 'JOB_TEMPBAN' AND isnull(unbanned) AND expiration_time > Now()") query1.Execute() while(query1.NextRow()) diff --git a/code/modules/admin/permissionverbs/permissionedit.dm b/code/modules/admin/permissionverbs/permissionedit.dm index b85e76e4d54..cbb1e9f7290 100644 --- a/code/modules/admin/permissionverbs/permissionedit.dm +++ b/code/modules/admin/permissionverbs/permissionedit.dm @@ -56,7 +56,7 @@ establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection")]")) return @@ -71,7 +71,7 @@ if(!istext(adm_ckey) || !istext(new_rank)) return - var/DBQuery/select_query = dbcon.NewQuery("SELECT id FROM erro_admin WHERE ckey = '[adm_ckey]'") + var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id FROM erro_admin WHERE ckey = '[adm_ckey]'") select_query.Execute() var/new_admin = 1 @@ -81,16 +81,16 @@ admin_id = text2num(select_query.item[1]) if(new_admin) - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO `erro_admin` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)") + var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO `erro_admin` (`id`, `ckey`, `rank`, `level`, `flags`) VALUES (null, '[adm_ckey]', '[new_rank]', -1, 0)") insert_query.Execute() - var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');") + var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added new admin [adm_ckey] to rank [new_rank]');") log_query.Execute() to_chat(usr, span_filter_adminlog("[span_blue("New admin added.")]")) else if(!isnull(admin_id) && isnum(admin_id)) - var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET rank = '[new_rank]' WHERE id = [admin_id]") + var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE `erro_admin` SET rank = '[new_rank]' WHERE id = [admin_id]") insert_query.Execute() - var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');") + var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Edited the rank of [adm_ckey] to [new_rank]');") log_query.Execute() to_chat(usr, span_filter_adminlog("[span_blue("Admin rank changed.")]")) @@ -105,7 +105,7 @@ return establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) to_chat(usr, span_filter_adminlog("[span_red("Failed to establish database connection!")]")) return @@ -123,7 +123,7 @@ if(!istext(adm_ckey) || !isnum(new_permission)) return - var/DBQuery/select_query = dbcon.NewQuery("SELECT id, flags FROM erro_admin WHERE ckey = '[adm_ckey]'") + var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id, flags FROM erro_admin WHERE ckey = '[adm_ckey]'") select_query.Execute() var/admin_id @@ -136,14 +136,14 @@ return if(admin_rights & new_permission) //This admin already has this permission, so we are removing it. - var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]") + var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE `erro_admin` SET flags = [admin_rights & ~new_permission] WHERE id = [admin_id]") insert_query.Execute() - var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');") + var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Removed permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]');") log_query.Execute() to_chat(usr, span_filter_adminlog("[span_blue("Permission removed.")]")) else //This admin doesn't have this permission, so we are adding it. - var/DBQuery/insert_query = dbcon.NewQuery("UPDATE `erro_admin` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]") + var/datum/db_query/insert_query = SSdbcore.NewQuery("UPDATE `erro_admin` SET flags = '[admin_rights | new_permission]' WHERE id = [admin_id]") insert_query.Execute() - var/DBQuery/log_query = dbcon.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')") + var/datum/db_query/log_query = SSdbcore.NewQuery("INSERT INTO `test`.`erro_admin_log` (`id` ,`datetime` ,`adminckey` ,`adminip` ,`log` ) VALUES (NULL , NOW( ) , '[usr.ckey]', '[usr.client.address]', 'Added permission [rights2text(new_permission)] (flag = [new_permission]) to admin [adm_ckey]')") log_query.Execute() to_chat(usr, span_filter_adminlog("[span_blue("Permission added.")]")) diff --git a/code/modules/admin/verbs/check_customitem_activity.dm b/code/modules/admin/verbs/check_customitem_activity.dm index 89be5ba6520..003a3da3776 100644 --- a/code/modules/admin/verbs/check_customitem_activity.dm +++ b/code/modules/admin/verbs/check_customitem_activity.dm @@ -30,7 +30,7 @@ var/inactive_keys = "None
" return establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) return //grab all ckeys associated with custom items @@ -55,7 +55,7 @@ var/inactive_keys = "None
" //run a query to get all ckeys inactive for over 2 months var/list/inactive_ckeys = list() if(ckeys_with_customitems.len) - var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey, lastseen FROM erro_player WHERE datediff(Now(), lastseen) > 60") + var/datum/db_query/query_inactive = SSdbcore.NewQuery("SELECT ckey, lastseen FROM erro_player WHERE datediff(Now(), lastseen) > 60") query_inactive.Execute() while(query_inactive.NextRow()) var/cur_ckey = query_inactive.item[1] @@ -67,9 +67,9 @@ var/inactive_keys = "None
" //if there are ckeys left over, check whether they have a database entry at all if(ckeys_with_customitems.len) for(var/cur_ckey in ckeys_with_customitems) - var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE ckey = '[cur_ckey]'") + var/datum/db_query/query_inactive = SSdbcore.NewQuery("SELECT ckey FROM erro_player WHERE ckey = '[cur_ckey]'") query_inactive.Execute() - if(!query_inactive.RowCount()) + if(!query_inactive.rows) inactive_ckeys += cur_ckey if(inactive_ckeys.len) diff --git a/code/modules/admin/verbs/dbcon_fix.dm b/code/modules/admin/verbs/dbcon_fix.dm index 1d523145202..99deb034a72 100644 --- a/code/modules/admin/verbs/dbcon_fix.dm +++ b/code/modules/admin/verbs/dbcon_fix.dm @@ -10,30 +10,30 @@ return FALSE log_admin("Attempting to fix database connection") - if(dbcon.IsConnected()) - dbcon.Disconnect() + if(SSdbcore.IsConnected()) + SSdbcore.Disconnect() else log_admin("Database already disconnected") - + establish_db_connection() - var/errno = dbcon.ErrorMsg() + var/errno = SSdbcore.ErrorMsg() if(errno) log_admin("Database connection returned error message `[errno]`. Aborting.") return FALSE - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) log_admin("Database could not be reconnected! Aborting.") return FALSE - log_admin("Database reconnected. Fixing player ages...") + log_admin("Database reconnected. Fixing player ages...") var/num = 0 for(var/client/C in GLOB.clients) C.log_client_to_db() - errno = dbcon.ErrorMsg() + errno = SSdbcore.ErrorMsg() if(errno) log_admin("Database connection returned error message `[errno]` after adjusting player ages for [num] players. [C] was being updated when the error struck. Aborting.") return FALSE if(C.player_age) num++ - + log_admin("Successfully updated non-0 player age for [num] clients.") - return FALSE \ No newline at end of file + return FALSE diff --git a/code/modules/admin/verbs/panicbunker.dm b/code/modules/admin/verbs/panicbunker.dm index c153eda9581..4b2722995e3 100644 --- a/code/modules/admin/verbs/panicbunker.dm +++ b/code/modules/admin/verbs/panicbunker.dm @@ -12,7 +12,7 @@ CONFIG_SET(flag/panic_bunker, !CONFIG_GET(flag/panic_bunker)) log_and_message_admins("has toggled the Panic Bunker, it is now [(CONFIG_GET(flag/panic_bunker) ? "on":"off")].", src) - if (CONFIG_GET(flag/panic_bunker) && (!dbcon || !dbcon.IsConnected())) + if (CONFIG_GET(flag/panic_bunker) && (!SSdbcore || !SSdbcore.IsConnected())) message_admins("The database is not connected! Panic bunker will not work until the connection is reestablished.") feedback_add_details("admin_verb","PANIC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -26,7 +26,7 @@ CONFIG_SET(flag/paranoia_logging, !CONFIG_GET(flag/paranoia_logging)) log_and_message_admins("has toggled Paranoia Logging, it is now [(CONFIG_GET(flag/paranoia_logging) ? "on":"off")].", src) - if (CONFIG_GET(flag/paranoia_logging) && (!dbcon || !dbcon.IsConnected())) + if (CONFIG_GET(flag/paranoia_logging) && (!SSdbcore || !SSdbcore.IsConnected())) message_admins("The database is not connected! Paranoia logging will not be able to give 'player age' (time since first connection) warnings, only Byond account warnings.") feedback_add_details("admin_verb","PARLOG") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -40,6 +40,6 @@ CONFIG_SET(flag/ip_reputation, !CONFIG_GET(flag/ip_reputation)) log_and_message_admins("has toggled IP reputation checks, it is now [(CONFIG_GET(flag/ip_reputation) ? "on":"off")].", src) - if (CONFIG_GET(flag/ip_reputation) && (!dbcon || !dbcon.IsConnected())) + if (CONFIG_GET(flag/ip_reputation) && (!SSdbcore || !SSdbcore.IsConnected())) message_admins("The database is not connected! IP reputation logging will not be able to allow existing players to bypass the reputation checks (if that is enabled).") feedback_add_details("admin_verb","IPREP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index e77285dc3be..cdb73164a8f 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -145,7 +145,7 @@ var/sql_discord = sql_sanitize_text(their_id) var/sql_ckey = sql_sanitize_text(ckey) - var/DBQuery/query = dbcon.NewQuery("UPDATE erro_player SET discord_id = '[sql_discord]' WHERE ckey = '[sql_ckey]'") + var/datum/db_query/query = SSdbcore.NewQuery("UPDATE erro_player SET discord_id = '[sql_discord]' WHERE ckey = '[sql_ckey]'") if(query.Execute()) to_chat(src, span_notice("Registration complete! Thank you for taking the time to register your Discord ID.")) log_and_message_admins("[ckey] has registered their Discord ID to obtain the Crew Member role. Their Discord snowflake ID is: [their_id]", src) @@ -391,12 +391,12 @@ /proc/get_player_age(key) establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) return null var/sql_ckey = sql_sanitize_text(ckey(key)) - var/DBQuery/query = dbcon.NewQuery("SELECT datediff(Now(),firstseen) as age FROM erro_player WHERE ckey = '[sql_ckey]'") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT datediff(Now(),firstseen) as age FROM erro_player WHERE ckey = '[sql_ckey]'") query.Execute() if(query.NextRow()) @@ -411,12 +411,12 @@ return establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) return var/sql_ckey = sql_sanitize_text(src.ckey) - var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM erro_player WHERE ckey = '[sql_ckey]'") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM erro_player WHERE ckey = '[sql_ckey]'") query.Execute() var/sql_id = 0 player_age = 0 // New players won't have an entry so knowing we have a connection we set this to zero to be updated if their is a record. @@ -426,24 +426,26 @@ break account_join_date = sanitizeSQL(findJoinDate()) - if(account_join_date && dbcon.IsConnected()) - var/DBQuery/query_datediff = dbcon.NewQuery("SELECT DATEDIFF(Now(),'[account_join_date]')") + if(account_join_date && SSdbcore.IsConnected()) + var/datum/db_query/query_datediff = SSdbcore.NewQuery("SELECT DATEDIFF(Now(),'[account_join_date]')") if(query_datediff.Execute() && query_datediff.NextRow()) account_age = text2num(query_datediff.item[1]) - var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE ip = '[address]'") + var/datum/db_query/query_ip = SSdbcore.NewQuery("SELECT ckey FROM erro_player WHERE ip = '[address]'") query_ip.Execute() related_accounts_ip = "" while(query_ip.NextRow()) related_accounts_ip += "[query_ip.item[1]], " break + qdel(query_ip) - var/DBQuery/query_cid = dbcon.NewQuery("SELECT ckey FROM erro_player WHERE computerid = '[computer_id]'") + var/datum/db_query/query_cid = SSdbcore.NewQuery("SELECT ckey FROM erro_player WHERE computerid = '[computer_id]'") query_cid.Execute() related_accounts_cid = "" while(query_cid.NextRow()) related_accounts_cid += "[query_cid.item[1]], " break + qdel(query_cid) //Just the standard check to see if it's actually a number if(sql_id) @@ -494,7 +496,7 @@ log_admin("Couldn't perform IP check on [key] with [address]") // VOREStation Edit Start - Department Hours - var/DBQuery/query_hours = dbcon.NewQuery("SELECT department, hours, total_hours FROM vr_player_hours WHERE ckey = '[sql_ckey]'") + var/datum/db_query/query_hours = SSdbcore.NewQuery("SELECT department, hours, total_hours FROM vr_player_hours WHERE ckey = '[sql_ckey]'") if(query_hours.Execute()) while(query_hours.NextRow()) department_hours[query_hours.item[1]] = text2num(query_hours.item[2]) @@ -507,16 +509,16 @@ if(sql_id) //Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables - var/DBQuery/query_update = dbcon.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]") + var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]") query_update.Execute() else //New player!! Need to insert all the stuff - var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO erro_player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')") + var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO erro_player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')") query_insert.Execute() //Logging player access var/serverip = "[world.internet_address]:[world.port]" - var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `erro_connection_log`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');") + var/datum/db_query/query_accesslog = SSdbcore.NewQuery("INSERT INTO `erro_connection_log`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');") query_accesslog.Execute() #undef UPLOAD_LIMIT diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index 3e63722eb48..1c115ffac53 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -44,7 +44,7 @@
\[Start Search\]
"} if(1) establish_db_connection() - if(!dbcon_old.IsConnected()) + if(!SSdbcore.IsConnected()) dat += span_red(span_bold("ERROR") + ": Unable to contact External Archive. Please contact your system administrator for assistance.") + "
" else if(!SQLquery) dat += span_red(span_bold("ERROR") + ": Malformed search request. Please contact your system administrator for assistance.") + "
" @@ -52,7 +52,7 @@ dat += {""} - var/DBQuery/query = dbcon_old.NewQuery(SQLquery) + var/datum/db_query/query = SSdbcore.NewQuery(SQLquery) query.Execute() while(query.NextRow()) @@ -277,13 +277,13 @@ //dat += "

" + span_red("arning: System Administrator has slated this archive for removal. Personal uploads should be taken to the NT board of internal literature.") + "

" //VOREStation Removal - if(!dbcon_old.IsConnected()) + if(!SSdbcore.IsConnected()) dat += span_red(span_bold("ERROR") + ": Unable to contact External Archive. Please contact your system administrator for assistance.") else dat += {"(Order book by SS13BN)

AUTHORTITLECATEGORYSS13BN
TITLE(Order book by SS13BN)

" dat += "
TITLE\[Del\]" dat += "
" + qdel(query) dat += "
(Return to main menu)
" user << browse("[dat]", "window=library") @@ -437,20 +438,20 @@ tgui_alert_async(usr, "This book has been rejected from the database. Aborting!") else establish_db_connection() - if(!dbcon_old.IsConnected()) + if(!SSdbcore.IsConnected()) tgui_alert_async(usr, "Connection to Archive has been severed. Aborting.") else /* - var/sqltitle = dbcon.Quote(scanner.cache.name) - var/sqlauthor = dbcon.Quote(scanner.cache.author) - var/sqlcontent = dbcon.Quote(scanner.cache.dat) - var/sqlcategory = dbcon.Quote(upload_category) + var/sqltitle = SSdbcore.Quote(scanner.cache.name) + var/sqlauthor = SSdbcore.Quote(scanner.cache.author) + var/sqlcontent = SSdbcore.Quote(scanner.cache.dat) + var/sqlcategory = SSdbcore.Quote(upload_category) */ var/sqltitle = sanitizeSQL(scanner.cache.name) var/sqlauthor = sanitizeSQL(scanner.cache.author) var/sqlcontent = sanitizeSQL(scanner.cache.dat) var/sqlcategory = sanitizeSQL(upload_category) - var/DBQuery/query = dbcon_old.NewQuery("INSERT INTO library (author, title, content, category) VALUES ('[sqlauthor]', '[sqltitle]', '[sqlcontent]', '[sqlcategory]')") + var/datum/db_query/query = SSdbcore.NewQuery("INSERT INTO library (author, title, content, category) VALUES ('[sqlauthor]', '[sqltitle]', '[sqlcontent]', '[sqlcategory]')") if(!query.Execute()) to_chat(usr,query.ErrorMsg()) else @@ -461,7 +462,7 @@ if(href_list["targetid"]) var/sqlid = sanitizeSQL(href_list["targetid"]) establish_db_connection() - if(!dbcon_old.IsConnected()) + if(!SSdbcore.IsConnected()) tgui_alert_async(usr, "Connection to Archive has been severed. Aborting.") if(bibledelay) for (var/mob/V in hearers(src)) @@ -470,7 +471,7 @@ bibledelay = 1 spawn(6) bibledelay = 0 - var/DBQuery/query = dbcon_old.NewQuery("SELECT * FROM library WHERE id=[sqlid]") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT * FROM library WHERE id=[sqlid]") query.Execute() while(query.NextRow()) @@ -492,10 +493,10 @@ return var/sqlid = sanitizeSQL(href_list["delid"]) establish_db_connection() - if(!dbcon_old.IsConnected()) + if(!SSdbcore.IsConnected()) tgui_alert_async(usr, "Connection to Archive has been severed. Aborting.") else - var/DBQuery/query = dbcon_old.NewQuery("DELETE FROM library WHERE id=[sqlid]") + var/datum/db_query/query = SSdbcore.NewQuery("DELETE FROM library WHERE id=[sqlid]") query.Execute() log_admin("[usr.key] has deleted the book [sqlid]") //VOREStation Addition diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 438d3663c28..387c6e01d41 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -73,11 +73,11 @@ if(!IsGuestKey(src.key)) establish_db_connection() - if(dbcon.IsConnected()) + if(SSdbcore.IsConnected()) var/isadmin = 0 if(src.client && src.client.holder) isadmin = 1 - var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_poll_question WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM erro_poll_vote WHERE ckey = \"[ckey]\") AND id NOT IN (SELECT pollid FROM erro_poll_textreply WHERE ckey = \"[ckey]\")") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT id FROM erro_poll_question WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM erro_poll_vote WHERE ckey = \"[ckey]\") AND id NOT IN (SELECT pollid FROM erro_poll_textreply WHERE ckey = \"[ckey]\")") query.Execute() var/newpoll = 0 while(query.NextRow()) @@ -234,12 +234,12 @@ if(href_list["privacy_poll"]) establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) return var/voted = 0 //First check if the person has not voted yet. - var/DBQuery/query = dbcon.NewQuery("SELECT * FROM erro_privacy WHERE ckey='[src.ckey]'") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT * FROM erro_privacy WHERE ckey='[src.ckey]'") query.Execute() while(query.NextRow()) voted = 1 @@ -265,7 +265,7 @@ if(!voted) var/sql = "INSERT INTO erro_privacy VALUES (null, Now(), '[src.ckey]', '[option]')" - var/DBQuery/query_insert = dbcon.NewQuery(sql) + var/datum/db_query/query_insert = SSdbcore.NewQuery(sql) query_insert.Execute() to_chat(usr, span_bold("Thank you for your vote!")) usr << browse(null,"window=privacypoll") diff --git a/code/modules/mob/new_player/poll.dm b/code/modules/mob/new_player/poll.dm index 977fa1e640b..751b3ebd997 100644 --- a/code/modules/mob/new_player/poll.dm +++ b/code/modules/mob/new_player/poll.dm @@ -1,11 +1,11 @@ /mob/new_player/proc/handle_privacy_poll() establish_db_connection() - if(!dbcon.IsConnected()) + if(!SSdbcore.IsConnected()) return var/voted = 0 - var/DBQuery/query = dbcon.NewQuery("SELECT * FROM erro_privacy WHERE ckey='[src.ckey]'") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT * FROM erro_privacy WHERE ckey='[src.ckey]'") query.Execute() while(query.NextRow()) voted = 1 @@ -48,12 +48,12 @@ /mob/new_player/proc/handle_player_polling() establish_db_connection() - if(dbcon.IsConnected()) + if(SSdbcore.IsConnected()) var/isadmin = 0 if(src.client && src.client.holder) isadmin = 1 - var/DBQuery/select_query = dbcon.NewQuery("SELECT id, question FROM erro_poll_question WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime") + var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT id, question FROM erro_poll_question WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime") select_query.Execute() var/output = "
Player polls" @@ -82,9 +82,9 @@ /mob/new_player/proc/poll_player(var/pollid = -1) if(pollid == -1) return establish_db_connection() - if(dbcon.IsConnected()) + if(SSdbcore.IsConnected()) - var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM erro_poll_question WHERE id = [pollid]") + var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM erro_poll_question WHERE id = [pollid]") select_query.Execute() var/pollstarttime = "" @@ -109,7 +109,7 @@ switch(polltype) //Polls that have enumerated options if("OPTION") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT optionid FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/datum/db_query/voted_query = SSdbcore.NewQuery("SELECT optionid FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() var/voted = 0 @@ -121,7 +121,7 @@ var/list/datum/polloption/options = list() - var/DBQuery/options_query = dbcon.NewQuery("SELECT id, text FROM erro_poll_option WHERE pollid = [pollid]") + var/datum/db_query/options_query = SSdbcore.NewQuery("SELECT id, text FROM erro_poll_option WHERE pollid = [pollid]") options_query.Execute() while(options_query.NextRow()) var/datum/polloption/PO = new() @@ -162,7 +162,7 @@ //Polls with a text input if("TEXT") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT replytext FROM erro_poll_textreply WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/datum/db_query/voted_query = SSdbcore.NewQuery("SELECT replytext FROM erro_poll_textreply WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() var/voted = 0 @@ -204,7 +204,7 @@ //Polls with a text input if("NUMVAL") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT o.text, v.rating FROM erro_poll_option o, erro_poll_vote v WHERE o.pollid = [pollid] AND v.ckey = '[usr.ckey]' AND o.id = v.optionid") + var/datum/db_query/voted_query = SSdbcore.NewQuery("SELECT o.text, v.rating FROM erro_poll_option o, erro_poll_vote v WHERE o.pollid = [pollid] AND v.ckey = '[usr.ckey]' AND o.id = v.optionid") voted_query.Execute() var/output = "
Player poll" @@ -230,7 +230,7 @@ var/minid = 999999 var/maxid = 0 - var/DBQuery/option_query = dbcon.NewQuery("SELECT id, text, minval, maxval, descmin, descmid, descmax FROM erro_poll_option WHERE pollid = [pollid]") + var/datum/db_query/option_query = SSdbcore.NewQuery("SELECT id, text, minval, maxval, descmin, descmid, descmax FROM erro_poll_option WHERE pollid = [pollid]") option_query.Execute() while(option_query.NextRow()) var/optionid = text2num(option_query.item[1]) @@ -273,7 +273,7 @@ src << browse("[output]","window=playerpoll;size=500x500") if("MULTICHOICE") - var/DBQuery/voted_query = dbcon.NewQuery("SELECT optionid FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/datum/db_query/voted_query = SSdbcore.NewQuery("SELECT optionid FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() var/list/votedfor = list() @@ -286,7 +286,7 @@ var/maxoptionid = 0 var/minoptionid = 0 - var/DBQuery/options_query = dbcon.NewQuery("SELECT id, text FROM erro_poll_option WHERE pollid = [pollid]") + var/datum/db_query/options_query = SSdbcore.NewQuery("SELECT id, text FROM erro_poll_option WHERE pollid = [pollid]") options_query.Execute() while(options_query.NextRow()) var/datum/polloption/PO = new() @@ -343,9 +343,9 @@ if(!isnum(pollid) || !isnum(optionid)) return establish_db_connection() - if(dbcon.IsConnected()) + if(SSdbcore.IsConnected()) - var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") + var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT starttime, endtime, question, polltype, multiplechoiceoptions FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") select_query.Execute() var/validpoll = 0 @@ -363,7 +363,7 @@ to_chat(usr, span_red("Poll is not valid.")) return - var/DBQuery/select_query2 = dbcon.NewQuery("SELECT id FROM erro_poll_option WHERE id = [optionid] AND pollid = [pollid]") + var/datum/db_query/select_query2 = SSdbcore.NewQuery("SELECT id FROM erro_poll_option WHERE id = [optionid] AND pollid = [pollid]") select_query2.Execute() var/validoption = 0 @@ -372,13 +372,14 @@ validoption = 1 break + qdel(select_query2) if(!validoption) to_chat(usr, span_red("Poll option is not valid.")) return var/alreadyvoted = 0 - var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/datum/db_query/voted_query = SSdbcore.NewQuery("SELECT id FROM erro_poll_vote WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() while(voted_query.NextRow()) @@ -399,7 +400,7 @@ adminrank = usr.client.holder.rank - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]')") + var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]')") insert_query.Execute() to_chat(usr, span_blue("Vote successful.")) @@ -413,9 +414,9 @@ if(!isnum(pollid) || !istext(replytext)) return establish_db_connection() - if(dbcon.IsConnected()) + if(SSdbcore.IsConnected()) - var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") + var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT starttime, endtime, question, polltype FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") select_query.Execute() var/validpoll = 0 @@ -432,7 +433,7 @@ var/alreadyvoted = 0 - var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM erro_poll_textreply WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") + var/datum/db_query/voted_query = SSdbcore.NewQuery("SELECT id FROM erro_poll_textreply WHERE pollid = [pollid] AND ckey = '[usr.ckey]'") voted_query.Execute() while(voted_query.NextRow()) @@ -457,7 +458,7 @@ to_chat(usr, "The text you entered was blank, contained illegal characters or was too long. Please correct the text and submit again.") return - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO erro_poll_textreply (id ,datetime ,pollid ,ckey ,ip ,replytext ,adminrank) VALUES (null, Now(), [pollid], '[usr.ckey]', '[usr.client.address]', '[replytext]', '[adminrank]')") + var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO erro_poll_textreply (id ,datetime ,pollid ,ckey ,ip ,replytext ,adminrank) VALUES (null, Now(), [pollid], '[usr.ckey]', '[usr.client.address]', '[replytext]', '[adminrank]')") insert_query.Execute() to_chat(usr, span_blue("Feedback logging successful.")) @@ -471,9 +472,9 @@ if(!isnum(pollid) || !isnum(optionid)) return establish_db_connection() - if(dbcon.IsConnected()) + if(SSdbcore.IsConnected()) - var/DBQuery/select_query = dbcon.NewQuery("SELECT starttime, endtime, question, polltype FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") + var/datum/db_query/select_query = SSdbcore.NewQuery("SELECT starttime, endtime, question, polltype FROM erro_poll_question WHERE id = [pollid] AND Now() BETWEEN starttime AND endtime") select_query.Execute() var/validpoll = 0 @@ -488,7 +489,7 @@ to_chat(usr, span_red("Poll is not valid.")) return - var/DBQuery/select_query2 = dbcon.NewQuery("SELECT id FROM erro_poll_option WHERE id = [optionid] AND pollid = [pollid]") + var/datum/db_query/select_query2 = SSdbcore.NewQuery("SELECT id FROM erro_poll_option WHERE id = [optionid] AND pollid = [pollid]") select_query2.Execute() var/validoption = 0 @@ -503,7 +504,7 @@ var/alreadyvoted = 0 - var/DBQuery/voted_query = dbcon.NewQuery("SELECT id FROM erro_poll_vote WHERE optionid = [optionid] AND ckey = '[usr.ckey]'") + var/datum/db_query/voted_query = SSdbcore.NewQuery("SELECT id FROM erro_poll_vote WHERE optionid = [optionid] AND ckey = '[usr.ckey]'") voted_query.Execute() while(voted_query.NextRow()) @@ -519,7 +520,7 @@ adminrank = usr.client.holder.rank - var/DBQuery/insert_query = dbcon.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank, rating) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]', [(isnull(rating)) ? "null" : rating])") + var/datum/db_query/insert_query = SSdbcore.NewQuery("INSERT INTO erro_poll_vote (id ,datetime ,pollid ,optionid ,ckey ,ip ,adminrank, rating) VALUES (null, Now(), [pollid], [optionid], '[usr.ckey]', '[usr.client.address]', '[adminrank]', [(isnull(rating)) ? "null" : rating])") insert_query.Execute() to_chat(usr, span_blue("Vote successful.")) diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm index 88c4ac92af2..2c5aae52e57 100644 --- a/code/modules/research/message_server.dm +++ b/code/modules/research/message_server.dm @@ -348,10 +348,10 @@ var/obj/machinery/blackbox_recorder/blackbox round_end_data_gathering() //round_end time logging and some other data processing establish_db_connection() - if(!dbcon.IsConnected()) return + if(!SSdbcore.IsConnected()) return var/round_id - var/DBQuery/query = dbcon.NewQuery("SELECT MAX(round_id) AS round_id FROM erro_feedback") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT MAX(round_id) AS round_id FROM erro_feedback") query.Execute() while(query.NextRow()) round_id = query.item[1] @@ -362,7 +362,7 @@ var/obj/machinery/blackbox_recorder/blackbox for(var/datum/feedback_variable/FV in feedback) var/sql = "INSERT INTO erro_feedback VALUES (null, Now(), [round_id], \"[FV.get_variable()]\", [FV.get_value()], \"[FV.get_details()]\")" - var/DBQuery/query_insert = dbcon.NewQuery(sql) + var/datum/db_query/query_insert = SSdbcore.NewQuery(sql) query_insert.Execute() // Sanitize inputs to avoid SQL injection attacks diff --git a/code/modules/tgs/v5/chat_commands.dm b/code/modules/tgs/v5/chat_commands.dm index a2cb48501b6..d6df106afb2 100644 --- a/code/modules/tgs/v5/chat_commands.dm +++ b/code/modules/tgs/v5/chat_commands.dm @@ -92,7 +92,7 @@ GLOBAL_LIST_EMPTY(pending_discord_registrations) /datum/tgs_chat_command/register/Run(datum/tgs_chat_user/sender, params) // Try to find if that ID is registered to someone already var/sql_discord = sql_sanitize_text(sender.id) - var/DBQuery/query = dbcon.NewQuery("SELECT discord_id FROM erro_player WHERE discord_id = '[sql_discord]'") + var/datum/db_query/query = SSdbcore.NewQuery("SELECT discord_id FROM erro_player WHERE discord_id = '[sql_discord]'") query.Execute() if(query.NextRow()) return "[sender.friendly_name], your Discord ID is already registered to a Byond username. Please contact an administrator if you changed your Byond username or Discord ID." @@ -115,7 +115,7 @@ GLOBAL_LIST_EMPTY(pending_discord_registrations) return "[sender.friendly_name], I couldn't find a logged-in user with the username of '[key_to_find]', which is what you provided after conversion to Byond's ckey format. Please connect to the game server and try again." var/sql_ckey = sql_sanitize_text(key_to_find) - query = dbcon.NewQuery("SELECT discord_id FROM erro_player WHERE ckey = '[sql_ckey]'") + query = SSdbcore.NewQuery("SELECT discord_id FROM erro_player WHERE ckey = '[sql_ckey]'") query.Execute() // We somehow found their client, BUT they don't exist in the database diff --git a/code/modules/tgui_panel/tgui_panel.dm b/code/modules/tgui_panel/tgui_panel.dm index 0e63c38c42c..df1f162fabf 100644 --- a/code/modules/tgui_panel/tgui_panel.dm +++ b/code/modules/tgui_panel/tgui_panel.dm @@ -73,7 +73,7 @@ /datum/tgui_panel/proc/on_message(type, payload) if(type == "ready") broken = FALSE - // window.send_message("connected", list("round_id" = GLOB.round_id)) // Sends the round ID to the chat, requires round IDs + window.send_message("connected", list("round_id" = GLOB.round_id)) // Sends the round ID to the chat, requires round IDs window.send_message("update", list( "config" = list( "client" = list( @@ -81,6 +81,9 @@ "address" = client.address, "computer_id" = client.computer_id, ), + "server" = list( + "round_id" = GLOB.round_id, + ), "window" = list( "fancy" = FALSE, "locked" = FALSE, diff --git a/tools/define_sanity/check.py b/tools/define_sanity/check.py index fef59d28dbd..acf6a6fd0e5 100644 --- a/tools/define_sanity/check.py +++ b/tools/define_sanity/check.py @@ -80,7 +80,7 @@ if number_of_defines == 0: print(red("No defines found! This is likely an error.")) sys.exit(1) -if number_of_defines <= 900: +if number_of_defines <= 850: print(red(f"Only found {number_of_defines} defines in {number_of_files} files! Something has likely gone wrong as the number of local defines should not be this low.")) sys.exit(1) diff --git a/vorestation.dme b/vorestation.dme index 895acf1a849..15d30d9cf50 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -58,6 +58,7 @@ #include "code\__defines\cooldowns.dm" #include "code\__defines\crafting.dm" #include "code\__defines\damage_organs.dm" +#include "code\__defines\database.dm" #include "code\__defines\diseases.dm" #include "code\__defines\dna.dm" #include "code\__defines\economy_misc.dm" @@ -174,6 +175,7 @@ #include "code\_global_vars\_regexes.dm" #include "code\_global_vars\bitfields.dm" #include "code\_global_vars\configuration.dm" +#include "code\_global_vars\logging.dm" #include "code\_global_vars\misc.dm" #include "code\_global_vars\mobs.dm" #include "code\_global_vars\time_vars.dm" @@ -350,6 +352,7 @@ #include "code\controllers\subsystems\chat.dm" #include "code\controllers\subsystems\chemistry.dm" #include "code\controllers\subsystems\circuits.dm" +#include "code\controllers\subsystems\dbcore.dm" #include "code\controllers\subsystems\dcs.dm" #include "code\controllers\subsystems\events.dm" #include "code\controllers\subsystems\garbage.dm" @@ -671,7 +674,6 @@ #include "code\defines\obj\weapon.dm" #include "code\defines\procs\announce.dm" #include "code\defines\procs\AStar.dm" -#include "code\defines\procs\dbcore.dm" #include "code\defines\procs\radio.dm" #include "code\defines\procs\statistics.dm" #include "code\game\atoms.dm"