00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "../../mem/mem.h"
00038 #include "../../dprint.h"
00039 #include "../../db/db_query.h"
00040 #include "val.h"
00041 #include "con.h"
00042 #include "row.h"
00043 #include "res.h"
00044 #include "list.h"
00045 #include "db_unixodbc.h"
00046 #include "dbase.h"
00047
00048
00049
00050
00051
00052 static int reconnect(const db_con_t* _h)
00053 {
00054 int ret = 0;
00055 SQLCHAR outstr[1024];
00056 SQLSMALLINT outstrlen;
00057 char conn_str[MAX_CONN_STR_LEN];
00058
00059 LM_ERR("Attempting DB reconnect\n");
00060
00061
00062 SQLDisconnect (CON_CONNECTION(_h));
00063
00064
00065 if (!db_unixodbc_build_conn_str(CON_ID(_h), conn_str)) {
00066 LM_ERR("failed to build connection string\n");
00067 return ret;
00068 }
00069
00070 ret = SQLDriverConnect(CON_CONNECTION(_h), (void *)1,
00071 (SQLCHAR*)conn_str, SQL_NTS, outstr, sizeof(outstr),
00072 &outstrlen, SQL_DRIVER_COMPLETE);
00073 if (!SQL_SUCCEEDED(ret)) {
00074 LM_ERR("failed to connect\n");
00075 db_unixodbc_extract_error("SQLDriverConnect", CON_CONNECTION(_h),
00076 SQL_HANDLE_DBC, NULL);
00077 return ret;
00078 }
00079
00080 ret = SQLAllocHandle(SQL_HANDLE_STMT, CON_CONNECTION(_h),
00081 &CON_RESULT(_h));
00082 if (!SQL_SUCCEEDED(ret)) {
00083 LM_ERR("Statement allocation error %d\n", (int)(long)CON_CONNECTION(_h));
00084 db_unixodbc_extract_error("SQLAllocStmt", CON_CONNECTION(_h), SQL_HANDLE_DBC,NULL);
00085 return ret;
00086 }
00087
00088 return ret;
00089 }
00090
00091
00092
00093
00094 static int db_unixodbc_submit_query(const db_con_t* _h, const str* _s)
00095 {
00096 int ret = 0;
00097 SQLCHAR sqlstate[7];
00098
00099 if (!_h || !_s || !_s->s) {
00100 LM_ERR("invalid parameter value\n");
00101 return -1;
00102 }
00103
00104
00105 if(CON_RESULT(_h))
00106 {
00107 SQLCloseCursor(CON_RESULT(_h));
00108 SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
00109 }
00110
00111 ret = SQLAllocHandle(SQL_HANDLE_STMT, CON_CONNECTION(_h), &CON_RESULT(_h));
00112 if (!SQL_SUCCEEDED(ret))
00113 {
00114 LM_ERR("statement allocation error %d\n",
00115 (int)(long)CON_CONNECTION(_h));
00116 db_unixodbc_extract_error("SQLAllocStmt", CON_CONNECTION(_h), SQL_HANDLE_DBC,
00117 (char*)sqlstate);
00118
00119
00120 if( !strncmp((char*)sqlstate,"08003",5) ||
00121 !strncmp((char*)sqlstate,"08S01",5) ) {
00122 ret = reconnect(_h);
00123 if( !SQL_SUCCEEDED(ret) ) return ret;
00124 } else {
00125 return ret;
00126 }
00127 }
00128
00129 ret=SQLExecDirect(CON_RESULT(_h), (SQLCHAR*)_s->s, _s->len);
00130 if (!SQL_SUCCEEDED(ret))
00131 {
00132 SQLCHAR sqlstate[7];
00133 LM_ERR("rv=%d. Query= %.*s\n", ret, _s->len, _s->s);
00134 db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h), SQL_HANDLE_STMT,
00135 (char*)sqlstate);
00136
00137
00138 if( !strncmp((char*)sqlstate,"08003",5) ||
00139 !strncmp((char*)sqlstate,"08S01",5)
00140 )
00141 {
00142 ret = reconnect(_h);
00143 if( SQL_SUCCEEDED(ret) ) {
00144
00145 ret=SQLExecDirect(CON_RESULT(_h), (SQLCHAR*)_s->s, _s->len);
00146 if (!SQL_SUCCEEDED(ret)) {
00147 LM_ERR("rv=%d. Query= %.*s\n", ret, _s->len, _s->s);
00148 db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h),
00149 SQL_HANDLE_STMT, (char*)sqlstate);
00150
00151 SQLCloseCursor(CON_RESULT(_h));
00152 SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
00153 }
00154 }
00155
00156 }
00157 else {
00158
00159 SQLCloseCursor(CON_RESULT(_h));
00160 SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
00161 }
00162 }
00163
00164 return ret;
00165 }
00166
00167
00168
00169
00170
00171
00172
00173 db_con_t* db_unixodbc_init(const str* _url)
00174 {
00175 return db_do_init(_url, (void*)db_unixodbc_new_connection);
00176 }
00177
00178
00179
00180
00181
00182 void db_unixodbc_close(db_con_t* _h)
00183 {
00184 return db_do_close(_h, db_unixodbc_free_connection);
00185 }
00186
00187
00188
00189
00190 static int db_unixodbc_store_result(const db_con_t* _h, db_res_t** _r)
00191 {
00192 if ((!_h) || (!_r))
00193 {
00194 LM_ERR("invalid parameter value\n");
00195 return -1;
00196 }
00197
00198 *_r = db_new_result();
00199
00200 if (*_r == 0)
00201 {
00202 LM_ERR("no memory left\n");
00203 return -2;
00204 }
00205
00206 if (db_unixodbc_convert_result(_h, *_r) < 0)
00207 {
00208 LM_ERR("failed to convert result\n");
00209 LM_DBG("freeing result set at %p\n", _r);
00210 pkg_free(*_r);
00211 *_r = 0;
00212 return -4;
00213 }
00214 return 0;
00215 }
00216
00217
00218
00219
00220 int db_unixodbc_free_result(db_con_t* _h, db_res_t* _r)
00221 {
00222 if ((!_h) || (!_r))
00223 {
00224 LM_ERR("invalid parameter value\n");
00225 return -1;
00226 }
00227
00228 if (db_free_result(_r) < 0)
00229 {
00230 LM_ERR("failed to free result structure\n");
00231 return -1;
00232 }
00233 SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
00234 CON_RESULT(_h) = 0;
00235 return 0;
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 int db_unixodbc_query(const db_con_t* _h, const db_key_t* _k, const db_op_t* _op,
00250 const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
00251 const db_key_t _o, db_res_t** _r)
00252 {
00253 return db_do_query(_h, _k, _op, _v, _c, _n, _nc, _o, _r,
00254 db_unixodbc_val2str, db_unixodbc_submit_query, db_unixodbc_store_result);
00255 }
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 int db_unixodbc_fetch_result(const db_con_t* _h, db_res_t** _r, const int nrows)
00273 {
00274 int row_n = 0, i = 0, ret = 0, len;
00275 SQLSMALLINT columns;
00276 list* rows = NULL;
00277 list* rowstart = NULL;
00278 strn* temp_row = NULL;
00279
00280 if ((!_h) || (!_r) || nrows < 0)
00281 {
00282 LM_ERR("invalid parameter value\n");
00283 return -1;
00284 }
00285
00286
00287 if (nrows == 0) {
00288 if (*_r)
00289 db_free_result(*_r);
00290 *_r = 0;
00291 return 0;
00292 }
00293
00294
00295 if(*_r == NULL) {
00296
00297 *_r = db_new_result();
00298 LM_DBG("just allocated a new db result structure");
00299
00300 if (*_r == NULL) {
00301 LM_ERR("no memory left\n");
00302 return -2;
00303 }
00304
00305
00306 if (db_unixodbc_get_columns(_h, *_r) < 0) {
00307 LM_ERR("getting column names failed\n");
00308 db_free_columns(*_r);
00309 return -2;
00310 }
00311
00312
00313 } else {
00314 LM_DBG("db result structure already exist, reusing\n");
00315
00316 if(RES_ROWS(*_r) != NULL)
00317 db_free_rows(*_r);
00318 RES_ROWS(*_r) = 0;
00319 RES_ROW_N(*_r) = 0;
00320 }
00321
00322 SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns);
00323
00324
00325 temp_row = (strn*)pkg_malloc( columns*sizeof(strn) );
00326 if(!temp_row) {
00327 LM_ERR("no private memory left\n");
00328 return -1;
00329 }
00330
00331
00332 len = sizeof(db_row_t) * nrows;
00333 RES_ROWS(*_r) = (struct db_row*)pkg_malloc(len);
00334 if (!RES_ROWS(*_r)) {
00335 LM_ERR("no memory left\n");
00336 return -5;
00337 }
00338 LM_DBG("allocated %d bytes for RES_ROWS at %p\n", len, RES_ROWS(*_r));
00339
00340 LM_DBG("Now fetching %i rows at most\n", nrows);
00341 while(SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h)))) {
00342 LM_DBG("fetching %d columns for row %d...\n",columns, row_n);
00343 for(i=0; i < columns; i++) {
00344 SQLLEN indicator;
00345 LM_DBG("fetching column %d\n",i);
00346
00347 ret = SQLGetData(CON_RESULT(_h), i+1, SQL_C_CHAR,
00348 temp_row[i].s, STRN_LEN, &indicator);
00349
00350 if (SQL_SUCCEEDED(ret)) {
00351 if (indicator == SQL_NULL_DATA)
00352 strcpy(temp_row[i].s, "NULL");
00353 } else {
00354 LM_ERR("SQLGetData failed\n");
00355 }
00356 }
00357
00358 LM_DBG("got temp_row at %p\n", temp_row);
00359
00360 if (db_unixodbc_list_insert(&rowstart, &rows, columns, temp_row) < 0) {
00361 LM_ERR("SQL result row insert failed\n");
00362 pkg_free(temp_row);
00363 temp_row= NULL;
00364 pkg_free(*_r);
00365 *_r = 0;
00366 return -5;
00367 }
00368
00369 row_n++;
00370 if (row_n == nrows) {
00371 break;
00372 }
00373 }
00374
00375
00376 LM_DBG("freeing temp_row at %p\n", temp_row);
00377 pkg_free(temp_row);
00378 CON_ROW(_h) = NULL;
00379
00380 RES_ROW_N(*_r) = row_n;
00381 if (!row_n) {
00382 LM_DBG("no more rows to process for db fetch");
00383 RES_ROWS(*_r) = 0;
00384 return 0;
00385 }
00386
00387
00388 memset(RES_ROWS(*_r), 0, len);
00389 i = 0;
00390 rows = rowstart;
00391 while(rows)
00392 {
00393 LM_DBG("converting row #%d\n", i);
00394 CON_ROW(_h) = rows->data;
00395 if (!CON_ROW(_h))
00396 {
00397 LM_ERR("string null\n");
00398 RES_ROW_N(*_r) = row_n;
00399 db_free_rows(*_r);
00400 return -3;
00401 }
00402 if (db_unixodbc_convert_row(_h, *_r, &(RES_ROWS(*_r)[i]), rows->lengths) < 0) {
00403 LM_ERR("converting fetched row #%d failed\n", i);
00404 RES_ROW_N(*_r) = i;
00405 db_free_rows(*_r);
00406 return -4;
00407 }
00408 i++;
00409 rows = rows->next;
00410 }
00411 db_unixodbc_list_destroy(rowstart);
00412
00413
00414 RES_LAST_ROW(*_r) += row_n;
00415 LM_DBG("fetch from db processed %d rows so far\n", RES_LAST_ROW(*_r));
00416
00417 return 0;
00418 }
00419
00420
00421
00422
00423
00424 int db_unixodbc_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r)
00425 {
00426 return db_do_raw_query(_h, _s, _r, db_unixodbc_submit_query,
00427 db_unixodbc_store_result);
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437 int db_unixodbc_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n)
00438 {
00439 return db_do_insert(_h, _k, _v, _n, db_unixodbc_val2str,
00440 db_unixodbc_submit_query);
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 int db_unixodbc_delete(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
00452 const db_val_t* _v, const int _n)
00453 {
00454 return db_do_delete(_h, _k, _o, _v, _n, db_unixodbc_val2str,
00455 db_unixodbc_submit_query);
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469 int db_unixodbc_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
00470 const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv, const int _n, const int _un)
00471 {
00472 return db_do_update(_h, _k, _o, _v, _uk, _uv, _n, _un, db_unixodbc_val2str,
00473 db_unixodbc_submit_query);
00474 }
00475
00476
00477
00478
00479 int db_unixodbc_replace(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n)
00480 {
00481 return db_do_replace(_h, _k, _v, _n, db_unixodbc_val2str,
00482 db_unixodbc_submit_query);
00483 }
00484
00485
00486
00487
00488
00489 int db_unixodbc_use_table(db_con_t* _h, const str* _t)
00490 {
00491 return db_use_table(_h, _t);
00492 }