db_postgres/km_res.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2003 August.Net Services, LLC
00005  * Copyright (C) 2006 Norman Brandinger
00006  * Copyright (C) 2008 1&1 Internet AG
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  * 2003-04-06 initial code written (Greg Fausak/Andy Fullford)
00027  *
00028  * 2006-07-26 added BPCHAROID as a valid type for DB1_STRING conversions
00029  *            this removes the "unknown type 1042" log messages (norm)
00030  *
00031  * 2006-10-27 Added fetch support (norm)
00032  *            Removed dependency on aug_* memory routines (norm)
00033  *            Added connection pooling support (norm)
00034  *            Standardized API routines to pg_* names (norm)
00035  */
00036 
00043 #include <stdlib.h>
00044 #include <string.h>
00045 #include "../../lib/srdb1/db_id.h"
00046 #include "../../lib/srdb1/db_res.h"
00047 #include "../../lib/srdb1/db_con.h"
00048 #include "../../dprint.h"
00049 #include "../../mem/mem.h"
00050 #include "km_res.h"
00051 #include "km_val.h"
00052 #include "km_pg_con.h"
00053 #include "km_pg_type.h"
00054 
00055 
00062 int db_postgres_convert_result(const db1_con_t* _h, db1_res_t* _r)
00063 {
00064         if (!_h || !_r)  {
00065                 LM_ERR("invalid parameter value\n");
00066                 return -1;
00067         }
00068 
00069         if (db_postgres_get_columns(_h, _r) < 0) {
00070                 LM_ERR("failed to get column names\n");
00071                 return -2;
00072         }
00073 
00074         if (db_postgres_convert_rows(_h, _r) < 0) {
00075                 LM_ERR("failed to convert rows\n");
00076                 db_free_columns(_r);
00077                 return -3;
00078         }
00079         return 0;
00080 }
00081 
00082 
00089 int db_postgres_get_columns(const db1_con_t* _h, db1_res_t* _r)
00090 {
00091         int col, datatype;
00092 
00093         if (!_h || !_r)  {
00094                 LM_ERR("invalid parameter value\n");
00095                 return -1;
00096         }
00097 
00098         /* Get the number of rows (tuples) in the query result. */
00099         RES_ROW_N(_r) = PQntuples(CON_RESULT(_h));
00100 
00101         /* Get the number of columns (fields) in each row of the query result. */
00102         RES_COL_N(_r) = PQnfields(CON_RESULT(_h));
00103 
00104         if (!RES_COL_N(_r)) {
00105                 LM_DBG("no columns returned from the query\n");
00106                 return -2;
00107         } else {
00108                 LM_DBG("%d columns returned from the query\n", RES_COL_N(_r));
00109         }
00110 
00111         if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) {
00112                 LM_ERR("could not allocate columns\n");
00113                 return -3;
00114         }
00115 
00116         /* For each column both the name and the OID number of the data type are saved. */
00117         for(col = 0; col < RES_COL_N(_r); col++) {
00118 
00119                 RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str));
00120                 if (! RES_NAMES(_r)[col]) {
00121                         LM_ERR("no private memory left\n");
00122                         db_free_columns(_r);
00123                         return -4;
00124                 }
00125                 LM_DBG("allocate %d bytes for RES_NAMES[%d] at %p\n", (unsigned int) sizeof(str), col,
00126                                 RES_NAMES(_r)[col]);
00127 
00128                 /* The pointer that is here returned is part of the result structure. */
00129                 RES_NAMES(_r)[col]->s = PQfname(CON_RESULT(_h), col);
00130                 RES_NAMES(_r)[col]->len = strlen(PQfname(CON_RESULT(_h), col));
00131 
00132                 LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col,
00133                                 RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s);
00134 
00135                 /* get the datatype of the column */
00136                 switch(datatype = PQftype(CON_RESULT(_h),col))
00137                 {
00138                         case INT2OID:
00139                         case INT4OID:
00140                                 LM_DBG("use DB1_INT result type\n");
00141                                 RES_TYPES(_r)[col] = DB1_INT;
00142                         break;
00143 
00144                         case INT8OID:
00145                                 LM_DBG("use DB1_BIGINT result type\n");
00146                                 RES_TYPES(_r)[col] = DB1_BIGINT;
00147 
00148                         case FLOAT4OID:
00149                         case FLOAT8OID:
00150                         case NUMERICOID:
00151                                 LM_DBG("use DB1_DOUBLE result type\n");
00152                                 RES_TYPES(_r)[col] = DB1_DOUBLE;
00153                         break;
00154 
00155                         case DATEOID:
00156                         case TIMESTAMPOID:
00157                         case TIMESTAMPTZOID:
00158                                 LM_DBG("use DB1_DATETIME result type\n");
00159                                 RES_TYPES(_r)[col] = DB1_DATETIME;
00160                         break;
00161 
00162                         case BOOLOID:
00163                         case CHAROID:
00164                         case VARCHAROID:
00165                         case BPCHAROID:
00166                                 LM_DBG("use DB1_STRING result type\n");
00167                                 RES_TYPES(_r)[col] = DB1_STRING;
00168                         break;
00169 
00170                         case TEXTOID:
00171                         case BYTEAOID:
00172                                 LM_DBG("use DB1_BLOB result type\n");
00173                                 RES_TYPES(_r)[col] = DB1_BLOB;
00174                         break;
00175 
00176                         case BITOID:
00177                         case VARBITOID:
00178                                 LM_DBG("use DB1_BITMAP result type\n");
00179                                 RES_TYPES(_r)[col] = DB1_BITMAP;
00180                         break;
00181                                 
00182                         default:
00183                                 LM_WARN("unhandled data type column (%.*s) type id (%d), "
00184                                                 "use DB1_STRING as default\n", RES_NAMES(_r)[col]->len,
00185                                                 RES_NAMES(_r)[col]->s, datatype);
00186                                 RES_TYPES(_r)[col] = DB1_STRING;
00187                         break;
00188                 }
00189         }
00190         return 0;
00191 }
00192 
00193 
00200 int db_postgres_convert_rows(const db1_con_t* _h, db1_res_t* _r)
00201 {
00202         char **row_buf, *s;
00203         int row, col, len;
00204 
00205         if (!_h || !_r)  {
00206                 LM_ERR("invalid parameter\n");
00207                 return -1;
00208         }
00209 
00210         if (!RES_ROW_N(_r)) {
00211                 LM_DBG("no rows returned from the query\n");
00212                 RES_ROWS(_r) = 0;
00213                 return 0;
00214         }
00215         /*Allocate an array of pointers per column to holds the string representation */
00216         len = sizeof(char *) * RES_COL_N(_r);
00217         row_buf = (char**)pkg_malloc(len);
00218         if (!row_buf) {
00219                 LM_ERR("no private memory left\n");
00220                 return -1;
00221         }
00222         LM_DBG("allocate for %d columns %d bytes in row buffer at %p\n", RES_COL_N(_r), len, row_buf);
00223 
00224         if (db_allocate_rows(_r) < 0) {
00225                 LM_ERR("could not allocate rows\n");
00226                 LM_DBG("freeing row buffer at %p\n", row_buf);
00227                 pkg_free(row_buf);
00228                 return -2;
00229         }
00230 
00231         for(row = RES_LAST_ROW(_r); row < (RES_LAST_ROW(_r) + RES_ROW_N(_r)); row++) {
00232                 /* reset row buf content */
00233                 memset(row_buf, 0, len);
00234                 for(col = 0; col < RES_COL_N(_r); col++) {
00235                         /*
00236                          * The row data pointer returned by PQgetvalue points to storage
00237                          * that is part of the PGresult structure. One should not modify
00238                          * the data it points to, and one must explicitly copy the data
00239                          * into other storage if it is to be used past the lifetime of
00240                          * the PGresult structure itself.
00241                          */
00242                         s = PQgetvalue(CON_RESULT(_h), row, col);
00243                         LM_DBG("PQgetvalue(%p,%d,%d)=[%s]\n", _h, row, col, s);
00244                         /*
00245                          * A empty string can be a NULL value, or just an empty string.
00246                          * This differs from the mysql behaviour, that further processing
00247                          * steps expect. So we need to simulate this here unfortunally.
00248                          */
00249                         if (PQgetisnull(CON_RESULT(_h), row, col) == 0) {
00250                                 row_buf[col] = s;
00251                                 LM_DBG("[%d][%d] Column[%.*s]=[%s]\n",
00252                                         row, col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, row_buf[col]);
00253                         }
00254                 }
00255 
00256                 /* ASSERT: row_buf contains an entire row in strings */
00257                 if(db_postgres_convert_row(_h, _r, &(RES_ROWS(_r)[row - RES_LAST_ROW(_r)]), row_buf)<0){
00258                         LM_ERR("failed to convert row #%d\n",  row);
00259                         RES_ROW_N(_r) = row - RES_LAST_ROW(_r);
00260                         LM_DBG("freeing row buffer at %p\n", row_buf);
00261                         pkg_free(row_buf);
00262                         db_free_rows(_r);
00263                         return -4;
00264                 }
00265         }
00266 
00267         LM_DBG("freeing row buffer at %p\n", row_buf);
00268         pkg_free(row_buf);
00269         row_buf = NULL;
00270         return 0;
00271 }
00272 
00273 
00282 int db_postgres_convert_row(const db1_con_t* _h, db1_res_t* _r, db_row_t* _row,
00283                 char **row_buf)
00284 {
00285         int col, col_len;
00286 
00287         if (!_h || !_r || !_row)  {
00288                 LM_ERR("invalid parameter value\n");
00289                 return -1;
00290         }
00291 
00292         if (db_allocate_row(_r, _row) != 0) {
00293                 LM_ERR("could not allocate row\n");
00294                 return -2;
00295         }
00296 
00297         /* For each column in the row */
00298         for(col = 0; col < ROW_N(_row); col++) {
00299                 /* because it can contain NULL */
00300                 if (!row_buf[col]) {
00301                         col_len = 0;
00302                 } else {
00303                         col_len = strlen(row_buf[col]);
00304                 }
00305                 /* Convert the string representation into the value representation */
00306                 if (db_postgres_str2val(RES_TYPES(_r)[col], &(ROW_VALUES(_row)[col]),
00307                 row_buf[col], col_len) < 0) {
00308                         LM_ERR("failed to convert value\n");
00309                         LM_DBG("free row at %p\n", _row);
00310                         db_free_row(_row);
00311                         return -3;
00312                 }
00313         }
00314         return 0;
00315 }