db_cmd.c

00001 /* 
00002  * $Id$ 
00003  *
00004  * Copyright (C) 2001-2005 FhG FOKUS
00005  * Copyright (C) 2006-2007 iptelorg GmbH
00006  *
00007  * This file is part of ser, a free SIP server.
00008  *
00009  * ser is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * For a license to use the ser software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact iptel.org by e-mail at the following addresses:
00017  *    info@iptel.org
00018  *
00019  * ser is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License 
00025  * along with this program; if not, write to the Free Software 
00026  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027  */
00028 
00033 #include "db_cmd.h"
00034 
00035 #include "../../dprint.h"
00036 #include "../../mem/mem.h"
00037 #include "../../ut.h"
00038 
00039 #include <string.h>
00040 #include <stdarg.h>
00041 
00042 
00043 db_cmd_t* db_cmd(enum db_cmd_type type, db_ctx_t* ctx, char* table, 
00044                                  db_fld_t* result, db_fld_t* match, db_fld_t* values)
00045 {
00046         char* fname;
00047         db_cmd_t* newp;
00048         db_con_t* con;
00049         int i, r, j;
00050         db_drv_func_t func;
00051 
00052         newp = (db_cmd_t*)pkg_malloc(sizeof(db_cmd_t));
00053         if (newp == NULL) goto err;
00054         memset(newp, '\0', sizeof(db_cmd_t));
00055         if (db_gen_init(&newp->gen) < 0) goto err;
00056         newp->ctx = ctx;
00057 
00058         newp->table.len = strlen(table);
00059         newp->table.s = (char*)pkg_malloc(newp->table.len + 1); 
00060         if (newp->table.s == NULL) goto err;
00061         memcpy(newp->table.s, table, newp->table.len + 1);
00062 
00063         newp->type = type;
00064 
00067         if (result) {
00068                 newp->result = db_fld_copy(result);
00069                 if (newp->result == NULL) goto err;
00070         }
00071 
00072         if (match) {
00073                 newp->match = db_fld_copy(match);
00074                 if (newp->match == NULL) goto err;
00075         }
00076 
00077         if (values) {
00078                 newp->vals = db_fld_copy(values);
00079                 if (newp->vals == NULL) goto err;
00080         }
00081 
00082         /* FIXME: This should be redesigned so that we do not need to connect
00083          * connections in context before comands are created, this takes splitting
00084          * the command initializatio sequence in two steps, one would be creating
00085          * all the data structures and the second would be checking corresponding
00086          * fields and tables on the server.
00087          */
00088         if (ctx->con_n == 0) {
00089                 ERR("No connections found in context %.*s\n", STR_FMT(&ctx->id));
00090                 goto err;
00091         }
00092 
00093         for(i = 0; i < ctx->con_n; i++) {
00094                 con = ctx->con[i];
00095 
00096                 r = db_drv_func(&func, &con->uri->scheme, "db_fld");
00097                 if (r < 0) goto err;
00098                 if (r > 0) func = NULL;
00099                 db_payload_idx = i;
00100 
00101                 if (!DB_FLD_EMPTY(newp->result)) {
00102                         for(j = 0; !DB_FLD_LAST(newp->result[j]); j++) {
00103                                 if (func && func(newp->result + j, table) < 0) goto err;
00104                         }
00105                         newp->result_count = j;
00106                 }
00107 
00108                 if (!DB_FLD_EMPTY(newp->match)) {
00109                         for(j = 0; !DB_FLD_LAST(newp->match[j]); j++) {
00110                                 if (func && func(newp->match + j, table) < 0) goto err;
00111                         }
00112                         newp->match_count = j;
00113                 }
00114 
00115                 if (!DB_FLD_EMPTY(newp->vals)) {
00116                         for(j = 0; !DB_FLD_LAST(newp->vals[j]); j++) {
00117                                 if (func && func(newp->vals + j, table) < 0) goto err;
00118                         }
00119                         newp->vals_count = j;
00120                 }
00121 
00122                 r = db_drv_call(&con->uri->scheme, "db_cmd", newp, i);
00123                 if (r < 0) {
00124                         ERR("db_drv_call(\"db_cmd\") failed\n");
00125                         goto err;
00126                 }
00127                 if (r > 0) {
00128                         ERR("DB driver %.*s does not implement mandatory db_cmd function\n",
00129                                 con->uri->scheme.len, ZSW(con->uri->scheme.s));
00130                         goto err;
00131                 }
00132                 if (newp->exec[i] == NULL) {
00133                         /* db_cmd in the db driver did not provide any runtime function, so try to lookup the
00134                          * default one through the module API
00135                          */
00136                         switch(type) {
00137                         case DB_PUT: fname = "db_put"; break;
00138                         case DB_DEL: fname = "db_del"; break;
00139                         case DB_GET: fname = "db_get"; break;
00140                         case DB_UPD: fname = "db_upd"; break;
00141                         case DB_SQL: fname = "db_sql"; break;
00142                         default: ERR("db_cmd: Unsupported command type\n"); goto err;
00143                         }
00144 
00145                         r = db_drv_func((void*)&(newp->exec[i]), &con->uri->scheme, fname);
00146                         if (r < 0) goto err;
00147                         if (r > 0) {
00148                                 ERR("DB driver %.*s does not provide runtime execution function %s\n",
00149                                         con->uri->scheme.len, ZSW(con->uri->scheme.s), fname);
00150                                 goto err;
00151                         }
00152                 }
00153 
00154                 if (type == DB_GET || type == DB_SQL) {
00155                         r = db_drv_func((void*)(&newp->first[i]), &con->uri->scheme, "db_first");
00156                         if (r < 0) goto err;
00157                         if (r > 0) {
00158                                 ERR("DB driver %.*s does not implement mandatory db_first function\n",
00159                                         con->uri->scheme.len, ZSW(con->uri->scheme.s));
00160                                 goto err;
00161                         }
00162                         
00163                         r = db_drv_func((void*)(&newp->next[i]), &con->uri->scheme, "db_next");
00164                         if (r < 0) goto err;
00165                         if (r > 0) {
00166                                 ERR("DB driver %.*s does not implement mandatory db_next function\n",
00167                                         con->uri->scheme.len, ZSW(con->uri->scheme.s));
00168                                 goto err;
00169                         }
00170                 }
00171         }
00172     return newp;
00173 
00174  err:
00175     ERR("db_cmd: Cannot create db_cmd structure\n");
00176     if (newp) {
00177                 db_gen_free(&newp->gen);
00178                 if (newp->result)  db_fld_free(newp->result);
00179                 if (newp->match)   db_fld_free(newp->match);
00180                 if (newp->vals)    db_fld_free(newp->vals);
00181                 if (newp->table.s) pkg_free(newp->table.s);
00182                 pkg_free(newp);
00183         }
00184         return NULL;
00185 }
00186 
00187 
00188 void db_cmd_free(db_cmd_t* cmd)
00189 {
00190     if (cmd == NULL) return;
00191         db_gen_free(&cmd->gen);
00192 
00193         if (cmd->result) db_fld_free(cmd->result);
00194         if (cmd->match)  db_fld_free(cmd->match);
00195         if (cmd->vals)   db_fld_free(cmd->vals);
00196     if (cmd->table.s) pkg_free(cmd->table.s);
00197     pkg_free(cmd);
00198 }
00199 
00200 
00201 int db_exec(db_res_t** res, db_cmd_t* cmd)
00202 {
00203         db_res_t* r = NULL;
00204         int ret;
00205         
00206         if (res) {
00207                 r = db_res(cmd);
00208                 if (r == NULL) return -1;
00209         }
00210 
00211         /* FIXME */
00212         db_payload_idx = 0;
00213         ret = cmd->exec[0](r, cmd);
00214         if (ret < 0) {
00215                 if (r) db_res_free(r);
00216                 return ret;
00217         }
00218 
00219         if (res) *res = r;
00220         return ret;
00221 }
00222 
00223 
00224 int db_getopt(db_cmd_t* cmd, char* optname, ...)
00225 {
00226         int i, r;
00227         db_drv_func_t func;
00228         db_con_t* con;
00229         va_list ap;
00230         
00231         for(i = 0; i < cmd->ctx->con_n; i++) {
00232                 con = cmd->ctx->con[i];
00233                 
00234                 r = db_drv_func(&func, &con->uri->scheme, "db_getopt");
00235                 if (r < 0) return -1;
00236                 if (r > 0) func = NULL;
00237                 db_payload_idx = i;
00238                 
00239                 va_start(ap, optname);
00240                 if (func && func(cmd, optname, ap) < 0) {
00241                         va_end(ap);
00242                         return -1;
00243                 }
00244                 va_end(ap);
00245         }
00246         
00247         return 0;
00248 }
00249 
00250 
00251 int db_setopt(db_cmd_t* cmd, char* optname, ...)
00252 {
00253        int i, r;
00254        db_drv_func_t func;
00255        db_con_t* con;
00256        va_list ap;
00257 
00258        for(i = 0; i < cmd->ctx->con_n; i++) {
00259                con = cmd->ctx->con[i];
00260 
00261                r = db_drv_func(&func, &con->uri->scheme, "db_setopt");
00262                if (r < 0) return -1;
00263                if (r > 0) func = NULL;
00264                db_payload_idx = i;
00265 
00266                va_start(ap, optname);
00267                if (func && func(cmd, optname, ap) < 0) {
00268                        va_end(ap);
00269                        return -1;
00270                }
00271                va_end(ap);
00272        }
00273 
00274        return 0;
00275 }
00276 
00277