1 /* mysqlConn.c - NeonServ v5.6
2 * Copyright (C) 2011-2012 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "mysqlConn.h"
19 #include "ConfigParser.h"
20 #define DATABASE_VERSION "20"
22 static void show_mysql_error();
24 struct mysql_conn_struct {
27 struct used_result *used_results;
28 struct escaped_string *escaped_strings;
29 struct mysql_conn_struct *next;
34 struct used_result *next;
37 struct escaped_string {
39 struct escaped_string *next;
42 struct mysql_conn_struct *get_mysql_conn_struct();
44 struct mysql_conn_struct *mysql_conns = NULL;
45 static int mysql_serverport;
46 static char *mysql_host, *mysql_user, *mysql_pass, *mysql_base;
49 static pthread_mutex_t synchronized;
52 static void check_mysql() {
53 MYSQL *mysql_conn = get_mysql_conn();
55 if((errid = mysql_ping(mysql_conn))) {
56 if(mysql_errno(mysql_conn) == CR_SERVER_GONE_ERROR) {
57 if(!mysql_real_connect(mysql_conn, mysql_host, mysql_user, mysql_pass, mysql_base, mysql_serverport, NULL, 0)) {
67 MYSQL_RES *mysql_use() {
68 struct mysql_conn_struct *mysql_conn = get_mysql_conn_struct();
69 MYSQL_RES *res = mysql_store_result(mysql_conn->mysql_conn);
70 struct used_result *result = malloc(sizeof(*result));
72 mysql_free_result(res);
76 result->next = mysql_conn->used_results;
77 mysql_conn->used_results = result;
82 struct mysql_conn_struct *mysql_conn = get_mysql_conn_struct();
83 if(!mysql_conn) return;
84 struct used_result *result, *next_result;
85 for(result = mysql_conn->used_results; result; result = next_result) {
86 next_result = result->next;
87 mysql_free_result(result->result);
90 mysql_conn->used_results = NULL;
91 struct escaped_string *escaped, *next_escaped;
92 for(escaped = mysql_conn->escaped_strings; escaped; escaped = next_escaped) {
93 next_escaped = escaped->next;
94 free(escaped->string);
97 mysql_conn->escaped_strings = NULL;
101 char *new_mysql_host = get_string_field("MySQL.host");
102 char *new_mysql_user = get_string_field("MySQL.user");
103 char *new_mysql_pass = get_string_field("MySQL.pass");
104 char *new_mysql_base = get_string_field("MySQL.base");
105 if(!(new_mysql_host && new_mysql_user && new_mysql_pass && new_mysql_base))
111 mysql_host = strdup(new_mysql_host);
115 mysql_user = strdup(new_mysql_user);
119 mysql_pass = strdup(new_mysql_pass);
123 mysql_base = strdup(new_mysql_base);
125 mysql_serverport = get_int_field("MySQL.port");
126 if(!mysql_serverport)
127 mysql_serverport = 3306;
132 THREAD_MUTEX_INIT(synchronized);
134 MYSQL *mysql_conn = get_mysql_conn();
136 //check database version...
138 if(!mysql_query(mysql_conn, "SELECT `database_version` FROM `version`")) {
139 MYSQL_RES *res = mysql_use();
141 if((row = mysql_fetch_row(res))) {
142 version = atoi(row[0]);
147 FILE *f = fopen("database.sql", "r");
148 mysql_set_server_option(mysql_conn, MYSQL_OPTION_MULTI_STATEMENTS_ON);
151 char query_buffer[8192];
152 int query_buffer_pos = 0;
153 while (fgets(line, sizeof(line), f)) {
154 query_buffer_pos += sprintf(query_buffer + query_buffer_pos, " %s", line);
155 if(line[(strlen(line) - 2)] == ';') {
156 if(mysql_query(mysql_conn, query_buffer))
158 query_buffer_pos = 0;
163 f = fopen("database.defaults.sql", "r");
166 char query_buffer[131072];
167 int query_buffer_pos = 0;
168 while (fgets(line, sizeof(line), f)) {
169 query_buffer_pos += sprintf(query_buffer + query_buffer_pos, " %s", line);
170 if(line[(strlen(line) - 2)] == ';') {
171 if(mysql_query(mysql_conn, query_buffer))
173 query_buffer_pos = 0;
179 MYSQL_RES *res = mysql_store_result(mysql_conn);
180 mysql_free_result(res);
181 } while(!mysql_next_result(mysql_conn));
182 mysql_set_server_option(mysql_conn, MYSQL_OPTION_MULTI_STATEMENTS_OFF);
183 mysql_query(mysql_conn, "INSERT INTO `version` (`database_version`) VALUES ('" DATABASE_VERSION "')");
185 else if(version < atoi(DATABASE_VERSION)) {
187 FILE *f = fopen("database.upgrade.sql", "r");
188 mysql_set_server_option(mysql_conn, MYSQL_OPTION_MULTI_STATEMENTS_ON);
191 char query_buffer[8192];
192 int query_buffer_pos = 0, use_querys = 0;
193 sprintf(query_buffer, "-- version: %d", version);
194 while (fgets(line, sizeof(line), f)) {
196 query_buffer_pos += sprintf(query_buffer + query_buffer_pos, " %s", line);
197 if(line[strlen(line) - 1] == ';') {
198 mysql_query(mysql_conn, query_buffer);
199 query_buffer_pos = 0;
201 } else if(!stricmplen(query_buffer, line, strlen(query_buffer))) {
205 if(query_buffer_pos) {
206 if(mysql_query(mysql_conn, query_buffer))
211 perror("database.sql missing!");
213 MYSQL_RES *res = mysql_store_result(mysql_conn);
214 mysql_free_result(res);
215 } while(!mysql_next_result(mysql_conn));
216 mysql_set_server_option(mysql_conn, MYSQL_OPTION_MULTI_STATEMENTS_OFF);
217 mysql_query(mysql_conn, "UPDATE `version` SET `database_version` = '" DATABASE_VERSION "'");
222 struct mysql_conn_struct *mysql_conn, *next;
223 for(mysql_conn = mysql_conns; mysql_conn; mysql_conn = next) {
224 next = mysql_conn->next;
225 mysql_close(mysql_conn->mysql_conn);
231 static void show_mysql_error() {
232 MYSQL *mysql_conn = get_mysql_conn();
234 putlog(LOGLEVEL_ERROR, "MySQL Error: %s\n", mysql_error(mysql_conn));
237 void printf_mysql_query(const char *text, ...) {
238 MYSQL *mysql_conn = get_mysql_conn();
240 char queryBuf[MYSQLMAXLEN];
243 va_start(arg_list, text);
244 pos = vsnprintf(queryBuf, MYSQLMAXLEN - 2, text, arg_list);
246 if (pos < 0 || pos > (MYSQLMAXLEN - 2)) pos = MYSQLMAXLEN - 2;
247 queryBuf[pos] = '\0';
248 putlog(LOGLEVEL_MYSQL, "MySQL: %s\n", queryBuf);
249 if(mysql_query(mysql_conn, queryBuf)) {
251 if(mysql_query(mysql_conn, queryBuf)) {
257 void printf_long_mysql_query(int len, const char *text, ...) {
258 MYSQL *mysql_conn = get_mysql_conn();
263 va_start(arg_list, text);
264 pos = vsnprintf(queryBuf, len - 2, text, arg_list);
266 if (pos < 0 || pos > (len - 2)) pos = len - 2;
267 queryBuf[pos] = '\0';
268 putlog(LOGLEVEL_MYSQL, "MySQL: %s\n", queryBuf);
269 if(mysql_query(mysql_conn, queryBuf)) {
271 if(mysql_query(mysql_conn, queryBuf)) {
277 char* escape_string(const char *str) {
278 struct mysql_conn_struct *mysql_conn = get_mysql_conn_struct();
279 struct escaped_string *escapedstr = malloc(sizeof(*escapedstr));
283 char escaped[strlen(str)*2+1];
284 mysql_real_escape_string(mysql_conn->mysql_conn, escaped, str, strlen(str));
285 escapedstr->string = strdup(escaped);
286 escapedstr->next = mysql_conn->escaped_strings;
287 mysql_conn->escaped_strings = escapedstr;
288 return escapedstr->string;
291 struct mysql_conn_struct *get_mysql_conn_struct() {
292 SYNCHRONIZE(synchronized);
293 struct mysql_conn_struct *mysql_conn;
296 tid = (unsigned int) pthread_self_tid();
300 for(mysql_conn = mysql_conns; mysql_conn; mysql_conn = mysql_conn->next) {
301 if(mysql_conn->tid == tid) {
302 DESYNCHRONIZE(synchronized);
306 mysql_conn = malloc(sizeof(*mysql_conn));
307 mysql_conn->mysql_conn = mysql_init(NULL);
308 mysql_conn->tid = tid;
309 mysql_conn->used_results = NULL;
310 mysql_conn->escaped_strings = NULL;
311 mysql_conn->next = mysql_conns;
312 mysql_conns = mysql_conn;
313 if (!mysql_real_connect(mysql_conn->mysql_conn, mysql_host, mysql_user, mysql_pass, mysql_base, mysql_serverport, NULL, 0)) {
317 DESYNCHRONIZE(synchronized);
321 MYSQL *get_mysql_conn() {
322 struct mysql_conn_struct *mysql_conn = get_mysql_conn_struct();
323 return mysql_conn->mysql_conn;