Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

my_cmd.c

Go to the documentation of this file.
00001 /* 
00002  * $Id: my_cmd.c,v 1.23 2009/01/04 15:41:13 bpintea Exp $
00003  *
00004  * Copyright (C) 2001-2003 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 #define _XOPEN_SOURCE 4     /* bsd */
00034 #define _XOPEN_SOURCE_EXTENDED 1    /* solaris */
00035 #define _SVID_SOURCE 1 /* timegm */
00036 
00037 #include "my_cmd.h"
00038 
00039 #include "my_con.h"
00040 #include "mysql_mod.h"
00041 #include "my_fld.h"
00042 
00043 #include "../../mem/mem.h"
00044 #include "../../str.h"
00045 #include "../../db/db_cmd.h"
00046 #include "../../ut.h"
00047 
00048 #include <stdlib.h>
00049 #include <strings.h>
00050 #include <stdio.h>
00051 #include <time.h>  /*strptime, XOPEN issue must be >=4 */
00052 #include <string.h>
00053 #include <mysql/errmsg.h>
00054 #include <mysql/mysqld_error.h>
00055 
00056 #define STR_BUF_SIZE 1024
00057 
00058 #ifdef MYSQL_FAKE_NULL
00059 
00060 #define FAKE_NULL_STRING "[~NULL~]"
00061 static str  FAKE_NULL_STR = STR_STATIC_INIT(FAKE_NULL_STRING);
00062 
00063 /* avoid warning: this decimal constant is unsigned only in ISO C90 :-) */
00064 #define FAKE_NULL_INT (-2147483647 - 1)
00065 #endif
00066 
00067 enum {
00068         STR_DELETE,
00069         STR_INSERT,
00070         STR_UPDATE,
00071         STR_SELECT,
00072         STR_REPLACE,
00073         STR_SET,
00074         STR_WHERE,
00075         STR_IS,
00076         STR_AND,
00077         STR_OR,
00078         STR_ESC,
00079         STR_OP_EQ,
00080         STR_OP_NE,
00081         STR_OP_LT,
00082         STR_OP_GT,
00083         STR_OP_LEQ,
00084         STR_OP_GEQ,
00085         STR_VALUES,
00086         STR_FROM
00087 };
00088 
00089 static str strings[] = {
00090         STR_STATIC_INIT("delete from "),
00091         STR_STATIC_INIT("insert into "),
00092         STR_STATIC_INIT("update "),
00093         STR_STATIC_INIT("select "),
00094         STR_STATIC_INIT("replace "),
00095         STR_STATIC_INIT(" set "),
00096         STR_STATIC_INIT(" where "),
00097         STR_STATIC_INIT(" is "),
00098         STR_STATIC_INIT(" and "),
00099         STR_STATIC_INIT(" or "),
00100         STR_STATIC_INIT("?"),
00101         STR_STATIC_INIT("="),
00102         STR_STATIC_INIT("!="),
00103         STR_STATIC_INIT("<"),
00104         STR_STATIC_INIT(">"),
00105         STR_STATIC_INIT("<="),
00106         STR_STATIC_INIT(">="),
00107         STR_STATIC_INIT(") values ("),
00108         STR_STATIC_INIT(" from ")
00109 };
00110 
00111 
00112 #define APPEND_STR(p, str) do {          \
00113         memcpy((p), (str).s, (str).len); \
00114         (p) += (str).len;                                \
00115 } while(0)
00116 
00117 
00118 #define APPEND_CSTR(p, cstr) do { \
00119     int _len = strlen(cstr);      \
00120         memcpy((p), (cstr), _len);        \
00121         (p) += _len;                              \
00122 } while(0)
00123 
00124 
00125 static int upload_cmd(db_cmd_t* cmd);
00126 
00127 
00128 static void my_cmd_free(db_cmd_t* cmd, struct my_cmd* payload)
00129 {
00130         db_drv_free(&payload->gen);
00131         if (payload->sql_cmd.s) pkg_free(payload->sql_cmd.s);
00132         if (payload->st) mysql_stmt_close(payload->st);
00133         pkg_free(payload);
00134 }
00135 
00136 
00142 static int build_delete_cmd(str* sql_cmd, db_cmd_t* cmd)
00143 {
00144         db_fld_t* fld;
00145         int i;
00146         char* p;
00147 
00148         sql_cmd->len = strings[STR_DELETE].len;
00149         sql_cmd->len += cmd->table.len;
00150 
00151         if (!DB_FLD_EMPTY(cmd->match)) {
00152                 sql_cmd->len += strings[STR_WHERE].len;
00153 
00154                 for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
00155                         sql_cmd->len += strlen(fld[i].name);
00156 
00157                         switch(fld[i].op) {
00158                         case DB_EQ:  sql_cmd->len += strings[STR_OP_EQ].len; break;
00159                         case DB_NE:  sql_cmd->len += strings[STR_OP_NE].len; break;
00160                         case DB_LT:  sql_cmd->len += strings[STR_OP_LT].len; break;
00161                         case DB_GT:  sql_cmd->len += strings[STR_OP_GT].len; break;
00162                         case DB_LEQ: sql_cmd->len += strings[STR_OP_LEQ].len; break;
00163                         case DB_GEQ: sql_cmd->len += strings[STR_OP_GEQ].len; break;
00164                         default:
00165                                 ERR("mysql: Unsupported db_fld operator %d\n", fld[i].op);
00166                                 return -1;
00167                         }
00168 
00169                         sql_cmd->len += strings[STR_ESC].len;
00170                         
00171                         if (!DB_FLD_LAST(fld[i + 1])) sql_cmd->len += strings[STR_AND].len;
00172                 }
00173         }
00174 
00175         sql_cmd->s = pkg_malloc(sql_cmd->len + 1);
00176         if (sql_cmd->s == NULL) {
00177                 ERR("mysql: No memory left\n");
00178                 return -1;
00179         }
00180         p = sql_cmd->s;
00181         
00182         APPEND_STR(p, strings[STR_DELETE]);
00183         APPEND_STR(p, cmd->table);
00184 
00185         if (!DB_FLD_EMPTY(cmd->match)) {
00186                 APPEND_STR(p, strings[STR_WHERE]);
00187 
00188                 for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
00189                         APPEND_CSTR(p, fld[i].name);
00190 
00191                         switch(fld[i].op) {
00192                         case DB_EQ:  APPEND_STR(p, strings[STR_OP_EQ]);  break;
00193                         case DB_NE:  APPEND_STR(p, strings[STR_OP_NE]);  break;
00194                         case DB_LT:  APPEND_STR(p, strings[STR_OP_LT]);  break;
00195                         case DB_GT:  APPEND_STR(p, strings[STR_OP_GT]);  break;
00196                         case DB_LEQ: APPEND_STR(p, strings[STR_OP_LEQ]); break;
00197                         case DB_GEQ: APPEND_STR(p, strings[STR_OP_GEQ]); break;
00198                         }
00199                         
00200                         APPEND_STR(p, strings[STR_ESC]);
00201                         if (!DB_FLD_LAST(fld[i + 1])) APPEND_STR(p, strings[STR_AND]);
00202                 }
00203         }
00204                         
00205         *p = '\0';
00206         return 0;
00207 }
00208 
00209 
00216 static int build_select_cmd(str* sql_cmd, db_cmd_t* cmd)
00217 {
00218         db_fld_t* fld;
00219         int i;
00220         char* p;
00221 
00222         sql_cmd->len = strings[STR_SELECT].len;
00223 
00224         if (DB_FLD_EMPTY(cmd->result)) {
00225                 sql_cmd->len += 1; /* "*" */
00226         } else {
00227                 for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
00228                         sql_cmd->len += strlen(fld[i].name);
00229                         if (!DB_FLD_LAST(fld[i + 1])) sql_cmd->len += 1; /* , */
00230                 }
00231         }
00232         sql_cmd->len += strings[STR_FROM].len;
00233         sql_cmd->len += cmd->table.len;
00234 
00235         if (!DB_FLD_EMPTY(cmd->match)) {
00236                 sql_cmd->len += strings[STR_WHERE].len;
00237 
00238                 for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
00239                         sql_cmd->len += strlen(fld[i].name);
00240 
00241                         switch(fld[i].op) {
00242                         case DB_EQ:  sql_cmd->len += strings[STR_OP_EQ].len; break;
00243                         case DB_NE:  sql_cmd->len += strings[STR_OP_NE].len; break;
00244                         case DB_LT:  sql_cmd->len += strings[STR_OP_LT].len; break;
00245                         case DB_GT:  sql_cmd->len += strings[STR_OP_GT].len; break;
00246                         case DB_LEQ: sql_cmd->len += strings[STR_OP_LEQ].len; break;
00247                         case DB_GEQ: sql_cmd->len += strings[STR_OP_GEQ].len; break;
00248                         default:
00249                                 ERR("mysql: Unsupported db_fld operator %d\n", fld[i].op);
00250                                 return -1;
00251                         }
00252 
00253                         sql_cmd->len += strings[STR_ESC].len;
00254                         
00255                         if (!DB_FLD_LAST(fld[i + 1])) sql_cmd->len += strings[STR_AND].len;
00256                 }
00257         }
00258 
00259         sql_cmd->s = pkg_malloc(sql_cmd->len + 1);
00260         if (sql_cmd->s == NULL) {
00261                 ERR("mysql: No memory left\n");
00262                 return -1;
00263         }
00264         p = sql_cmd->s;
00265         
00266         APPEND_STR(p, strings[STR_SELECT]);
00267         if (DB_FLD_EMPTY(cmd->result)) {
00268                 *p++ = '*';
00269         } else {
00270                 for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
00271                         APPEND_CSTR(p, fld[i].name);
00272                         if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
00273                 }
00274         }
00275         APPEND_STR(p, strings[STR_FROM]);
00276         APPEND_STR(p, cmd->table);
00277 
00278         if (!DB_FLD_EMPTY(cmd->match)) {
00279                 APPEND_STR(p, strings[STR_WHERE]);
00280 
00281                 for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
00282                         APPEND_CSTR(p, fld[i].name);
00283 
00284                         switch(fld[i].op) {
00285                         case DB_EQ:  APPEND_STR(p, strings[STR_OP_EQ]);  break;
00286                         case DB_NE:  APPEND_STR(p, strings[STR_OP_NE]);  break;
00287                         case DB_LT:  APPEND_STR(p, strings[STR_OP_LT]);  break;
00288                         case DB_GT:  APPEND_STR(p, strings[STR_OP_GT]);  break;
00289                         case DB_LEQ: APPEND_STR(p, strings[STR_OP_LEQ]); break;
00290                         case DB_GEQ: APPEND_STR(p, strings[STR_OP_GEQ]); break;
00291                         }
00292                         
00293                         APPEND_STR(p, strings[STR_ESC]);
00294                         if (!DB_FLD_LAST(fld[i + 1])) APPEND_STR(p, strings[STR_AND]);
00295                 }
00296         }
00297 
00298         *p = '\0';
00299         return 0;
00300 }
00301 
00302 
00308 static int build_replace_cmd(str* sql_cmd, db_cmd_t* cmd)
00309 {
00310         db_fld_t* fld;
00311         int i;
00312         char* p;
00313 
00314         sql_cmd->len = strings[STR_REPLACE].len;
00315         sql_cmd->len += cmd->table.len;
00316         sql_cmd->len += 2; /* " (" */
00317 
00318         for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {
00319                 sql_cmd->len += strlen(fld[i].name);
00320                 sql_cmd->len += strings[STR_ESC].len;
00321                 if (!DB_FLD_LAST(fld[i + 1])) sql_cmd->len += 2; /* , twice */
00322         }
00323         sql_cmd->len += strings[STR_VALUES].len;
00324     sql_cmd->len += 1; /* ) */
00325 
00326         sql_cmd->s = pkg_malloc(sql_cmd->len + 1);
00327         if (sql_cmd->s == NULL) {
00328                 ERR("mysql: No memory left\n");
00329                 return -1;
00330         }
00331         p = sql_cmd->s;
00332         
00333         APPEND_STR(p, strings[STR_REPLACE]);
00334         APPEND_STR(p, cmd->table);
00335         *p++ = ' ';
00336         *p++ = '(';
00337 
00338         for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {
00339                 APPEND_CSTR(p, fld[i].name);
00340                 if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
00341         }
00342         APPEND_STR(p, strings[STR_VALUES]);
00343 
00344         for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {
00345                 APPEND_STR(p, strings[STR_ESC]);
00346                 if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
00347         }
00348         *p++ = ')';
00349         *p = '\0';
00350         return 0;
00351 }
00352 
00353 
00357 struct string_buffer {
00358         char *s;                        
00359         int   len;                      
00360         int   size;                     
00361         int   increment;        
00362 };
00363 
00364 
00371 static inline int sb_add(struct string_buffer *sb, str *nstr)
00372 {
00373         int new_size = 0;
00374         int rsize = sb->len + nstr->len;
00375         int asize;
00376         char *newp;
00377         
00378         if ( rsize > sb->size ) {
00379                 asize = rsize - sb->size;
00380                 new_size = sb->size + (asize / sb->increment  + (asize % sb->increment > 0)) * sb->increment;
00381                 newp = pkg_malloc(new_size);
00382                 if (!newp) {
00383                         ERR("mysql: No memory left\n");
00384                         return -1;
00385                 }
00386                 if (sb->s) {
00387                         memcpy(newp, sb->s, sb->len);
00388                         pkg_free(sb->s);
00389                 }
00390                 sb->s = newp;
00391                 sb->size = new_size;
00392         }
00393         memcpy(sb->s + sb->len, nstr->s, nstr->len);
00394         sb->len += nstr->len;
00395         return 0;
00396 }
00397 
00398 
00403 static inline str* set_str(str *str, const char *s)
00404 {
00405         str->s = (char *)s;
00406         str->len = strlen(s);
00407         return str;
00408 }
00409 
00410 
00417 static int build_update_cmd(str* sql_cmd, db_cmd_t* cmd)
00418 {
00419         struct string_buffer sql_buf = {.s = NULL, .len = 0, .size = 0, .increment = 128};
00420         db_fld_t* fld;
00421         int i;
00422         int rv = 0;
00423         str tmpstr;
00424 
00425         rv = sb_add(&sql_buf, &strings[STR_UPDATE]);    /* "UPDATE " */
00426         rv |= sb_add(&sql_buf, &cmd->table);                    /* table name */
00427         rv |= sb_add(&sql_buf, &strings[STR_SET]);              /* " SET " */
00428 
00429         /* column name-value pairs */
00430         for(i = 0, fld = cmd->vals; !DB_FLD_LAST(fld[i]); i++) {
00431                 rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
00432                 rv |= sb_add(&sql_buf, set_str(&tmpstr, " = "));
00433                 rv |= sb_add(&sql_buf, &strings[STR_ESC]);
00434                 if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, set_str(&tmpstr, ", "));
00435         }
00436         if (rv) {
00437                 goto err;
00438         }
00439 
00440         if (!DB_FLD_EMPTY(cmd->match)) {
00441                 rv |= sb_add(&sql_buf, &strings[STR_WHERE]);
00442 
00443                 for(i = 0, fld = cmd->match; !DB_FLD_LAST(fld[i]); i++) {
00444                         rv |= sb_add(&sql_buf, set_str(&tmpstr, fld[i].name));
00445 
00446                         switch(fld[i].op) {
00447                         case DB_EQ:  rv |= sb_add(&sql_buf, &strings[STR_OP_EQ]);  break;
00448                         case DB_NE:  rv |= sb_add(&sql_buf, &strings[STR_OP_NE]);  break;
00449                         case DB_LT:  rv |= sb_add(&sql_buf, &strings[STR_OP_LT]);  break;
00450                         case DB_GT:  rv |= sb_add(&sql_buf, &strings[STR_OP_GT]);  break;
00451                         case DB_LEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_LEQ]); break;
00452                         case DB_GEQ: rv |= sb_add(&sql_buf, &strings[STR_OP_GEQ]); break;
00453                         }
00454                         
00455                         rv |= sb_add(&sql_buf, &strings[STR_ESC]);
00456                         if (!DB_FLD_LAST(fld[i + 1])) rv |= sb_add(&sql_buf, &strings[STR_AND]);
00457                 }
00458         }
00459         rv |= sb_add(&sql_buf, set_str(&tmpstr, "\0"));
00460         if (rv) {
00461                 goto err;
00462         }
00463         sql_cmd->s = sql_buf.s;
00464         sql_cmd->len = sql_buf.len;
00465         return 0;
00466 
00467 err:
00468         if (sql_buf.s) pkg_free(sql_buf.s);
00469         return -1;
00470 }
00471 
00472 
00473 static inline void update_field(MYSQL_BIND *param, db_fld_t* fld)
00474 {
00475         struct my_fld* fp;      /* field payload */
00476         struct tm* t;
00477         
00478         fp = DB_GET_PAYLOAD(fld);
00479 
00480 #ifndef MYSQL_FAKE_NULL
00481         fp->is_null = fld->flags & DB_NULL;
00482         if (fp->is_null) return;
00483 #else
00484         if (fld->flags & DB_NULL) {
00485                 switch(fld->type) {
00486                 case DB_STR:
00487                 case DB_CSTR:
00488                         param->buffer = FAKE_NULL_STR.s;
00489                         fp->length = FAKE_NULL_STR.len;
00490                         break;
00491                 case DB_INT:
00492                         *(int*)param->buffer = FAKE_NULL_INT;
00493                         break;
00494                 case DB_BLOB:
00495                 case DB_DATETIME:
00496                 case DB_NONE:
00497                 case DB_FLOAT:
00498                 case DB_DOUBLE:
00499                 case DB_BITMAP:
00500                         /* we don't have fake null value for these types */
00501                         fp->is_null = DB_NULL;
00502                         break;
00503                 }
00504                 return;
00505         }
00506 #endif
00507         switch(fld->type) {
00508         case DB_STR:
00509                 param->buffer = fld->v.lstr.s;
00510                 fp->length = fld->v.lstr.len;
00511                 break;
00512 
00513         case DB_BLOB:
00514                 param->buffer = fld->v.blob.s;
00515                 fp->length = fld->v.blob.len;
00516                 break;
00517 
00518         case DB_CSTR:
00519                 param->buffer = (char*)fld->v.cstr;
00520                 fp->length = strlen(fld->v.cstr);
00521                 break;
00522 
00523         case DB_DATETIME:
00524                 t = gmtime(&fld->v.time);
00525                 fp->time.second = t->tm_sec;
00526                 fp->time.minute = t->tm_min;
00527                 fp->time.hour = t->tm_hour;
00528                 fp->time.day = t->tm_mday;
00529                 fp->time.month = t->tm_mon + 1;
00530                 fp->time.year = t->tm_year + 1900;
00531                 break;
00532                 
00533         case DB_NONE:
00534         case DB_INT:
00535         case DB_FLOAT:
00536         case DB_DOUBLE:
00537         case DB_BITMAP:
00538                 /* No need to do anything for these types */
00539                 break;
00540 
00541         }
00542 }
00543 
00544 
00551 static inline void set_mysql_params(db_cmd_t* cmd)
00552 {
00553         struct my_cmd* mcmd;
00554         int i;
00555 
00556         mcmd = DB_GET_PAYLOAD(cmd);
00557 
00558         /* FIXME: We are updating internals of the prepared statement here,
00559          * this is probably not nice but I could not find another way of
00560          * updating the pointer to the buffer without the need to run
00561          * mysql_stmt_bind_param again (which would be innefficient)
00562          */
00563         for(i = 0; i < cmd->vals_count; i++) {
00564                 update_field(mcmd->st->params + i, cmd->vals + i);
00565         }
00566 
00567         for(i = 0; i < cmd->match_count; i++) {
00568                 update_field(mcmd->st->params + cmd->vals_count + i, cmd->match + i);
00569         }
00570 }
00571 
00572 
00573 static inline int update_result(db_fld_t* result, MYSQL_STMT* st)
00574 {
00575         int i;
00576         struct my_fld* rp; /* Payload of the current field in result */
00577         struct tm t;
00578 
00579         /* Iterate through all the fields returned by MySQL and convert
00580          * them to DB API representation if necessary
00581          */
00582 
00583         for(i = 0; i < st->field_count; i++) {
00584                 rp = DB_GET_PAYLOAD(result + i);
00585 
00586                 if (rp->is_null) {
00587                         result[i].flags |= DB_NULL;
00588                         continue;
00589                 } else {
00590                         result[i].flags &= ~DB_NULL;
00591                 }
00592 
00593                 switch(result[i].type) {
00594                 case DB_STR:
00595                         result[i].v.lstr.len = rp->length;
00596 #ifdef MYSQL_FAKE_NULL
00597                         if (STR_EQ(FAKE_NULL_STR,result[i].v.lstr)) {
00598                                 result[i].flags |= DB_NULL;
00599                         }
00600 #endif
00601                         break;
00602 
00603                 case DB_BLOB:
00604                         result[i].v.blob.len = rp->length;
00605                         break;
00606 
00607                 case DB_CSTR:
00608                         if (rp->length < STR_BUF_SIZE) {
00609                                 result[i].v.cstr[rp->length] = '\0';
00610                         } else {
00611                                 /* Truncated field but rp->length contains full size,
00612                                  * zero terminated the last byte in the buffer
00613                                  */
00614                                 result[i].v.cstr[STR_BUF_SIZE - 1] = '\0';
00615                         }
00616 #ifdef MYSQL_FAKE_NULL
00617                         if (strcmp(FAKE_NULL_STR.s,result[i].v.cstr)==0) {
00618                                 result[i].flags |= DB_NULL;
00619                         }
00620 #endif
00621                         break;
00622                         
00623                 case DB_DATETIME:
00624                         memset(&t, '\0', sizeof(struct tm));
00625                         t.tm_sec = rp->time.second;
00626                         t.tm_min = rp->time.minute;
00627                         t.tm_hour = rp->time.hour;
00628                         t.tm_mday = rp->time.day;
00629                         t.tm_mon = rp->time.month - 1;
00630                         t.tm_year = rp->time.year - 1900;
00631 
00632                         /* Daylight saving information got lost in the database
00633                          * so let timegm to guess it. This eliminates the bug when
00634                          * contacts reloaded from the database have different time
00635                          * of expiration by one hour when daylight saving is used
00636                          */ 
00637                         t.tm_isdst = -1;
00638 #ifdef HAVE_TIMEGM
00639                         result[i].v.time = timegm(&t);
00640 #else
00641                         result[i].v.time = _timegm(&t);
00642 #endif /* HAVE_TIMEGM */
00643                         break;
00644 
00645                 case DB_INT:
00646 #ifdef MYSQL_FAKE_NULL
00647                         if (FAKE_NULL_INT==result[i].v.int4) {
00648                                 result[i].flags |= DB_NULL;
00649                         }
00650                         break;
00651 #endif
00652                 case DB_NONE:
00653                 case DB_FLOAT:
00654                 case DB_DOUBLE:
00655                 case DB_BITMAP:
00656                         /* No need to do anything for these types */
00657                         break;
00658                 }
00659         }
00660         
00661         return 0;
00662 }
00663 
00664 
00672 static int exec_cmd_safe(db_cmd_t* cmd)
00673 {
00674         int i, err;
00675         db_con_t* con;
00676         struct my_cmd* mcmd;
00677         struct my_con* mcon;
00678 
00679         /* First things first: retrieve connection info
00680          * from the currently active connection and also
00681          * mysql payload from the database command
00682          */
00683         mcmd = DB_GET_PAYLOAD(cmd);
00684         con = cmd->ctx->con[db_payload_idx];
00685         mcon = DB_GET_PAYLOAD(con);
00686 
00687         for(i = 0; i <= my_retries; i++) {
00688                 /* Next check the number of resets in the database connection,
00689                  * if this number is higher than the number we keep in my_cmd
00690                  * structure in last_reset variable then the connection was
00691                  * reset and we need to upload the command again to the server
00692                  * before executing it, because the server recycles all server
00693                  * side information upon disconnect.
00694                  */
00695                 if (mcon->resets > mcmd->last_reset) {
00696                         INFO("mysql: Connection reset detected, uploading command to server\n");
00697                         err = upload_cmd(cmd);
00698                         if (err < 0) {
00699                                 INFO("mysql: Error while uploading command\n");
00700                                 /* MySQL error, skip execution and try again if we have attempts left */
00701                                 continue;
00702                         } else if (err > 0) {
00703                                 /* DB API error, this is a serious problem such
00704                                  * as memory allocation failure, bail out
00705                                  */
00706                                 return 1;
00707                         }
00708                 }
00709 
00710                 set_mysql_params(cmd);
00711                 err = mysql_stmt_execute(mcmd->st);
00712                 if (err == 0) {
00713                         /* The command was executed successfully, now fetch all data
00714                          * to the client if it was requested by the user */
00715                         if (mcmd->flags & MY_FETCH_ALL) {
00716                                 err = mysql_stmt_store_result(mcmd->st);
00717                                 if (err) {
00718                                         INFO("mysql: Error while fetching data to client.\n");
00719                                         goto error;
00720                                 }
00721                         }
00722                         return 0;
00723                 }
00724                 
00725         error:
00726                 /* Command execution failed, log a message and try to reconnect */
00727                 INFO("mysql: libmysql: %d, %s\n", mysql_stmt_errno(mcmd->st),
00728                          mysql_stmt_error(mcmd->st));
00729                 INFO("mysql: Error while executing command on server, trying to reconnect\n");
00730                 my_con_disconnect(con);
00731                 if (my_con_connect(con)) {
00732                         INFO("mysql: Failed to reconnect server\n");
00733                 } else {
00734                         INFO("mysql: Successfully reconnected server\n");
00735                 }
00736         }
00737 
00738         INFO("mysql: Failed to execute command, giving up\n");
00739         return -1;
00740 }
00741 
00742 
00743 int my_cmd_exec(db_res_t* res, db_cmd_t* cmd)
00744 {
00745         struct my_cmd* mcmd;
00746 
00747         mcmd = DB_GET_PAYLOAD(cmd);
00748 
00749         mcmd->next_flag = -1;
00750         return exec_cmd_safe(cmd);
00751 }
00752 
00753 
00759 static void set_field(MYSQL_BIND *bind, db_fld_t* fld)
00760 {
00761         struct my_fld* f;
00762         
00763         f = DB_GET_PAYLOAD(fld);
00764         bind->is_null = &f->is_null;
00765         /* We can do it for all the types here, mysql will ignore it
00766          * for fixed-size types such as MYSQL_TYPE_LONG
00767          */
00768         bind->length = &f->length;
00769         switch(fld->type) {
00770         case DB_INT:
00771         case DB_BITMAP:
00772                 bind->buffer_type = MYSQL_TYPE_LONG;
00773                 bind->buffer = &fld->v.int4;
00774                 break;
00775         
00776         case DB_FLOAT:
00777                 bind->buffer_type = MYSQL_TYPE_FLOAT;
00778                 bind->buffer = &fld->v.flt;
00779                 break;
00780                 
00781         case DB_DOUBLE:
00782                 bind->buffer_type = MYSQL_TYPE_DOUBLE;
00783                 bind->buffer = &fld->v.dbl;
00784                 break;
00785         
00786         case DB_DATETIME:
00787                 bind->buffer_type = MYSQL_TYPE_DATETIME;
00788                 bind->buffer = &f->time;
00789                 break;
00790         
00791         case DB_STR:
00792         case DB_CSTR:
00793                 bind->buffer_type = MYSQL_TYPE_VAR_STRING;
00794                 bind->buffer = ""; /* Updated on runtime */
00795                 break;
00796         
00797         case DB_BLOB:
00798                 bind->buffer_type = MYSQL_TYPE_BLOB;
00799                 bind->buffer = ""; /* Updated on runtime */
00800                 break;
00801         
00802         case DB_NONE:
00803                 /* Eliminates gcc warning */
00804                 break;
00805         
00806         }
00807 }
00808 
00809 
00822 static int bind_mysql_params(MYSQL_STMT* st, db_fld_t* params1, db_fld_t* params2)
00823 {
00824         int my_idx, fld_idx;
00825         int count1, count2;
00826         MYSQL_BIND* my_params;
00827         int err = 0;
00828 
00829         /* Calculate the number of parameters */
00830         for(count1 = 0; !DB_FLD_EMPTY(params1) && !DB_FLD_LAST(params1[count1]); count1++);
00831         for(count2 = 0; !DB_FLD_EMPTY(params2) && !DB_FLD_LAST(params2[count2]); count2++);
00832         if (st->param_count != count1 + count2) {
00833                 BUG("mysql: Number of parameters in SQL command does not match number of DB API parameters\n");
00834                 return 1;
00835         }
00836         
00837         my_params = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * (count1 + count2));
00838         if (my_params == NULL) {
00839                 ERR("mysql: No memory left\n");
00840                 return 1;
00841         }
00842         memset(my_params, '\0', sizeof(MYSQL_BIND) * (count1 + count2));
00843 
00844         /* params1 */
00845         my_idx = 0;
00846         for (fld_idx = 0; fld_idx < count1; fld_idx++, my_idx++) {
00847                 set_field(&my_params[my_idx], params1 + fld_idx);
00848         }
00849         /* params2 */
00850         for (fld_idx = 0; fld_idx < count2; fld_idx++, my_idx++) {
00851                 set_field(&my_params[my_idx], params2 + fld_idx);
00852         }
00853 
00854         err = mysql_stmt_bind_param(st, my_params);
00855         if (err) {
00856                 ERR("mysql: libmysqlclient: %d, %s\n", 
00857                         mysql_stmt_errno(st), mysql_stmt_error(st));
00858                 err = -abs(err);
00859                 goto error;
00860         }
00861 
00862         /* We do not need the array of MYSQL_BIND anymore, mysql_stmt_bind_param
00863          * creates a copy in the statement and we will update it there
00864          */
00865         pkg_free(my_params);
00866         return err;
00867    
00868  error:
00869         if (my_params) pkg_free(my_params);
00870         return err;
00871 }
00872 
00873 
00874 /*
00875  * FIXME: This function will only work if we have one db connection
00876  * in every context, otherwise it would initialize the result set
00877  * from the first connection in the context.
00878  */
00879 static int check_result(db_cmd_t* cmd, struct my_cmd* payload)
00880 {
00881         int i, n;
00882         MYSQL_FIELD *fld;
00883         MYSQL_RES *meta = NULL;
00884 
00885         meta = mysql_stmt_result_metadata(payload->st);
00886         if (meta == NULL) {
00887                 /* No error means no result set to be checked */
00888                 if (mysql_stmt_errno(payload->st) == 0) return 0;
00889                 ERR("mysql: Error while getting metadata of SQL command: %d, %s\n",
00890                         mysql_stmt_errno(payload->st), mysql_stmt_error(payload->st));
00891                 return -1;
00892         }
00893         n = mysql_num_fields(meta);
00894         if (cmd->result == NULL) {
00895                 /* The result set parameter of db_cmd function was empty, that
00896                  * means the command is select * and we have to create the array
00897                  * of result fields in the cmd structure manually.
00898                  */
00899                 cmd->result = db_fld(n + 1);
00900                 cmd->result_count = n;
00901                 for(i = 0; i < cmd->result_count; i++) {
00902                         struct my_fld *f;
00903                         if (my_fld(cmd->result + i, cmd->table.s) < 0) goto error;
00904                         f = DB_GET_PAYLOAD(cmd->result + i);
00905                         fld = mysql_fetch_field_direct(meta, i);
00906                         f->name = pkg_malloc(strlen(fld->name)+1);
00907                         if (f->name == NULL) {
00908                                 ERR("mysql: Out of private memory\n");
00909                                 goto error;
00910                         }
00911                         strcpy(f->name, fld->name);
00912                         cmd->result[i].name = f->name;
00913                 }
00914         } else {
00915                 if (cmd->result_count != n) {
00916                         BUG("mysql: Number of fields in MySQL result does not match number of parameters in DB API\n");
00917                         goto error;
00918                 }
00919         }
00920 
00921         /* Now iterate through all the columns in the result set and replace
00922          * any occurrence of DB_UNKNOWN type with the type of the column
00923          * retrieved from the database and if no column name was provided then
00924          * update it from the database as well. 
00925          */
00926         for(i = 0; i < cmd->result_count; i++) {
00927                 fld = mysql_fetch_field_direct(meta, i);
00928                 if (cmd->result[i].type != DB_NONE) continue;
00929                 switch(fld->type) {
00930                 case MYSQL_TYPE_TINY:
00931                 case MYSQL_TYPE_SHORT:
00932                 case MYSQL_TYPE_INT24:
00933                 case MYSQL_TYPE_LONG:
00934                         cmd->result[i].type = DB_INT;
00935                         break;
00936 
00937                 case MYSQL_TYPE_FLOAT:
00938                         cmd->result[i].type = DB_FLOAT;
00939                         break;
00940 
00941                 case MYSQL_TYPE_DOUBLE:
00942                         cmd->result[i].type = DB_DOUBLE;
00943                         break;
00944 
00945                 case MYSQL_TYPE_TIMESTAMP:
00946                 case MYSQL_TYPE_DATETIME:
00947                         cmd->result[i].type = DB_DATETIME;
00948                         break;
00949 
00950                 case MYSQL_TYPE_STRING:
00951                 case MYSQL_TYPE_VAR_STRING:
00952                         cmd->result[i].type = DB_STR;
00953                         break;
00954 
00955                 default:
00956                         ERR("mysql: Unsupported MySQL column type: %d, table: %s, column: %s\n",
00957                                 fld->type, cmd->table.s, fld->name);
00958                         goto error;
00959                 }
00960         }
00961         
00962         if (meta) mysql_free_result(meta);
00963         return 0;
00964 
00965 error:
00966         if (meta) mysql_free_result(meta);
00967         return 1;
00968 }
00969 
00970 
00971 /* FIXME: Add support for DB_NONE, in this case the function should determine
00972  * the type of the column in the database and set the field type appropriately.
00973  * This function must be called after check_result.
00974  */
00975 static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
00976 {
00977         int i, n, err = 0;
00978         struct my_fld* f;
00979         MYSQL_BIND* result;
00980 
00981         /* Calculate the number of fields in the result */
00982         for(n = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[n]); n++);
00983         /* Return immediately if there are no fields in the result set */
00984         if (n == 0) return 0;
00985 
00986         result = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * n);
00987         if (result == NULL) {
00988                 ERR("mysql: No memory left\n");
00989                 return 1;
00990         }
00991         memset(result, '\0', sizeof(MYSQL_BIND) * n);
00992         
00993         for(i = 0; i < n; i++) {
00994                 f = DB_GET_PAYLOAD(fld + i);
00995                 result[i].is_null = &f->is_null;
00996                 /* We can do it for all the types here, mysql will ignore it
00997                  * for fixed-size types such as MYSQL_TYPE_LONG
00998                  */
00999                 result[i].length = &f->length;
01000                 switch(fld[i].type) {
01001                 case DB_INT:
01002                 case DB_BITMAP:
01003                         result[i].buffer_type = MYSQL_TYPE_LONG;
01004                         result[i].buffer = &fld[i].v.int4;
01005                         break;
01006 
01007                 case DB_FLOAT:
01008                         result[i].buffer_type = MYSQL_TYPE_FLOAT;
01009                         result[i].buffer = &fld[i].v.flt;
01010                         break;
01011                         
01012                 case DB_DOUBLE:
01013                         result[i].buffer_type = MYSQL_TYPE_DOUBLE;
01014                         result[i].buffer = &fld[i].v.dbl;
01015                         break;
01016 
01017                 case DB_DATETIME:
01018                         result[i].buffer_type = MYSQL_TYPE_DATETIME;
01019                         result[i].buffer = &f->time;
01020                         break;
01021 
01022                 case DB_STR:
01023                         result[i].buffer_type = MYSQL_TYPE_VAR_STRING;
01024                         if (!f->buf.s) f->buf.s = pkg_malloc(STR_BUF_SIZE);
01025                         if (f->buf.s == NULL) {
01026                                 ERR("mysql: No memory left\n");
01027                                 err = 1;
01028                                 goto error;
01029                         }
01030                         result[i].buffer = f->buf.s;
01031                         fld[i].v.lstr.s = f->buf.s;
01032                         result[i].buffer_length = STR_BUF_SIZE - 1;
01033                         break;
01034 
01035                 case DB_CSTR:
01036                         result[i].buffer_type = MYSQL_TYPE_VAR_STRING;
01037                         if (!f->buf.s) f->buf.s = pkg_malloc(STR_BUF_SIZE);
01038                         if (f->buf.s == NULL) {
01039                                 ERR("mysql: No memory left\n");
01040                                 err = 1;
01041                                 goto error;
01042                         }
01043                         result[i].buffer = f->buf.s;
01044                         fld[i].v.cstr = f->buf.s;
01045                         result[i].buffer_length = STR_BUF_SIZE - 1;
01046                         break;
01047 
01048                 case DB_BLOB:
01049                         result[i].buffer_type = MYSQL_TYPE_BLOB;
01050                         if (!f->buf.s) f->buf.s = pkg_malloc(STR_BUF_SIZE);
01051                         if (f->buf.s == NULL) {
01052                                 ERR("mysql: No memory left\n");
01053                                 err = 1;
01054                                 goto error;
01055                         }
01056                         result[i].buffer = f->buf.s;
01057                         fld[i].v.blob.s = f->buf.s;
01058                         result[i].buffer_length = STR_BUF_SIZE - 1;
01059                         break;
01060 
01061                 case DB_NONE:
01062                         /* Eliminates gcc warning */
01063                         break;
01064 
01065                 }
01066         }
01067 
01068         err = mysql_stmt_bind_result(st, result);
01069         if (err) {
01070                 ERR("mysql: Error while binding result: %s\n", mysql_stmt_error(st));
01071                 err = -abs(err);
01072                 goto error;
01073         }
01074 
01075         /* We do not need the array of MYSQL_BIND anymore, mysql_stmt_bind_param
01076          * creates a copy in the statement and we will update it there
01077          */
01078         if (result) pkg_free(result);
01079         return 0;
01080    
01081  error:
01082         if (result) pkg_free(result);
01083         return err;
01084 }
01085 
01086 
01092 static int upload_cmd(db_cmd_t* cmd)
01093 {
01094         struct my_cmd* res;
01095         struct my_con* mcon;
01096         int err = 0;
01097 
01098         res = DB_GET_PAYLOAD(cmd);
01099 
01100         /* FIXME: The function should take the connection as one of parameters */
01101         mcon = DB_GET_PAYLOAD(cmd->ctx->con[db_payload_idx]);
01102 
01103         /* If there is a previous pre-compiled statement, close it first */
01104         if (res->st) mysql_stmt_close(res->st);
01105         res->st = NULL;
01106 
01107         /* Create a new pre-compiled statement data structure */
01108         res->st = mysql_stmt_init(mcon->con);
01109         if (res->st == NULL) {
01110                 ERR("mysql: Error while creating new MySQL_STMT data structure (no memory left)\n");
01111                 err = -1;
01112                 goto error;
01113         }
01114 
01115         /* Try to upload the command to the server */
01116         err = mysql_stmt_prepare(res->st, res->sql_cmd.s, res->sql_cmd.len);
01117         if (err) {
01118                 ERR("mysql: libmysql: %d, %s\n", mysql_stmt_errno(res->st), 
01119                         mysql_stmt_error(res->st));
01120                 ERR("mysql: An error occurred while uploading a command to MySQL server\n");
01121                 err = -abs(err); /* mysql_stmt_prepare() can return + for err */
01122                 goto error;
01123         }
01124 
01125         err = bind_mysql_params(res->st, cmd->vals, cmd->match);
01126         if (err) goto error;
01127 
01128         if (cmd->type == DB_GET || cmd->type == DB_SQL) {
01129                 err = check_result(cmd, res);
01130                 if (err) goto error;
01131                 err = bind_result(res->st, cmd->result);
01132                 if (err) goto error;
01133         }
01134 
01135         res->last_reset = mcon->resets;
01136         return 0;
01137 
01138  error:
01139         if (res->st) {
01140                 ERR("mysql: libmysqlclient: %d, %s\n", 
01141                         mysql_stmt_errno(res->st), 
01142                         mysql_stmt_error(res->st));
01143                 mysql_stmt_close(res->st);
01144                 res->st = NULL;
01145         }
01146         return err;
01147 }
01148 
01149 
01150 int my_cmd(db_cmd_t* cmd)
01151 {
01152         struct my_cmd* res;
01153  
01154         res = (struct my_cmd*)pkg_malloc(sizeof(struct my_cmd));
01155         if (res == NULL) {
01156                 ERR("mysql: No memory left\n");
01157                 goto error;
01158         }
01159         memset(res, '\0', sizeof(struct my_cmd));
01160         /* Fetch all data to client at once by default */
01161         res->flags |= MY_FETCH_ALL;
01162         if (db_drv_init(&res->gen, my_cmd_free) < 0) goto error;
01163 
01164         switch(cmd->type) {
01165         case DB_PUT:
01166                 if (DB_FLD_EMPTY(cmd->vals)) {
01167                         BUG("mysql: No parameters provided for DB_PUT in context '%.*s'\n", 
01168                                 cmd->ctx->id.len, ZSW(cmd->ctx->id.s));
01169                         goto error;
01170                 }
01171                 if (build_replace_cmd(&res->sql_cmd, cmd) < 0) goto error;
01172                 break;
01173 
01174         case DB_DEL:
01175                 if (build_delete_cmd(&res->sql_cmd, cmd) < 0) goto error;
01176                 break;
01177 
01178         case DB_GET:
01179                 if (build_select_cmd(&res->sql_cmd, cmd) < 0) goto error;
01180                 break;
01181 
01182         case DB_UPD:
01183                 if (build_update_cmd(&res->sql_cmd, cmd) < 0) goto error;
01184                 break;
01185 
01186         case DB_SQL:
01187                 res->sql_cmd.s = (char*)pkg_malloc(cmd->table.len);
01188                 if (res->sql_cmd.s == NULL) {
01189                         ERR("mysql: Out of private memory\n");
01190                         goto error;
01191                 }
01192                 memcpy(res->sql_cmd.s,cmd->table.s, cmd->table.len);
01193                 res->sql_cmd.len = cmd->table.len;
01194         break;
01195         }
01196 
01197         DB_SET_PAYLOAD(cmd, res);
01198         if (upload_cmd(cmd) != 0) goto error;
01199         return 0;
01200 
01201  error:
01202         if (res) {
01203                 DB_SET_PAYLOAD(cmd, NULL);
01204                 db_drv_free(&res->gen);
01205                 if (res->sql_cmd.s) pkg_free(res->sql_cmd.s);
01206                 pkg_free(res);
01207         }
01208         return -1;
01209 }
01210 
01211 
01212 int my_cmd_first(db_res_t* res) {
01213         struct my_cmd* mcmd;
01214 
01215         mcmd = DB_GET_PAYLOAD(res->cmd);
01216         switch (mcmd->next_flag) {
01217         case -2: /* table is empty */
01218                 return 1;
01219         case 0:  /* cursor position is 0 */
01220                 return 0;
01221         case 1:  /* next row */
01222         case 2:  /* EOF */
01223                 ERR("mysql: Unbuffered queries do not support cursor reset.\n");
01224                 return -1;
01225         default:
01226                 return my_cmd_next(res);
01227         }
01228 }
01229 
01230 
01231 int my_cmd_next(db_res_t* res)
01232 {
01233         int ret;
01234         struct my_cmd* mcmd;
01235 
01236         mcmd = DB_GET_PAYLOAD(res->cmd);
01237         if (mcmd->next_flag == 2 || mcmd->next_flag == -2) return 1;
01238 
01239         if (mcmd->st == NULL) {
01240                 ERR("mysql: Prepared statement not found\n");
01241                 return -1;
01242         }
01243 
01244         ret = mysql_stmt_fetch(mcmd->st);
01245         
01246         if (ret == MYSQL_NO_DATA) {
01247                 mcmd->next_flag =  mcmd->next_flag<0?-2:2;
01248                 return 1;
01249         }
01250         /* MYSQL_DATA_TRUNCATED is only defined in mysql >= 5.0 */
01251 #if defined MYSQL_DATA_TRUNCATED
01252         if (ret == MYSQL_DATA_TRUNCATED) {
01253                 int i;
01254                 ERR("mysql: mysql_stmt_fetch, data truncated, fields: %d\n", res->cmd->result_count);
01255                 for (i = 0; i < res->cmd->result_count; i++) {
01256                         if (mcmd->st->bind[i].error /*&& mcmd->st->bind[i].buffer_length*/) {
01257                                 ERR("mysql: truncation, bind %d, length: %lu, buffer_length: %lu\n", 
01258                                         i, *(mcmd->st->bind[i].length), mcmd->st->bind[i].buffer_length);
01259                         }
01260                 }
01261                 ret = 0;
01262         }
01263 #endif
01264         if (mcmd->next_flag <= 0) {
01265                 mcmd->next_flag++;
01266         }
01267         if (ret != 0) {
01268                 ERR("mysql: Error in mysql_stmt_fetch (ret=%d): %s\n", ret, mysql_stmt_error(mcmd->st));
01269                 return -1;
01270         }
01271 
01272         if (update_result(res->cmd->result, mcmd->st) < 0) {
01273                 mysql_stmt_free_result(mcmd->st);
01274                 return -1;
01275         }
01276 
01277         res->cur_rec->fld = res->cmd->result;
01278         return 0;
01279 }
01280 
01281 
01282 int my_getopt(db_cmd_t* cmd, char* optname, va_list ap)
01283 {
01284         struct my_cmd* mcmd;
01285         long long* id;
01286         int* val;
01287 
01288         mcmd = (struct my_cmd*)DB_GET_PAYLOAD(cmd);
01289 
01290         if (!strcasecmp("last_id", optname)) {
01291                 id = va_arg(ap, long long*);
01292                 if (id == NULL) {
01293                         BUG("mysql: NULL pointer passed to 'last_id' option\n");
01294                         goto error;
01295                 }
01296 
01297                 if (mcmd->st->last_errno != 0) {
01298                         BUG("mysql: Option 'last_id' called but previous command failed, "
01299                                 "check your code\n");
01300                         return -1;
01301                 }
01302 
01303                 *id = mysql_stmt_insert_id(mcmd->st);
01304                 if ((*id) == 0) {
01305                         BUG("mysql: Option 'last_id' called but there is no auto-increment"
01306                                 " column in table, SQL command: %.*s\n", STR_FMT(&mcmd->sql_cmd));
01307                         return -1;
01308                 }
01309         } else if (!strcasecmp("fetch_all", optname)) {
01310                 val = va_arg(ap, int*);
01311                 if (val == NULL) {
01312                         BUG("mysql: NULL pointer passed to 'fetch_all' DB option\n");
01313                         goto error;
01314                 }
01315                 *val = mcmd->flags;
01316         } else {
01317                 return 1;
01318         }
01319         return 0;
01320 
01321  error:
01322         return -1;
01323 }
01324 
01325 
01326 int my_setopt(db_cmd_t* cmd, char* optname, va_list ap)
01327 {
01328         struct my_cmd* mcmd;
01329         int* val;
01330 
01331         mcmd = (struct my_cmd*)DB_GET_PAYLOAD(cmd);
01332         if (!strcasecmp("fetch_all", optname)) {
01333                 val = va_arg(ap, int*);
01334                 if (val != 0) {
01335                         mcmd->flags |= MY_FETCH_ALL;
01336                 } else {
01337                         mcmd->flags &= ~MY_FETCH_ALL;
01338                 }
01339         } else {
01340                 return 1;
01341         }
01342         return 0;
01343 }
01344 

Generated on Tue Sep 7 04:16:02 2010 for SIPExpressRouter by  doxygen 1.3.9.1