db_ops.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2006 iptelorg GmbH
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * For a license to use the ser software under conditions
00014  * other than those described here, or to purchase support for this
00015  * software, please contact iptel.org by e-mail at the following addresses:
00016  *    info@iptel.org
00017  *
00018  * ser is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  */
00027 
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <stdio.h>
00031 #include <ctype.h>
00032 #include "../../sr_module.h"
00033 #include "../../mem/mem.h"
00034 #include "../../str.h"
00035 #include "../../error.h"
00036 #include "../../config.h"
00037 #include "../../trim.h"
00038 #include "../../lib/srdb2/db.h"
00039 #include "../../select.h"
00040 #include "../../script_cb.h"
00041 #include "../xlog/xl_lib.h"
00042 #include "../../route.h"
00043 #include "../../action.h"
00044 #include "../../ut.h"
00045 #include "../../str_hash.h"
00046 
00047 
00048 MODULE_VERSION
00049 
00050 #define MODULE_NAME "db_ops"
00051 #define MODULE_NAME2 "db"
00052 
00053 static char* db_url = DEFAULT_DB_URL;
00054 static int xlbuf_size = 4096;
00055 
00056 enum dbops_type {OPEN_QUERY_OPS, INSERT_OPS, UPDATE_OPS, REPLACE_OPS, DELETE_OPS};
00057 
00058 #define FLD_DELIM ','
00059 #define PART_DELIM '/'
00060 
00061 #define NO_SCRIPT -1
00062 
00063 static str* xl_nul = NULL;
00064 static xl_print_log_f* xl_print = NULL;
00065 static xl_parse_format_f* xl_parse = NULL;
00066 static xl_get_nulstr_f* xl_getnul = NULL;
00067 
00068 static char *xlbuf = 0;
00069 static char *xlbuf_tail;
00070 
00071 struct xlstr {
00072         char *s;
00073         xl_elog_t* xlfmt;
00074 };
00075 
00076 struct extra_ops { 
00077         char *name;
00078         int type;
00079         char *value;
00080 };
00081 
00082 struct dbops_action {
00083         char *query_name;
00084         char *db_url;
00085 
00086         db_ctx_t* ctx;
00087         db_cmd_t* cmd;
00088 
00089         enum dbops_type operation;
00090         int query_no;
00091         int is_raw_query;
00092         struct xlstr table;
00093 
00094         int field_count;
00095         struct xlstr* fields;
00096 
00097         int where_count;
00098         struct xlstr* wheres;
00099         int op_count;
00100 
00101         struct xlstr* ops;
00102         int value_count;
00103         struct xlstr* values;
00104         int* value_types;
00105 
00106         struct xlstr order;
00107         struct xlstr raw;
00108 
00109         int extra_ops_count;    
00110         struct extra_ops* extra_ops;
00111 
00112         db_res_t* result;   /* result of SELECT */
00113 
00114         struct dbops_action* next;
00115 };
00116 
00117 struct dbops_handle {
00118         char *handle_name;
00119         struct dbops_action* action;
00120         db_res_t* result;
00121         int cur_row_no;
00122         struct dbops_handle *next;
00123 };
00124 
00125 
00126 /* list of all operations */
00127 static struct dbops_action* dbops_actions = 0;
00128 
00129 /* list of declared handles, close them in post script callback */
00130 static struct dbops_handle* dbops_handles = 0;
00131 
00132 #define eat_spaces(_p) \
00133         while( *(_p)==' ' || *(_p)=='\t' ){\
00134         (_p)++;}
00135 
00136 #define eat_alphanum(_p) \
00137         while ( (*(_p) >= 'a' && *(_p) <= 'z') || (*(_p) >= 'A' && *(_p) <= 'Z') || (*(_p) >= '0' && *(_p) <= '9') || (*(_p) == '_') ) {\
00138                 (_p)++;\
00139         }
00140 
00141 static struct dbops_action* find_action_by_name(char *name, int len) {
00142         struct dbops_action *a;
00143         if (len == -1) len = strlen(name);
00144         for (a=dbops_actions; a; a = a->next) {         
00145                 if (a->query_name && strlen(a->query_name)==len && strncmp(name, a->query_name, len) == 0)
00146                         return a;
00147         }
00148         return NULL;
00149 }
00150 
00151 static struct dbops_handle* find_handle_by_name(char *name, int len) {
00152         struct dbops_handle *a;
00153         if (len == -1) len = strlen(name);
00154         for (a=dbops_handles; a; a = a->next) {         
00155                 if (a->handle_name && strlen(a->handle_name)==len && strncmp(name, a->handle_name, len) == 0)
00156                         return a;
00157         }
00158         return NULL;
00159 }
00160 
00161 static void trim_apostr(char **s) {
00162         int i;
00163         while ( **s == '\'') {
00164                 (*s)++;
00165         }
00166         i = strlen(*s);
00167         while (i && (*s)[i-1] == '\'') {
00168                 i--;
00169                 (*s)[i] = 0;
00170         }
00171 }
00172 
00173 static int get_next_part(char** s, char** part, char delim, int read_only) {
00174         char *c, *c2;
00175         char flag = 0;
00176 
00177         c = c2 = *s;
00178         eat_spaces(c);
00179 
00180         while (!(((*c2 == delim) && !flag) || *c2==0)) {
00181                 if (*c2=='\'')
00182                         flag = !flag;
00183                 c2++;
00184         }
00185         if ((*c2)==0 && flag) {
00186                 ERR(MODULE_NAME": string '%s' is not terminated\n", *s);
00187                 return E_CFG;
00188         }
00189         if (*c2) {
00190                 if (!read_only) *c2 = 0;
00191                 *s = c2+1;
00192         }
00193         else {
00194                 *s = c2;
00195         }
00196         eat_spaces(*s);
00197         c2--;
00198         /* rtrim */
00199         while ( c2 > c && ((*c2 == ' ')||(*c2 == '\t')) ) {
00200                 if (!read_only) *c2 = 0;
00201                 c2--;
00202         }
00203         *part = c;
00204         return 0;
00205 }
00206 
00207 static int split_fields(char *part, int *n, struct xlstr **strs) {
00208         int i, res;
00209         char *c, *fld;
00210 
00211         *n = 0;
00212         *strs = 0;
00213         c = part;
00214         while (*c) {
00215                 res = get_next_part(&c, &fld, FLD_DELIM, 1);
00216                 if (res < 0) return res;
00217                 (*n)++;
00218         }
00219         *strs = pkg_malloc( (*n)*sizeof(**strs));
00220         if (!strs) {
00221                 ERR(MODULE_NAME": split_fields: not enough pkg memory\n");
00222                 return E_OUT_OF_MEM;
00223         }
00224         memset(*strs, 0, (*n)*sizeof(**strs));
00225         i = 0;
00226         c = part;
00227         while (*c) {
00228                 res = get_next_part(&c, &(*strs)[i].s, FLD_DELIM, 0);
00229                 if (res < 0) return res;
00230                 trim_apostr(&(*strs)[i].s);
00231                 i++;
00232         }
00233         return 0;
00234 }
00235 
00236 static int get_type(char **s, int *type) {
00237         if (*s && (*s)[0] && (*s)[1]==':') {
00238                 switch ((*s)[0]) {
00239                         case 't':
00240                                 *type = DB_DATETIME;
00241                                 break;
00242                         case 'i':
00243                                 *type = DB_INT;
00244                                 break;
00245                         case 'f':
00246                                 *type = DB_FLOAT;
00247                                 break;
00248                         case 'd':
00249                                 *type = DB_DOUBLE;
00250                                 break;
00251                         case 's':
00252                                 *type = DB_CSTR;
00253                                 break;
00254                         default:
00255                                 ERR(MODULE_NAME": get_type: bad param type in '%s'\n", *s);
00256                                 return E_CFG;
00257                 }
00258                 (*s)+=2;
00259         }
00260         return 0;
00261 }
00262 
00263 static int parse_ops(char* act_s, struct dbops_action** action, int has_name) {
00264         int res = 0, i;
00265         char *c, *s, *part;
00266         static int query_no = 0;
00267 
00268         s = act_s;
00269         *action = pkg_malloc(sizeof(**action));
00270         if (!*action) return E_OUT_OF_MEM;
00271         memset(*action, 0, sizeof(**action));
00272         (*action)->query_no = query_no++;
00273 
00274         eat_spaces(s);
00275         c = s;
00276         eat_alphanum(c);
00277         if (has_name) {
00278                 char *c2;
00279                 c2 = c;
00280                 eat_spaces(c2);
00281                 if (c != s && *c2 == '=') {
00282                         *c = '\0';
00283                         if (find_action_by_name(s, -1) != NULL) {
00284                                 ERR(MODULE_NAME": parse_ops: duplicate query name: %s\n", s);
00285                                 return E_CFG;
00286                         }               
00287                         (*action)->query_name = s;
00288                         s = c2+1;
00289                         eat_spaces(s);
00290                         c = s;
00291                         eat_alphanum(c);
00292                 }
00293                 else {
00294                         ERR(MODULE_NAME": parse_ops: query_no: %d, valid query name not found in '%s'\n%s\n%s\n", (*action)->query_no, s, c, c2);
00295                         return E_CFG;
00296                 }
00297         }
00298 
00299         if (c[0] == ':' && c[1] == '/' && c[2] == '/') { /* database part is optional */
00300                 for (c=s; *c!=':'; c++) {
00301                         *c = tolower(*c);                       /* _type_://user:host/database_name/ */
00302                 }
00303                 (*action)->db_url = s;
00304                 s = c+1;
00305                 while (*s == '/') s++;
00306                 res = get_next_part(&s, &part, PART_DELIM, 1);  /* type://_user:host_/database_name/ */
00307                 if (res < 0) return res;
00308 
00309 
00310                 res = get_next_part(&s, &part, PART_DELIM, 0);  /* type://user:host/_database_name_/ */
00311                 if (res < 0) return res;
00312         }
00313         res = get_next_part(&s, &part, PART_DELIM, 0);
00314         if (res < 0) return res;
00315 
00316         for (c = part; *c && *c != PART_DELIM; c++) {
00317                 if (*c == ' ') {
00318                         (*action)->is_raw_query = 1;
00319                         *c = '\0';
00320                         break;
00321                 }
00322         }
00323         if (strcasecmp(part, "select") == 0)
00324                 (*action)->operation = OPEN_QUERY_OPS;
00325         else if (strcasecmp(part, "insert") == 0)
00326                 (*action)->operation = INSERT_OPS;
00327         else if (strcasecmp(part, "update") == 0)
00328                 (*action)->operation = UPDATE_OPS;
00329         else if (strcasecmp(part, "replace") == 0)
00330                 (*action)->operation = REPLACE_OPS;
00331         else if (strcasecmp(part, "delete") == 0)
00332                 (*action)->operation = DELETE_OPS;
00333         else {
00334                 if ((*action)->is_raw_query) *c = ' ';
00335                 ERR(MODULE_NAME": parse_ops: query: %s(%d), unknown type of query '%s'\n", (*action)->query_name, (*action)->query_no, part);
00336                 return E_CFG;
00337         }
00338         if ((*action)->is_raw_query) {
00339                 *c = ' ';
00340                 (*action)->raw.s = part;
00341                 (*action)->table.s = part;
00342         }
00343 
00344         res = get_next_part(&s, &part, PART_DELIM, 0);
00345         if (res < 0) return res;
00346         if (!(*action)->is_raw_query) {
00347 
00348                 if (!*part) {
00349                         ERR(MODULE_NAME": parse_ops: query: %s(%d), table not specified near '%s' in '%s'\n", (*action)->query_name, (*action)->query_no, s, act_s);
00350                         return E_CFG;
00351                 }
00352                 trim_apostr(&part);
00353                 (*action)->table.s = part;
00354 
00355                 res = get_next_part(&s, &part, PART_DELIM, 0);
00356                 if (res < 0) return res;
00357                 switch ((*action)->operation) {
00358                         case OPEN_QUERY_OPS:
00359                         case UPDATE_OPS:
00360                         case REPLACE_OPS:
00361                         case INSERT_OPS:
00362                                 res = split_fields(part, &(*action)->field_count, &(*action)->fields);
00363                                 if (res < 0) return res;
00364                                 if ((*action)->field_count == 0) {
00365                                         ERR(MODULE_NAME": parse_ops: query: %s(%d), no field specified near '%s' ?n '%s'\n", (*action)->query_name, (*action)->query_no, part, act_s);
00366                                         return E_CFG;
00367                                 }
00368                                 break;
00369                         case DELETE_OPS:
00370                                 res = split_fields(part, &(*action)->where_count, &(*action)->wheres);
00371                                 if (res < 0) return res;
00372                                 res = get_next_part(&s, &part, PART_DELIM, 0);
00373                                 if (res < 0) return res;
00374                                 res = split_fields(part, &(*action)->op_count, &(*action)->ops);
00375                                 if (res < 0) return res;
00376                                 break;
00377                         default:;
00378                 }
00379 
00380                 res = get_next_part(&s, &part, PART_DELIM, 0);
00381                 if (res < 0) return res;
00382                 switch ((*action)->operation) {
00383                         case OPEN_QUERY_OPS:
00384                         case UPDATE_OPS:
00385                                 res = split_fields(part, &(*action)->where_count, &(*action)->wheres);
00386                                 if (res < 0) return res;
00387                                 res = get_next_part(&s, &part, PART_DELIM, 0);
00388                                 if (res < 0) return res;
00389                                 res = split_fields(part, &(*action)->op_count, &(*action)->ops);
00390                                 if (res < 0) return res;
00391                                 res = get_next_part(&s, &part, PART_DELIM, 0);
00392                                 if (res < 0) return res;
00393                                 switch ((*action)->operation) {
00394                                         case OPEN_QUERY_OPS:
00395                                                 if (*part) {
00396                                                         (*action)->order.s = part;
00397                                                 }
00398                                                 res = get_next_part(&s, &part, PART_DELIM, 0);
00399                                                 if (res < 0) return res;
00400                                                 break;
00401                                         default:;
00402                                 }
00403                                 break;
00404                         default:
00405                                 ;
00406                 }
00407         }
00408 
00409         /* values */
00410         res = split_fields(part, &(*action)->value_count, &(*action)->values);
00411         if (res < 0) return res;
00412 
00413         if ((*action)->value_count) {
00414                 (*action)->value_types = (int*)pkg_malloc(sizeof(int) * (*action)->value_count);
00415                 if ((*action)->value_types == NULL) {
00416                         ERR(MODULE_NAME": No memory left\n");
00417                         return -1;
00418                 }
00419 
00420                 for (i=0; i<(*action)->value_count; i++) {
00421                         (*action)->value_types[i] = DB_CSTR; // DB_NONE; /* let decide db driver itself, FIXME: until jjanak changes then default type is string */
00422                         res = get_type(&(*action)->values[i].s, &(*action)->value_types[i]);
00423                         if (res < 0) return res;
00424                 }
00425         }
00426 
00427         /* extra options */
00428         res = get_next_part(&s, &part, PART_DELIM, 0);
00429         if (res < 0) return res;
00430 
00431         (*action)->extra_ops_count = 0;
00432         c = part;
00433         while (*c) {
00434                 char *fld;
00435                 res = get_next_part(&c, &fld, FLD_DELIM, 1);
00436                 if (res < 0) return res;
00437                 (*action)->extra_ops_count++;
00438         }
00439         if ((*action)->extra_ops_count > 0) {
00440                 (*action)->extra_ops = pkg_malloc( (*action)->extra_ops_count*sizeof(*(*action)->extra_ops));
00441                 if (!(*action)->extra_ops) {
00442                         ERR(MODULE_NAME": parse_ops: not enough pkg memory\n");
00443                         return E_OUT_OF_MEM;
00444                 }
00445                 memset((*action)->extra_ops, 0, (*action)->extra_ops_count*sizeof(*(*action)->extra_ops));
00446 
00447                 i = 0;
00448                 c = part;
00449                 while (*c) {
00450                         char *fld;
00451                         res = get_next_part(&c, &fld, FLD_DELIM, 0);
00452                         if (res < 0) return res;
00453                         /* name=[i|s]:value */
00454                         (*action)->extra_ops[i].name = fld;
00455                         eat_alphanum(fld);
00456                         if (*fld != '=') {
00457                                 ERR(MODULE_NAME": parse_ops: query: %s(%d), bad extra parameter format in '%s'\n", (*action)->query_name, (*action)->query_no, (*action)->extra_ops[i].name);
00458                                 return E_CFG;
00459                         }
00460                         *fld = '\0';
00461                         fld++;
00462                         while (*fld==' ' || *fld=='\t') fld++;
00463                         (*action)->extra_ops[i].type = DB_NONE;
00464                         res = get_type(&fld, &(*action)->extra_ops[i].type);
00465                         if (res < 0) return res;
00466                         trim_apostr(&fld);
00467                         (*action)->extra_ops[i].value = fld;
00468                         DEBUG(MODULE_NAME": extra_ops #%d, name='%s', type=%d, val='%s'\n", i, (*action)->extra_ops[i].name, (*action)->extra_ops[i].type, (*action)->extra_ops[i].value);
00469                         i++;
00470                 }
00471         }
00472 
00473         if (*s) {
00474                 ERR(MODULE_NAME": parse_ops: query: %s(%d), too many parameters/parts, remaining '%s' in '%s'\n", (*action)->query_name, (*action)->query_no, s, act_s);
00475                 return E_CFG;
00476         }
00477         if ((*action)->is_raw_query) {
00478                 DEBUG(MODULE_NAME": query: %s(%d) oper:%d database:'%s' query:'%s' value#:%d extra_ops#:%d\n", (*action)->query_name, (*action)->query_no, (*action)->operation, (*action)->db_url, (*action)->raw.s, (*action)->value_count, (*action)->extra_ops_count);
00479         }
00480         else {
00481                 /* check num of fields */
00482                 if ((((*action)->operation==OPEN_QUERY_OPS)?0:(*action)->field_count)+(*action)->where_count != (*action)->value_count) {
00483                         ERR(MODULE_NAME": parse_ops: query: %s(%d), number of values does not correspond to number of fields (%d+%d!=%d) in '%s'\n", (*action)->query_name, (*action)->query_no, ((*action)->operation==OPEN_QUERY_OPS)?0:(*action)->field_count,  (*action)->where_count, (*action)->value_count, act_s);
00484                         return E_CFG;
00485                 }
00486                 DEBUG(MODULE_NAME": query_no:%d oper:%d database:'%s' table:'%s' 'field#:'%d' where#:'%d' order:'%s' value#:%d extra_ops#:%d\n", (*action)->query_no, (*action)->operation, (*action)->db_url, (*action)->table.s, (*action)->field_count,  (*action)->where_count, (*action)->order.s, (*action)->value_count, (*action)->extra_ops_count);
00487         }
00488         return 0;
00489 }
00490 
00491 static int parse_xlstr(struct xlstr* s) {
00492 
00493         if (!s->s) return 0;
00494         if (!strchr(s->s, '%')) return 0;
00495         /* probably xl_log formating */
00496 
00497         if (!xl_print) {
00498                 xl_print=(xl_print_log_f*)find_export("xprint", NO_SCRIPT, 0);
00499 
00500                 if (!xl_print) {
00501                         ERR(MODULE_NAME": cannot find \"xprint\", is module xlog loaded?\n");
00502                         return E_UNSPEC;
00503                 }
00504         }
00505 
00506         if (!xl_parse) {
00507                 xl_parse=(xl_parse_format_f*)find_export("xparse", NO_SCRIPT, 0);
00508 
00509                 if (!xl_parse) {
00510                         ERR(MODULE_NAME": cannot find \"xparse\", is module xlog loaded?\n");
00511                         return E_UNSPEC;
00512                 }
00513         }
00514 
00515         if (!xl_nul) {
00516                 xl_getnul=(xl_get_nulstr_f*)find_export("xnulstr", NO_SCRIPT, 0);
00517                 if (xl_getnul)
00518                         xl_nul=xl_getnul();
00519 
00520                 if (!xl_nul){
00521                         ERR(MODULE_NAME": cannot find \"xnulstr\", is module xlog loaded?\n");
00522                         return E_UNSPEC;
00523                 }
00524         else
00525                 INFO(MODULE_NAME": xlog null is \"%.*s\"\n", xl_nul->len, xl_nul->s);
00526         }
00527 
00528         if(xl_parse(s->s, &s->xlfmt) < 0) {
00529                 ERR(MODULE_NAME": wrong format '%s'\n", s->s);
00530                 return E_UNSPEC;
00531         }
00532 
00533         return 0;
00534 }
00535 
00536 static int eval_xlstr(struct sip_msg* msg, struct xlstr* s) {
00537         static char* null_str = "";
00538         int len;
00539         if (s->xlfmt) {
00540                 len = xlbuf_size - (xlbuf_tail-xlbuf);
00541                 if (xl_print(msg, s->xlfmt, xlbuf_tail, &len) < 0) {
00542                         ERR(MODULE_NAME": eval_xlstr: Error while formating result\n");
00543                         return E_UNSPEC;
00544                 }
00545 
00546                 /* note: xl_null value is returned as "<null>" string. It's pretty useless checking "if xlbuf_tail==xl_null then xlbuf_tail="";" because xl_null may be also inside string. What about implementing xl_set_nullstr to xl_lib? */
00547                 if ((xl_nul) && (xl_nul->len==len) && strncmp(xl_nul->s, xlbuf_tail, len)==0) {
00548                         s->s = null_str;
00549                 }
00550                 else {
00551                         s->s = xlbuf_tail;
00552                         s->s[len] = '\0';
00553                         xlbuf_tail += len+1;
00554                 }
00555         }
00556         else {
00557                 if (!s->s)
00558                         s->s = null_str;
00559         }
00560         return 0;
00561 }
00562 
00563 static int dbops_func(struct sip_msg* m, struct dbops_action* action) 
00564 {
00565 /*      char* order;*/
00566         int res, i;
00567 /* raw query is pre-compiled too 
00568         if (action->is_raw_query) {
00569                 DEBUG(MODULE_NAME": dbops_func(raw, %d, '%s'\n", action->operation, action->raw.s);
00570                 res = eval_xlstr(m, &action->raw);
00571                 if (res < 0) return res;
00572                 
00573                  * FIXME: We have to make sure that we do not use pre-compiled statements
00574                  * here because these must not change at runtime: to be checked by janakj
00575                  *
00576                 action->cmd->table.s = action->raw.s;
00577                 action->cmd->table.len = strlen(action->raw.s);
00578                 
00579                 if (db_exec((action->operation==OPEN_QUERY_OPS?&action->result:NULL), action->cmd) < 0) {
00580                         ERR(MODULE_NAME": database operation (%d) error, raw: '%s'\n", action->operation, action->raw.s);
00581                         return -1;
00582                 }
00583                 return 1;
00584         }
00585 */
00586         if (action->is_raw_query) {
00587                 DEBUG(MODULE_NAME": dbops_func(%s, %d, raw, %d, '%s', %d)\n", action->query_name, action->query_no, action->operation, action->cmd->table.s, action->value_count);
00588                 /* raw query is pre-compiled too 
00589                 res = eval_xlstr(m, &action->raw);
00590                 if (res < 0) return res;
00591                 
00592                  * FIXME: We have to make sure that we do not use pre-compiled statements
00593                  * here because these must not change at runtime: to be checked by janakj
00594                  *
00595                 action->cmd->table.s = action->raw.s;
00596                 action->cmd->table.len = strlen(action->raw.s);
00597                 */
00598         }
00599         else {
00600                 DEBUG(MODULE_NAME": dbops_func(%s, %d, %d, '%s', %d, %d, %d)\n", action->query_name, action->query_no, action->operation, action->table.s, action->field_count, action->where_count, action->value_count);
00601         
00602                 /* FIXME: We do not support volatile table names yet */
00603                 /*      res = eval_xlstr(m, &action->table); 
00604                         if (res < 0) return res;
00605                 */
00606 
00607                 /*
00608                  * FIXME: Changing field names in result set is not yet supported
00609                         for (i=0; i<action->field_count; i++) {
00610                                 res = eval_xlstr(m, &action->fields[i]);
00611                                 if (res < 0) goto cleanup;
00612                                 action->cmd->result[i].v.name = action->fields[i].s;
00613                         }
00614                 */
00615                 /*
00616                  * FIXME: Changing parameters names and operation not yet
00617                  * supported at runtime
00618                         for (i=0; i<action->where_count; i++) {
00619                                 res = eval_xlstr(m, &action->wheres[i]);
00620                                 if (res < 0) goto cleanup;
00621                                 action->cmd->params[i].name = action->wheres[i].s;
00622 
00623                                 if (i < action->op_count) {
00624                                         res = eval_xlstr(m, &action->ops[i]);
00625                                         if (res < 0) goto cleanup;
00626                                         action->cmd->params[i].op = action->ops[i].s;
00627                                 }
00628                                 else {
00629                                         action->cmd->params[i].op = OP_EQ;
00630                                 }
00631                         }
00632                 */
00633                 /* FIXME: Changing parameters names and operation not yet
00634                  * supported at runtime
00635                         if (action->operation == OPEN_QUERY_OPS) {
00636                                 if (action->order.s) {
00637                                         res = eval_xlstr(m, &action->order);
00638                                         if (res < 0) return res;
00639                                 }
00640                                 order = action->order.s;
00641                         }
00642                 */
00643         }
00644         for (i=0; i<action->value_count; i++) {
00645                 char *end;
00646                 db_fld_t *cmd_params;
00647                 res = eval_xlstr(m, &action->values[i]);
00648                 if (res < 0) goto cleanup;
00649 
00650                 /* split single db_ops values range to db_api matches and vals ranges */
00651                 if (action->is_raw_query) {
00652                         cmd_params = action->cmd->match+i;
00653                 }
00654                 else {
00655                         switch (action->operation) {
00656                                 case OPEN_QUERY_OPS:
00657                                 case DELETE_OPS:
00658                                         cmd_params = action->cmd->match+i;
00659                                         break;
00660                                 case UPDATE_OPS:
00661                                         if (i < action->field_count)
00662                                                 cmd_params = action->cmd->vals+i;
00663                                         else
00664                                                 cmd_params = action->cmd->match+i-action->field_count;
00665                                         break;
00666                                 case REPLACE_OPS:
00667                                 case INSERT_OPS:
00668                                         cmd_params = action->cmd->vals+i;
00669                                         break;
00670                                 default:
00671                                         BUG("Unknown operation type: %d\n", action->operation);
00672                                         goto err;
00673                         }
00674                 }
00675                 
00676                 if (!action->values[i].s || !action->values[i].s[0]) cmd_params->flags |= DB_NULL;
00677                 switch (cmd_params->type) {
00678                         case DB_DATETIME:
00679                                 if (!(cmd_params->flags & DB_NULL))
00680                                         cmd_params->v.time = strtol(action->values[i].s, &end, 10);
00681                                 break;
00682                         case DB_INT:
00683                                 if (!(cmd_params->flags & DB_NULL))
00684                                         cmd_params->v.int4 = strtol(action->values[i].s, &end, 10);
00685                                 break;
00686                         case DB_FLOAT:
00687                                 if (!(cmd_params->flags & DB_NULL))
00688                                 #ifdef  __USE_ISOC99
00689                                         cmd_params->v.flt = strtof(action->values[i].s, &end);
00690                                 #else
00691                                         cmd_params->v.flt = strtod(action->values[i].s, &end);
00692                                 #endif
00693                                 break;
00694                         case DB_DOUBLE:
00695                                 if (!(cmd_params->flags & DB_NULL))
00696                                         cmd_params->v.dbl = strtod(action->values[i].s, &end);
00697                                 break;
00698                         case DB_CSTR:
00699                                 cmd_params->v.cstr = action->values[i].s;
00700                                 cmd_params->flags &= ~DB_NULL;
00701                                 break;
00702                 default:
00703                                 BUG("Unknown value type: %d\n", cmd_params->type);
00704                                 goto err;
00705                 }
00706         }
00707         if (db_exec((action->operation==OPEN_QUERY_OPS?&action->result:NULL), action->cmd) < 0) goto err;
00708         res = 1;
00709 cleanup:
00710         return res;
00711 err:
00712         ERR(MODULE_NAME": query: %s(%d), database operation (%d) error, table: '%s'\n", action->query_name, action->query_no, action->operation, action->table.s);
00713         res = -1;
00714         goto cleanup;
00715 }
00716 
00717 static int do_seek(db_res_t* result, int *cur_row_no, int row_no) {
00718 
00719         if (row_no == *cur_row_no) return 0;
00720         if (row_no < *cur_row_no) *cur_row_no = -1;
00721 
00722         DEBUG(MODULE_NAME": do_seek: currowno:%d, rowno=%d\n", *cur_row_no, row_no);
00723         if (*cur_row_no < 0) {
00724                 if (!db_first(result)) return -1;
00725                 *cur_row_no = 0;
00726         }
00727         while (*cur_row_no < row_no) {
00728                 if (!db_next(result)) {
00729                         *cur_row_no = -1;
00730                         return -1;
00731                 }
00732                 (*cur_row_no)++;
00733         }
00734         return 0;
00735 }
00736 
00737 static int sel_get_field(str* res, int *cur_row_no, int field_no, db_res_t* result) {
00738 /* return string in static buffer, I'm not sure if local static variable is OK, e.g. when comparing 2 selects */
00739         int len;
00740         db_rec_t* rec;
00741         len = xlbuf_size-(xlbuf_tail-xlbuf);
00742         res->s = xlbuf_tail;
00743         res->len = 0;
00744         if (field_no == -2) {  /* cur_row_no */
00745                 res->len = snprintf(res->s, len, "%d", *cur_row_no);
00746         }
00747         else if (field_no < 0) {  /* count(*) | is empty */
00748                 int n;
00749                 if (*cur_row_no < 0) {
00750                         rec = db_first(result);
00751                         if (rec) {
00752                                 *cur_row_no = 0;
00753                         }
00754                 }
00755                 if (field_no == -3) { /* is_empty */
00756                         if (*cur_row_no >= 0) 
00757                                 n = 0;
00758                         else
00759                                 n = 1;
00760                 }
00761                 else {
00762                         n = 0;
00763                         if (*cur_row_no >= 0) {
00764                                 do {
00765                                         n++;
00766                                         rec = db_next(result);
00767                                 } while (rec);
00768                         }
00769                         *cur_row_no = -1;
00770                 }
00771                 res->len = snprintf(res->s, len, "%d", n);
00772         }
00773         else {
00774                 if (*cur_row_no < 0) {
00775                         ERR(MODULE_NAME": cursor points beyond data\n");
00776                         return -1;      
00777                 }
00778                 if (field_no >= result->field_count) {
00779                         ERR(MODULE_NAME": field (%d) does not exist, num fields: %d\n", field_no, result->field_count);
00780                         return -1;
00781                 }
00782                 rec = result->cur_rec;
00783                 if (!(rec->fld[field_no].flags & DB_NULL)) {
00784                         switch (rec->fld[field_no].type) {
00785                                 case DB_INT:
00786                                         res->len = snprintf(res->s, len, "%d", rec->fld[field_no].v.int4);
00787                                         break;
00788                                 case DB_FLOAT:
00789                                         res->len = snprintf(res->s, len, "%f", rec->fld[field_no].v.flt);
00790                                         break;
00791                                 case DB_DOUBLE:
00792                                         res->len = snprintf(res->s, len, "%f", rec->fld[field_no].v.dbl);
00793                                         break;
00794                                 case DB_STR:
00795                                         res->len = snprintf(res->s, len, "%.*s", 
00796                                                                                 rec->fld[field_no].v.lstr.len,
00797                                                                                 rec->fld[field_no].v.lstr.s);
00798                                         break;
00799                                 case DB_BLOB:
00800                                         res->len = snprintf(res->s, len, "%.*s", 
00801                                                                                 rec->fld[field_no].v.blob.len,
00802                                                                                 rec->fld[field_no].v.blob.s);
00803                                         break;
00804                                 case DB_CSTR:
00805                                         res->len = snprintf(res->s, len, "%s", rec->fld[field_no].v.cstr);
00806                                         break;
00807                                 case DB_DATETIME:
00808                                         res->len = snprintf(res->s, len, "%u", (unsigned int) rec->fld[field_no].v.time);
00809                                         break;
00810                                 case DB_BITMAP:
00811                                         res->len = snprintf(res->s, len, "%u", (unsigned int) rec->fld[field_no].v.bitmap);
00812                                         break;
00813                                 default:
00814                                         break;
00815                         }
00816                 }
00817         }
00818         xlbuf_tail += res->len;
00819         return 0;
00820 }
00821 
00822 static int sel_do_select(str* result, str *query_name, int row_no, int field_no, struct sip_msg* msg) {
00823         struct dbops_action *a;
00824         int cur_row_no, res;
00825 
00826         a = find_action_by_name(query_name->s, query_name->len);
00827         if (!a) {
00828                 ERR(MODULE_NAME": select: query: %.*s not declared using declare_query param\n", query_name->len, query_name->s);
00829                 return -1;
00830         }
00831         if (a->operation != OPEN_QUERY_OPS) {
00832                 ERR(MODULE_NAME": select: query: %.*s is not select\n", query_name->len, query_name->s);
00833                 return -1;
00834         }
00835 
00836         if (row_no < 0) {
00837                 ERR(MODULE_NAME": select: Row number must not be negative: %d\n", row_no);
00838                 return -1;
00839         }
00840 
00841         res = dbops_func(msg, a);
00842         if (res < 0) return res;
00843         cur_row_no = -1;
00844         if (field_no >= 0) {
00845                 if (do_seek(a->result, &cur_row_no, row_no) < 0)
00846                         return -1;
00847         }
00848 
00849         res = sel_get_field(result, &cur_row_no, field_no, a->result);
00850         db_res_free(a->result);
00851         return res;
00852 }
00853 
00854 static inline int check_query_opened(struct dbops_handle *handle, char *f) {
00855         if (!handle->result) {
00856                 ERR(MODULE_NAME": %s: handle '%s' is not opened. Use db_query() first\n", f, handle->handle_name);
00857                 return -1;
00858         }
00859         else
00860                 return 1;
00861 }
00862 
00863 static int sel_do_fetch(str* result, str *handle_name, int field_no, struct sip_msg* msg) {
00864         struct dbops_handle *a;
00865         a = find_handle_by_name(handle_name->s, handle_name->len);
00866         if (!a) {
00867                 ERR(MODULE_NAME": fetch: handle (%.*s) is not declared\n", handle_name->len, handle_name->s);
00868                 return -1;
00869         }
00870         if (check_query_opened(a, "fetch") < 0) return -1;      
00871         return sel_get_field(result, &a->cur_row_no, field_no, a->result);
00872 }
00873 
00874 static int sel_dbops(str* res, select_t* s, struct sip_msg* msg) {  /* dummy */
00875         return 0;
00876 }
00877 
00878 static int sel_select(str* res, select_t* s, struct sip_msg* msg) {
00879         return sel_do_select(res, &s->params[2].v.s, 0, 0, msg);
00880 }
00881 
00882 static int sel_select_is_empty(str* res, select_t* s, struct sip_msg* msg) {
00883         return sel_do_select(res, &s->params[2].v.s, 0, -3, msg);
00884 }
00885 
00886 static int sel_select_count(str* res, select_t* s, struct sip_msg* msg) {
00887         return sel_do_select(res, &s->params[2].v.s, 0, -1, msg);
00888 }
00889 
00890 static int sel_select_row(str* res, select_t* s, struct sip_msg* msg) {
00891         return sel_do_select(res, &s->params[2].v.s, s->params[4].v.i, 0, msg);
00892 }
00893 
00894 
00895 static int sel_select_row_field(str* res, select_t* s, struct sip_msg* msg) {
00896         return sel_do_select(res, &s->params[2].v.s, s->params[4].v.i, s->params[6].v.i, msg);
00897 }
00898 
00899 static int sel_select_field(str* res, select_t* s, struct sip_msg* msg) {
00900         return sel_do_select(res, &s->params[2].v.s, 0, s->params[4].v.i, msg);
00901 }
00902 
00903 static int sel_fetch(str* res, select_t* s, struct sip_msg* msg) {
00904         return sel_do_fetch(res, &s->params[2].v.s, 0, msg);
00905 }
00906 
00907 static int sel_fetch_field(str* res, select_t* s, struct sip_msg* msg) {
00908         return sel_do_fetch(res, &s->params[2].v.s, s->params[4].v.i, msg);
00909 }
00910 
00911 static int sel_fetch_cur_row_no(str* res, select_t* s, struct sip_msg* msg) {
00912         return sel_do_fetch(res, &s->params[2].v.s, -2, msg);
00913 }
00914 
00915 static int sel_fetch_is_empty(str* res, select_t* s, struct sip_msg* msg) {
00916         return sel_do_fetch(res, &s->params[2].v.s, -3, msg);
00917 }
00918 
00919 static int sel_fetch_count(str* res, select_t* s, struct sip_msg* msg) {
00920         return sel_do_fetch(res, &s->params[2].v.s, -1, msg);
00921 }
00922 
00923 
00924 SELECT_F(select_any_nameaddr)
00925 SELECT_F(select_any_uri)
00926 
00927 select_row_t sel_declaration[] = {
00928         { NULL, SEL_PARAM_STR, STR_STATIC_INIT(MODULE_NAME2), sel_dbops, SEL_PARAM_EXPECTED},
00929 
00930         { sel_dbops, SEL_PARAM_STR, STR_STATIC_INIT("query"), sel_select, CONSUME_NEXT_STR},
00931         { sel_select, SEL_PARAM_STR, STR_STATIC_INIT("is_empty"), sel_select_is_empty},
00932         { sel_select, SEL_PARAM_STR, STR_STATIC_INIT("count"), sel_select_count},
00933         { sel_select, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR},
00934         { sel_select, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_any_uri, NESTED | CONSUME_NEXT_STR},
00935         { sel_select, SEL_PARAM_STR, STR_STATIC_INIT("field"), sel_select_field, CONSUME_NEXT_INT},
00936         { sel_select_field, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR},
00937         { sel_select_field, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_any_uri, NESTED | CONSUME_NEXT_STR},
00938         
00939         { sel_select, SEL_PARAM_STR, STR_STATIC_INIT("row"), sel_select_row, CONSUME_NEXT_INT},
00940         { sel_select_row, SEL_PARAM_STR, STR_STATIC_INIT("field"), sel_select_row_field, CONSUME_NEXT_INT},
00941         { sel_select_row_field, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR},
00942         { sel_select_row_field, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_any_uri, NESTED | CONSUME_NEXT_STR},
00943         
00944         { sel_dbops, SEL_PARAM_STR, STR_STATIC_INIT("fetch"), sel_fetch, CONSUME_NEXT_STR},
00945         { sel_fetch, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR},
00946         { sel_fetch, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_any_uri, NESTED | CONSUME_NEXT_STR},
00947         { sel_fetch, SEL_PARAM_STR, STR_STATIC_INIT("row_no"), sel_fetch_cur_row_no, 0},
00948         { sel_fetch, SEL_PARAM_STR, STR_STATIC_INIT("count"), sel_fetch_count, 0},
00949         { sel_fetch, SEL_PARAM_STR, STR_STATIC_INIT("is_empty"), sel_fetch_is_empty, 0},
00950         { sel_fetch, SEL_PARAM_STR, STR_STATIC_INIT("field"), sel_fetch_field, CONSUME_NEXT_INT},
00951         { sel_fetch_field, SEL_PARAM_STR, STR_STATIC_INIT("nameaddr"), select_any_nameaddr, NESTED | CONSUME_NEXT_STR},
00952         { sel_fetch_field, SEL_PARAM_STR, STR_STATIC_INIT("uri"), select_any_uri, NESTED | CONSUME_NEXT_STR},
00953                 
00954         { NULL, SEL_PARAM_INT, STR_NULL, NULL, 0}
00955 };
00956 
00957 static int dbops_close_query_func(struct sip_msg* m, char* handle, char* dummy) {
00958         struct dbops_handle *a = (void *)handle;
00959         if (a->result) {
00960                 db_res_free(a->result);
00961                 a->result = 0;
00962         }
00963         return 1;
00964 }
00965 
00966 static int dbops_pre_script_cb(struct sip_msg *msg, unsigned int flags, void *param) {
00967         xlbuf_tail = xlbuf;
00968         return 1;
00969 }
00970 
00971 static int dbops_post_script_cb(struct sip_msg *msg, unsigned int flags, void *param) {
00972         struct dbops_handle *a;
00973         for (a = dbops_handles; a; a=a->next) {
00974                 dbops_close_query_func(msg, (char*) a, 0);
00975         }
00976         return 1;
00977 }
00978 
00979 static int init_action(struct dbops_action* action) {
00980         int res, i;
00981 
00982         if (!action->db_url)
00983                 action->db_url = db_url;
00984 
00985         res = parse_xlstr(&action->table);
00986         if (res < 0) return res;
00987         for (i=0; i<action->field_count; i++) {
00988                 res = parse_xlstr(&action->fields[i]);
00989                 if (res < 0) return res;
00990         }
00991 
00992         for (i=0; i<action->where_count; i++) {
00993                 res = parse_xlstr(&action->wheres[i]);
00994                 if (res < 0) return res;
00995         }
00996         for (i=0; i<action->value_count; i++) {
00997                 res = parse_xlstr(&action->values[i]);
00998                 if (res < 0) return res;
00999         }
01000         res = parse_xlstr(&action->order);
01001         if (res < 0) return res;
01002         res = parse_xlstr(&action->raw);
01003 
01004         return res;
01005 }
01006 
01007 static int dbops_fixup_func(void** param, int init_act) {
01008         struct dbops_action **p, *a;
01009         char *c;
01010         int res;
01011 
01012         /* check if is it a declare_no that references to declare_xxxx */
01013         c = *param;
01014         eat_spaces(c);
01015         *param = c;
01016         eat_alphanum(c);
01017         if (*c == 0) {
01018                 a = find_action_by_name(*param, -1);
01019                 if (!a) {
01020                         ERR(MODULE_NAME": fixup_func: query (%s) not declared\n", (char*) *param);
01021                         return -1;
01022                 }
01023                 *param = (void*) a;
01024                 return 0;
01025         }
01026 
01027         for (p = &dbops_actions; *p; p=&(*p)->next);    /* add at the end of list */
01028         res = parse_ops(*param, p, init_act == 0 /* declare query has name */);
01029         if (res < 0) return res;
01030         /* pkg_free(*param); do not free it!*/
01031         *param = (void*) *p;
01032         if (init_act)
01033                 return init_action(*p);   /* fixup is acquired after init_mod() therefore initialize new action */
01034         else
01035                 return 0;
01036 }
01037 
01038 static int mod_init(void) {
01039         struct dbops_action* p;
01040 
01041         xlbuf = pkg_malloc((xlbuf_size+1)*sizeof(char));
01042         if (!xlbuf) {
01043                 ERR(MODULE_NAME": out of memory, cannot create xlbuf\n");
01044                 return E_OUT_OF_MEM;
01045         }
01046 
01047         for (p=dbops_actions; p; p=p->next) {
01048                 int res;
01049                 res = init_action(p);
01050                 if (res < 0)
01051                         return res;
01052         }
01053 
01054         register_script_cb(dbops_pre_script_cb, REQUEST_CB | ONREPLY_CB | PRE_SCRIPT_CB, 0);
01055         register_script_cb(dbops_post_script_cb, REQUEST_CB | ONREPLY_CB | POST_SCRIPT_CB, 0);
01056         register_select_table(sel_declaration);
01057 
01058         return 0;
01059 }
01060 
01061 
01062 static int build_match(db_fld_t** match, struct dbops_action* p)
01063 {
01064         int i;
01065         db_fld_t* newp;
01066 
01067         if (!p->where_count) {
01068                 *match = NULL;
01069                 return 0;
01070         }
01071 
01072         newp = (db_fld_t*)pkg_malloc(sizeof(db_fld_t) * (p->where_count + 1));
01073         if (newp == NULL) {
01074                 ERR(MODULE_NAME": No memory left\n");
01075                 return -1;
01076         }
01077         memset(newp, '\0', sizeof(db_fld_t) * p->where_count);
01078 
01079         for(i = 0; i < p->where_count; i++) {
01080                 newp[i].name = p->wheres[i].s;
01081                 newp[i].type = p->value_types[i];
01082 
01083                 if (i < p->op_count) {
01084                         if (!strcmp(p->ops[i].s, "=")) {
01085                                 newp[i].op = DB_EQ;
01086                         } else if (!strcmp(p->ops[i].s, "<=")) {
01087                                 newp[i].op = DB_LEQ;
01088                         } else if (!strcmp(p->ops[i].s, "<")) {
01089                                 newp[i].op = DB_LT;
01090                         } else if (!strcmp(p->ops[i].s, ">")) {
01091                                 newp[i].op = DB_GT;
01092                         } else if (!strcmp(p->ops[i].s, ">=")) {
01093                                 newp[i].op = DB_GEQ;
01094                         } else if (!strcmp(p->ops[i].s, "<>")) {
01095                                 newp[i].op = DB_NE;
01096                         } else if (!strcmp(p->ops[i].s, "!=")) {
01097                                 newp[i].op = DB_NE;
01098                         } else {
01099                                 ERR(MODULE_NAME": Unsupported operator type: %s\n", p->ops[i].s);
01100                                 pkg_free(newp);
01101                                 return -1;
01102                         }
01103                 }
01104                 else {
01105                         newp[i].op = DB_EQ;
01106                 }
01107         }
01108         newp[i].name = NULL;
01109         
01110         *match = newp;
01111         return 0;
01112 }
01113 
01114 
01115 static int build_result(db_fld_t** result, struct dbops_action* p)
01116 {
01117         int i;
01118         db_fld_t* newp;
01119 
01120         if (!p->field_count) {
01121                 *result = NULL;
01122                 return 0;
01123         }
01124 
01125         newp = (db_fld_t*)pkg_malloc(sizeof(db_fld_t) * (p->field_count + 1));
01126         if (newp == NULL) {
01127                 ERR(MODULE_NAME": No memory left\n");
01128                 return -1;
01129         }
01130         memset(newp, '\0', sizeof(db_fld_t) * p->field_count);
01131 
01132         for(i = 0; i < p->field_count; i++) {
01133                 newp[i].name = p->fields[i].s;
01134                 newp[i].type = DB_NONE;
01135         }
01136         newp[i].name = NULL;
01137         *result = newp;
01138         return 0;
01139 }
01140 
01141 
01142 static int build_params(db_fld_t** params, struct dbops_action* p)
01143 {
01144         int i;
01145         db_fld_t* newp;
01146 
01147         if (!p->value_count) {
01148                 *params = NULL;
01149                 return 0;
01150         }
01151 
01152         newp = (db_fld_t*)pkg_malloc(sizeof(db_fld_t) * (p->value_count - p->where_count + 1));
01153         if (newp == NULL) {
01154                 ERR(MODULE_NAME": No memory left\n");
01155                 return -1;
01156         }
01157         memset(newp, '\0', sizeof(db_fld_t) * p->value_count);
01158 
01159         for(i = 0; i < p->value_count - p->where_count; i++) {
01160                 newp[i].name = (i < p->field_count)?p->fields[i].s:""; /* in case of raw query it's empty */
01161                 newp[i].type = p->value_types[i];
01162         }
01163         newp[i].name = NULL;
01164         
01165         *params = newp;
01166         return 0;
01167 }
01168 
01169 
01170 
01171 static int init_db(struct dbops_action* p)
01172 {
01173         db_fld_t* matches = NULL, *result = NULL, *values = NULL;
01174         int type, i;
01175 
01176         DEBUG(MODULE_NAME": init_db: query: %s(%d)\n", p->query_name, p->query_no);
01177         if (p->db_url == NULL) {
01178                 ERR(MODULE_NAME": No database URL specified\n");
01179                 return -1;
01180         }
01181         p->ctx = db_ctx(MODULE_NAME);
01182         if (p->ctx == NULL) {
01183                 ERR(MODULE_NAME": Error while initializing database layer\n");
01184                 return -1;
01185         }
01186         
01187         if (db_add_db(p->ctx, p->db_url) < 0) return -1;
01188         if (db_connect(p->ctx) < 0) return -1;
01189 
01190         if (p->is_raw_query) {
01191                 type = DB_SQL;
01192                 if (build_params(&matches, p) < 0) return -1;
01193         }
01194         else {
01195                 switch(p->operation) {
01196                 case INSERT_OPS:
01197                 case REPLACE_OPS:
01198                         type = DB_PUT;
01199                         if (build_params(&values, p) < 0) return -1;
01200                         break;
01201 
01202                 case UPDATE_OPS:
01203                         type = DB_UPD;
01204                         if (build_match(&matches, p) < 0) return -1;
01205                         if (build_params(&values, p) < 0) {
01206                                 if (matches) pkg_free(matches);
01207                                 return -1;
01208                         }
01209                         break;
01210 
01211                 case DELETE_OPS:
01212                         type = DB_DEL;
01213 
01214                         if (build_match(&matches, p) < 0) return -1;
01215                         break;
01216 
01217                 case OPEN_QUERY_OPS:
01218                         type = DB_GET;
01219                         if (build_match(&matches, p) < 0) return -1;
01220                         if (build_result(&result, p) < 0) {
01221                                 if (matches) pkg_free(matches);
01222                                 return -1;
01223                         }
01224                         break;
01225                 default:
01226                         BUG("Unknown operation %d\n", p->operation);
01227                         return -1;
01228                 }
01229         }
01230 
01231         p->cmd = db_cmd(type, p->ctx, p->table.s, result, matches, values);
01232         if (p->cmd == NULL) {
01233                 ERR(MODULE_NAME": init_db: query: %s(%d), error while compiling database query\n", p->query_name, p->query_no);
01234                 if (values) pkg_free(values);
01235                 if (matches) pkg_free(matches);
01236                 if (result) pkg_free(result);
01237                 db_disconnect(p->ctx);
01238                 db_ctx_free(p->ctx);
01239                 return -1;
01240         }
01241         if (values) pkg_free(values);
01242         if (matches) pkg_free(matches);
01243         if (result) pkg_free(result);
01244 
01245         for (i=0; i<p->extra_ops_count; i++) {
01246                 char *end;
01247                 DEBUG(MODULE_NAME": init_db: query_no: %s(%d), setopt('%s', %i, '%s'\n", p->query_name, p->query_no, p->extra_ops[i].name, p->extra_ops[i].type, p->extra_ops[i].value);
01248                 switch (p->extra_ops[i].type) {
01249                         case DB_NONE: 
01250                                 /* set null ?? */
01251                                 break;                  
01252                         case DB_DATETIME: {
01253                                 time_t v;
01254                                 v = strtol(p->extra_ops[i].value, &end, 10);
01255                                 if (db_setopt(p->cmd, p->extra_ops[i].name, v) < 0) return -1;
01256                                 break;
01257                         }
01258                         case DB_INT: {
01259                                 int v;
01260                                 v = strtol(p->extra_ops[i].value, &end, 10);
01261                                 if (db_setopt(p->cmd, p->extra_ops[i].name, v) < 0) return -1;
01262                                 break;
01263                         }
01264                         case DB_FLOAT: {
01265                                 float v;
01266                                 #ifdef  __USE_ISOC99
01267                                 v = strtof(p->extra_ops[i].value, &end);
01268                                 #else
01269                                 v = strtod(p->extra_ops[i].value, &end);
01270                                 #endif
01271                                 if (db_setopt(p->cmd, p->extra_ops[i].name, v) < 0) return -1;
01272                                 break;
01273                         }
01274                         case DB_DOUBLE: {
01275                                 double v;
01276                                 v = strtod(p->extra_ops[i].value, &end);
01277                                 if (db_setopt(p->cmd, p->extra_ops[i].name, v) < 0) return -1;
01278                                 break;
01279                         }
01280                         case DB_CSTR:
01281                                 if (db_setopt(p->cmd, p->extra_ops[i].name, p->extra_ops[i].value) < 0) return -1;
01282                                 break;
01283                 default:
01284                                 BUG("Unknown extra_op type: %d\n", p->extra_ops[i].type);
01285                                 return -1;
01286                 }
01287         }
01288         return 0;
01289 }
01290 
01291 static int child_init(int rank) {
01292         struct dbops_action *p, *p2;
01293         if (rank!=PROC_INIT && rank != PROC_MAIN && rank != PROC_TCP_MAIN) {
01294                 for (p=dbops_actions; p; p=p->next) {
01295                         for (p2=dbops_actions; p!=p2; p2=p2->next) {  /* check if database is already opened */
01296                                 if (strcmp(p->db_url, p2->db_url) == 0) {
01297                                         p->ctx = p2->ctx;
01298                                         break;
01299                                 }
01300                         }
01301 
01302                         /* FIXME: Initialize database layer here */
01303 
01304                         if (init_db(p) < 0) {
01305                                 ERR(MODULE_NAME": CHILD INIT #err\n");
01306 
01307                                 return -1;
01308                         }
01309                 }
01310         }
01311         return 0;
01312 }
01313 
01314 static int dbops_close_query_fixup(void** param, int param_no) {
01315         struct dbops_handle *a;
01316         a = find_handle_by_name((char*) *param, -1);
01317         if (!a) {
01318                 ERR(MODULE_NAME": handle '%s' is not declared\n", (char*) *param);
01319                 return E_CFG;
01320         }
01321         pkg_free (*param);
01322         *param = (void*) a;
01323         return 0;
01324 }
01325 
01326 static int dbops_query_fixup(void** param, int param_no) {
01327         int res = 0;
01328         if (param_no == 1) {
01329                 res = dbops_fixup_func(param, 1);
01330                 if (res < 0) return res;
01331                 if (((struct dbops_action*)*param)->operation == OPEN_QUERY_OPS) {
01332                         if (fixup_get_param_count(param, param_no) != 2) {
01333                                 ERR(MODULE_NAME": query_fixup: SELECT query requires 2 parameters\n");
01334                                 return E_CFG;
01335                         }
01336                 }
01337                 else {
01338                         if (fixup_get_param_count(param, param_no) != 1) {
01339                                 ERR(MODULE_NAME": query_fixup: non SELECT query requires only 1 parameter\n");
01340                                 return E_CFG;
01341                         }
01342                 }
01343         }
01344         else if (param_no == 2) {
01345                 return dbops_close_query_fixup(param, param_no);
01346         }
01347         return res;
01348 }
01349 
01350 static int dbops_query_func(struct sip_msg* m, char* dbops_action, char* handle) {
01351         if ( ((struct dbops_action*) dbops_action)->operation == OPEN_QUERY_OPS ) {
01352                 int res;
01353                 struct dbops_handle *a = (void*) handle;
01354                 dbops_close_query_func(m, handle, 0);
01355                 res = dbops_func(m, (void*) dbops_action);
01356                 if (res < 0) return res;
01357                 a->action = (struct dbops_action*) dbops_action;
01358                 a->cur_row_no = -1;
01359                 a->result = ((struct dbops_action*) dbops_action)->result;
01360                 res = do_seek(((struct dbops_action*) dbops_action)->result, &a->cur_row_no, 0);
01361                 if (res < 0) return res;
01362                 return 1;
01363         }
01364         else
01365                 return dbops_func(m, (void*) dbops_action);
01366 }
01367 
01368 static int dbops_seek_fixup(void** param, int param_no) {
01369         if (param_no == 1) {
01370                 return dbops_close_query_fixup(param, param_no);
01371         }
01372         else if (param_no == 2) {
01373                 return fixup_int_12(param, param_no);
01374         }
01375         return 0;
01376 }
01377 
01378 static int dbops_seek_func(struct sip_msg* m, char* handle, char* row_no) {
01379         int res, n;
01380         struct dbops_handle *a = (void *) handle;
01381         res = check_query_opened(a, "seek");
01382         if (res < 0) return res;
01383 
01384         if (get_int_fparam(&n, m, (fparam_t*) row_no) < 0) {
01385                 return -1;
01386         }
01387         res = do_seek(a->result, &a->cur_row_no, n);
01388         if (res < 0) return res;
01389         return 1;
01390 }
01391 
01392 static int dbops_first_func(struct sip_msg* m, char* handle, char* row_no) {
01393         int res;
01394         struct dbops_handle *a = (void *) handle;
01395         res = check_query_opened(a, "first");
01396         if (res < 0) return res;
01397         
01398         a->cur_row_no = -1; /* force seek */
01399         res = do_seek(a->result, &a->cur_row_no, 0);
01400         if (res < 0) return res;
01401         return 1;
01402 }
01403 
01404 static int dbops_next_func(struct sip_msg* m, char* handle, char* row_no) {
01405         int res;
01406         struct dbops_handle *a = (void *) handle;
01407         res = check_query_opened(a, "next");
01408         if (res < 0) return res;
01409         
01410         res = do_seek(a->result, &a->cur_row_no, a->cur_row_no+1);
01411         if (res < 0) return res;
01412         return 1;
01413 }
01414 
01415 static int dbops_foreach_fixup(void** param, int param_no) {
01416         if (param_no == 1) {
01417                 return dbops_close_query_fixup(param, param_no);
01418         }
01419         else if (param_no == 2) {
01420                 int n;
01421                 n = route_get(&main_rt, (char*) *param);
01422                 if (n == -1) {
01423                         ERR(MODULE_NAME": db_foreach: bad route\n");
01424                         return E_CFG;
01425                 }
01426                 pkg_free(*param);
01427                 *param=(void*) (unsigned long) n;
01428         }
01429         return 0;
01430 }
01431 
01432 
01433 static int dbops_foreach_func(struct sip_msg* m, char* handle, char* route_no) {
01434         int res;
01435         db_rec_t* rec;
01436         struct dbops_handle *a = (void *) handle;
01437         struct run_act_ctx ra_ctx;
01438         
01439         if ((long)route_no >= main_rt.idx) {
01440                 BUG("invalid routing table number #%ld of %d\n", (long) route_no, main_rt.idx);
01441                 return -1;
01442         }
01443         if (!main_rt.rlist[(long) route_no]) {
01444                 WARN(MODULE_NAME": route not declared (hash:%ld)\n", (long) route_no);
01445                 return -1;
01446         }
01447         res = check_query_opened(a, "for_each");
01448         if (res < 0) return res;
01449 
01450         res = -1;
01451         a->cur_row_no = 0;
01452         for(rec = db_first(a->result);
01453                         rec != NULL;
01454                         rec = db_next(a->result),
01455                         a->cur_row_no++) {
01456                 /* exec the routing script */
01457                 init_run_actions_ctx(&ra_ctx);
01458                 res = run_actions(&ra_ctx, main_rt.rlist[(long) route_no], m);
01459                 if (res <= 0) break;
01460         }
01461         if (!rec) a->cur_row_no = -1;
01462         return res;
01463 }
01464 
01465 static int declare_query(modparam_t type, char* param) {
01466         void* p = param;
01467         return dbops_fixup_func(&p, 0); /* add at the end of the action list */
01468 }
01469 
01470 static int declare_handle(modparam_t type, char* param) {
01471         struct dbops_handle *a;
01472         if (strlen(param) == 0) {
01473                 ERR(MODULE_NAME": declare_handle: handle name is empty\n");
01474                 return E_CFG;
01475         }
01476         a = find_handle_by_name(param, -1);
01477         if (a) {
01478                 ERR(MODULE_NAME": declare_handle: handle '%s' already exists\n", param);
01479                 return E_CFG;
01480         }
01481         
01482         a = pkg_malloc(sizeof(*a));
01483         if (!a) {
01484                 ERR(MODULE_NAME": Out od memory\n");
01485                 return E_OUT_OF_MEM;
01486         }
01487         memset(a, 0, sizeof(*a));
01488         a->handle_name = param;
01489         a->next = dbops_handles;
01490         dbops_handles = a;
01491         return 0;
01492 }
01493 
01494 static int dbops_proper_func(struct sip_msg* m, char* dummy1, char* dummy2) {
01495         dbops_pre_script_cb(m, 0, NULL);
01496         dbops_post_script_cb(m, 0, NULL);
01497         return 1;
01498 }
01499 
01500 /*
01501  * Exported functions
01502  */
01503 static cmd_export_t cmds[] = {
01504         {MODULE_NAME2"_query", dbops_query_func, 1, dbops_query_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
01505         {MODULE_NAME2"_query", dbops_query_func, 2, dbops_query_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
01506         {MODULE_NAME2"_first", dbops_first_func, 1, dbops_close_query_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
01507         {MODULE_NAME2"_next", dbops_next_func, 1, dbops_close_query_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
01508         {MODULE_NAME2"_seek", dbops_seek_func, 2, dbops_seek_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
01509         {MODULE_NAME2"_close", dbops_close_query_func, 1, dbops_close_query_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
01510         {MODULE_NAME2"_foreach", dbops_foreach_func, 2, dbops_foreach_fixup, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE | ONSEND_ROUTE},
01511         {MODULE_NAME2"_proper", dbops_proper_func, 0, 0, FAILURE_ROUTE},
01512         {0, 0, 0, 0, 0}
01513 };
01514 
01515 
01516 /*
01517  * Exported parameters
01518  */
01519 static param_export_t params[] = {
01520         {"db_url",    PARAM_STRING, &db_url},
01521         {"declare_query", PARAM_STRING|PARAM_USE_FUNC, (void*) declare_query},
01522         {"declare_handle", PARAM_STRING|PARAM_USE_FUNC, (void*) declare_handle},
01523         {"xlbuf_size", PARAM_INT, &xlbuf_size},
01524         {0, 0, 0}
01525 };
01526 
01527 
01528 struct module_exports exports = {
01529         MODULE_NAME,
01530         cmds,        /* Exported commands */
01531         0,           /* RPC */
01532         params,      /* Exported parameters */
01533         mod_init,           /* module initialization function */
01534         0,           /* response function*/
01535         0,           /* destroy function */
01536         0,           /* oncancel function */
01537         child_init   /* per-child init function */
01538 };