db_unixodbc/res.c

Go to the documentation of this file.
00001 /* 
00002  * $Id: res.c 5430 2009-01-07 14:45:25Z henningw $
00003  *
00004  * UNIXODBC module result related functions
00005  *
00006  * Copyright (C) 2005-2006 Marco Lorrai
00007  * Copyright (C) 2007-2008 1&1 Internet AG
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  *
00026  * History:
00027  * --------
00028  *  2005-12-01  initial commit (chgen)
00029  *  2006-04-04  fixed memory leak in convert_rows (sgupta)
00030  *  2006-05-05  removed static allocation of 1k per column data (sgupta)
00031  */
00032 
00033 #include "../../mem/mem.h"
00034 #include "../../dprint.h"
00035 #include "row.h"
00036 #include "../../db/db_res.h"
00037 #include "con.h"
00038 #include "res.h"
00039 #include "list.h"
00040 #include <stdlib.h>
00041 #include <string.h>
00042 
00043 /*
00044  * Get and convert columns from a result
00045  */
00046 int db_unixodbc_get_columns(const db_con_t* _h, db_res_t* _r)
00047 {
00048    int col;
00049    SQLSMALLINT cols; /* because gcc don't like RES_COL_N */
00050 
00051    if ((!_h) || (!_r)) {
00052       LM_ERR("invalid parameter\n");
00053       return -1;
00054    }
00055 
00056    /* Save number of columns in the result structure */
00057    SQLNumResultCols(CON_RESULT(_h), &cols);
00058    RES_COL_N(_r) = cols;
00059    if (!RES_COL_N(_r)) {
00060       LM_ERR("no columns returned from the query\n");
00061       return -2;
00062    } else {
00063       LM_DBG("%d columns returned from the query\n", RES_COL_N(_r));
00064    }
00065 
00066    if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) {
00067       LM_ERR("could not allocate columns\n");
00068       return -3;
00069    }
00070 
00071    for(col = 0; col < RES_COL_N(_r); col++)
00072    {
00073       RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str));
00074       if (! RES_NAMES(_r)[col]) {
00075          LM_ERR("no private memory left\n");
00076          db_free_columns(_r);
00077          return -4;
00078       }
00079       LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n",
00080          (unsigned long)sizeof(str),col,  RES_NAMES(_r)[col]);
00081 
00082       char columnname[80];
00083       SQLRETURN ret;
00084       SQLSMALLINT namelength, datatype, decimaldigits, nullable;
00085       SQLULEN columnsize;
00086 
00087       ret = SQLDescribeCol(CON_RESULT(_h), col + 1, (SQLCHAR *)columnname, 80,
00088          &namelength, &datatype, &columnsize, &decimaldigits, &nullable);
00089       if(!SQL_SUCCEEDED(ret)) {
00090          LM_ERR("SQLDescribeCol failed: %d\n", ret);
00091          db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h), SQL_HANDLE_STMT,
00092             NULL);
00093          // FIXME should we fail here completly?
00094       }
00095       /* The pointer that is here returned is part of the result structure. */
00096       RES_NAMES(_r)[col]->s = columnname;
00097       RES_NAMES(_r)[col]->len = namelength;
00098 
00099       LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col,
00100             RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s);
00101 
00102       switch(datatype)
00103       {
00104          case SQL_SMALLINT:
00105          case SQL_INTEGER:
00106          case SQL_TINYINT:
00107          case SQL_DECIMAL:
00108          case SQL_NUMERIC:
00109             LM_DBG("use DB_INT result type\n");
00110             RES_TYPES(_r)[col] = DB_INT;
00111             break;
00112 
00113          case SQL_BIGINT:
00114             LM_DBG("use DB_BIGINT result type\n");
00115             RES_TYPES(_r)[col] = DB_BIGINT;
00116             break;
00117 
00118          case SQL_REAL:
00119          case SQL_FLOAT:
00120          case SQL_DOUBLE:
00121             LM_DBG("use DB_DOUBLE result type\n");
00122             RES_TYPES(_r)[col] = DB_DOUBLE;
00123             break;
00124 
00125          case SQL_TYPE_TIMESTAMP:
00126          case SQL_DATE:
00127          case SQL_TIME:
00128          case SQL_TIMESTAMP:
00129          case SQL_TYPE_DATE:
00130          case SQL_TYPE_TIME:
00131             LM_DBG("use DB_DATETIME result type\n");
00132             RES_TYPES(_r)[col] = DB_DATETIME;
00133             break;
00134 
00135          case SQL_CHAR:
00136          case SQL_VARCHAR:
00137          case SQL_WCHAR:
00138          case SQL_WVARCHAR:
00139             LM_DBG("use DB_STRING result type\n");
00140             RES_TYPES(_r)[col] = DB_STRING;
00141             break;
00142 
00143          case SQL_BINARY:
00144          case SQL_VARBINARY:
00145          case SQL_LONGVARBINARY:
00146          case SQL_BIT:
00147          case SQL_LONGVARCHAR:
00148          case SQL_WLONGVARCHAR:
00149             LM_DBG("use DB_BLOB result type\n");
00150             RES_TYPES(_r)[col] = DB_BLOB;
00151             break;
00152 
00153          default:
00154             LM_WARN("unhandled data type column (%.*s) type id (%d), "
00155                   "use DB_STRING as default\n", RES_NAMES(_r)[col]->len,
00156                   RES_NAMES(_r)[col]->s, datatype);
00157             RES_TYPES(_r)[col] = DB_STRING;
00158             break;
00159       }
00160    }
00161    return 0;
00162 }
00163 
00164 /*
00165  * Convert rows from UNIXODBC to db API representation
00166  */
00167 static inline int db_unixodbc_convert_rows(const db_con_t* _h, db_res_t* _r)
00168 {
00169    int i = 0, ret = 0;
00170    SQLSMALLINT columns;
00171    list* rows = NULL;
00172    list* rowstart = NULL;
00173    strn* temp_row = NULL;
00174 
00175    if((!_h) || (!_r)) {
00176       LM_ERR("invalid parameter\n");
00177       return -1;
00178    }
00179 
00180    SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns);
00181    temp_row = (strn*)pkg_malloc( columns*sizeof(strn) );
00182    if(!temp_row) {
00183       LM_ERR("no private memory left\n");
00184       return -1;
00185    }
00186 
00187    while(SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h))))
00188    {
00189       for(i=0; i < columns; i++)
00190       {
00191          SQLLEN indicator;
00192          ret = SQLGetData(CON_RESULT(_h), i+1, SQL_C_CHAR,
00193             temp_row[i].s, STRN_LEN, &indicator);
00194          if (SQL_SUCCEEDED(ret)) {
00195             if (indicator == SQL_NULL_DATA)
00196                strcpy(temp_row[i].s, "NULL");
00197          }
00198          else {
00199             LM_ERR("SQLGetData failed\n");
00200          }
00201       }
00202 
00203       if (db_unixodbc_list_insert(&rowstart, &rows, columns, temp_row) < 0) {
00204          LM_ERR("insert failed\n");
00205          pkg_free(temp_row);
00206          temp_row= NULL;
00207          return -5;
00208       }
00209       RES_ROW_N(_r)++;
00210    }
00211    /* free temporary row data */
00212    pkg_free(temp_row);
00213    CON_ROW(_h) = NULL;
00214 
00215    if (!RES_ROW_N(_r)) {
00216       RES_ROWS(_r) = 0;
00217       return 0;
00218    }
00219 
00220    if (db_allocate_rows(_r) != 0) {
00221       LM_ERR("could not allocate rows");
00222       db_unixodbc_list_destroy(rowstart);
00223       return -2;
00224    }
00225 
00226    i = 0;
00227    rows = rowstart;
00228    while(rows)
00229    {
00230       CON_ROW(_h) = rows->data;
00231       if (!CON_ROW(_h))
00232       {
00233          LM_ERR("string null\n");
00234          RES_ROW_N(_r) = i;
00235          db_free_rows(_r);
00236          db_unixodbc_list_destroy(rowstart);
00237          return -3;
00238       }
00239       if (db_unixodbc_convert_row(_h, _r, &(RES_ROWS(_r)[i]), rows->lengths) < 0) {
00240          LM_ERR("converting row failed #%d\n", i);
00241          RES_ROW_N(_r) = i;
00242          db_free_rows(_r);
00243          db_unixodbc_list_destroy(rowstart);
00244          return -4;
00245       }
00246       i++;
00247       rows = rows->next;
00248    }
00249    db_unixodbc_list_destroy(rowstart);
00250    return 0;
00251 }
00252 
00253 
00254 /*
00255  * Fill the structure with data from database
00256  */
00257 int db_unixodbc_convert_result(const db_con_t* _h, db_res_t* _r)
00258 {
00259    if (!_h || !_r) {
00260       LM_ERR("invalid parameter\n");
00261       return -1;
00262    }
00263 
00264    if (db_unixodbc_get_columns(_h, _r) < 0) {
00265       LM_ERR("getting column names failed\n");
00266       return -2;
00267    }
00268 
00269    if (db_unixodbc_convert_rows(_h, _r) < 0) {
00270       LM_ERR("converting rows failed\n");
00271       db_free_columns(_r);
00272       return -3;
00273    }
00274    return 0;
00275 }

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