summaryrefslogtreecommitdiffstatsabout
path: root/mod_log_sql_mysql.c
diff options
context:
space:
mode:
Diffstat (limited to 'mod_log_sql_mysql.c')
-rw-r--r--mod_log_sql_mysql.c219
1 files changed, 101 insertions, 118 deletions
diff --git a/mod_log_sql_mysql.c b/mod_log_sql_mysql.c
index 3f05935..d0666fe 100644
--- a/mod_log_sql_mysql.c
+++ b/mod_log_sql_mysql.c
@@ -1,4 +1,4 @@
1/* $Id: mod_log_sql_mysql.c,v 1.1 2004/02/29 23:36:18 urkle Exp $ */ 1/* $Id: mod_log_sql_mysql.c,v 1.2 2004/03/02 05:34:50 urkle Exp $ */
2#include "mysql.h" 2#include "mysql.h"
3#include "mysqld_error.h" 3#include "mysqld_error.h"
4 4
@@ -28,160 +28,133 @@
28/* The enduser won't modify these */ 28/* The enduser won't modify these */
29#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away") 29#define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away")
30 30
31logsql_opendb log_sql_mysql_connect(server_rec *s, logsql_dbconnection *db, 31/* Connect to the MYSQL database */
32 apr_table_t *dbparms) 32logsql_opendb_ret log_sql_mysql_connect(server_rec *s, logsql_dbconnection *db)
33{ 33{
34 MYSQL *dblink; 34 const char *host = apr_table_get(db->parms,"host");
35 char *host = apr_table_get(dbparms,"host"); 35 const char *user = apr_table_get(db->parms,"user");
36 char *user = apr_table_get(dbparms,"user"); 36 const char *passwd = apr_table_get(db->parms,"passwd");
37 char *passwd = apr_table_get(dbparms,"passwd"); 37 const char *database = apr_table_get(db->parms,"database");
38 char *database = apr_table_get(dbparms,"database"); 38 unsigned int tcpport = atoi(apr_table_get(db->parms,"tcpport"));
39 char *tcpport = apr_table_get(dbparms,"tcpport"); 39 const char *socketfile = apr_table_get(db->parms,"socketfile");
40 char *socketfile = apr_table_get(dbparms,"socketfile"); 40 MYSQL *dblink = db->handle;
41 mysql_init(&dblink); 41
42 if (mysql_real_connect(&dblink, host, user, passwd, database, tcpport, 42 dblink = mysql_init(dblink);
43 socketfile, 0) { 43 db->handle = (void *)dblink;
44
45 if (mysql_real_connect(dblink, host, user, passwd, database, tcpport,
46 socketfile, 0)) {
44 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", 47 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'",
45 host, tcpport, database, user, socketfile); 48 host, tcpport, database, user, socketfile);
46 return LOGSQL_OPENDB_SUCCESS; 49 return LOGSQL_OPENDB_SUCCESS;
47 } else { 50 } else {
48 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: database connection error: %s", 51 log_error(APLOG_MARK,APLOG_DEBUG,s,"mod_log_sql: database connection error: %s",
49 MYSQL_ERROR(&dblink)); 52 MYSQL_ERROR(dblink));
50 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", 53 log_error(APLOG_MARK,APLOG_DEBUG,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'",
51 host, tcpport, database, user, socketfile); 54 host, tcpport, database, user, socketfile);
52 return LOGSQL_OPENDB_FAIL; 55 return LOGSQL_OPENDB_FAIL;
53 } 56 }
54} 57}
55 58
56/*-----------------------------------------------------* 59void log_sql_mysql_close(logsql_dbconnection *db)
57 * safe_sql_query: perform a database query with * 60{
58 * a degree of safety and error checking. * 61 mysql_close((MYSQL *)db->handle);
59 * * 62}
60 * Parms: request record, SQL insert statement * 63
61 * Returns: 0 (OK) on success * 64/* Routine to escape the 'dangerous' characters that would otherwise
62 * 1 if have no log handle * 65 * corrupt the INSERT string: ', \, and "
63 * 2 if insert delayed failed (kluge) * 66 */
64 * the actual MySQL return code on error * 67const char *log_sql_mysql_escape(const char *from_str, apr_pool_t *p,
65 *-----------------------------------------------------*/ 68 logsql_dbconnection *db)
66unsigned int log_sql_mysql_query(request_rec *r, const char *query) 69{
70 if (!from_str)
71 return NULL;
72 else {
73 char *to_str;
74 unsigned long length = strlen(from_str);
75 unsigned long retval;
76
77 /* Pre-allocate a new string that could hold twice the original, which would only
78 * happen if the whole original string was 'dangerous' characters.
79 */
80 to_str = (char *) apr_palloc(p, length * 2 + 1);
81 if (!to_str) {
82 return from_str;
83 }
84
85 if (!db->connected) {
86 /* Well, I would have liked to use the current database charset. mysql is
87 * unavailable, however, so I fall back to the slightly less respectful
88 * mysql_escape_string() function that uses the default charset.
89 */
90 retval = mysql_escape_string(to_str, from_str, length);
91 } else {
92 /* MySQL is available, so I'll go ahead and respect the current charset when
93 * I perform the escape.
94 */
95 retval = mysql_real_escape_string((MYSQL *)db->handle, to_str, from_str, length);
96 }
97
98 if (retval)
99 return to_str;
100 else
101 return from_str;
102 }
103}
104
105logsql_query_ret log_sql_mysql_query(request_rec *r,logsql_dbconnection *db,
106 const char *query)
67{ 107{
68 int retval; 108 int retval;
69 struct timespec delay, remainder;
70 int ret;
71 void (*handler) (int); 109 void (*handler) (int);
72 logsql_state *cls;
73 unsigned int real_error = 0; 110 unsigned int real_error = 0;
74 const char *real_error_str = NULL; 111 /*const char *real_error_str = NULL;*/
112
113 MYSQL *dblink = (MYSQL *)db->handle;
75 114
115 if (!dblink) {
116 return LOGSQL_QUERY_NOLINK;
117 }
76 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */ 118 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
77 handler = signal(SIGPIPE, SIG_IGN); 119 handler = signal(SIGPIPE, SIG_IGN);
78 120
79 /* First attempt for the query */ 121 /* Run the query */
80 if (!global_config.server_p) { 122 if (!(retval = mysql_query(dblink, query))) {
81 signal(SIGPIPE, handler);
82 return 1;
83 } else if (!(retval = mysql_query(global_config.server_p, query))) {
84 signal(SIGPIPE, handler); 123 signal(SIGPIPE, handler);
85 return 0; 124 return LOGSQL_QUERY_SUCCESS;
86 } 125 }
87
88 /* If we ran the query and it returned an error, try to be robust.
89 * (After all, the module thought it had a valid mysql_log connection but the query
90 * could have failed for a number of reasons, so we have to be extra-safe and check.) */
91
92 /* Check to see if the error is "nonexistent table" */ 126 /* Check to see if the error is "nonexistent table" */
93 if (global_config.insertdelayed) { 127 real_error = mysql_errno(dblink);
94 real_error_str = MYSQL_ERROR(global_config.server_p); 128
95 retval = (strstr(real_error_str, "Table")) && (strstr(real_error_str,"doesn't exist")); 129 if (real_error == ER_NO_SUCH_TABLE) {
96 } else {
97 real_error = mysql_errno(global_config.server_p);
98 retval = (real_error == ER_NO_SUCH_TABLE);
99 }
100 if (retval) {
101 log_error(APLOG_MARK,APLOG_ERR,r->server,"table does not exist, preserving query"); 130 log_error(APLOG_MARK,APLOG_ERR,r->server,"table does not exist, preserving query");
102 preserve_entry(r, query);
103 /* Restore SIGPIPE to its original handler function */ 131 /* Restore SIGPIPE to its original handler function */
104 signal(SIGPIPE, handler); 132 signal(SIGPIPE, handler);
105 return ER_NO_SUCH_TABLE; 133 return LOGSQL_QUERY_NOTABLE;
106 } 134 }
107 135
108 /* Handle all other types of errors */
109
110 cls = ap_get_module_config(r->server->module_config, &log_sql_module);
111
112 /* Something went wrong, so start by trying to restart the db link. */
113 if (global_config.insertdelayed) {
114 real_error = 2;
115 } /*else {
116 real_error = mysql_errno(global_config.server_p);
117 }*/
118
119 log_error(APLOG_MARK,APLOG_ERR,r->server,"first attempt failed, API said: error %d, \"%s\"", real_error, MYSQL_ERROR(global_config.server_p));
120 mysql_close(global_config.server_p);
121 global_config.server_p = NULL;
122 open_logdb_link(r->server);
123
124 if (global_config.server_p == NULL) { /* still unable to link */
125 signal(SIGPIPE, handler);
126 log_error(APLOG_MARK,APLOG_ERR,r->server,"reconnect failed, unable to reach database. SQL logging stopped until child regains a db connection.");
127 log_error(APLOG_MARK,APLOG_ERR,r->server,"log entries are being preserved in %s", cls->preserve_file);
128 return 1;
129 } else
130 log_error(APLOG_MARK,APLOG_ERR,r->server,"db reconnect successful");
131
132 /* First sleep for a tiny amount of time. */
133 delay.tv_sec = 0;
134 delay.tv_nsec = 250000000; /* max is 999999999 (nine nines) */
135 ret = nanosleep(&delay, &remainder);
136 if (ret && errno != EINTR)
137 log_error(APLOG_MARK,APLOG_ERR,r->server,"nanosleep unsuccessful");
138
139 /* Then make our second attempt */
140 retval = mysql_query(global_config.server_p,query);
141
142 /* If this one also failed, log that and append to our local offline file */
143 if (retval) {
144 if (global_config.insertdelayed) {
145 real_error = 2;
146 } else {
147 real_error = mysql_errno(global_config.server_p);
148 }
149
150 log_error(APLOG_MARK,APLOG_ERR,r->server,"second attempt failed, API said: error %d, \"%s\" -- preserving", real_error, MYSQL_ERROR(global_config.server_p));
151 preserve_entry(r, query);
152 retval = real_error;
153 } else {
154 log_error(APLOG_MARK,APLOG_ERR,r->server,"second attempt successful");
155 retval = 0;
156 }
157 /* Restore SIGPIPE to its original handler function */ 136 /* Restore SIGPIPE to its original handler function */
158 signal(SIGPIPE, handler); 137 signal(SIGPIPE, handler);
159 return retval; 138 return LOGSQL_QUERY_FAIL;
160} 139}
161 140
162/*-----------------------------------------------------* 141logsql_table_ret log_sql_mysql_create(request_rec *r, logsql_dbconnection *db,
163 * safe_create_tables: create SQL table set for the * 142 logsql_tabletype table_type, const char *table_name)
164 * virtual server represented by cls. *
165 * *
166 * Parms: virtserver structure, request record, *
167 * tables to create *
168 * Returns: 0 on no errors *
169 * mysql error code on failure *
170 *-----------------------------------------------------*/
171int mod_log_mysql_create_tables(request_rec *r, logsql_tabletype table_type,
172 const char *table_name)
173{ 143{
174 int retval; 144 int retval;
175 145 const char *tabletype = apr_table_get(db->parms,"tabletype");
146 void (*handler) (int);
176 char *type_suffix = NULL; 147 char *type_suffix = NULL;
177 148
178 char *create_prefix = "create table if not exists `"; 149 char *create_prefix = "create table if not exists `";
179 char *create_suffix = NULL; 150 char *create_suffix = NULL;
180 char *create_sql; 151 char *create_sql;
181 152
182 if (!global_config.createtables) { 153 MYSQL *dblink = (MYSQL *)db->handle;
154
155/* if (!global_config.createtables) {
183 return APR_SUCCESS; 156 return APR_SUCCESS;
184 } 157 }*/
185 158
186 switch (table_type) { 159 switch (table_type) {
187 case LOGSQL_TABLE_ACCESS: 160 case LOGSQL_TABLE_ACCESS:
@@ -223,9 +196,9 @@ int mod_log_mysql_create_tables(request_rec *r, logsql_tabletype table_type,
223 break; 196 break;
224 } 197 }
225 198
226 if (global_config.tabletype) { 199 if (tabletype) {
227 type_suffix = apr_pstrcat(r->pool, " TYPE=", 200 type_suffix = apr_pstrcat(r->pool, " TYPE=",
228 global_config.tabletype, NULL); 201 tabletype, NULL);
229 } 202 }
230 /* Find memory long enough to hold the whole CREATE string + \0 */ 203 /* Find memory long enough to hold the whole CREATE string + \0 */
231 create_sql = apr_pstrcat(r->pool, create_prefix, table_name, create_suffix, 204 create_sql = apr_pstrcat(r->pool, create_prefix, table_name, create_suffix,
@@ -233,9 +206,19 @@ int mod_log_mysql_create_tables(request_rec *r, logsql_tabletype table_type,
233 206
234 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"create string: %s", create_sql); 207 log_error(APLOG_MARK,APLOG_DEBUG,r->server,"create string: %s", create_sql);
235 208
236 if ((retval = safe_sql_query(r, create_sql))) { 209 if (!dblink) {
210 return LOGSQL_QUERY_NOLINK;
211 }
212 /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */
213 handler = signal(SIGPIPE, SIG_IGN);
214
215 /* Run the create query */
216 if ((retval = mysql_query(dblink, create_sql))) {
237 log_error(APLOG_MARK,APLOG_ERR,r->server,"failed to create table: %s", 217 log_error(APLOG_MARK,APLOG_ERR,r->server,"failed to create table: %s",
238 table_name); 218 table_name);
219 signal(SIGPIPE, handler);
220 return LOGSQL_TABLE_FAIL;
239 } 221 }
240 return retval; 222 signal(SIGPIPE, handler);
223 return LOGSQL_TABLE_SUCCESS;
241} 224}