825d86a00d9e901a2b9690fbfe8a66632cfc4cfd
[sip-router] / db / db_fifo.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 Fhg Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License 
24  * along with this program; if not, write to the Free Software 
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  * 
27  * History:
28  * --------
29  *  2003-10-21  file created (bogdan)
30  *  2004-06-06  init_db_fifo added, DB api updated (andrei)
31  */
32
33
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <time.h>
41
42 #include "../mem/mem.h"
43 #include "../fifo_server.h"
44 #include "../dprint.h"
45 #include "../str.h"
46 #include "db.h"
47 #include "db_fifo.h"
48
49 #define MAX_SIZE_LINE 512
50 #define MAX_ARRAY     32
51
52 #define SELECT_CMD  1
53 #define DELETE_CMD  2
54 #define INSERT_CMD  3
55 #define UPDATE_CMD  4
56 #define RAWQUERY_CMD     5
57 #define RAWQUERYRES_CMD  6
58
59 #define SELECT_STR          "select"
60 #define SELECT_STR_LEN      (sizeof(SELECT_STR)-1)
61 #define DELETE_STR          "delete"
62 #define DELETE_STR_LEN      (sizeof(DELETE_STR)-1)
63 #define INSERT_STR          "insert"
64 #define INSERT_STR_LEN      (sizeof(INSERT_STR)-1)
65 #define UPDATE_STR          "update"
66 #define UPDATE_STR_LEN      (sizeof(UPDATE_STR)-1)
67 #define RAWQUERY_STR        "raw_query"
68 #define RAWQUERY_STR_LEN    (sizeof(RAWQUERY_STR)-1)
69 #define RAWQUERYRES_STR     "raw_query_response"
70 #define RAWQUERYRES_STR_LEN (sizeof(RAWQUERYRES_STR)-1)
71 #define END_CHR    '.'
72
73 #define INT_TYPE         "int"
74 #define INT_TYPE_LEN     (sizeof(INT_TYPE)-1)
75 #define DOUBLE_TYPE      "double"
76 #define DOUBLE_TYPE_LEN  (sizeof(DOUBLE_TYPE)-1)
77 #define STRING_TYPE      "string"
78 #define STRING_TYPE_LEN  (sizeof(STRING_TYPE)-1)
79 #define DATE_TYPE        "date"
80 #define DATE_TYPE_LEN    (sizeof(DATE_TYPE)-1)
81 #define BLOB_TYPE        "blob"
82 #define BLOB_TYPE_LEN    (sizeof(BLOB_TYPE)-1)
83 #define BITMAP_TYPE      "bitmap"
84 #define BITMAP_TYPE_LEN  (sizeof(BITMAP_TYPE)-1)
85
86 #define NULL_VAL         "null"
87 #define NULL_VAL_LEN    (sizeof(NULL_VAL)-1)
88
89
90 #define trim_spaces(str) \
91         do { \
92                 for(;(str).s[0]==' ';(str).s++,((str).len)--);\
93                 for(;(str).s[(str).len-1]==' ';(str).s[--((str).len)]='\0');\
94         }while(0)
95
96 #define double_log( _str_ ) \
97         do { \
98                 fprintf( rpl, "ERROR: %s\n",_str_); \
99                 LOG( L_ERR, "ERROR:(%s:%d): %s\n",__FILE__,__LINE__,_str_); \
100         }while(0)
101
102 #define semidouble_log( _str_ ) \
103         do { \
104                 fprintf( rpl, "ERROR: Internal Server Error\n"); \
105                 LOG( L_ERR, "ERROR:(%s:%d): %s\n",__FILE__,__LINE__,_str_); \
106         }while(0)
107
108 #define get_int(_p_,_end_,_res_,_n_,_err_s_,_err_) \
109         do { \
110                 _res_ = 0;\
111                 for( _n_=0 ; (_p_)<(_end_) && isdigit(*(_p_)) ; (_p_)++,(_n_)++)\
112                         (_res_)=(_res_)*10+(*(_p_)-'0');\
113                 if ((_n_)==0) {\
114                         double_log( _err_s_ );\
115                         goto _err_;\
116                 }\
117         }while(0);
118
119
120
121
122 static char   buf[MAX_SIZE_LINE];
123 static FILE*  rpl;
124 static db_con_t*     fifo_db_con=0;
125 static db_func_t fifo_dbf;
126
127
128
129
130 static inline int sgn_str2float(str* _s, float* _r, db_type_t* _type )
131 {
132         int i, dot = 0;
133         int ngv = 0;
134         float order = 0.1;
135
136         *_r = 0;
137         *_type = DB_INT;
138         i = 0;
139         if (_s->len==0) return -3;
140         if ( (_s->s[0]=='-' && (ngv=1)==1) || (_s->s[0]=='+') )
141                 i++;
142         for( ; i < _s->len; i++) {
143                 if (_s->s[i] == '.') {
144                         if (dot) return -1;
145                         dot = 1;
146                         *_type = DB_DOUBLE;
147                         continue;
148                 }
149                 if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
150                         if (dot) {
151                                 *_r += (_s->s[i] - '0') * order;
152                                 order /= 10;
153                         } else {
154                                 *_r *= 10;
155                                 *_r += _s->s[i] - '0';
156                         }
157                 } else {
158                         return -2;
159                 }
160         }
161         if (ngv) *_r = -(*_r);
162         return 0;
163 }
164
165
166
167 static inline int parse_db_value( str *s, db_val_t *val, str **ret_s)
168 {
169         db_type_t type;
170         db_type_t nr_type;
171         int cast;
172         struct tm td;
173         char *p;
174         char *end;
175         int n;
176         float nr;
177
178         cast = 0;
179         *ret_s = 0;
180         p = 0;
181         type = DB_STR;
182
183         /* some safety checks */
184         if (s->len==0 || s->s==0) {
185                 semidouble_log("BUG -> parse_db_value gets a len/s=0 string");
186                 goto error;
187         }
188
189         /* is there some data cast operator? */
190         if (s->s[0]=='[') {
191                 /* get the end of the cast operator */
192                 for(p=s->s,end=s->s+s->len ; p<end && *p!=']' ; p++);
193                 if (p>=end-1) {
194                         double_log("Bad cast operator format (expected attr=[type]val)");
195                         goto error;
196                 }
197                 n = p - s->s - 1;
198                 p = s->s + 1;
199                 DBG("---><%.*s>\n",n,p);
200                 /*identify the cast type*/
201                 if (n==INT_TYPE_LEN && !strncasecmp(p,INT_TYPE,n)) {
202                         type = DB_INT;
203                 } else if (n==DOUBLE_TYPE_LEN && !strncasecmp(p,DOUBLE_TYPE,n)) {
204                         type = DB_DOUBLE;
205                 } else if (n==STRING_TYPE_LEN && !strncasecmp(p,STRING_TYPE,n)) {
206                         type = DB_STR;
207                 } else if (n==BLOB_TYPE_LEN && !strncasecmp(p,BLOB_TYPE,n)) {
208                         type = DB_BLOB;
209                 } else if (n==DATE_TYPE_LEN && !strncasecmp(p,DATE_TYPE,n)) {
210                         type = DB_DATETIME;
211                 } else if (n==BITMAP_TYPE_LEN && !strncasecmp(p,BITMAP_TYPE,n)) {
212                         type = DB_BITMAP;
213                 } else {
214                         double_log("Unknown cast type");
215                         goto error;
216                 }
217                 cast = 1;
218                 s->s += n+2;
219                 s->len -= n+2;
220         }
221
222         /* string has at least one caracter */
223         DBG("DEBUG:parse_db_value: value id <%.*s>\n",s->len,s->s);
224         if ( s->s[0]=='\"' && s->s[s->len-1]=='\"' && s->len!=1) {
225                 /* can be DB_STR, DB_STRING, DB_BLOB */
226                 /* get rid of the quoting */
227                 s->s++;
228                 s->len -= 2;
229                 /* if casted, check if is valid */
230                 if (cast) {
231                         if (type!=DB_STR && type!=DB_BLOB) {
232                                 double_log("Invalid cast for quoted value");
233                                 goto error;
234                         }
235                 } else {
236                         type = DB_STR;
237                 }
238                 /* fill in the val struct */
239                 memset( val, 0, sizeof(db_val_t));
240                 val->type = type;
241                 if (type==DB_STR) {
242                         val->val.str_val = *s;
243                         *ret_s = &val->val.str_val;
244                 } else if (type==DB_BLOB) {
245                         val->val.blob_val = *s;
246                         *ret_s = &val->val.blob_val;
247                 } else {
248                         semidouble_log("BUG -> type is not STR or BLOB");
249                         goto error;
250                 }
251         } else if ( s->s[0]=='<' && s->s[s->len-1]=='>' && s->len!=1) {
252                 /* can be only date+time type DB_DATETIME*/
253                 /* if casted, check if is valid */
254                 if (cast && type!=DB_DATETIME) {
255                         double_log("Invalid cast for quoted value");
256                         goto error;
257                 }
258                 /* get rid of the quoting */
259                 s->s++;
260                 s->len -= 2;
261                 /* start parsing */
262                 p = s->s;
263                 end = s->s + s->len;
264                 td.tm_wday = 0;
265                 td.tm_yday = 0;
266                 /* get year */
267                 get_int( p, end, td.tm_year, n, "Missing year in date format",error);
268                 td.tm_year -= 1900; /* corection */
269                 if (*(p++)!='-') goto date_error;
270                 /* get month */
271                 get_int( p, end, td.tm_mon, n, "Missing month in date format",error);
272                 td.tm_mon --; /* corection */
273                 if (*(p++)!='-') goto date_error;
274                 /* get day */
275                 get_int( p, end, td.tm_mday, n, "Missing day in date format",error);
276                 if (*(p++)!=' ') goto date_error;
277                 /* get hour */
278                 get_int( p, end, td.tm_hour, n, "Missing hour in date format",error);
279                 if (*(p++)!=':') goto date_error;
280                 /* get minutes */
281                 get_int( p, end, td.tm_min, n, "Missing minutes in date format",error);
282                 if (*(p++)!=':') goto date_error;
283                 /* get seconds */
284                 get_int( p, end, td.tm_sec, n,"Missing seconds in date format",error);
285                 if (p!=end) goto date_error;
286                 td.tm_isdst = -1 ; /*daylight*/
287                 /* fill the val struct */
288                 val->type = DB_DATETIME;
289                 val->val.time_val = mktime( &td );
290                 /*DBG("DBG: <%.*s> is %s\n",s->len,s->s,ctime(&val->val.time_val));*/
291         } else if ( (*(p=s->s)=='+') || (*p=='-') || isdigit(*p) ) {
292                 /* can be a DB_INT / DB_DOUBLE / DB_BITMAP value */
293                 if (sgn_str2float( s, &nr, &nr_type)!=0) {
294                         double_log("Bad int/float value format (expected [+/-]nr[.nr])");
295                         goto error;
296                 }
297                 /* if casted, check if valid */
298                 if (cast) {
299                         switch (type) {
300                                 case DB_BITMAP:
301                                         if ( nr_type!=DB_INT || nr<0 ) {
302                                                 double_log("Invalid value for BITMAP type");
303                                                 goto error;
304                                         }
305                                         break;
306                                 case DB_INT:
307                                 case DB_DOUBLE:
308                                         if (type==DB_INT && nr_type==DB_DOUBLE ) {
309                                                 double_log("Invalid cast to INT for a DOUBLE value");
310                                                 goto error;
311                                         }
312                                         break;
313                                 default:
314                                         double_log("Invalid cast for numerical value");
315                                         goto error;
316                         }
317                 } else {
318                         type = nr_type;
319                 }
320                 /* fill the val struct */
321                 val->type = type;
322                 switch (type) {
323                         case DB_INT:
324                                 val->val.int_val = (int)nr; break;
325                         case DB_DOUBLE:
326                                 val->val.double_val = nr; break;
327                         case DB_BITMAP:
328                                 val->val.bitmap_val = (int)nr; break;
329                         default:
330                                 semidouble_log("BUG -> unknown type when filling num. val");
331                                 goto error;
332                 }
333         } else if (s->len==NULL_VAL_LEN && !strncasecmp(s->s,NULL_VAL,s->len) ) {
334                 /* it's a NULL val */
335                 if (!cast) {
336                         double_log("NULL values requires type casting");
337                         goto error;
338                 }
339                 val->type = type;
340                 val->nul = 1;
341         } else {
342                 double_log("Unable to recognize value type");
343                 goto error;
344         }
345
346         return 0;
347 date_error:
348         double_log("Bad <date time> format (expected <YYYY-MM-DD hh:mm:ss>)\n");
349 error:
350         return -1;
351 }
352
353
354
355 /* returns : -1 error
356  *            0 success */
357 static inline int get_avps( FILE *fifo , db_key_t *keys, db_op_t *ops,
358                                                                                 db_val_t *vals, int *nr, int max_nr)
359 {
360         str  line;
361         str  key,op,val;
362         char *c;
363         str  *p_val;
364         int  sp_found;
365
366         *nr = 0;
367
368         while(1) {
369                 /* read a new line */
370                 line.s = buf;
371                 if (read_line( line.s, MAX_SIZE_LINE, fifo, &line.len)!=1) {
372                         double_log("Comamnd end when reading AVPs - missing . at after "
373                                 "AVP list?");
374                         goto error;
375                 }
376                 trim_spaces(line);
377                 /* is this the separter/end char? */
378                 if (line.len==1 && *line.s==END_CHR)
379                         return 0;
380                 /* we have a new avp */
381                 if (*nr<max_nr) {
382                         /* parse the line key|op|val */
383                         c = line.s;
384                         /* parse the key name */
385                         for( key.s=c ; *c && (isalnum(*c)||*c=='_') ; c++ );
386                         if (!*c) goto parse_error;
387                         key.len = c-key.s;
388                         if (key.len==0) goto parse_error;
389                         /* possible spaces? */
390                         for( sp_found=0 ; *c && isspace(*c) ; c++,sp_found=1 );
391                         if (!*c) goto parse_error;
392                         /* parse the operator */
393                         op.s = c;
394                         switch (*c) {
395                                 case '<':
396                                 case '>':
397                                         if (*(c+1)=='=') c++;
398                                 case '=':
399                                         c++;
400                                         if (!*c) goto parse_error;
401                                         break;
402                                 default:
403                                         /* at least one space must be before unknown ops */
404                                         if(!sp_found) goto parse_error;
405                                         /* eat everything to first space */
406                                         for( ; *c && !isspace(*c) ; c++ );
407                                         if (!*c || c==op.s) goto parse_error; /* 0 length */
408                                         /* include into operator str. one space before and after*/
409                                         op.s--;
410                                         c++;
411                         }
412                         op.len = c - op.s;
413                         /* possible spaces? */
414                         for( ; *c && isspace(*c) ; c++ );
415                         if (!*c) goto parse_error;
416                         /* get value */
417                         val.s = c;
418                         val.len = line.len - (c-line.s);
419                         if (val.len==0) goto parse_error;
420                         if (parse_db_value( &val, &vals[*nr], &p_val)!=0)
421                                 goto error;
422                         /* duplicate the avp -> make all null terminated */
423                         c = (char*)pkg_malloc(key.len+op.len+2+(p_val?p_val->len+1:0));
424                         if (c==0) {
425                                 semidouble_log("no more pkg memory");
426                                 goto error;
427                         }
428                         /*copy the key */
429                         keys[*nr] = c;
430                         memcpy( c, key.s, key.len);
431                         c[key.len] = 0;
432                         c += key.len + 1;
433                         /*copy the op */
434                         ops[*nr] = c;
435                         memcpy( c, op.s, op.len);
436                         c[op.len] = 0;
437                         c += op.len + 1;
438                         /*copy the val */
439                         if (p_val) {
440                                 memcpy( c, p_val->s, p_val->len);
441                                 c[p_val->len] = 0;
442                                 p_val->s = c;
443                         }
444                         /* done */
445                         (*nr)++;
446                 } else {
447                         LOG(L_WARN,"WARNING:get_avps: too many avps (max=%d), ignoring "
448                                 "\"%.*s\"\n",max_nr,line.len,line.s);
449                 }
450         }
451 parse_error:
452         LOG(L_ERR,"ERROR:get_avps: parse error in \"%.*s\" at char [%d][%c] "
453                 "offset %d\n",line.len,line.s,*c,*c,c-line.s);
454         double_log("Broken AVP(attr|op|val) in DB command");
455 error:
456         for(;*nr;(*nr)--)
457                 pkg_free( (void*)keys[(*nr)-1] );
458         return -1;
459 }
460
461
462
463 /* returns : -1 error
464  *            0 success */
465 static inline int get_keys( FILE *fifo , db_key_t *keys, int *nr, int max_nr)
466 {
467         str line;
468         char *key;
469
470         *nr = 0;
471
472         while(1) {
473                 /* read a new line */
474                 line.s = buf;
475                 if (!read_line( line.s, MAX_SIZE_LINE, fifo, &line.len) || !line.len) {
476                         double_log("Bad key list in SELECT DB command "
477                                 "(missing '.' at the end?)");
478                         goto error;
479                 }
480                 trim_spaces(line);
481                 /* is this the separter/end char? */
482                 if (line.len==1 && *line.s==END_CHR)
483                         return 0;
484                 /* we have a new key */
485                 if (*nr<max_nr) {
486                         /* duplicate the key -> null terminated */
487                         key = (char*)pkg_malloc(line.len+1);
488                         if (key==0) {
489                                 semidouble_log("no more pkg memory");
490                                 goto error;
491                         }
492                         memcpy( key, line.s, line.len);
493                         key[line.len] = 0;
494                         keys[*nr] = key;
495                         (*nr)++;
496                 } else {
497                         LOG(L_WARN,"WARNING:get_keys: too many keys (max=%d), ignoring "
498                                 "\"%.*s\"\n",max_nr,line.len,line.s);
499                 }
500         }
501
502 error:
503         for(;*nr;(*nr)--)
504                 pkg_free( (void*)keys[(*nr)-1] );
505         return -1;
506 }
507
508
509
510 static inline void print_res(db_res_t* res, FILE *rpl)
511 {
512         int i, j;
513
514         for(i = 0; i < RES_COL_N(res); i++) {
515                 fprintf(rpl, "%s ", RES_NAMES(res)[i]);
516         }
517         fprintf(rpl,"\n");
518
519         for(i = 0; i < RES_ROW_N(res); i++) {
520                 for(j = 0; j < RES_COL_N(res); j++) {
521                         if (RES_ROWS(res)[i].values[j].nul) {
522                                 fprintf(rpl,"NULL ");
523                                 continue;
524                         }
525                         switch(RES_ROWS(res)[i].values[j].type) {
526                                 case DB_INT:
527                                         fprintf(rpl,"%d ",
528                                                 RES_ROWS(res)[i].values[j].val.int_val);
529                                         break;
530                                 case DB_DOUBLE:
531                                         fprintf(rpl,"%f ",
532                                                 RES_ROWS(res)[i].values[j].val.double_val);
533                                 break;
534                                 case DB_DATETIME:
535                                         fprintf(rpl,"%s ",
536                                                 ctime(&(RES_ROWS(res)[i].values[j].val.time_val)));
537                                         break;
538                                 case DB_STRING:
539                                         fprintf(rpl,"%s ",
540                                                 RES_ROWS(res)[i].values[j].val.string_val);
541                                         break;
542                                 case DB_STR:
543                                         fprintf(rpl,"%.*s ", 
544                                                 RES_ROWS(res)[i].values[j].val.str_val.len,
545                                                 RES_ROWS(res)[i].values[j].val.str_val.s);
546                                         break;
547                                 case DB_BLOB:
548                                         fprintf(rpl,"%.*s ",
549                                                 RES_ROWS(res)[i].values[j].val.blob_val.len,
550                                                 RES_ROWS(res)[i].values[j].val.blob_val.s);
551                                         break;
552                                 case DB_BITMAP:
553                                         fprintf(rpl,"%d ",
554                                                 RES_ROWS(res)[i].values[j].val.bitmap_val);
555                                         break;
556                         }
557                 }
558                 fprintf(rpl,"\n");
559         }
560 }
561
562
563
564 /* binds the database module, initializes the database and 
565  * registers the db fifo cmd
566  * returns 0 on success, -1 on error */
567 int init_db_fifo(char* fifo_db_url)
568 {
569         if ( bind_dbmod(fifo_db_url, &fifo_dbf)==0 ) {
570                 if ( (fifo_db_con=fifo_dbf.init( fifo_db_url ))==0) {
571                         /* connection failed */
572                         LOG(L_ERR,"ERROR: init_db_fifo: unable to connect to database -> "
573                                 "fifo DB commands disabled!\n");
574                 }else if (register_fifo_cmd(db_fifo_cmd, FIFO_DB, 0)<0) {
575                         LOG(L_ERR, "ERROR: init_db_fifo: unable to register '%s'"
576                                         " FIFO cmd\n", FIFO_DB);
577                 } else {
578                         return 0; /* success */
579                 }
580         }else{
581                 LOG(L_WARN, "WARNING: init_db_fifo: unable to find any db module - "
582                         "fifo DB commands disabled!\n");
583         }
584         return -1; /* error */
585 }
586
587
588
589
590
591 int db_fifo( FILE *fifo, char *response_file )
592 {
593         static db_key_t keys1[MAX_ARRAY];
594         static db_op_t  ops1[MAX_ARRAY];
595         static db_val_t vals1[MAX_ARRAY];
596         static db_key_t keys2[MAX_ARRAY];
597         static db_op_t  ops2[MAX_ARRAY];
598         static db_val_t vals2[MAX_ARRAY];
599         static db_res_t *select_res;
600         str   line;
601         int   db_cmd;
602         int   nr1, nr2;
603         int   ret;
604         int   n;
605
606         ret = -1; /* default is error */
607         rpl =  0;
608
609         if (fifo_db_con==0) /* disabled due to database init/binding errors */
610                 goto error;
611         /* first check the response file */
612         rpl = open_reply_pipe( response_file );
613         if (rpl==0)
614                 goto error;
615
616         /* first name must be the real name of the DB operation */
617         line.s = buf;
618         if (!read_line( line.s, MAX_SIZE_LINE, fifo, &line.len) || line.len==0) {
619                 double_log("DB command name expected");
620                 goto error;
621         }
622         trim_spaces(line);
623
624         /* check the name of the command */
625         if (line.len==SELECT_STR_LEN
626         && !strncasecmp( line.s, SELECT_STR, line.len)) {
627                 db_cmd = SELECT_CMD;
628         } else if (line.len==DELETE_STR_LEN
629         && !strncasecmp( line.s, DELETE_STR, line.len)) {
630                 db_cmd = DELETE_CMD;
631         } else if (line.len==INSERT_STR_LEN
632         && !strncasecmp( line.s, INSERT_STR, line.len)) {
633                 db_cmd = INSERT_CMD;
634         } else if (line.len==UPDATE_STR_LEN
635         && !strncasecmp( line.s, UPDATE_STR, line.len)) {
636                 db_cmd = UPDATE_CMD;
637         } else if (line.len==RAWQUERY_STR_LEN
638         && !strncasecmp( line.s, RAWQUERY_STR, line.len)) {
639                 db_cmd = RAWQUERY_CMD;
640         } else if (line.len==RAWQUERYRES_STR_LEN
641         && !strncasecmp( line.s, RAWQUERYRES_STR, line.len)) {
642                 db_cmd = RAWQUERYRES_CMD;
643         } else {
644                 double_log("Unknown DB command name");
645                 goto error;
646         }
647         DBG("DEBUG:db_fifo: cmd \"%.*s\" received\n",line.len,line.s);
648
649         nr1 = 0;
650         nr2 = 0;
651
652         if (db_cmd==SELECT_CMD) {
653                 /* read the colums to be fetched */
654                 if ( get_keys( fifo, keys1, &nr1, MAX_ARRAY)!=0 )
655                         goto error;
656         } else if (db_cmd==UPDATE_CMD) {
657                 /* read the col=val pairs to be updated */
658                 if (get_avps( fifo , keys1, ops1, vals1, &nr1, MAX_ARRAY)!=0 )
659                         goto error;
660                 /* must be at least one AVP in an update command */
661                 if (nr1==0) {
662                         double_log("UPDATE command must have at least one"
663                                 " field to update");
664                         goto error;
665                 }
666                 /* all the operators must be '=' */
667                 for(n=0;n<nr1;n++) {
668                         if (ops1[n][0]!='=' || ops1[n][1]!='\0') {
669                                 double_log("Invalid operator in updated fileds (expected = )");
670                                 goto error1;
671                         }
672                 }/*end for*/
673         } else if (db_cmd==RAWQUERY_CMD || db_cmd==RAWQUERYRES_CMD) {
674                 /* read the raw db command  */
675                 line.s = buf;
676                 if (!read_line( line.s, MAX_SIZE_LINE-1,fifo,&line.len) || !line.len) {
677                         double_log("Raw db command expected");
678                         goto error;
679                 }
680                 trim_spaces(line);
681                 /* run the command */
682                 if (db_cmd==RAWQUERY_CMD)
683                         n = fifo_dbf.raw_query( fifo_db_con, line.s, 0);
684                 else
685                         n = fifo_dbf.raw_query( fifo_db_con, line.s, &select_res);
686                 if (n!=0) {
687                         double_log("Internal Server error - DB query failed");
688                         goto error;
689                 }
690                 /* any results? */
691                 if (db_cmd==RAWQUERYRES_CMD) {
692                         /* get all response and write them into reply fifo */
693                         print_res( select_res, rpl);
694                         /* free the query response */
695                         fifo_dbf.free_result( fifo_db_con, select_res);
696                 }
697                 /* done with success */
698                 goto done;
699         }
700
701         /* read the table name */
702         line.s = buf;
703         if (!read_line( line.s, MAX_SIZE_LINE-1, fifo, &line.len) || !line.len) {
704                 double_log("Table name expected");
705                 goto error1;
706         }
707         trim_spaces(line);
708
709         /* select the correct table */
710         line.s[line.len] = 0; /* make it null terminated */
711
712         if (fifo_dbf.use_table( fifo_db_con, line.s) < 0) {
713                 double_log("use_table function failed");
714                 goto error1;
715         }
716
717         /*read 'where' avps */
718         if (get_avps( fifo , keys2, ops2, vals2, &nr2, MAX_ARRAY)!=0 )
719                 goto error1;
720
721         switch (db_cmd) {
722                 case SELECT_CMD:
723                         /* push the query */
724                         n = fifo_dbf.query( fifo_db_con, nr2?keys2:0, nr2?ops2:0,
725                                                 nr2?vals2:0, nr1?keys1:0, nr2, nr1, 0, &select_res );
726                         if (n!=0) {
727                                 double_log("Internal Server error - DB query failed");
728                                 goto error2;
729                         }
730                         /* get all response and write them into reply fifo */
731                         print_res( select_res, rpl);
732                         /* free the query response */
733                         fifo_dbf.free_result( fifo_db_con, select_res);
734                         break;
735                 case UPDATE_CMD:
736                         if (nr1==0) {
737                                 double_log("No values for update (empty first AVP list)");
738                                 goto error;
739                         }
740                         /* all the operators must be '=' in the first avp list */
741                         for(n=0;n<nr1;n++) {
742                                 if (ops1[n][0]!='=' || ops1[n][1]!='\0') {
743                                         double_log("Invalid operator in updated fileds "
744                                                 "(expected = )");
745                                         goto error;
746                                 }
747                         }/*end for*/
748                         /* push the query */
749                         n = fifo_dbf.update( fifo_db_con, nr2?keys2:0, nr2?ops2:0,
750                                         nr2?vals2:0, keys1, vals1, nr2, nr1 );
751                         if (n!=0) {
752                                 double_log("Internal Server error - DB query failed");
753                                 goto error2;
754                         }
755                         break;
756                 case DELETE_CMD:
757                         /* push the query */
758                         n = fifo_dbf.delete( fifo_db_con, nr2?keys2:0, nr2?ops2:0,
759                                         nr2?vals2:0, nr2);
760                         if (n!=0) {
761                                 double_log("Internal Server error - DB query failed");
762                                 goto error2;
763                         }
764                         break;
765                 case INSERT_CMD:
766                         if (nr2==0) {
767                                 double_log("Nothing to insert (empty AVP list)");
768                                 goto error;
769                         }
770                         /* all the operators must be '=' */
771                         for(n=0;n<nr2;n++) {
772                                 if (ops2[n][0]!='=' || ops2[n][1]!='\0') {
773                                         double_log("Invalid operator in inserted fileds "
774                                                 "(expected = )");
775                                         goto error;
776                                 }
777                         }/*end for*/
778                         /* push the query */
779                         n = fifo_dbf.insert( fifo_db_con, nr2?keys2:0, nr2?vals2:0, nr2);
780                         if (n!=0) {
781                                 double_log("Internal Server error - DB query failed");
782                                 goto error2;
783                         }
784                         break;
785         }
786
787         /* success */
788 done:
789         ret = 0;
790 error2:
791         for(;nr2;nr2--)
792                 pkg_free( (void*)keys2[nr2-1] );
793 error1:
794         for(;nr1;nr1--)
795                 pkg_free( (void*)keys1[nr1-1] );
796 error:
797         if (rpl) fclose(rpl);
798         return ret;
799 }
800