dbt_res.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dbt_res.c 5713 2009-03-16 17:29:25Z henningw $
00003  *
00004  * DBText module core functions
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * History:
00025  * --------
00026  * 2009-03-01 added support for ORDER-BY clause by Edgar Holleis
00027  * 2003-06-05 fixed bug: when comparing two values and the first was less than
00028  *           the second one, the result of 'dbt_row_match' was always true,
00029  *           thanks to Gabriel, (Daniel)
00030  * 2003-02-04 created by Daniel
00031  * 
00032  */
00033 
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <sys/types.h>
00037 #include <stdlib.h>
00038 #include <setjmp.h>
00039 
00040 #include "../../mem/mem.h"
00041 
00042 #include "dbt_res.h"
00043 
00044 #define SIGN(_i) ((_i) > 0 ? 1 : ((_i) < 0 ? -1 : 0))
00045 
00046 dbt_result_p dbt_result_new(dbt_table_p _dtp, int *_lres, int _sz)
00047 {
00048    dbt_result_p _dres = NULL;
00049    int i, n;
00050    char *p;
00051    
00052    if(!_dtp || _sz < 0)
00053       return NULL;
00054 
00055    if(!_lres)
00056       _sz = _dtp->nrcols;
00057    
00058    _dres = (dbt_result_p)pkg_malloc(sizeof(dbt_result_t));
00059    if(!_dres)
00060       return NULL;
00061    _dres->colv = (dbt_column_p)pkg_malloc(_sz*sizeof(dbt_column_t));
00062    if(!_dres->colv)
00063    {
00064       LM_DBG("no pkg memory!\n");
00065       pkg_free(_dres);
00066       return NULL;
00067    }
00068    memset(_dres->colv, 0, _sz*sizeof(dbt_column_t));
00069    LM_DBG("new res with %d cols\n", _sz);
00070    for(i = 0; i < _sz; i++)
00071    {
00072       n = (_lres)?_dtp->colv[_lres[i]]->name.len:_dtp->colv[i]->name.len;
00073       p = (_lres)?_dtp->colv[_lres[i]]->name.s:_dtp->colv[i]->name.s;
00074       _dres->colv[i].name.s = (char*)pkg_malloc((n+1)*sizeof(char));
00075       if(!_dres->colv[i].name.s)
00076       {
00077          LM_DBG("no pkg memory\n");
00078          goto clean;
00079       }
00080       _dres->colv[i].name.len = n;
00081       strncpy(_dres->colv[i].name.s, p, n);
00082       _dres->colv[i].name.s[n] = 0;
00083       _dres->colv[i].type =
00084             (_lres)?_dtp->colv[_lres[i]]->type:_dtp->colv[i]->type;
00085    }
00086    
00087    _dres->nrcols = _sz;
00088    _dres->nrrows = 0;
00089    _dres->rows = NULL;
00090 
00091    return _dres;
00092 clean:
00093    while(i>=0)
00094    {
00095       if(_dres->colv[i].name.s)
00096          pkg_free(_dres->colv[i].name.s);
00097       i--;
00098    }
00099    pkg_free(_dres->colv);
00100    pkg_free(_dres);
00101    
00102    return NULL;
00103 }
00104 
00105 int dbt_result_free(dbt_result_p _dres)
00106 {
00107    dbt_row_p _rp=NULL, _rp0=NULL;
00108    int i;
00109 
00110    if(!_dres)
00111       return -1;
00112    _rp = _dres->rows;
00113    while(_rp)
00114    {
00115       _rp0=_rp;
00116       if(_rp0->fields)
00117       {
00118          for(i=0; i<_dres->nrcols; i++)
00119          {
00120             if((_dres->colv[i].type==DB_STR 
00121                      || _dres->colv[i].type==DB_STRING)
00122                   && _rp0->fields[i].val.str_val.s)
00123                pkg_free(_rp0->fields[i].val.str_val.s);
00124          }
00125          pkg_free(_rp0->fields);
00126       }
00127       pkg_free(_rp0);
00128       _rp=_rp->next;
00129    }
00130    if(_dres->colv)
00131    {
00132       for(i=0; i<_dres->nrcols; i++)
00133       {
00134          if(_dres->colv[i].name.s)
00135             pkg_free(_dres->colv[i].name.s);
00136       }
00137       pkg_free(_dres->colv);
00138    }
00139 
00140    pkg_free(_dres);
00141 
00142    return 0;
00143 }
00144 
00145 int dbt_result_add_row(dbt_result_p _dres, dbt_row_p _drp)
00146 {
00147    if(!_dres || !_drp)
00148       return -1;
00149    _dres->nrrows++;
00150    
00151    if(_dres->rows)
00152       (_dres->rows)->prev = _drp;
00153    _drp->next = _dres->rows;
00154    _dres->rows = _drp;
00155 
00156    return 0;
00157 }
00158 
00159 int* dbt_get_refs(dbt_table_p _dtp, db_key_t* _k, int _n)
00160 {
00161    int i, j, *_lref=NULL;
00162    
00163    if(!_dtp || !_k || _n < 0)
00164       return NULL;
00165 
00166    _lref = (int*)pkg_malloc(_n*sizeof(int));
00167    if(!_lref)
00168       return NULL;
00169 
00170    for(i=0; i < _n; i++)
00171    {
00172       for(j=0; j<_dtp->nrcols; j++)
00173       {
00174          if(_k[i]->len==_dtp->colv[j]->name.len
00175             && !strncasecmp(_k[i]->s, _dtp->colv[j]->name.s,
00176                   _dtp->colv[j]->name.len))
00177          {
00178             _lref[i] = j;
00179             break;
00180          }
00181       }
00182       if(j>=_dtp->nrcols)
00183       {
00184          LM_ERR("column <%.*s> not found\n", _k[i]->len, _k[i]->s);
00185          pkg_free(_lref);
00186          return NULL;
00187       }
00188    }
00189    return _lref;
00190 }  
00191 
00192 
00193 int dbt_row_match(dbt_table_p _dtp, dbt_row_p _drp, int* _lkey,
00194              db_op_t* _op, db_val_t* _v, int _n)
00195 {
00196    int i, res;
00197    if(!_dtp || !_drp)
00198       return 0;
00199    if(!_lkey)
00200       return 1;
00201    for(i=0; i<_n; i++)
00202    {
00203       res = dbt_cmp_val(&_drp->fields[_lkey[i]], &_v[i]);
00204       if(!_op || !strcmp(_op[i], OP_EQ))
00205       {
00206          if(res!=0)
00207             return 0;
00208       }else{
00209       if(!strcmp(_op[i], OP_LT))
00210       {
00211          if(res!=-1)
00212             return 0;
00213       }else{
00214       if(!strcmp(_op[i], OP_GT))
00215       {
00216          if(res!=1)
00217             return 0;
00218       }else{
00219       if(!strcmp(_op[i], OP_LEQ))
00220       {
00221          if(res==1)
00222             return 0;
00223       }else{
00224       if(!strcmp(_op[i], OP_GEQ))
00225       {
00226          if(res==-1)
00227             return 0;
00228       }else{
00229          return 0;
00230       }}}}}    
00231    }
00232    return 1;
00233 }
00234 
00235 int dbt_result_extract_fields(dbt_table_p _dtp, dbt_row_p _drp,
00236             int* _lres, dbt_result_p _dres)
00237 {
00238    dbt_row_p _rp=NULL;
00239    int i, n;
00240    
00241    if(!_dtp || !_drp || !_dres || _dres->nrcols<=0)   
00242       return -1;
00243    
00244    _rp = dbt_result_new_row(_dres);
00245    if(!_rp)
00246       return -1;
00247 
00248    for(i=0; i<_dres->nrcols; i++)
00249    {
00250       n = (_lres)?_lres[i]:i;
00251       if(dbt_is_neq_type(_dres->colv[i].type, _dtp->colv[n]->type))
00252       {
00253          LM_DBG("wrong types!\n");
00254          goto clean;
00255       }
00256       _rp->fields[i].nul = _drp->fields[n].nul;
00257       if(_rp->fields[i].nul)
00258       {
00259          memset(&(_rp->fields[i].val), 0, sizeof(_rp->fields[i].val));
00260          continue;
00261       }
00262       
00263       switch(_dres->colv[i].type)
00264       {
00265          case DB_INT:
00266          case DB_DATETIME:
00267          case DB_BITMAP:
00268             _rp->fields[i].type = _dres->colv[i].type;
00269             _rp->fields[i].val.int_val = _drp->fields[n].val.int_val;
00270          break;
00271          case DB_DOUBLE:
00272             _rp->fields[i].type = DB_DOUBLE;
00273             _rp->fields[i].val.double_val=_drp->fields[n].val.double_val;
00274          break;
00275          case DB_STRING:
00276          case DB_STR:
00277          case DB_BLOB:
00278             _rp->fields[i].type = _dres->colv[i].type;
00279             _rp->fields[i].val.str_val.len =
00280                   _drp->fields[n].val.str_val.len;
00281             _rp->fields[i].val.str_val.s =(char*)pkg_malloc(sizeof(char)*
00282                   (_drp->fields[n].val.str_val.len+1));
00283             if(!_rp->fields[i].val.str_val.s)
00284                goto clean;
00285             memcpy(_rp->fields[i].val.str_val.s,
00286                   _drp->fields[n].val.str_val.s,
00287                   _rp->fields[i].val.str_val.len);
00288             _rp->fields[i].val.str_val.s[_rp->fields[i].val.str_val.len]=0;
00289          break;
00290          default:
00291             goto clean;
00292       }
00293    }
00294 
00295    if(_dres->rows)
00296       (_dres->rows)->prev = _rp;
00297    _rp->next = _dres->rows;
00298    _dres->rows = _rp;
00299    _dres->nrrows++;
00300 
00301    return 0;
00302 
00303 clean:
00304    LM_DBG("make clean!\n");
00305    while(i>=0)
00306    {
00307       if((_rp->fields[i].type == DB_STRING
00308                || _rp->fields[i].type == DB_STR
00309                || _rp->fields[i].type == DB_BLOB)
00310             && !_rp->fields[i].nul
00311             && _rp->fields[i].val.str_val.s)
00312          pkg_free(_rp->fields[i].val.str_val.s);
00313             
00314       i--;
00315    }
00316    pkg_free(_rp->fields);
00317    pkg_free(_rp);
00318 
00319    return -1;
00320 }
00321 
00322 int dbt_result_print(dbt_result_p _dres)
00323 {
00324 #if 0
00325    int i;
00326    FILE *fout = stdout;
00327    dbt_row_p rowp = NULL;
00328    char *p;
00329 
00330    if(!_dres || _dres->nrcols<=0)
00331       return -1;
00332 
00333    fprintf(fout, "\nContent of result\n");
00334    
00335    for(i=0; i<_dres->nrcols; i++)
00336    {
00337       switch(_dres->colv[i].type)
00338       {
00339          case DB_INT:
00340             fprintf(fout, "%.*s(int", _dres->colv[i].name.len,
00341                         _dres->colv[i].name.s);
00342             if(_dres->colv[i].flag & DBT_FLAG_NULL)
00343                fprintf(fout, ",null");
00344             fprintf(fout, ") ");
00345          break;
00346          case DB_DOUBLE:
00347             fprintf(fout, "%.*s(double", _dres->colv[i].name.len,
00348                      _dres->colv[i].name.s);
00349             if(_dres->colv[i].flag & DBT_FLAG_NULL)
00350                fprintf(fout, ",null");
00351             fprintf(fout, ") ");
00352          break;
00353          case DB_STR:
00354             fprintf(fout, "%.*s(str", _dres->colv[i].name.len,
00355                   _dres->colv[i].name.s);
00356             if(_dres->colv[i].flag & DBT_FLAG_NULL)
00357                fprintf(fout, ",null");
00358             fprintf(fout, ") ");
00359          break;
00360          default:
00361             return -1;
00362       }
00363    }
00364    fprintf(fout, "\n");
00365    rowp = _dres->rows;
00366    while(rowp)
00367    {
00368       for(i=0; i<_dres->nrcols; i++)
00369       {
00370          switch(_dres->colv[i].type)
00371          {
00372             case DB_INT:
00373                if(rowp->fields[i].nul)
00374                   fprintf(fout, "N ");
00375                else
00376                   fprintf(fout, "%d ",
00377                         rowp->fields[i].val.int_val);
00378             break;
00379             case DB_DOUBLE:
00380                if(rowp->fields[i].nul)
00381                   fprintf(fout, "N ");
00382                else
00383                   fprintf(fout, "%.2f ",
00384                         rowp->fields[i].val.double_val);
00385             break;
00386             case DB_STR:
00387                fprintf(fout, "\"");
00388                if(!rowp->fields[i].nul)
00389                {
00390                   p = rowp->fields[i].val.str_val.s;
00391                   while(p < rowp->fields[i].val.str_val.s
00392                         + rowp->fields[i].val.str_val.len)
00393                   {
00394                      switch(*p)
00395                      {
00396                         case '\n':
00397                            fprintf(fout, "\\n");
00398                         break;
00399                         case '\r':
00400                            fprintf(fout, "\\r");
00401                         break;
00402                         case '\t':
00403                            fprintf(fout, "\\t");
00404                         break;
00405                         case '\\':
00406                            fprintf(fout, "\\\\");
00407                         break;
00408                         case '"':
00409                            fprintf(fout, "\\\"");
00410                         break;
00411                         case '\0':
00412                            fprintf(fout, "\\0");
00413                         break;
00414                         default:
00415                            fprintf(fout, "%c", *p);
00416                      }
00417                      p++;
00418                   }
00419                }
00420                fprintf(fout, "\" ");
00421             break;
00422             default:
00423                return -1;
00424          }
00425       }
00426       fprintf(fout, "\n");
00427       rowp = rowp->next;
00428    }
00429 #endif
00430 
00431    return 0;
00432 }
00433 
00434 int dbt_cmp_val(dbt_val_p _vp, db_val_t* _v)
00435 {
00436    int _l, _n;
00437    if(!_vp && !_v)
00438       return 0;
00439    if(!_v)
00440       return 1;
00441    if(!_vp)
00442       return -1;
00443    if(_vp->nul && _v->nul)
00444       return 0;
00445    if(_v->nul)
00446       return 1;
00447    if(_vp->nul)
00448       return -1;
00449    
00450    switch(VAL_TYPE(_v))
00451    {
00452       case DB_INT:
00453          return (_vp->val.int_val<_v->val.int_val)?-1:
00454                (_vp->val.int_val>_v->val.int_val)?1:0;
00455 
00456       case DB_BIGINT:
00457          LM_ERR("BIGINT not supported");
00458          return -1;
00459 
00460       case DB_DOUBLE:
00461          return (_vp->val.double_val<_v->val.double_val)?-1:
00462                (_vp->val.double_val>_v->val.double_val)?1:0;
00463       case DB_DATETIME:
00464          return (_vp->val.int_val<_v->val.time_val)?-1:
00465                (_vp->val.int_val>_v->val.time_val)?1:0;
00466       case DB_STRING:
00467          _l = strlen(_v->val.string_val);
00468          _l = (_l>_vp->val.str_val.len)?_vp->val.str_val.len:_l;
00469          _n = strncasecmp(_vp->val.str_val.s, _v->val.string_val, _l);
00470          if(_n)
00471             return SIGN(_n);
00472          if(_vp->val.str_val.len == strlen(_v->val.string_val))
00473             return 0;
00474          if(_l==_vp->val.str_val.len)
00475             return -1;
00476          return 1;
00477       case DB_STR:
00478          _l = _v->val.str_val.len;
00479          _l = (_l>_vp->val.str_val.len)?_vp->val.str_val.len:_l;
00480          _n = strncasecmp(_vp->val.str_val.s, _v->val.str_val.s, _l);
00481          if(_n)
00482             return SIGN(_n);
00483          if(_vp->val.str_val.len == _v->val.str_val.len)
00484             return 0;
00485          if(_l==_vp->val.str_val.len)
00486             return -1;
00487          return 1;
00488       case DB_BLOB:
00489          _l = _v->val.blob_val.len;
00490          _l = (_l>_vp->val.str_val.len)?_vp->val.str_val.len:_l;
00491          _n = strncasecmp(_vp->val.str_val.s, _v->val.blob_val.s, _l);
00492          if(_n)
00493             return SIGN(_n);
00494          if(_vp->val.str_val.len == _v->val.blob_val.len)
00495             return 0;
00496          if(_l==_vp->val.str_val.len)
00497             return -1;
00498          return 1;
00499       case DB_BITMAP:
00500          return (_vp->val.int_val<_v->val.bitmap_val)?-1:
00501             (_vp->val.int_val>_v->val.bitmap_val)?1:0;
00502    }
00503    LM_ERR("invalid datatype %d\n", VAL_TYPE(_v));
00504    return -2;
00505 }
00506 
00507 dbt_row_p dbt_result_new_row(dbt_result_p _dres)
00508 {
00509    dbt_row_p _drp = NULL;
00510    if(!_dres || _dres->nrcols<=0)
00511       return NULL;
00512    
00513    _drp = (dbt_row_p)pkg_malloc(sizeof(dbt_row_t));
00514    if(!_drp)
00515       return NULL;
00516    memset(_drp, 0, sizeof(dbt_row_t));
00517    _drp->fields = (dbt_val_p)pkg_malloc(_dres->nrcols*sizeof(dbt_val_t));
00518    if(!_drp->fields)
00519    {
00520       pkg_free(_drp);
00521       return NULL;
00522    }
00523    memset(_drp->fields, 0, _dres->nrcols*sizeof(dbt_val_t));
00524 
00525    _drp->next = _drp->prev = NULL;
00526 
00527    return _drp;
00528 }
00529 
00530 
00531 /* The _o clause to query is not really a db_key_t, it is SQL (str).
00532  * db_mysql and db_postgres simply paste it into SQL, we need to parse it. */
00533 /* Format of _o:  column1 [ASC|DESC], column2 [ASC|DESC], ... */
00534 int dbt_parse_orderbyclause(db_key_t **_o_k, char **_o_op, int *_o_n, db_key_t _o)
00535 {
00536    char *_po, *_ps, *_pe;
00537    char _c = '\0';
00538    char _d[8];
00539    int _n;
00540    int _i;
00541    str *_s;
00542 
00543    /* scan _o, count ',' -> upper bound for no of columns */
00544    _n = 1;
00545    for (_i=0; _i < _o->len; _i++)
00546       if (_o->s[_i] == ',')
00547          _n++;
00548 
00549     /* *_o_k will include the db_key_ts, the strs, a copy of _o and \0 */
00550    *_o_k = pkg_malloc((sizeof(db_key_t)+sizeof(str)) * _n + _o->len + 1);
00551    if (!*_o_k)
00552       return -1;
00553    _s = (str *)((char *)(*_o_k) + sizeof(db_key_t) * _n);
00554    for (_i=0; _i < _n; _i++)
00555        (*_o_k)[_i] = &_s[_i];
00556    _po = (char *)(*_o_k) + (sizeof(db_key_t) + sizeof(str)) * _n;
00557    memcpy(_po, _o->s, _o->len);
00558    *(_po+_o->len) = '\0';
00559 
00560    *_o_op = pkg_malloc(sizeof(db_op_t) * _n);
00561    if (!*_o_op)
00562    {
00563       pkg_free(*_o_k);
00564       return -1;
00565    }
00566 
00567    *_o_n = 0;
00568    _ps = _po;
00569    while (*_o_n < _n)
00570    {
00571       while (*_ps == ' ') _ps++;
00572       if (*_ps == '\0')
00573          break;
00574       strcpy(_d, " \f\n\r\t\v,"); /* isspace() and comma */
00575       if (*_ps == '"' || *_ps == '\'') /* detect quote */
00576       {
00577          _d[0] = *_ps;
00578          _d[1] = '\0';
00579          _ps++;
00580       }
00581       _pe = strpbrk(_ps, _d); /* search quote, space, comma or eos */
00582       if (!_pe && _d[0] == ' ') /* if token is last token in string */
00583          _pe = _po + _o->len; /* point to end of string */
00584       if (! _pe) /* we were looking for quote but found none */
00585          goto parse_error;
00586 
00587       /* _ps points to start of column-name,
00588        * _pe points after the column-name, on quote, space, comma, or '\0' */
00589       _c = *_pe;
00590       *_pe = '\0';
00591       (*_o_k)[*_o_n]->s = _ps;
00592       (*_o_k)[*_o_n]->len = _pe - _ps;
00593       (*_o_op)[*_o_n] = '<'; /* default */
00594       (*_o_n)++;
00595 
00596       if (_c == '\0')
00597          break;
00598 
00599       /* go beyond current token */
00600       _ps = _pe + 1;
00601       if (_c == ',')
00602          continue;
00603       while (*_ps == ' ') _ps++;
00604       if (*_ps == ',')
00605       {
00606          _ps++;
00607          continue;
00608       }
00609       if (*_ps == '\0')
00610          break;
00611 
00612       /* there is ASC OR DESC qualifier */
00613       if (strncasecmp(_ps, "DESC", 4) == 0)
00614       {
00615          (*_o_op)[*_o_n-1] = '>';
00616          _ps += 4;
00617       } else if (strncasecmp(_ps, "ASC", 3) == 0)
00618       {
00619          _ps += 3;
00620       } else goto parse_error;
00621 
00622       /* point behind qualifier */
00623       while (*_ps == ' ') _ps++;
00624       if (*_ps == ',')
00625       {
00626          _ps++;
00627          continue;
00628       }
00629       if (*_ps == '\0')
00630          break;
00631       goto parse_error;
00632    }
00633 
00634    if (*_ps != '\0' && _c != '\0')   /* that means more elements than _tbc->nrcols */
00635       goto parse_error;
00636 
00637    if (*_o_n == 0) /* there weren't actually any columns */
00638    {
00639       pkg_free(*_o_k);
00640       pkg_free(*_o_op);
00641       *_o_op = NULL;
00642       *_o_k = NULL;
00643       return 0; /* return success anyway */
00644    }
00645 
00646    return 0;
00647 
00648 parse_error:
00649    pkg_free(*_o_k);
00650    pkg_free(*_o_op);
00651    *_o_op = NULL;
00652    *_o_k = NULL;
00653    *_o_n = 0;
00654    return -1;
00655 }
00656 
00657 
00658 /* lres/_nc is the selected columns, _o_l/_o_n is the order-by columns:
00659  *   All order-by columns need to be extracted along with the selected columns,
00660  *   so any column in _o_l and not lres needs to be added to lres. _o_nc keeps
00661  *   track of the number of columns added to lres. */
00662 int dbt_mangle_columnselection(int **_lres, int *_nc, int *_o_nc, int *_o_l, int _o_n)
00663 {
00664    int _i, _j;
00665 
00666    *_o_nc = 0;
00667 
00668    if (! *_lres)
00669       return 0; /* all columns selected, no need to worry */
00670 
00671    /* count how many columns are affected */
00672    for (_i=0; _i < _o_n; _i++) /* loop over order-by columns */
00673    {
00674       for (_j=0; _j < *_nc && (*_lres)[_j] != _o_l[_i]; _j++);
00675       if (_j == *_nc) /* order-by column not found in select columns */
00676          (*_o_nc)++;
00677    }
00678 
00679    if (*_o_nc == 0)
00680       return 0; /* all order-by columns also selected, we're fine */
00681 
00682    /* make _lres bigger */
00683    *_lres = pkg_realloc(*_lres, sizeof(int) * (*_nc + *_o_nc));
00684    if (! *_lres)
00685       return -1;
00686 
00687    /* add oder-by columns to select columns */
00688    for (_i=0; _i < _o_n; _i++) /* loop over order-by columns */
00689    {
00690       for (_j=0; _j < *_nc && (*_lres)[_j] != _o_l[_i]; _j++);
00691       if (_j == *_nc) /* order-by column not found in select columns */
00692       {
00693          (*_lres)[*_nc] = _o_l[_i];
00694          (*_nc)++;
00695       }
00696    }
00697 
00698    /* _lres, _nc modified, _o_nc returned */
00699    return 0;
00700 }
00701 
00702 /* globals for qsort */
00703 dbt_result_p dbt_sort_dres;
00704 int *dbt_sort_o_l;
00705 char *dbt_sort_o_op;
00706 int dbt_sort_o_n;
00707 jmp_buf dbt_sort_jmpenv;
00708 
00709 
00710 /* comparison function for qsort */
00711 int dbt_qsort_compar(const void *_a, const void *_b)
00712 {
00713    int _i, _j, _r;
00714 
00715    for (_i=0; _i<dbt_sort_o_n; _i++)
00716    {
00717       _j = dbt_sort_o_l[_i];
00718       _r = dbt_cmp_val(&(*(dbt_row_p *)_a)->fields[_j], &(*(dbt_row_p *)_b)->fields[_j]);
00719       if (_r == 0)
00720          continue; /* no result yet, compare next column */
00721       if (_r == +1 || _r == -1)
00722          return (dbt_sort_o_op[_i] == '<') ? _r : -_r; /* ASC OR DESC */
00723       /* error */
00724       longjmp(dbt_sort_jmpenv, _r);
00725    }
00726 
00727    /* no result after comparing all columns, same */
00728    return 0;
00729 }
00730 
00731 
00732 int dbt_sort_result(dbt_result_p _dres, int *_o_l, char *_o_op, int _o_n, int *_lres, int _nc)
00733 {
00734    int _i, _j;
00735    dbt_row_p *_a;
00736    dbt_row_p _el;
00737 
00738    /* first we need to rewrite _o_l in terms of _lres */
00739    if (_lres)
00740    {
00741       for (_i=0; _i < _o_n; _i++) /* loop over order-by columns */
00742       {
00743          /* depends on correctness of dbt_mangle_columnselection */
00744          for (_j=0; _lres[_j] != _o_l[_i]; _j++ /*, assert(_j < _nc)*/);
00745          _o_l[_i] = _j;
00746       }
00747    }
00748 
00749    /* rewrite linked list to array */
00750    _a = pkg_malloc(sizeof(dbt_row_t) * _dres->nrrows);
00751    if (!_a)
00752       return -1;
00753    for (_el=_dres->rows, _i=0; _el != NULL; _el=_el->next, _i++)
00754       _a[_i] = _el;
00755 
00756    /* set globals */
00757    dbt_sort_dres = _dres;
00758    dbt_sort_o_l = _o_l;
00759    dbt_sort_o_op = _o_op;
00760    dbt_sort_o_n = _o_n;
00761    _i = setjmp(dbt_sort_jmpenv);  /* exception handling */
00762    if (_i)
00763    {
00764       /* error occured during qsort */
00765       LM_ERR("qsort aborted\n");
00766       pkg_free(_a);
00767       return _i;
00768    }
00769 
00770    qsort(_a, _dres->nrrows, sizeof(dbt_row_p), &dbt_qsort_compar);
00771 
00772    /* restore linked list */
00773    for (_i=0; _i < _dres->nrrows; _i++)
00774    {
00775       _a[_i]->prev = (_i > 0) ? _a[_i-1] : NULL;
00776       _a[_i]->next = (_i+1 < _dres->nrrows) ? _a[_i+1] : NULL;
00777    }
00778    _dres->rows = _a[0];
00779 
00780    pkg_free(_a);
00781    return 0;
00782 }
00783 
00784 
00785 /* Remove the columns that were added to the result to facilitate sorting.
00786  *   The additional columns constitute the end of the queue. Instead of
00787  *   actually removing them with realloc, they are simply kept around, but
00788  *   hidden. For string-columns, the allocated string is however freed. */
00789 void dbt_project_result(dbt_result_p _dres, int _o_nc)
00790 {
00791    int _i;
00792    dbt_row_p _drp;
00793 
00794    if (! _o_nc)
00795       return;
00796 
00797    /* check whether there are string columns, free them */
00798    for (_i = _dres->nrcols - _o_nc; _i < _dres->nrcols; _i++)
00799    {
00800       if (_dres->colv[_i].type == DB_STRING ||
00801             _dres->colv[_i].type == DB_STR ||
00802             _dres->colv[_i].type == DB_BLOB)
00803       {
00804          for (_drp=_dres->rows; _drp != NULL; _drp = _drp->next)
00805          {
00806             if (! _drp->fields[_i].nul &&
00807                (_drp->fields[_i].type == DB_STRING ||
00808                _drp->fields[_i].type == DB_STR ||
00809                _drp->fields[_i].type == DB_BLOB ))
00810             {
00811                pkg_free(_drp->fields[_i].val.str_val.s);
00812                _drp->fields[_i].val.str_val.s = NULL;
00813                _drp->fields[_i].val.str_val.len = 0;
00814             }
00815          }
00816       }
00817 
00818       /* free the string containing the column name */
00819       pkg_free(_dres->colv[_i].name.s);
00820       _dres->colv[_i].name.s = NULL;
00821       _dres->colv[_i].name.len = 0;
00822    }
00823 
00824    /* pretend the columns are gone, in dbt_free_query free will do the right thing */
00825    _dres->nrcols -= _o_nc;
00826 }
00827 

Generated on Tue May 22 14:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6