OSDN Git Service

* Changed DEBUG Log.
[modchxj/mod_chxj.git] / src / chxj_mysql.c
1 /*
2  * Copyright (C) 2005-2011 Atsushi Konno All rights reserved.
3  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #ifdef USE_MYSQL_COOKIE
18 #include "mod_chxj.h"
19 #include "chxj_cookie.h"
20 #include "chxj_url_encode.h"
21 #include "chxj_apply_convrule.h"
22
23 #include "ap_release.h"
24
25 #include "apu.h"
26 #include "apr_uuid.h"
27 #include "apr_md5.h"
28 #include "apr_base64.h"
29 #include "apr_uri.h"
30
31 #include <unistd.h>
32
33 /* for MySQL */
34 #include <mysql.h>
35 #include <errmsg.h>
36
37
38 #define CHXJ_MYSQL_RECONNECT_WAIT_TIME (5000)
39 #define CHXJ_MYSQL_RECONNECT_COUNT (3)
40
41 typedef struct {
42   MYSQL *handle;
43   char host[255];
44   char username[255];
45   char database[255];
46   time_t last_used;
47   int reconnect;
48 } mysql_connection;
49
50 static mysql_connection connection = {NULL, "", "", "", 0, 0};
51
52
53 static apr_status_t
54 _mysql_cleanup(void *UNUSED(notused))
55 {
56   chxj_close_mysql_handle();
57   return APR_SUCCESS;
58 }
59
60 static apr_status_t
61 _mysql_cleanup_child(void *UNUSED(notused))
62 {
63   return APR_SUCCESS;
64 }
65
66
67 void
68 chxj_close_mysql_handle()
69 {
70   if (connection.handle) {
71     mysql_close(connection.handle);
72     connection.handle = NULL;
73   }
74 }
75
76 int
77 chxj_open_mysql_handle(request_rec *r, mod_chxj_config *m)
78 {
79   static MYSQL mysql_conn;
80   char query[MAX_STRING_LEN];
81
82   if (connection.handle && connection.reconnect == 0) {
83     if ((!m->mysql.host || (strcasecmp(m->mysql.host, "localhost") == 0)) && connection.host[0] == '\0'
84         &&  (m->mysql.username && strcmp(m->mysql.username, connection.username) == 0)) {
85
86       if (m->mysql.database && strcmp(m->mysql.database, connection.database) == 0) {
87         DBG(r,"REQ[%X] already connected",TO_ADDR(r));
88         DBG(r,"REQ[%X] end chxj_open_mysql_handle()",TO_ADDR(r));
89         return 1;
90       }
91       else {
92         if (mysql_select_db(connection.handle,m->mysql.database) != 0) {
93           ERR(r, "%s:%d MySQL ERROR: %s", APLOG_MARK, mysql_error(connection.handle));
94           return 0;
95         }
96         else {
97           strcpy (connection.database, m->mysql.database);
98           DBG(r,"REQ[%X] already connected. new database:[%s]", TO_ADDR(r),m->mysql.database);
99           return 1;
100         }
101       }
102     }
103   }
104
105   chxj_close_mysql_handle();
106   connection.handle = mysql_init(&mysql_conn);
107   if (! connection.handle) {
108     ERR(r, "%s:%d MySQL ERROR: %s", APLOG_MARK, mysql_error(&mysql_conn));
109     return 0;
110   }
111
112   if (!m->mysql.host || strcmp(m->mysql.host,"localhost") == 0) {
113     connection.host[0] = '\0';
114   } else {
115     strcpy(connection.host, m->mysql.host);
116   }
117
118   connection.handle = mysql_real_connect(&mysql_conn,connection.host,m->mysql.username,
119                                   m->mysql.password, NULL, m->mysql.port, m->mysql.socket_path, 0);
120   if (!connection.handle) {
121     ERR(r,"REQ[%X] MySQL ERROR: %s. host:[%s] username:[%s] password:[%s] port:[%d] socket_path:[%s]",
122        TO_ADDR(r),
123        mysql_error(&mysql_conn), 
124        connection.host, 
125        m->mysql.username,
126        m->mysql.password,
127        m->mysql.port,
128        m->mysql.socket_path);
129     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
130     return 0;
131   }
132
133   apr_pool_cleanup_register(r->pool, (void *)NULL, _mysql_cleanup, _mysql_cleanup_child);
134   if (m->mysql.username) {
135     strcpy(connection.username, m->mysql.username);
136   }
137   else {
138     connection.username[0] = '\0';
139   }
140
141   if (mysql_select_db(connection.handle,m->mysql.database) != 0) {
142     ERR(r, "%s:%d MySQL ERROR: %s", APLOG_MARK, mysql_error(connection.handle));
143     return 0;
144   }
145
146   strcpy (connection.database, m->mysql.database);
147   if (m->mysql.charset) {
148     apr_snprintf(query, sizeof(query)-1, "SET CHARACTER SET %s", m->mysql.charset);
149     if (mysql_query(connection.handle, query) != 0) {
150       ERR(r, "REQ[%X] %s:%d MySQL ERROR: %s: %s", TO_ADDR(r),APLOG_MARK, mysql_error(connection.handle), r->uri);
151       return 0;
152     }
153   }
154
155   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
156   return 1;
157 }
158
159
160 int
161 chxj_mysql_exist_cookie_table(request_rec *r, mod_chxj_config *m)
162 {
163   MYSQL_RES *result;
164   char query[MAX_STRING_LEN];
165   int retry_count = 0;
166   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
167
168   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
169   apr_snprintf(query, sizeof(query)-1, "desc %s", m->mysql.tablename);
170   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
171   do { 
172     if (!chxj_open_mysql_handle(r, m)) {
173       ERR(r, "%s:%d failed chxj_open_mysql_handle() query:[%s]", APLOG_MARK, query);
174       return 0;
175     }
176     connection.reconnect = 0;
177     if (mysql_query(connection.handle, query) != 0) {
178       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
179         connection.reconnect = 1;
180         retry_count++;
181         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
182           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
183           return 0;
184         }
185         apr_sleep(wait_time);
186         continue;
187       }
188       WRN(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
189       return 0;
190     }
191   }
192   while(0);
193
194   result = mysql_store_result(connection.handle);
195   if (result) mysql_free_result(result);
196   
197   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
198   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
199
200   return 1;
201 }
202
203
204 int
205 chxj_mysql_exist_cookie_table_expire(request_rec *r, mod_chxj_config *m)
206 {
207   MYSQL_RES *result;
208   char query[MAX_STRING_LEN];
209   int retry_count = 0;
210   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
211
212   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
213   apr_snprintf(query, sizeof(query)-1, "desc %s_expire", m->mysql.tablename);
214   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
215
216   do { 
217     if (!chxj_open_mysql_handle(r, m)) {
218       ERR(r, "%s:%d failed chxj_open_mysql_handle() query:[%s]", APLOG_MARK, query);
219       return 0;
220     }
221     connection.reconnect = 0;
222     if (mysql_query(connection.handle, query) != 0) {
223       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
224         connection.reconnect = 1;
225         retry_count++;
226         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
227           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
228           return 0;
229         }
230         apr_sleep(wait_time);
231         continue;
232       }
233       WRN(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
234       return 0;
235     }
236   } while(0);
237
238   result = mysql_store_result(connection.handle);
239   if (result) mysql_free_result(result);
240
241   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
242   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
243
244   return 1;
245 }
246
247
248 int
249 chxj_mysql_create_cookie_table(request_rec *r, mod_chxj_config *m)
250 {
251   MYSQL_RES *result;
252   char query[MAX_STRING_LEN];
253   int retry_count = 0;
254   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
255
256   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
257   apr_snprintf(query, sizeof(query)-1, "CREATE TABLE %s  (cookie_id VARCHAR(%d) NOT NULL, data TEXT, PRIMARY KEY(cookie_id)) TYPE=InnoDB;",
258     m->mysql.tablename,
259     apr_base64_encode_len(APR_MD5_DIGESTSIZE) * 3);
260   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
261   do {
262     if (!chxj_open_mysql_handle(r, m)) {
263       ERR(r, "%s:%d failed chxj_open_mysql_handle() query:[%s]", APLOG_MARK, query);
264       return 0;
265     }
266     connection.reconnect = 0;
267     if (mysql_query(connection.handle, query) != 0) {
268       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
269         connection.reconnect = 1;
270         retry_count++;
271         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
272           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
273           return 0;
274         }
275         apr_sleep(wait_time);
276         continue;
277       }
278       WRN(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
279       return 0;
280     }
281   }
282   while(0);
283
284   result = mysql_store_result(connection.handle);
285   if (result) mysql_free_result(result);
286   
287   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
288   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
289
290   return 1;
291 }
292
293 int
294 chxj_mysql_create_cookie_expire_table(request_rec *r, mod_chxj_config *m)
295 {
296   MYSQL_RES *result;
297   char query[MAX_STRING_LEN];
298   int retry_count = 0;
299   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
300
301   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
302   apr_snprintf(query, sizeof(query)-1, "CREATE TABLE %s_expire  (cookie_id VARCHAR(%d) NOT NULL, created_at DATETIME, PRIMARY KEY(cookie_id)) TYPE=InnoDB;",
303     m->mysql.tablename,
304     apr_base64_encode_len(APR_MD5_DIGESTSIZE) * 3);
305
306   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
307
308   do {
309     if (!chxj_open_mysql_handle(r, m)) {
310       ERR(r, "%s:%d failed chxj_open_mysql_handle() query:[%s]", APLOG_MARK, query);
311       return 0;
312     }
313     connection.reconnect = 0;
314     if (mysql_query(connection.handle, query) != 0) {
315       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
316         connection.reconnect = 1;
317         retry_count++;
318         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
319           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
320           return 0;
321         }
322         apr_sleep(wait_time);
323         continue;
324       }
325       WRN(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
326       return 0;
327     }
328   }
329   while(0);
330
331   result = mysql_store_result(connection.handle);
332   if (result) mysql_free_result(result);
333   
334   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
335   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
336
337   return 1;
338 }
339
340
341 char *
342 chxj_mysql_get_cookie_from_cookie_id(request_rec *r, mod_chxj_config *m, const char *cookie_id)
343 {
344   MYSQL_RES *result;
345   char query[MAX_STRING_LEN];
346   char *retval = NULL;
347   apr_size_t clen = strlen(cookie_id);
348   char *sql_safe_cookie_id = apr_palloc(r->pool, clen*2+1);
349   int retry_count = 0;
350   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
351
352   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
353   mysql_escape_string(sql_safe_cookie_id,cookie_id,clen);
354
355   apr_snprintf(query, sizeof(query)-1, "SELECT data, length(data) FROM %s WHERE cookie_id = '%s'", m->mysql.tablename, sql_safe_cookie_id);
356   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
357   do {
358     if (!chxj_open_mysql_handle(r, m)) {
359       ERR(r, "%s:%d failed chxj_open_mysql_handle() query:[%s]", APLOG_MARK, query);
360       return 0;
361     }
362     connection.reconnect = 0;
363     if (mysql_query(connection.handle, query) != 0) {
364       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
365         connection.reconnect = 1;
366         retry_count++;
367         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
368           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
369           return 0;
370         }
371         apr_sleep(wait_time);
372         continue;
373       }
374       WRN(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
375       return NULL;
376     }
377   }
378   while(0);
379
380   result = mysql_store_result(connection.handle);
381   if (result && (mysql_num_rows(result) >= 1)) {
382     MYSQL_ROW data = mysql_fetch_row(result);
383     int len;
384     if (! data[0]) {
385       mysql_free_result(result);
386       ERR(r, "%s:%d MySQL cookie_id:[%s] has no valid cookie_id. %s", APLOG_MARK, cookie_id, r->uri);
387       return NULL;
388     }
389     len = atoi(data[1]);
390     retval = (char *) apr_palloc(r->pool, len + 1);
391     memcpy(retval, data[0], len);
392   }
393   if (result) mysql_free_result(result);
394
395   
396   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
397   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
398
399   return retval;
400 }
401
402
403 char *
404 chxj_mysql_get_cookie_expire_from_cookie_id(request_rec *r, mod_chxj_config *m, const char *cookie_id)
405 {
406   MYSQL_RES *result;
407   char query[MAX_STRING_LEN];
408   apr_size_t clen = strlen(cookie_id);
409   char *retval = NULL;
410   char *sql_safe_cookie_id = apr_palloc(r->pool, clen*2+1);
411   int retry_count = 0;
412   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
413
414   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
415   mysql_escape_string(sql_safe_cookie_id,cookie_id,clen);
416
417   apr_snprintf(query, sizeof(query)-1, "SELECT DATE_FORMAT(created_at, '%%Y%%m%%d%%H%%i%%s') FROM %s_expire WHERE cookie_id = '%s'", 
418     m->mysql.tablename, sql_safe_cookie_id);
419
420   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
421
422   do {
423     if (!chxj_open_mysql_handle(r, m)) {
424       ERR(r, "%s:%d failed chxj_open_mysql_handle() query:[%s]", APLOG_MARK, query);
425       return NULL;
426     }
427     connection.reconnect = 0;
428     if (mysql_query(connection.handle, query) != 0) {
429       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
430         connection.reconnect = 1;
431         retry_count++;
432         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
433           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
434           return 0;
435         }
436         apr_sleep(wait_time);
437         continue;
438       }
439       WRN(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
440       return NULL;
441     }
442   }
443   while(0);
444
445   result = mysql_store_result(connection.handle);
446   if (result && (mysql_num_rows(result) >= 1)) {
447     MYSQL_ROW data = mysql_fetch_row(result);
448     if (! data[0]) {
449       mysql_free_result(result);
450       ERR(r, "%s:%d MySQL cookie_id:[%s] has no valid cookie_id. %s", APLOG_MARK, cookie_id, r->uri);
451       return NULL;
452     }
453     retval = (char *) apr_palloc(r->pool, 19 + 1);
454     memset(retval, 0, 19+1);
455     memcpy(retval, data[0], 19);
456   }
457   if (result) mysql_free_result(result);
458   
459   DBG(r,"REQ[%X] query:[%s] retval:[%s]", TO_ADDR(r),query, retval);
460   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
461
462   return retval;
463 }
464
465
466 int
467 chxj_mysql_insert_or_update_cookie(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *data)
468 {
469   MYSQL_RES *result;
470   char query[MAX_STRING_LEN];
471   char *cid = ap_escape_logitem(r->pool, cookie_id);
472   char *cdt = ap_escape_logitem(r->pool, data);
473   int retry_count = 0;
474   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
475
476   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
477   DBG(r,"REQ[%X] data:[%s]", TO_ADDR(r),data);
478   do {
479     if (!chxj_open_mysql_handle(r, m)) {
480       ERR(r, "%s:%d failed chxj_open_mysql_handle()", APLOG_MARK);
481       return 0;
482     }
483     connection.reconnect = 0;
484     apr_snprintf(query, sizeof(query)-1, "BEGIN;");
485     DBG(r, "query:[%s]", query);
486     if (mysql_query(connection.handle, query) != 0) {
487       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
488         connection.reconnect = 1;
489         retry_count++;
490         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
491           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
492           return 0;
493         }
494         apr_sleep(wait_time);
495         continue;
496       }
497       ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
498       return 0;
499     }
500   }
501   while(0);
502
503   apr_snprintf(query, sizeof(query)-1, "INSERT INTO %s (cookie_id, data) VALUES ('%s','%s');", m->mysql.tablename, cid, cdt);
504   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
505   if (mysql_query(connection.handle, query) != 0) {
506     WRN(r, "MySQL WARN: %s: %s", mysql_error(connection.handle), r->uri);
507     if (!chxj_mysql_get_cookie_from_cookie_id(r, m, cookie_id)) {
508       ERR(r, "%s:%d failed chxj_mysql_get_cookie_from_cookie_id() cookie_id:[%s]", APLOG_MARK, cookie_id);
509       return 0;
510     }
511     apr_snprintf(query, sizeof(query)-1, "UPDATE %s set data = '%s' WHERE cookie_id = '%s';", m->mysql.tablename, cdt, cid);
512     DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
513     if (mysql_query(connection.handle, query) != 0) {
514       ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
515       chxj_mysql_rollback(r, m);
516       return 0;
517     }
518   }
519
520   apr_snprintf(query, sizeof(query)-1, "COMMIT;");
521   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
522   if (mysql_query(connection.handle, query) != 0) {
523     ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
524     chxj_mysql_rollback(r, m);
525     return 0;
526   }
527
528   result = mysql_store_result(connection.handle);
529   if (result) mysql_free_result(result);
530   
531   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
532
533   return 1;
534 }
535
536
537 int
538 chxj_mysql_insert_or_update_cookie_expire(request_rec *r, mod_chxj_config *m, const char *cookie_id)
539 {
540   MYSQL_RES *result;
541   char query[MAX_STRING_LEN];
542   char *cid = ap_escape_logitem(r->pool, cookie_id);
543   int retry_count = 0;
544   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
545
546   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
547
548   do {
549     if (!chxj_open_mysql_handle(r, m)) {
550       ERR(r, "%s:%d failed chxj_open_mysql_handle()", APLOG_MARK);
551       return 0;
552     }
553     connection.reconnect = 0; 
554     apr_snprintf(query, sizeof(query)-1, "BEGIN;");
555     DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
556     if (mysql_query(connection.handle, query) != 0) {
557       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
558         connection.reconnect = 1;
559         retry_count++;
560         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
561           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
562           return 0;
563         }
564         apr_sleep(wait_time);
565         continue;
566       }
567       ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK,mysql_error(connection.handle), r->uri);
568       return 0;
569     }
570   }
571   while(0);
572
573   apr_snprintf(query, sizeof(query)-1, "INSERT INTO %s_expire (cookie_id, created_at) VALUES ('%s',localtime);", m->mysql.tablename, cid);
574   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
575   if (mysql_query(connection.handle, query) != 0) {
576     WRN(r, "MySQL WARN: %s: %s", mysql_error(connection.handle), r->uri);
577     if (!chxj_mysql_get_cookie_from_cookie_id(r, m, cookie_id)) {
578       ERR(r, "%s:%d failed chxj_mysql_get_cookie_from_cookie_id() cookie_id:[%s]", APLOG_MARK, cookie_id);
579       return 0;
580     }
581     apr_snprintf(query, sizeof(query)-1, "UPDATE %s_expire set created_at = localtime WHERE cookie_id = '%s';", m->mysql.tablename, cid);
582     DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
583     if (mysql_query(connection.handle, query) != 0) {
584       ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
585       chxj_mysql_rollback(r, m);
586       return 0;
587     }
588   }
589
590   apr_snprintf(query, sizeof(query)-1, "COMMIT;");
591   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
592   if (mysql_query(connection.handle, query) != 0) {
593     ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
594     chxj_mysql_rollback(r, m);
595     return 0;
596   }
597
598   result = mysql_store_result(connection.handle);
599   if (result) mysql_free_result(result);
600   
601   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
602
603   return 1;
604 }
605
606
607 int
608 chxj_mysql_rollback(request_rec *r, mod_chxj_config *m)
609 {
610   char query[MAX_STRING_LEN];
611
612   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
613
614   apr_snprintf(query, sizeof(query)-1, "ROLLBACK;");
615
616   if (!chxj_open_mysql_handle(r, m)) {
617     DBG(r, "end chxj_mysql_rollback()");
618     return 1; /* TRUE */
619   }
620   if (mysql_query(connection.handle, query) != 0) {
621     ERR(r, "%s:%d MySQL ERROR: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
622     return 0; /* FALSE */
623   }
624   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
625   return 1;
626 }
627
628 char *
629 chxj_mysql_load_cookie(request_rec *r, mod_chxj_config *m, const char *cookie_id)
630 {
631   MYSQL_RES *result;
632   char query[MAX_STRING_LEN];
633   apr_size_t clen = strlen(cookie_id);
634   char *retval = NULL;
635   char *sql_safe_cookie_id = apr_palloc(r->pool, clen*2+1);
636   int retry_count = 0;
637   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
638   
639   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
640   mysql_escape_string(sql_safe_cookie_id,cookie_id,clen);
641
642   apr_snprintf(query, sizeof(query)-1, "SELECT data, length(data) FROM %s WHERE cookie_id = '%s';", m->mysql.tablename, sql_safe_cookie_id);
643
644   DBG(r, "REQ[%X] query:[%s]", TO_ADDR(r),query);
645
646   do {
647     if (!chxj_open_mysql_handle(r, m)) {
648       ERR(r, "%s:%d failed chxj_open_mysql_handle() query:[%s]", APLOG_MARK, query);
649       return NULL;
650     }
651     connection.reconnect = 0;
652     if (mysql_query(connection.handle, query) != 0) {
653       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
654         connection.reconnect = 1;
655         retry_count++;
656         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
657           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
658           return NULL;
659         }
660         apr_sleep(wait_time);
661         continue;
662       }
663       WRN(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
664       return NULL;
665     }
666   }
667   while(0);
668
669   result = mysql_store_result(connection.handle);
670   if (result && (mysql_num_rows(result) >= 1)) {
671     MYSQL_ROW data = mysql_fetch_row(result);
672     int len;
673     if (! data[0]) {
674       ERR(r, "%s:%d MySQL cookie_id:[%s] has no valid cookie_id. %s", APLOG_MARK, cookie_id, r->uri);
675       mysql_free_result(result);
676       return NULL;
677     }
678     len = atoi(data[1]);
679     retval = (char *) apr_palloc(r->pool, len + 1);
680     memset(retval, 0, len + 1);
681     memcpy(retval, data[0], len);
682   }
683   if (result) mysql_free_result(result);
684   
685   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
686   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
687
688   return retval;
689 }
690
691
692 char *
693 chxj_mysql_load_cookie_expire(request_rec *r, mod_chxj_config *m, const char *cookie_id)
694 {
695   MYSQL_RES *result;
696   char query[MAX_STRING_LEN];
697   char *retval = NULL;
698   apr_size_t clen = strlen(cookie_id);
699   char *sql_safe_cookie_id = apr_palloc(r->pool, clen*2+1);
700   int retry_count = 0;
701   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
702
703   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
704   mysql_escape_string(sql_safe_cookie_id,cookie_id,clen);
705
706   apr_snprintf(query, 
707                sizeof(query)-1, 
708                "SELECT DATE_FORMAT(created_at, '%%Y%%m%%d%%H%%i%%s') FROM %s_expire WHERE cookie_id = '%s';", 
709                m->mysql.tablename, 
710                sql_safe_cookie_id);
711
712   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
713
714   do {
715     if (!chxj_open_mysql_handle(r, m)) {
716       ERR(r, "%s:%d failed chxj_open_mysql_handle() query:[%s]", APLOG_MARK,query);
717       return NULL;
718     }
719     connection.reconnect = 0;
720     if (mysql_query(connection.handle, query) != 0) {
721       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
722         connection.reconnect = 1;
723         retry_count++;
724         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
725           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK,mysql_error(connection.handle), r->uri);
726           return 0;
727         }
728         apr_sleep(wait_time);
729         continue;
730       }
731       WRN(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
732       return NULL;
733     }
734   }
735   while(0);
736
737   result = mysql_store_result(connection.handle);
738   if (result && (mysql_num_rows(result) >= 1)) {
739     MYSQL_ROW data = mysql_fetch_row(result);
740     if (! data[0]) {
741       ERR(r, "%s:%d MySQL cookie_id:[%s] has no valid cookie_id. %s", APLOG_MARK,cookie_id, r->uri);
742       mysql_free_result(result);
743       return NULL;
744     }
745     retval = (char *) apr_palloc(r->pool, 14 + 1);
746     memcpy(retval, data[0], 14);
747   }
748   if (result) mysql_free_result(result);
749   
750   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
751   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
752
753   return retval;
754 }
755
756
757 int
758 chxj_mysql_delete_cookie(request_rec *r, mod_chxj_config *m, const char *cookie_id)
759 {
760   MYSQL_RES *result;
761   char query[MAX_STRING_LEN];
762   char *cid = ap_escape_logitem(r->pool, cookie_id);
763   int retry_count = 0;
764   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
765
766   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
767   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
768
769   do {
770     if (!chxj_open_mysql_handle(r, m)) {
771       ERR(r, "%s:%d failed chxj_open_mysql_handle()", APLOG_MARK);
772       return 0;
773     }
774     connection.reconnect = 0;
775     apr_snprintf(query, sizeof(query)-1, "BEGIN;");
776     DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
777     if (mysql_query(connection.handle, query) != 0) {
778       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
779         connection.reconnect = 1;
780         retry_count++;
781         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
782           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK,mysql_error(connection.handle), r->uri);
783           return 0;
784         }
785         apr_sleep(wait_time);
786         continue;
787       }
788       ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
789       return 0;
790     }
791   }
792   while(0);
793
794   if (!chxj_mysql_get_cookie_from_cookie_id(r, m, cookie_id)) {
795     ERR(r, "%s:%d failed chxj_mysql_get_cookie_from_cookie_id() cookie_id:[%s]", APLOG_MARK,cookie_id);
796     return 0;
797   }
798   apr_snprintf(query, sizeof(query)-1, "DELETE FROM %s WHERE cookie_id = '%s';", m->mysql.tablename, cid);
799   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
800   if (mysql_query(connection.handle, query) != 0) {
801     ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
802     chxj_mysql_rollback(r, m);
803     return 0;
804   }
805
806   apr_snprintf(query, sizeof(query)-1, "COMMIT;");
807   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
808   if (mysql_query(connection.handle, query) != 0) {
809     ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
810     chxj_mysql_rollback(r, m);
811     return 0;
812   }
813
814   result = mysql_store_result(connection.handle);
815   if (result) mysql_free_result(result);
816   
817   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
818
819   return 1;
820 }
821
822
823 int
824 chxj_mysql_delete_cookie_expire(request_rec *r, mod_chxj_config *m, const char *cookie_id)
825 {
826   MYSQL_RES *result;
827   char query[MAX_STRING_LEN];
828   char *cid = ap_escape_logitem(r->pool, cookie_id);
829   int retry_count = 0;
830   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
831
832   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
833   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
834
835   do {
836     if (!chxj_open_mysql_handle(r, m)) {
837       ERR(r, "%s:%d failed chxj_open_mysql_handle()", APLOG_MARK);
838       return 0;
839     }
840     connection.reconnect = 0; 
841     apr_snprintf(query, sizeof(query)-1, "BEGIN;");
842     DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
843     if (mysql_query(connection.handle, query) != 0) {
844       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
845         connection.reconnect = 1;
846         retry_count++;
847         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
848           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK,mysql_error(connection.handle), r->uri);
849           return 0;
850         }
851         apr_sleep(wait_time);
852         continue;
853       }
854       ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK,mysql_error(connection.handle), r->uri);
855       return 0;
856     }
857   }
858   while(0);
859
860   if (!chxj_mysql_get_cookie_expire_from_cookie_id(r, m, cookie_id)) {
861     ERR(r, "%s:%d failed chxj_mysql_get_cookie_expire_from_cookie_id() cookie_id:[%s]", APLOG_MARK,cookie_id);
862     return 0;
863   }
864   apr_snprintf(query, sizeof(query)-1, "DELETE FROM %s_expire WHERE cookie_id = '%s';", m->mysql.tablename, cid);
865   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
866   if (mysql_query(connection.handle, query) != 0) {
867     ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK,mysql_error(connection.handle), r->uri);
868     chxj_mysql_rollback(r, m);
869     return 0;
870   }
871
872   apr_snprintf(query, sizeof(query)-1, "COMMIT;");
873   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
874   if (mysql_query(connection.handle, query) != 0) {
875     ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
876     chxj_mysql_rollback(r, m);
877     return 0;
878   }
879
880   result = mysql_store_result(connection.handle);
881   if (result) mysql_free_result(result);
882   
883   DBG(r,"REQ[%X] cookie_id:[%s]",TO_ADDR(r),cookie_id);
884   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
885
886   return 1;
887 }
888
889 char *
890 chxj_mysql_get_timeout_localtime(request_rec *r, mod_chxj_config *m)
891 {
892   MYSQL_RES *result;
893   char query[MAX_STRING_LEN];
894   char *retval = NULL;
895   int retry_count = 0;
896   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
897
898   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
899   do {
900     if (!chxj_open_mysql_handle(r, m)) {
901       ERR(r, "%s:%d failed chxj_open_mysql_handle()", APLOG_MARK);
902       return 0;
903     }
904     connection.reconnect = 0;
905     apr_snprintf(query, sizeof(query)-1, "SELECT DATE_SUB(localtime, interval %ld second);",
906       (m->cookie_timeout == 0) ? DEFAULT_COOKIE_TIMEOUT : m->cookie_timeout);
907     DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
908     if (mysql_query(connection.handle, query) != 0) {
909       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
910         connection.reconnect = 1;
911         retry_count++;
912         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
913           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK, mysql_error(connection.handle), r->uri);
914           return 0;
915         }
916         apr_sleep(wait_time);
917         continue;
918       }
919       ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
920       return NULL;
921     }
922   }
923   while(0);
924   result = mysql_store_result(connection.handle);
925   if (result && (mysql_num_rows(result) >= 1)) {
926     MYSQL_ROW data = mysql_fetch_row(result);
927     if (! data[0]) {
928       ERR(r, "%s:%d MySQL ERROR: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
929       mysql_free_result(result);
930       return NULL;
931     }
932     retval = (char *) apr_palloc(r->pool, 19 + 1);
933     memset(retval, 0, 19+1);
934     memcpy(retval, data[0], 19);
935   }
936   if (result) mysql_free_result(result);
937    
938   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
939
940   return retval;
941 }
942
943 int
944 chxj_mysql_delete_expired_cookie(request_rec *r, mod_chxj_config *m)
945 {
946   MYSQL_RES *result;
947   char query[MAX_STRING_LEN];
948   char *timeout;
949   int retry_count = 0;
950   apr_interval_time_t wait_time = CHXJ_MYSQL_RECONNECT_WAIT_TIME;
951
952   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
953
954   do {
955     if (!chxj_open_mysql_handle(r, m)) {
956       ERR(r, "%s:%d failed chxj_open_mysql_handle()", APLOG_MARK);
957       return 0;
958     }
959     connection.reconnect = 0;
960     apr_snprintf(query, sizeof(query)-1, "BEGIN;");
961     DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
962     if (mysql_query(connection.handle, query) != 0) {
963       if (mysql_errno(connection.handle) == CR_SERVER_GONE_ERROR) {
964         connection.reconnect = 1;
965         retry_count++;
966         if (retry_count >= CHXJ_MYSQL_RECONNECT_COUNT) {
967           ERR(r, "%s:%d MySQL ERROR: %s: %s(retry over)", APLOG_MARK,mysql_error(connection.handle), r->uri);
968           return 0;
969         }
970         apr_sleep(wait_time);
971         continue;
972       }
973       ERR(r, "%s:%d MySQL ERROR: %s: %s", APLOG_MARK,mysql_error(connection.handle), r->uri);
974       return 0;
975     }
976   }
977   while (0);
978
979   timeout = chxj_mysql_get_timeout_localtime(r, m);
980   if (! timeout) {
981     ERR(r, "%s:%d MySQL ERROR: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
982     return 0;
983   }
984
985   apr_snprintf(query, sizeof(query)-1, "SELECT * FROM %s_expire WHERE created_at <= '%s'", m->mysql.tablename, timeout);
986   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
987   if (mysql_query(connection.handle, query) != 0) {
988     ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK,mysql_error(connection.handle), r->uri);
989     chxj_mysql_rollback(r, m);
990     return 0;
991   }
992   result = mysql_store_result(connection.handle);
993   if (result) mysql_free_result(result);
994   result = NULL;
995
996   /* delete from chxj_cookie */
997   apr_snprintf(query, sizeof(query)-1, "DELETE %s FROM %s, %s_expire WHERE %s_expire.created_at <= '%s' AND %s.cookie_id = %s_expire.cookie_id;", 
998      m->mysql.tablename, 
999      m->mysql.tablename,
1000      m->mysql.tablename,
1001      m->mysql.tablename,
1002      timeout,
1003      m->mysql.tablename,
1004      m->mysql.tablename);
1005   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
1006   if (mysql_query(connection.handle, query) != 0) {
1007     ERR(r, "%s:%d MySQL ERROR: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
1008     chxj_mysql_rollback(r, m);
1009     return 0;
1010   }
1011   result = mysql_store_result(connection.handle);
1012   if (result) mysql_free_result(result);
1013   result = NULL;
1014
1015   /* delete from chxj_cookie_expire */
1016   apr_snprintf(query, sizeof(query)-1, "DELETE %s_expire FROM %s_expire WHERE %s_expire.created_at <= '%s';", 
1017      m->mysql.tablename, 
1018      m->mysql.tablename,
1019      m->mysql.tablename,
1020      timeout);
1021   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
1022   if (mysql_query(connection.handle, query) != 0) {
1023     ERR(r, "%s:%d MySQL ERROR: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
1024     chxj_mysql_rollback(r, m);
1025     return 0;
1026   }
1027   result = mysql_store_result(connection.handle);
1028   if (result) mysql_free_result(result);
1029   result = NULL;
1030
1031   apr_snprintf(query, sizeof(query)-1, "COMMIT;");
1032   DBG(r,"REQ[%X] query:[%s]",TO_ADDR(r),query);
1033   if (mysql_query(connection.handle, query) != 0) {
1034     ERR(r, "%s:%d MySQL WARN: %s: %s", APLOG_MARK, mysql_error(connection.handle), r->uri);
1035     chxj_mysql_rollback(r, m);
1036     return 0;
1037   }
1038
1039   result = mysql_store_result(connection.handle);
1040   if (result) mysql_free_result(result);
1041
1042   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1043   return 1;
1044 }
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056 int
1057 chxj_save_cookie_mysql(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
1058 {
1059   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1060   if (! chxj_open_mysql_handle(r, m)) {
1061     ERR(r, "Cannot open mysql connection");
1062     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1063     return CHXJ_FALSE;
1064   }
1065
1066   if (!chxj_mysql_exist_cookie_table(r, m)) {
1067     DBG(r,"REQ[%X] not found cookie table:[%s]", TO_ADDR(r),m->mysql.tablename);
1068     if (!chxj_mysql_create_cookie_table(r, m)) {
1069       ERR(r, "cannot create cookie table:[%s]", m->mysql.tablename);
1070       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1071       return CHXJ_FALSE;
1072     }
1073   }
1074   if (! chxj_mysql_insert_or_update_cookie(r, m, cookie_id, store_string)) {
1075     ERR(r, "cannot store to cookie table:[%s]", m->mysql.tablename);
1076     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1077     return CHXJ_FALSE;
1078   }
1079
1080   /* *NEED NOT* close database. */
1081   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1082   return CHXJ_TRUE;
1083 }
1084
1085 int
1086 chxj_update_cookie_mysql(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
1087 {
1088   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1089   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1090   if (! chxj_open_mysql_handle(r, m)) {
1091     ERR(r, "Cannot open mysql connection");
1092     DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1093     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1094     return CHXJ_FALSE;
1095   }
1096
1097   if (!chxj_mysql_exist_cookie_table(r, m)) {
1098     DBG(r,"REQ[%X] not found cookie table:[%s]",TO_ADDR(r),m->mysql.tablename);
1099     if (!chxj_mysql_create_cookie_table(r, m)) {
1100       ERR(r, "cannot create cookie table:[%s]", m->mysql.tablename);
1101       DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1102       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1103       return CHXJ_FALSE;
1104     }
1105   }
1106   if (! chxj_mysql_insert_or_update_cookie(r, m, cookie_id, store_string)) {
1107     ERR(r, "cannot create cookie table:[%s]", m->mysql.tablename);
1108     DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1109     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1110     return CHXJ_FALSE;
1111   }
1112
1113   /* *NEED NOT* close database. */
1114   /* chxj_close_mysql_handle(); */
1115   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1116   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1117   return CHXJ_TRUE;
1118 }
1119
1120
1121 char *
1122 chxj_load_cookie_mysql(request_rec *r, mod_chxj_config *m, const char *cookie_id)
1123 {
1124   char *load_string;
1125
1126   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1127   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1128   if (! chxj_open_mysql_handle(r, m)) {
1129     ERR(r, "Cannot open mysql connection");
1130     DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1131     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1132     return NULL;
1133   }
1134
1135   if (!chxj_mysql_exist_cookie_table(r, m)) {
1136     DBG(r,"REQ[%X] not found cookie table:[%s]", TO_ADDR(r),m->mysql.tablename);
1137     if (!chxj_mysql_create_cookie_table(r, m)) {
1138       ERR(r, "cannot create cookie table:[%s]", m->mysql.tablename);
1139       DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1140       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1141       return NULL;
1142     }
1143   }
1144   if (!(load_string = chxj_mysql_load_cookie(r, m, cookie_id))) {
1145     ERR(r, "%s:%d not found cookie. cookie_id:[%s]", APLOG_MARK, cookie_id);
1146     DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1147     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1148     return NULL;
1149   }
1150
1151   /* *NEED NOT* close database. */
1152   /* chxj_close_mysql_handle(); */
1153   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1154   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1155   return load_string;
1156 }
1157
1158
1159 int
1160 chxj_delete_cookie_mysql(request_rec *r, mod_chxj_config *m, const char *cookie_id)
1161 {
1162   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1163   DBG(r,"REQ[%X] cookie_id=[%s]", TO_ADDR(r),cookie_id);
1164   if (! chxj_open_mysql_handle(r, m)) {
1165     ERR(r, "%s:%d Cannot open mysql connection cookie_id=[%s]", APLOG_MARK, cookie_id);
1166     return CHXJ_FALSE;
1167   }
1168   if (!chxj_mysql_exist_cookie_table(r, m)) {
1169     DBG(r,"REQ[%X] not found cookie table:[%s]", TO_ADDR(r),m->mysql.tablename);
1170     if (!chxj_mysql_create_cookie_table(r, m)) {
1171       ERR(r, "%s:%d cannot create cookie table:[%s]", APLOG_MARK, m->mysql.tablename);
1172       return CHXJ_FALSE;
1173     }
1174   }
1175   else {
1176     if (!chxj_mysql_delete_cookie(r, m, cookie_id)) {
1177       ERR(r, "%s:%d failed: chxj_mysql_delete_cookie() cookie_id:[%s]", APLOG_MARK, cookie_id);
1178       return CHXJ_FALSE;
1179     }
1180   }
1181   DBG(r,"REQ[%X] cookie_id=[%s]", TO_ADDR(r),cookie_id);
1182   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1183   return CHXJ_TRUE;
1184 }
1185
1186
1187 int
1188 chxj_save_cookie_expire_mysql(request_rec *r, mod_chxj_config *m, const char *cookie_id)
1189 {
1190   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1191   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1192   if (! chxj_open_mysql_handle(r, m)) {
1193     ERR(r, "%s:%d Cannot open mysql connection cookie_id=[%s]",APLOG_MARK, cookie_id);
1194     return CHXJ_FALSE;
1195   }
1196
1197   if (!chxj_mysql_exist_cookie_table_expire(r, m)) {
1198     DBG(r,"REQ[%X] not found cookie table:[%s_expire]", TO_ADDR(r),m->mysql.tablename);
1199     if (!chxj_mysql_create_cookie_expire_table(r, m)) {
1200       ERR(r, "%s:%d cannot create cookie table:[%s_expire] cookie_id:[%s]", APLOG_MARK, m->mysql.tablename, cookie_id);
1201       return CHXJ_FALSE;
1202     }
1203   }
1204   if (! chxj_mysql_insert_or_update_cookie_expire(r, m, cookie_id)) {
1205     ERR(r, "%s:%d cannot create cookie table:[%s_expire] cookie_id:[%s]", APLOG_MARK, m->mysql.tablename, cookie_id);
1206     return CHXJ_FALSE;
1207   }
1208
1209   /* *NEED NOT* close database. */
1210   /* chxj_close_mysql_handle(); */
1211
1212   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1213   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1214   return CHXJ_TRUE;
1215 }
1216
1217
1218 int
1219 chxj_delete_cookie_expire_mysql(request_rec *r, mod_chxj_config *m, const char *cookie_id)
1220 {
1221   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1222   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1223   if (! chxj_open_mysql_handle(r, m)) {
1224     ERR(r, "%s:%d Cannot open mysql connection", APLOG_MARK);
1225     return CHXJ_FALSE;
1226   }
1227
1228   if (!chxj_mysql_exist_cookie_table_expire(r, m)) {
1229     DBG(r,"REQ[%X] not found cookie table:[%s_expire]", TO_ADDR(r),m->mysql.tablename);
1230     if (!chxj_mysql_create_cookie_expire_table(r, m)) {
1231       ERR(r, "%s:%d cannot create cookie table:[%s_expire] cookie_id:[%s]", APLOG_MARK, m->mysql.tablename, cookie_id);
1232       return CHXJ_FALSE;
1233     }
1234   } else {
1235     if (!chxj_mysql_delete_cookie_expire(r, m, cookie_id)) {
1236       ERR(r, "%s:%d failed: chxj_mysql_delete_cookie() cookie_id:[%s]", APLOG_MARK, cookie_id);
1237       return CHXJ_FALSE;
1238     }
1239   }
1240   DBG(r,"REQ[%X] cookie_id:[%s]", TO_ADDR(r),cookie_id);
1241   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1242   return CHXJ_TRUE;
1243 }
1244
1245
1246 int
1247 chxj_cookie_expire_gc_mysql(request_rec *r, mod_chxj_config *m)
1248 {
1249   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1250   if (! chxj_open_mysql_handle(r, m)) {
1251     ERR(r, "Cannot open mysql connection");
1252     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1253     return CHXJ_FALSE;
1254   }
1255   if (!chxj_mysql_exist_cookie_table_expire(r, m)) {
1256     DBG(r,"REQ[%X] not found cookie table:[%s_expire]", TO_ADDR(r),m->mysql.tablename);
1257     if (!chxj_mysql_create_cookie_expire_table(r, m)) {
1258       ERR(r, "%s:%d cannot create cookie table:[%s_expire]", APLOG_MARK, m->mysql.tablename);
1259       return CHXJ_FALSE;
1260     }
1261   } else {
1262     if (!chxj_mysql_delete_expired_cookie(r, m)) {
1263       ERR(r, "%s:%d failed: chxj_mysql_delete_expired_cookie()", APLOG_MARK);
1264       return CHXJ_FALSE;
1265     }
1266   }
1267   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1268   return CHXJ_TRUE;
1269 }
1270
1271
1272 int
1273 chxj_cookie_lock_mysql(request_rec *r, mod_chxj_config *m)
1274 {
1275   MYSQL_RES *result;
1276   char query[MAX_STRING_LEN];
1277   DBG(r,"REQ[%X] start %s()",TO_ADDR(r),__func__);
1278   if (! chxj_open_mysql_handle(r, m)) {
1279     ERR(r, "Cannot open mysql connection");
1280     DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1281     return CHXJ_FALSE;
1282   }
1283   if (!chxj_mysql_exist_cookie_table_expire(r, m)) {
1284     DBG(r,"REQ[%X] not found cookie table:[%s_expire]", TO_ADDR(r),m->mysql.tablename);
1285     if (!chxj_mysql_create_cookie_expire_table(r, m)) {
1286       ERR(r, "cannot create cookie table:[%s_expire]", m->mysql.tablename);
1287       DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1288       return CHXJ_FALSE;
1289     }
1290   }
1291   apr_snprintf(query, sizeof(query)-1, "LOCK TABLES %s WRITE", m->mysql.tablename);
1292   DBG(r,"REQ[%X] query:[%s]", TO_ADDR(r),query);
1293   if (mysql_query(connection.handle, query) != 0) {
1294     chxj_mysql_rollback(r, m);
1295     ERR(r, "MySQL WARN: %s: %s", mysql_error(connection.handle), r->uri);
1296     return CHXJ_FALSE;
1297   }
1298
1299   result = mysql_store_result(connection.handle);
1300   if (result) mysql_free_result(result);
1301   
1302   DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1303   return CHXJ_TRUE;
1304 }
1305
1306
1307 int
1308 chxj_cookie_unlock_mysql(request_rec *r, mod_chxj_config *UNUSED(m))
1309 {
1310   char query[MAX_STRING_LEN];
1311   if (r) DBG(r, "REQ[%X] start %s()",TO_ADDR(r),__func__);
1312   apr_snprintf(query, sizeof(query)-1, "UNLOCK TABLES");
1313   if (mysql_query(connection.handle, query) != 0) {
1314      if (r) {
1315        ERR(r, "MySQL WARN: %s: %s", mysql_error(connection.handle), r->uri);
1316        DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1317      }
1318     return CHXJ_FALSE;
1319   }
1320   if (r) DBG(r,"REQ[%X] end %s()",TO_ADDR(r),__func__);
1321   return CHXJ_TRUE;
1322 }
1323 #endif
1324 /*
1325  * vim:ts=2 et
1326  */