db.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. /*
  2. * This file is part of RuneOptimizer.
  3. *
  4. * RuneOptimizer is free software: you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the Free
  6. * Software Foundation, either version 3 of the License, or (at your option)
  7. * any later version.
  8. *
  9. * RuneOptimizer is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * RuneOptimizer. If not, see <https://www.gnu.org/licenses/>.
  16. */
  17. /**
  18. * @file db.c
  19. *
  20. * Implementation of the database functions.
  21. *
  22. * This file implements all the database related functions defined in
  23. * {@link db.h}. It also defines and implements some static functions used by
  24. * them.
  25. */
  26. #include <stdio.h>
  27. #include <sqlite3.h>
  28. #include <string.h>
  29. #include <sys/stat.h>
  30. #include <unistd.h>
  31. #include "../runeoptimizer.h"
  32. #include "../error/error.h"
  33. #include "db.h"
  34. /**
  35. * Ensures that the directory structure for the database exist.
  36. *
  37. * Creates the required directories for the file in the glovan variable
  38. * {@link db_location}. It doesn't create the database file itself. It doesn't
  39. * have return values, so the caller won't know if the folder structure was
  40. * succesfully created, but {@link db_open} will throw an error when called
  41. * if they werent created.
  42. */
  43. static void db_create_directories();
  44. /**
  45. * Creates all database tables.
  46. *
  47. * Runs CREATE TABLE stetements against the database to set up all the tables
  48. * the application uses. It is called from {@link db_open} if it detects that
  49. * the database has just been created. All the statements contains the IF NOT
  50. * EXIST clause, so there will be no errors if they actually exists.
  51. *
  52. * In case of error, it will print a message to stderr.
  53. *
  54. * @return {@link SUCCESS} if all the tables were created, or an error defined
  55. * in {@link error.h} if one or more tables could not be created.
  56. */
  57. static int db_create_tables();
  58. extern int db_close(){
  59. if (db != NULL){
  60. int result = sqlite3_close_v2(db);
  61. if (result != SQLITE_OK){
  62. fprintf(
  63. stderr,
  64. "Error closing database connection: %s", sqlite3_errmsg(db)
  65. );
  66. return(result);
  67. }
  68. }
  69. db = NULL;
  70. return(SUCCESS);
  71. }
  72. extern int db_open(char *path){
  73. db_close();
  74. char exists = TRUE;
  75. if (access( db_location, F_OK ) != 0) {
  76. exists = FALSE;
  77. db_create_directories();
  78. }
  79. // Get the path, relative to the program
  80. char location[sizeof(db_location)];
  81. // If db specified as argument, use it, else use the default location.
  82. if (path == NULL) strcpy(location, db_location);
  83. else strcpy(location, path);
  84. if (
  85. SUCCESS !=
  86. sqlite3_open_v2(
  87. location, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL
  88. )
  89. ){
  90. fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db));
  91. db_close();
  92. return(ERROR_DB_CANT_OPEN);
  93. }
  94. // If the database was just created, create the tables
  95. if (exists == FALSE && access( db_location, F_OK ) == 0){
  96. if (SUCCESS != db_create_tables()){
  97. return ERROR_DB_CANT_OPEN;
  98. }
  99. }
  100. return(SUCCESS);
  101. }
  102. extern int db_query(sqlite3_stmt **stmt, char query[], char *parameters[]){
  103. // If the connection has not been initialized, do it now
  104. if (NULL == db && SUCCESS != db_open(NULL)){
  105. return ERROR_DB_CANT_OPEN;
  106. }
  107. if (SQLITE_OK != sqlite3_prepare_v2(db, query, -1, stmt, 0)) {
  108. fprintf(
  109. stderr, "ERROR executing query '%s': %s\n", query, sqlite3_errmsg(db)
  110. );
  111. sqlite3_finalize(*stmt);
  112. return(ERROR_DB_QUERY);
  113. }
  114. // Loop and bind parameters
  115. char total_parameters = sqlite3_bind_parameter_count(*stmt);
  116. if (total_parameters > 0 && parameters == NULL){
  117. return(ERROR_DB_QUERY_NO_PARAMETERS);
  118. }
  119. for (int i = 0; i < total_parameters; i ++){
  120. sqlite3_bind_text(
  121. *stmt, i + 1, parameters[i], strlen(parameters[i]), NULL
  122. );
  123. }
  124. //printf("PREP QUERY: %s\n", sqlite3_expanded_sql(*stmt));
  125. return(SUCCESS);
  126. }
  127. extern int db_execute(char query[], char *parameters[]){
  128. // If the connection has not been initialized, do it now
  129. if (NULL == db && SUCCESS != db_open(NULL)){
  130. return ERROR_DB_CANT_OPEN;
  131. }
  132. sqlite3_stmt *stmt;
  133. if (SQLITE_OK != sqlite3_prepare_v2(db, query, -1, &stmt, 0)) {
  134. fprintf(
  135. stderr, "ERROR executing statement '%s': %s\n",
  136. query, sqlite3_errmsg(db)
  137. );
  138. sqlite3_finalize(stmt);
  139. return(ERROR_DB_EXECUTE);
  140. }
  141. // Loop and bind parameters
  142. char total_parameters = sqlite3_bind_parameter_count(stmt);
  143. if (total_parameters > 0 && parameters == NULL){
  144. return(ERROR_DB_EXECUTE_NO_PARAMETERS);
  145. }
  146. for (int i = 0; i < total_parameters; i ++){
  147. sqlite3_bind_text(
  148. stmt, i + 1, parameters[i], strlen(parameters[i]), NULL
  149. );
  150. }
  151. //printf("PREP QUERY: %s\n", sqlite3_expanded_sql(stmt));
  152. if (SQLITE_DONE != sqlite3_step(stmt)){
  153. fprintf(
  154. stderr, "ERROR Executing statement '%s': %s\n",
  155. query, sqlite3_errmsg(db)
  156. );
  157. sqlite3_finalize(stmt);
  158. return(ERROR_DB_EXECUTE);
  159. }
  160. sqlite3_finalize(stmt);
  161. return(SUCCESS);
  162. }
  163. static void db_create_directories(){
  164. char dir_to_make[sizeof(db_location)];
  165. int last_path_separator = -1;
  166. for(int i = 0; i < (int) strlen(db_location); i ++){
  167. if(db_location[i] == '/' || db_location[i] == '\\'){
  168. last_path_separator = i + 1;
  169. }
  170. }
  171. if (last_path_separator != -1){
  172. strncpy(dir_to_make, db_location, last_path_separator);
  173. dir_to_make[last_path_separator] = '\0';
  174. }
  175. #ifdef _WIN32
  176. mkdir(dir_to_make);
  177. #else
  178. mkdir(dir_to_make, 0777);
  179. #endif
  180. return;
  181. }
  182. static int db_create_tables(){
  183. // Table rune_stats
  184. if (
  185. SUCCESS !=
  186. db_execute(
  187. "CREATE TABLE IF NOT EXISTS rune_stats("
  188. " rune CHAR(12), slot INT, stat INT, value INT, grind INT, enchant INT"
  189. ");",
  190. NULL
  191. )
  192. ){
  193. fprintf(
  194. stderr,
  195. "Unable to create table rune_stats: %s\n", sqlite3_errmsg(db)
  196. );
  197. return ERROR_DB_CREATE_RUNE_STATS;
  198. }
  199. // Table runes
  200. if (
  201. SUCCESS !=
  202. db_execute(
  203. "CREATE TABLE IF NOT EXISTS runes("
  204. " id CHAR(12),"
  205. " unit CHAR(12),"
  206. " type INT,"
  207. " slot INT,"
  208. " stars INT,"
  209. " level INT,"
  210. " quality INT,"
  211. " efficiency FLOAT,"
  212. " max_efficiency FLOAT,"
  213. " main_stat INT,"
  214. " current_hp_percent INT,"
  215. " current_atk_percent INT,"
  216. " current_def_percent INT,"
  217. " current_hp_flat INT,"
  218. " current_atk_flat INT,"
  219. " current_def_flat INT,"
  220. " current_spd INT,"
  221. " current_crr INT,"
  222. " current_crd INT,"
  223. " current_acc INT,"
  224. " current_res INT,"
  225. " lv12_hp_percent INT,"
  226. " lv12_atk_percent INT,"
  227. " lv12_def_percent INT,"
  228. " lv12_hp_flat INT,"
  229. " lv12_atk_flat INT,"
  230. " lv12_def_flat INT,"
  231. " lv12_spd INT,"
  232. " lv12_crr INT,"
  233. " lv12_crd INT,"
  234. " lv12_acc INT,"
  235. " lv12_res INT,"
  236. " lv15_hp_percent INT,"
  237. " lv15_atk_percent INT,"
  238. " lv15_def_percent INT,"
  239. " lv15_hp_flat INT,"
  240. " lv15_atk_flat INT,"
  241. " lv15_def_flat INT,"
  242. " lv15_spd INT,"
  243. " lv15_crr INT,"
  244. " lv15_crd INT,"
  245. " lv15_acc INT,"
  246. " lv15_res INT"
  247. ");",
  248. NULL
  249. )
  250. ){
  251. fprintf(
  252. stderr, "Unable to create table runes: %s\n", sqlite3_errmsg(db)
  253. );
  254. return ERROR_DB_CREATE_RUNES;
  255. }
  256. // Table units
  257. if (
  258. SUCCESS !=
  259. db_execute(
  260. "CREATE TABLE IF NOT EXISTS units("
  261. " id CHAR(12),"
  262. " monster INT,"
  263. " name CHAR(128),"
  264. " stars INT,"
  265. " level INT,"
  266. " storage INT,"
  267. " base_hp INT,"
  268. " base_atk INT,"
  269. " base_def INT,"
  270. " base_spd INT,"
  271. " base_crr INT,"
  272. " base_crd INT,"
  273. " base_res INT,"
  274. " base_acc INT,"
  275. " current_hp INT,"
  276. " current_atk INT,"
  277. " current_def INT,"
  278. " current_spd INT,"
  279. " current_crr INT,"
  280. " current_crd INT,"
  281. " current_res INT,"
  282. " current_acc INT"
  283. ");",
  284. NULL
  285. )
  286. ){
  287. fprintf(
  288. stderr,
  289. "Unable to create table units: %s\n", sqlite3_errmsg(db)
  290. );
  291. return ERROR_DB_CREATE_UNITS;
  292. }
  293. // Table info
  294. if (
  295. SUCCESS !=
  296. db_execute(
  297. "CREATE TABLE IF NOT EXISTS info("
  298. " player_id CHAR(12),"
  299. " player_name CHAR(64),"
  300. " player_level INT,"
  301. " ts DATETIME,"
  302. " modified INT"
  303. ");",
  304. NULL
  305. )
  306. ){
  307. fprintf(
  308. stderr,
  309. "Unable to create table info: %s\n", sqlite3_errmsg(db)
  310. );
  311. return ERROR_DB_CREATE_INFO;
  312. }
  313. // Tables teams and units_teams
  314. if (
  315. SUCCESS !=
  316. db_execute(
  317. "CREATE TABLE IF NOT EXISTS "
  318. "units_teams(unit CHAR(12), team CHAR(12));",
  319. NULL
  320. )
  321. ){
  322. fprintf(
  323. stderr,
  324. "Unable to create table units_teams: %s\n", sqlite3_errmsg(db)
  325. );
  326. return ERROR_DB_CREATE_UNITS_TEAMS;
  327. }
  328. if (
  329. SUCCESS !=
  330. db_execute(
  331. "CREATE TABLE IF NOT EXISTS "
  332. "teams(id CHAR(12), name CHAR(50), priority INT);",
  333. NULL
  334. )
  335. ){
  336. fprintf(
  337. stderr,
  338. "Unable to create table teams: %s\n", sqlite3_errmsg(db)
  339. );
  340. return ERROR_DB_CREATE_TEAMS;
  341. }
  342. return SUCCESS;
  343. }