modules: several small doxygen bug fixes
[sip-router] / modules / db_mysql / km_res.c
1 /* 
2  * $Id$ 
3  *
4  * MySQL module result related functions
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  * Copyright (C) 2007-2008 1&1 Internet AG
8  *
9  * This file is part of Kamailio, a free SIP server.
10  *
11  * Kamailio is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version
15  *
16  * Kamailio is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License 
22  * along with this program; if not, write to the Free Software 
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26
27 /*! \file
28  *  \brief DB_MYSQL :: Result related functions
29  *  \ingroup db_mysql
30  *  Module: \ref db_mysql
31  */
32
33
34 #include <string.h>
35 #include <mysql/mysql.h>
36 #include "../../lib/srdb1/db_res.h"
37 #include "../../mem/mem.h"
38 #include "../../dprint.h"
39 #include "km_row.h"
40 #include "km_my_con.h"
41 #include "km_res.h"
42
43
44 /*!
45  * \brief Get and convert columns from a result
46  *
47  * Get and convert columns from a result, fills the result structure
48  * with data from the database.
49  * \param _h database connection
50  * \param _r database result set
51  * \return 0 on success, negative on failure
52  */
53 int db_mysql_get_columns(const db1_con_t* _h, db1_res_t* _r)
54 {
55         int col;
56         MYSQL_FIELD* fields;
57
58         if ((!_h) || (!_r)) {
59                 LM_ERR("invalid parameter\n");
60                 return -1;
61         }
62
63         RES_COL_N(_r) = mysql_field_count(CON_CONNECTION(_h));
64         if (!RES_COL_N(_r)) {
65                 LM_ERR("no columns returned from the query\n");
66                 return -2;
67         } else {
68                 LM_DBG("%d columns returned from the query\n", RES_COL_N(_r));
69         }
70         
71         if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) {
72                 LM_ERR("could not allocate columns\n");
73                 return -3;
74         }
75
76         fields = mysql_fetch_fields(CON_RESULT(_h));
77         for(col = 0; col < RES_COL_N(_r); col++) {
78                 RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str));
79                 if (! RES_NAMES(_r)[col]) {
80                         LM_ERR("no private memory left\n");
81                         db_free_columns(_r);
82                         return -4;
83                 }
84                 LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n",
85                                 (unsigned long)sizeof(str), col, RES_NAMES(_r)[col]);
86
87                 /* The pointer that is here returned is part of the result structure. */
88                 RES_NAMES(_r)[col]->s = fields[col].name;
89                 RES_NAMES(_r)[col]->len = strlen(fields[col].name);
90
91                 LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col,
92                                 RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s);
93
94                 switch(fields[col].type) {
95                         case MYSQL_TYPE_TINY:
96                         case MYSQL_TYPE_SHORT:
97                         case MYSQL_TYPE_LONG:
98                         case MYSQL_TYPE_INT24:
99                         case MYSQL_TYPE_TIMESTAMP:
100                                 LM_DBG("use DB1_INT result type\n");
101                                 RES_TYPES(_r)[col] = DB1_INT;
102                                 break;
103
104                         case MYSQL_TYPE_LONGLONG:
105                                 LM_DBG("use DB1_BIGINT result type\n");
106                                 RES_TYPES(_r)[col] = DB1_BIGINT;
107                                 break;
108
109                         case MYSQL_TYPE_FLOAT:
110                         case MYSQL_TYPE_DOUBLE:
111                                 LM_DBG("use DB1_DOUBLE result type\n");
112                                 RES_TYPES(_r)[col] = DB1_DOUBLE;
113                                 break;
114
115                         case MYSQL_TYPE_DATETIME:
116                                 LM_DBG("use DB1_DATETIME result type\n");
117                                 RES_TYPES(_r)[col] = DB1_DATETIME;
118                                 break;
119
120                         case MYSQL_TYPE_BLOB:
121                                 LM_DBG("use DB1_BLOB result type\n");
122                                 RES_TYPES(_r)[col] = DB1_BLOB;
123                                 break;
124
125                         case FIELD_TYPE_SET:
126                                 LM_DBG("use DB1_BITMAP result type\n");
127                                 RES_TYPES(_r)[col] = DB1_BITMAP;
128                                 break;
129
130                         case MYSQL_TYPE_DECIMAL:
131                         #if MYSQL_VERSION_ID > 49999
132                         case MYSQL_TYPE_NEWDECIMAL:
133                         #endif
134                         case MYSQL_TYPE_STRING:
135                         case MYSQL_TYPE_VAR_STRING:
136                                 LM_DBG("use DB1_STRING result type\n");
137                                 RES_TYPES(_r)[col] = DB1_STRING;
138                                 break;
139
140                         default:
141                                 LM_WARN("unhandled data type column (%.*s) type id (%d), "
142                                                 "use DB1_STRING as default\n", RES_NAMES(_r)[col]->len,
143                                                 RES_NAMES(_r)[col]->s, fields[col].type);
144                                 RES_TYPES(_r)[col] = DB1_STRING;
145                                 break;
146                 }
147         }
148         return 0;
149 }
150
151
152 /*!
153  * \brief Convert rows from mysql to db API representation
154  * \param _h database connection
155  * \param _r database result set
156  * \return 0 on success, negative on failure
157  */
158 static inline int db_mysql_convert_rows(const db1_con_t* _h, db1_res_t* _r)
159 {
160         int row;
161
162         if ((!_h) || (!_r)) {
163                 LM_ERR("invalid parameter\n");
164                 return -1;
165         }
166
167         RES_ROW_N(_r) = mysql_num_rows(CON_RESULT(_h));
168         if (!RES_ROW_N(_r)) {
169                 LM_DBG("no rows returned from the query\n");
170                 RES_ROWS(_r) = 0;
171                 return 0;
172         }
173
174         if (db_allocate_rows(_r) < 0) {
175                 LM_ERR("could not allocate rows");
176                 return -2;
177         }
178
179         for(row = 0; row < RES_ROW_N(_r); row++) {
180                 CON_ROW(_h) = mysql_fetch_row(CON_RESULT(_h));
181                 if (!CON_ROW(_h)) {
182                         LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h)));
183                         RES_ROW_N(_r) = row;
184                         db_free_rows(_r);
185                         return -3;
186                 }
187                 if (db_mysql_convert_row(_h, _r, &(RES_ROWS(_r)[row])) < 0) {
188                         LM_ERR("error while converting row #%d\n", row);
189                         RES_ROW_N(_r) = row;
190                         db_free_rows(_r);
191                         return -4;
192                 }
193         }
194         return 0;
195 }
196
197
198 /*!
199  * \brief Fill the result structure with data from database
200  * \param _h database connection
201  * \param _r database result
202  * \return 0 on success, negative on failure
203  */
204 int db_mysql_convert_result(const db1_con_t* _h, db1_res_t* _r)
205 {
206         if ((!_h) || (!_r)) {
207                 LM_ERR("invalid parameter\n");
208                 return -1;
209         }
210
211         if (db_mysql_get_columns(_h, _r) < 0) {
212                 LM_ERR("error while getting column names\n");
213                 return -2;
214         }
215
216         if (db_mysql_convert_rows(_h, _r) < 0) {
217                 LM_ERR("error while converting rows\n");
218                 db_free_columns(_r);
219                 return -3;
220         }
221         return 0;
222 }
223