fixed bug (the table name in the query used to get overwritten).
[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 char   tbl_buf[MAX_SIZE_LINE]; /* current 'table name' buffer */
124 static FILE*  rpl;
125 static db_con_t*     fifo_db_con=0;
126 static db_func_t fifo_dbf;
127
128
129
130
131 static inline int sgn_str2float(str* _s, float* _r, db_type_t* _type )
132 {
133         int i, dot = 0;
134         int ngv = 0;
135         float order = 0.1;
136
137         *_r = 0;
138         *_type = DB_INT;
139         i = 0;
140         if (_s->len==0) return -3;
141         if ( (_s->s[0]=='-' && (ngv=1)==1) || (_s->s[0]=='+') )
142                 i++;
143         for( ; i < _s->len; i++) {
144                 if (_s->s[i] == '.') {
145                         if (dot) return -1;
146                         dot = 1;
147                         *_type = DB_DOUBLE;
148                         continue;
149                 }
150                 if ((_s->s[i] >= '0') && (_s->s[i] <= '9')) {
151                         if (dot) {
152                                 *_r += (_s->s[i] - '0') * order;
153                                 order /= 10;
154                         } else {
155                                 *_r *= 10;
156                                 *_r += _s->s[i] - '0';
157                         }
158                 } else {
159                         return -2;
160                 }
161         }
162         if (ngv) *_r = -(*_r);
163         return 0;
164 }
165
166
167
168 static inline int parse_db_value( str *s, db_val_t *val, str **ret_s)
169 {
170         db_type_t type;
171         db_type_t nr_type;
172         int cast;
173         struct tm td;
174         char *p;
175         char *end;
176         int n;
177         float nr;
178
179         cast = 0;
180         *ret_s = 0;
181         p = 0;
182         type = DB_STR;
183
184         /* some safety checks */
185         if (s->len==0 || s->s==0) {
186                 semidouble_log("BUG -> parse_db_value gets a len/s=0 string");
187                 goto error;
188         }
189
190         /* is there some data cast operator? */
191         if (s->s[0]=='[') {
192                 /* get the end of the cast operator */
193                 for(p=s->s,end=s->s+s->len ; p<end && *p!=']' ; p++);
194                 if (p>=end-1) {
195                         double_log("Bad cast operator format (expected attr=[type]val)");
196                         goto error;
197                 }
198                 n = p - s->s - 1;
199                 p = s->s + 1;
200                 DBG("---><%.*s>\n",n,p);
201                 /*identify the cast type*/
202                 if (n==INT_TYPE_LEN && !strncasecmp(p,INT_TYPE,n)) {
203                         type = DB_INT;
204                 } else if (n==DOUBLE_TYPE_LEN && !strncasecmp(p,DOUBLE_TYPE,n)) {
205                         type = DB_DOUBLE;
206                 } else if (n==STRING_TYPE_LEN && !strncasecmp(p,STRING_TYPE,n)) {
207                         type = DB_STR;
208                 } else if (n==BLOB_TYPE_LEN && !strncasecmp(p,BLOB_TYPE,n)) {
209                         type = DB_BLOB;
210                 } else if (n==DATE_TYPE_LEN && !strncasecmp(p,DATE_TYPE,n)) {
211                         type = DB_DATETIME;
212                 } else if (n==BITMAP_TYPE_LEN && !strncasecmp(p,BITMAP_TYPE,n)) {
213                         type = DB_BITMAP;
214                 } else {
215                         double_log("Unknown cast type");
216                         goto error;
217                 }
218                 cast = 1;
219                 s->s += n+2;
220                 s->len -= n+2;
221         }
222
223         /* string has at least one character */
224         DBG("DEBUG:parse_db_value: value id <%.*s>\n",s->len,s->s);
225         if ( s->s[0]=='\"' && s->s[s->len-1]=='\"' && s->len!=1) {
226                 /* can be DB_STR, DB_STRING, DB_BLOB */
227                 /* get rid of the quoting */
228                 s->s++;
229                 s->len -= 2;
230                 /* if casted, check if is valid */
231                 if (cast) {
232                         if (type!=DB_STR && type!=DB_BLOB) {
233                                 double_log("Invalid cast for quoted value");
234                                 goto error;
235                         }
236                 } else {
237                         type = DB_STR;
238                 }
239                 /* fill in the val struct */
240                 memset( val, 0, sizeof(db_val_t));
241                 val->type = type;
242                 if (type==DB_STR) {
243                         val->val.str_val = *s;
244                         *ret_s = &val->val.str_val;
245                 } else if (type==DB_BLOB) {
246                         val->val.blob_val = *s;
247                         *ret_s = &val->val.blob_val;
248                 } else {
249                         semidouble_log("BUG -> type is not STR or BLOB");
250                         goto error;
251                 }
252         } else if ( s->s[0]=='<' && s->s[s->len-1]=='>' && s->len!=1) {
253                 /* can be only date+time type DB_DATETIME*/
254                 /* if casted, check if is valid */
255                 if (cast && type!=DB_DATETIME) {
256                         double_log("Invalid cast for quoted value");
257                         goto error;
258                 }
259                 /* get rid of the quoting */
260                 s->s++;
261                 s->len -= 2;
262                 /* start parsing */
263                 p = s->s;
264                 end = s->s + s->len;
265                 td.tm_wday = 0;
266                 td.tm_yday = 0;
267                 /* get year */
268                 get_int( p, end, td.tm_year, n, "Missing year in date format",error);
269                 td.tm_year -= 1900; /* correction */
270                 if (*(p++)!='-') goto date_error;
271                 /* get month */
272                 get_int( p, end, td.tm_mon, n, "Missing month in date format",error);
273                 td.tm_mon --; /* correction */
274                 if (*(p++)!='-') goto date_error;
275                 /* get day */
276                 get_int( p, end, td.tm_mday, n, "Missing day in date format",error);
277                 if (*(p++)!=' ') goto date_error;
278                 /* get hour */
279                 get_int( p, end, td.tm_hour, n, "Missing hour in date format",error);
280                 if (*(p++)!=':') goto date_error;
281                 /* get minutes */
282                 get_int( p, end, td.tm_min, n, "Missing minutes in date format",error);
283                 if (*(p++)!=':') goto date_error;
284                 /* get seconds */
285                 get_int( p, end, td.tm_sec, n,"Missing seconds in date format",error);
286                 if (p!=end) goto date_error;
287                 td.tm_isdst = -1 ; /*daylight*/
288                 /* fill the val struct */
289                 val->type = DB_DATETIME;
290                 val->val.time_val = mktime( &td );
291                 /*DBG("DBG: <%.*s> is %s\n",s->len,s->s,ctime(&val->val.time_val));*/
292         } else if ( (*(p=s->s)=='+') || (*p=='-') || isdigit(*p) ) {
293                 /* can be a DB_INT / DB_DOUBLE / DB_BITMAP value */
294                 if (sgn_str2float( s, &nr, &nr_type)!=0) {
295                         double_log("Bad int/float value format (expected [+/-]nr[.nr])");
296                         goto error;
297                 }
298                 /* if casted, check if valid */
299                 if (cast) {
300                         switch (type) {
301                                 case DB_BITMAP:
302                                         if ( nr_type!=DB_INT || nr<0 ) {
303                                                 double_log("Invalid value for BITMAP type");
304                                                 goto error;
305                                         }
306                                         break;
307                                 case DB_INT:
308                                 case DB_DOUBLE:
309                                         if (type==DB_INT && nr_type==DB_DOUBLE ) {
310                                                 double_log("Invalid cast to INT for a DOUBLE value");
311                                                 goto error;
312                                         }
313                                         break;
314                                 default:
315                                         double_log("Invalid cast for numerical value");
316                                         goto error;
317                         }
318                 } else {
319                         type = nr_type;
320                 }
321                 /* fill the val struct */
322                 val->type = type;
323                 switch (type) {
324                         case DB_INT:
325                                 val->val.int_val = (int)nr; break;
326                         case DB_DOUBLE:
327                                 val->val.double_val = nr; break;
328                         case DB_BITMAP:
329                                 val->val.bitmap_val = (int)nr; break;
330                         default:
331                                 semidouble_log("BUG -> unknown type when filling num. val");
332                                 goto error;
333                 }
334         } else if (s->len==NULL_VAL_LEN && !strncasecmp(s->s,NULL_VAL,s->len) ) {
335                 /* it's a NULL val */
336                 if (!cast) {
337                         double_log("NULL values requires type casting");
338                         goto error;
339                 }
340                 val->type = type;
341                 val->nul = 1;
342         } else {
343                 double_log("Unable to recognize value type");
344                 goto error;
345         }
346
347         return 0;
348 date_error:
349         double_log("Bad <date time> format (expected <YYYY-MM-DD hh:mm:ss>)\n");
350 error:
351         return -1;
352 }
353
354
355
356 /* returns : -1 error
357  *            0 success */
358 static inline int get_avps( FILE *fifo , db_key_t *keys, db_op_t *ops,
359                                                                                 db_val_t *vals, int *nr, int max_nr)
360 {
361         str  line;
362         str  key,op,val;
363         char *c;
364         str  *p_val;
365         int  sp_found;
366
367         *nr = 0;
368
369         while(1) {
370                 /* read a new line */
371                 line.s = buf;
372                 if (read_line( line.s, MAX_SIZE_LINE, fifo, &line.len)!=1) {
373                         double_log("Command end when reading AVPs - missing . at after "
374                                 "AVP list?");
375                         goto error;
376                 }
377                 trim_spaces(line);
378                 /* is this the separter/end char? */
379                 if (line.len==1 && *line.s==END_CHR)
380                         return 0;
381                 /* we have a new avp */
382                 if (*nr<max_nr) {
383                         /* parse the line key|op|val */
384                         c = line.s;
385                         /* parse the key name */
386                         for( key.s=c ; *c && (isalnum(*c)||*c=='_') ; c++ );
387                         if (!*c) goto parse_error;
388                         key.len = c-key.s;
389                         if (key.len==0) goto parse_error;
390                         /* possible spaces? */
391                         for( sp_found=0 ; *c && isspace(*c) ; c++,sp_found=1 );
392                         if (!*c) goto parse_error;
393                         /* parse the operator */
394                         op.s = c;
395                         switch (*c) {
396                                 case '<':
397                                 case '>':
398                                         if (*(c+1)=='=') c++;
399                                 case '=':
400                                         c++;
401                                         if (!*c) goto parse_error;
402                                         break;
403                                 default:
404                                         /* at least one space must be before unknown ops */
405                                         if(!sp_found) goto parse_error;
406                                         /* eat everything to first space */
407                                         for( ; *c && !isspace(*c) ; c++ );
408                                         if (!*c || c==op.s) goto parse_error; /* 0 length */
409                                         /* include into operator str. one space before and after*/
410                                         op.s--;
411                                         c++;
412                         }
413                         op.len = c - op.s;
414                         /* possible spaces? */
415                         for( ; *c && isspace(*c) ; c++ );
416                         if (!*c) goto parse_error;
417                         /* get value */
418                         val.s = c;
419                         val.len = line.len - (c-line.s);
420                         if (val.len==0) goto parse_error;
421                         if (parse_db_value( &val, &vals[*nr], &p_val)!=0)
422                                 goto error;
423                         /* duplicate the avp -> make all null terminated */
424                         c = (char*)pkg_malloc(key.len+op.len+2+(p_val?p_val->len+1:0));
425                         if (c==0) {
426                                 semidouble_log("no more pkg memory");
427                                 goto error;
428                         }
429                         /*copy the key */
430                         keys[*nr] = c;
431                         memcpy( c, key.s, key.len);
432                         c[key.len] = 0;
433                         c += key.len + 1;
434                         /*copy the op */
435                         ops[*nr] = c;
436                         memcpy( c, op.s, op.len);
437                         c[op.len] = 0;
438                         c += op.len + 1;
439                         /*copy the val */
440                         if (p_val) {
441                                 memcpy( c, p_val->s, p_val->len);
442                                 c[p_val->len] = 0;
443                                 p_val->s = c;
444                         }
445                         /* done */
446                         (*nr)++;
447                 } else {
448                         LOG(L_WARN,"WARNING:get_avps: too many avps (max=%d), ignoring "
449                                 "\"%.*s\"\n",max_nr,line.len,line.s);
450                 }
451         }
452 parse_error:
453         LOG(L_ERR,"ERROR:get_avps: parse error in \"%.*s\" at char [%d][%c] "
454                 "offset %d\n",line.len,line.s,*c,*c,c-line.s);
455         double_log("Broken AVP(attr|op|val) in DB command");
456 error:
457         for(;*nr;(*nr)--)
458                 pkg_free( (void*)keys[(*nr)-1] );
459         return -1;
460 }
461
462
463
464 /* returns : -1 error
465  *            0 success */
466 static inline int get_keys( FILE *fifo , db_key_t *keys, int *nr, int max_nr)
467 {
468         str line;
469         char *key;
470
471         *nr = 0;
472
473         while(1) {
474                 /* read a new line */
475                 line.s = buf;
476                 if (!read_line( line.s, MAX_SIZE_LINE, fifo, &line.len) || !line.len) {
477                         double_log("Bad key list in SELECT DB command "
478                                 "(missing '.' at the end?)");
479                         goto error;
480                 }
481                 trim_spaces(line);
482                 /* is this the separter/end char? */
483                 if (line.len==1 && *line.s==END_CHR)
484                         return 0;
485                 /* we have a new key */
486                 if (*nr<max_nr) {
487                         /* duplicate the key -> null terminated */
488                         key = (char*)pkg_malloc(line.len+1);
489                         if (key==0) {
490                                 semidouble_log("no more pkg memory");
491                                 goto error;
492                         }
493                         memcpy( key, line.s, line.len);
494                         key[line.len] = 0;
495                         keys[*nr] = key;
496                         (*nr)++;
497                 } else {
498                         LOG(L_WARN,"WARNING:get_keys: too many keys (max=%d), ignoring "
499                                 "\"%.*s\"\n",max_nr,line.len,line.s);
500                 }
501         }
502
503 error:
504         for(;*nr;(*nr)--)
505                 pkg_free( (void*)keys[(*nr)-1] );
506         return -1;
507 }
508
509
510
511 static inline void print_res(db_res_t* res, FILE *rpl)
512 {
513         int i, j;
514
515         for(i = 0; i < RES_COL_N(res); i++) {
516                 fprintf(rpl, "%s ", RES_NAMES(res)[i]);
517         }
518         fprintf(rpl,"\n");
519
520         for(i = 0; i < RES_ROW_N(res); i++) {
521                 for(j = 0; j < RES_COL_N(res); j++) {
522                         if (RES_ROWS(res)[i].values[j].nul) {
523                                 fprintf(rpl,"NULL ");
524                                 continue;
525                         }
526                         switch(RES_ROWS(res)[i].values[j].type) {
527                                 case DB_INT:
528                                         fprintf(rpl,"%d ",
529                                                 RES_ROWS(res)[i].values[j].val.int_val);
530                                         break;
531                                 case DB_DOUBLE:
532                                         fprintf(rpl,"%f ",
533                                                 RES_ROWS(res)[i].values[j].val.double_val);
534                                 break;
535                                 case DB_DATETIME:
536                                         fprintf(rpl,"%s ",
537                                                 ctime(&(RES_ROWS(res)[i].values[j].val.time_val)));
538                                         break;
539                                 case DB_STRING:
540                                         fprintf(rpl,"%s ",
541                                                 RES_ROWS(res)[i].values[j].val.string_val);
542                                         break;
543                                 case DB_STR:
544                                         fprintf(rpl,"%.*s ", 
545                                                 RES_ROWS(res)[i].values[j].val.str_val.len,
546                                                 RES_ROWS(res)[i].values[j].val.str_val.s);
547                                         break;
548                                 case DB_BLOB:
549                                         fprintf(rpl,"%.*s ",
550                                                 RES_ROWS(res)[i].values[j].val.blob_val.len,
551                                                 RES_ROWS(res)[i].values[j].val.blob_val.s);
552                                         break;
553                                 case DB_BITMAP:
554                                         fprintf(rpl,"%d ",
555                                                 RES_ROWS(res)[i].values[j].val.bitmap_val);
556                                         break;
557                         }
558                 }
559                 fprintf(rpl,"\n");
560         }
561 }
562
563
564
565 /* binds the database module, initializes the database and 
566  * registers the db fifo cmd
567  * returns 0 on success, -1 on error */
568 int init_db_fifo(char* fifo_db_url)
569 {
570         if ( bind_dbmod(fifo_db_url, &fifo_dbf)==0 ) {
571                 if (!DB_CAPABILITY(fifo_dbf, DB_CAP_ALL | DB_CAP_RAW_QUERY)) {
572                         LOG(L_ERR, "ERROR: init_db_fifo: Database module does "
573                             "not implement all function needed by AVP code\n");
574                         return -1;
575                 }
576
577                 if ( (fifo_db_con=fifo_dbf.init( fifo_db_url ))==0) {
578                         /* connection failed */
579                         LOG(L_ERR,"ERROR: init_db_fifo: unable to connect to database -> "
580                                 "fifo DB commands disabled!\n");
581                 }else if (register_fifo_cmd(db_fifo_cmd, FIFO_DB, 0)<0) {
582                         LOG(L_ERR, "ERROR: init_db_fifo: unable to register '%s'"
583                                         " FIFO cmd\n", FIFO_DB);
584                 } else {
585                         return 0; /* success */
586                 }
587         }else{
588                 LOG(L_WARN, "WARNING: init_db_fifo: unable to find any db module - "
589                         "fifo DB commands disabled!\n");
590         }
591         return -1; /* error */
592 }
593
594
595
596
597
598 int db_fifo( FILE *fifo, char *response_file )
599 {
600         static db_key_t keys1[MAX_ARRAY];
601         static db_op_t  ops1[MAX_ARRAY];
602         static db_val_t vals1[MAX_ARRAY];
603         static db_key_t keys2[MAX_ARRAY];
604         static db_op_t  ops2[MAX_ARRAY];
605         static db_val_t vals2[MAX_ARRAY];
606         static db_res_t *select_res;
607         str   line;
608         int   db_cmd;
609         int   nr1, nr2;
610         int   ret;
611         int   n;
612
613         ret = -1; /* default is error */
614         rpl =  0;
615
616         if (fifo_db_con==0) /* disabled due to database init/binding errors */
617                 goto error;
618         /* first check the response file */
619         rpl = open_reply_pipe( response_file );
620         if (rpl==0)
621                 goto error;
622
623         /* first name must be the real name of the DB operation */
624         line.s = buf;
625         if (!read_line( line.s, MAX_SIZE_LINE, fifo, &line.len) || line.len==0) {
626                 double_log("DB command name expected");
627                 goto error;
628         }
629         trim_spaces(line);
630
631         /* check the name of the command */
632         if (line.len==SELECT_STR_LEN
633         && !strncasecmp( line.s, SELECT_STR, line.len)) {
634                 db_cmd = SELECT_CMD;
635         } else if (line.len==DELETE_STR_LEN
636         && !strncasecmp( line.s, DELETE_STR, line.len)) {
637                 db_cmd = DELETE_CMD;
638         } else if (line.len==INSERT_STR_LEN
639         && !strncasecmp( line.s, INSERT_STR, line.len)) {
640                 db_cmd = INSERT_CMD;
641         } else if (line.len==UPDATE_STR_LEN
642         && !strncasecmp( line.s, UPDATE_STR, line.len)) {
643                 db_cmd = UPDATE_CMD;
644         } else if (line.len==RAWQUERY_STR_LEN
645         && !strncasecmp( line.s, RAWQUERY_STR, line.len)) {
646                 db_cmd = RAWQUERY_CMD;
647         } else if (line.len==RAWQUERYRES_STR_LEN
648         && !strncasecmp( line.s, RAWQUERYRES_STR, line.len)) {
649                 db_cmd = RAWQUERYRES_CMD;
650         } else {
651                 double_log("Unknown DB command name");
652                 goto error;
653         }
654         DBG("DEBUG:db_fifo: cmd \"%.*s\" received\n",line.len,line.s);
655
656         nr1 = 0;
657         nr2 = 0;
658
659         if (db_cmd==SELECT_CMD) {
660                 /* read the columns to be fetched */
661                 if ( get_keys( fifo, keys1, &nr1, MAX_ARRAY)!=0 )
662                         goto error;
663         } else if (db_cmd==UPDATE_CMD) {
664                 /* read the col=val pairs to be updated */
665                 if (get_avps( fifo , keys1, ops1, vals1, &nr1, MAX_ARRAY)!=0 )
666                         goto error;
667                 /* must be at least one AVP in an update command */
668                 if (nr1==0) {
669                         double_log("UPDATE command must have at least one"
670                                 " field to update");
671                         goto error;
672                 }
673                 /* all the operators must be '=' */
674                 for(n=0;n<nr1;n++) {
675                         if (ops1[n][0]!='=' || ops1[n][1]!='\0') {
676                                 double_log("Invalid operator in updated fields (expected = )");
677                                 goto error1;
678                         }
679                 }/*end for*/
680         } else if (db_cmd==RAWQUERY_CMD || db_cmd==RAWQUERYRES_CMD) {
681                 /* read the raw db command  */
682                 line.s = buf;
683                 if (!read_line( line.s, MAX_SIZE_LINE-1,fifo,&line.len) || !line.len) {
684                         double_log("Raw db command expected");
685                         goto error;
686                 }
687                 trim_spaces(line);
688                 /* run the command */
689                 if (db_cmd==RAWQUERY_CMD)
690                         n = fifo_dbf.raw_query( fifo_db_con, line.s, 0);
691                 else
692                         n = fifo_dbf.raw_query( fifo_db_con, line.s, &select_res);
693                 if (n!=0) {
694                         double_log("Internal Server error - DB query failed");
695                         goto error;
696                 }
697                 /* any results? */
698                 if (db_cmd==RAWQUERYRES_CMD) {
699                         /* get all response and write them into reply fifo */
700                         print_res( select_res, rpl);
701                         /* free the query response */
702                         fifo_dbf.free_result( fifo_db_con, select_res);
703                 }
704                 /* done with success */
705                 goto done;
706         }
707
708         /* read the table name */
709         line.s = tbl_buf;/*buf;*/
710         if (!read_line( line.s, MAX_SIZE_LINE-1, fifo, &line.len) || !line.len) {
711                 double_log("Table name expected");
712                 goto error1;
713         }
714         trim_spaces(line);
715
716         /* select the correct table */
717         line.s[line.len] = 0; /* make it null terminated */
718
719         if (fifo_dbf.use_table( fifo_db_con, line.s) < 0) {
720                 double_log("use_table function failed");
721                 goto error1;
722         }
723
724         /*read 'where' avps */
725         if (get_avps( fifo , keys2, ops2, vals2, &nr2, MAX_ARRAY)!=0 )
726                 goto error1;
727
728         switch (db_cmd) {
729                 case SELECT_CMD:
730                         /* push the query */
731                         n = fifo_dbf.query( fifo_db_con, nr2?keys2:0, nr2?ops2:0,
732                                                 nr2?vals2:0, nr1?keys1:0, nr2, nr1, 0, &select_res );
733                         if (n!=0) {
734                                 double_log("Internal Server error - DB query failed");
735                                 goto error2;
736                         }
737                         /* get all response and write them into reply fifo */
738                         print_res( select_res, rpl);
739                         /* free the query response */
740                         fifo_dbf.free_result( fifo_db_con, select_res);
741                         break;
742                 case UPDATE_CMD:
743                         if (nr1==0) {
744                                 double_log("No values for update (empty first AVP list)");
745                                 goto error;
746                         }
747                         /* all the operators must be '=' in the first avp list */
748                         for(n=0;n<nr1;n++) {
749                                 if (ops1[n][0]!='=' || ops1[n][1]!='\0') {
750                                         double_log("Invalid operator in updated fields "
751                                                 "(expected = )");
752                                         goto error;
753                                 }
754                         }/*end for*/
755                         /* push the query */
756                         n = fifo_dbf.update( fifo_db_con, nr2?keys2:0, nr2?ops2:0,
757                                         nr2?vals2:0, keys1, vals1, nr2, nr1 );
758                         if (n!=0) {
759                                 double_log("Internal Server error - DB query failed");
760                                 goto error2;
761                         }
762                         break;
763                 case DELETE_CMD:
764                         /* push the query */
765                         n = fifo_dbf.delete( fifo_db_con, nr2?keys2:0, nr2?ops2:0,
766                                         nr2?vals2:0, nr2);
767                         if (n!=0) {
768                                 double_log("Internal Server error - DB query failed");
769                                 goto error2;
770                         }
771                         break;
772                 case INSERT_CMD:
773                         if (nr2==0) {
774                                 double_log("Nothing to insert (empty AVP list)");
775                                 goto error;
776                         }
777                         /* all the operators must be '=' */
778                         for(n=0;n<nr2;n++) {
779                                 if (ops2[n][0]!='=' || ops2[n][1]!='\0') {
780                                         double_log("Invalid operator in inserted fields "
781                                                 "(expected = )");
782                                         goto error;
783                                 }
784                         }/*end for*/
785                         /* push the query */
786                         n = fifo_dbf.insert( fifo_db_con, nr2?keys2:0, nr2?vals2:0, nr2);
787                         if (n!=0) {
788                                 double_log("Internal Server error - DB query failed");
789                                 goto error2;
790                         }
791                         break;
792         }
793
794         /* success */
795 done:
796         ret = 0;
797 error2:
798         for(;nr2;nr2--)
799                 pkg_free( (void*)keys2[nr2-1] );
800 error1:
801         for(;nr1;nr1--)
802                 pkg_free( (void*)keys1[nr1-1] );
803 error:
804         if (rpl) fclose(rpl);
805         return ret;
806 }
807