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
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 #ifdef HAVE_ORACLE
00071
00072 #include <oci.h>
00073
00074
00075 static int oracle_select(void *theconn, const Octstr *sql, List *binds, List **res);
00076
00077 struct ora_conn {
00078
00079 OCIEnv *envp;
00080
00081 OCISvcCtx *svchp;
00082
00083 OCIError *errhp;
00084 };
00085
00086
00087 static void oracle_checkerr(OCIError *errhp, sword status)
00088 {
00089 text errbuf[512];
00090 sb4 errcode = 0;
00091
00092 switch (status) {
00093 case OCI_SUCCESS:
00094 break;
00095 case OCI_SUCCESS_WITH_INFO:
00096 error(0, "Error - OCI_SUCCESS_WITH_INFO");
00097 break;
00098 case OCI_NEED_DATA:
00099 error(0, "Error - OCI_NEED_DATA");
00100 break;
00101 case OCI_NO_DATA:
00102 error(0, "Error - OCI_NODATA");
00103 break;
00104 case OCI_ERROR:
00105 if (errhp == NULL) break;
00106 (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode,
00107 errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
00108 error(0, "Error - %.*s", 512, errbuf);
00109 break;
00110 case OCI_INVALID_HANDLE:
00111 error(0, "Error - OCI_INVALID_HANDLE");
00112 break;
00113 case OCI_STILL_EXECUTING:
00114 error(0, "Error - OCI_STILL_EXECUTE");
00115 break;
00116 case OCI_CONTINUE:
00117 error(0, "Error - OCI_CONTINUE");
00118 break;
00119 default:
00120 break;
00121 }
00122 }
00123
00124
00125
00126
00127
00128 static void *oracle_malloc(void *ctx, size_t size)
00129 {
00130 void *ret = gw_malloc(size);
00131 debug("dbpool.oracle",0,"oracle_malloc called size=%d @%08lx", size,
00132 (long) ret);
00133 return ret;
00134 }
00135
00136
00137
00138
00139
00140 static void oracle_free(void *ctx, void *ptr)
00141 {
00142 debug("dbpool.oracle",0,"oracle_free called @%08lx", (long) ptr);
00143 gw_free(ptr);
00144 }
00145
00146
00147
00148
00149
00150 static void *oracle_realloc(void *ctx, void *ptr, size_t size)
00151 {
00152 void *ret = gw_realloc(ptr, size);
00153 debug("dbpool.oracle",0,"oracle_realloc called size=%d", size);
00154 return ret;
00155 }
00156
00157 static void* oracle_open_conn(const DBConf *db_conf)
00158 {
00159 OracleConf *cfg = db_conf->oracle;
00160 sword errorcode = 0;
00161 text version[512];
00162 struct ora_conn *conn = gw_malloc(sizeof(struct ora_conn));
00163
00164 gw_assert(conn != NULL);
00165 memset(conn, 0, sizeof(struct ora_conn));
00166
00167 debug("dbpool.oracle",0,"oracle_open_conn called");
00168
00169
00170 errorcode = OCIEnvCreate(&conn->envp,
00171 OCI_THREADED|OCI_ENV_NO_MUTEX,
00172 NULL,
00173 oracle_malloc,
00174 oracle_realloc,
00175 oracle_free,
00176 0,0);
00177 if (errorcode != OCI_SUCCESS) {
00178 oracle_checkerr(NULL, errorcode);
00179 error(0, "Got error while OCIEnvCreate %d", errorcode);
00180 gw_free(conn);
00181 return NULL;
00182 }
00183
00184 debug("dbpool.oracle",0,"oci environment created");
00185
00186
00187 errorcode = OCIHandleAlloc(conn->envp, (dvoid**) &conn->errhp,
00188 OCI_HTYPE_ERROR, 0, 0);
00189 if (errorcode != OCI_SUCCESS) {
00190 oracle_checkerr(NULL, errorcode);
00191 OCIHandleFree(conn->envp, OCI_HTYPE_ENV);
00192 gw_free(conn);
00193 return NULL;
00194 }
00195
00196 debug("dbpool.oracle",0,"oci error handle allocated");
00197
00198
00199 errorcode = OCILogon(conn->envp, conn->errhp, &conn->svchp,
00200 octstr_get_cstr(cfg->username), octstr_len(cfg->username),
00201 octstr_get_cstr(cfg->password), octstr_len(cfg->password),
00202 octstr_get_cstr(cfg->tnsname), octstr_len(cfg->tnsname));
00203
00204 if (errorcode != OCI_SUCCESS) {
00205 oracle_checkerr(conn->errhp, errorcode);
00206 OCIHandleFree(conn->errhp, OCI_HTYPE_ERROR);
00207 OCIHandleFree(conn->envp, OCI_HTYPE_ENV);
00208 gw_free(conn);
00209 return NULL;
00210 }
00211
00212 debug("dbpool.oracle",0,"connected to database");
00213
00214 errorcode = OCIServerVersion(conn->svchp, conn->errhp, version,
00215 sizeof(version), OCI_HTYPE_SVCCTX);
00216 if (errorcode != OCI_SUCCESS) {
00217 oracle_checkerr(conn->errhp, errorcode);
00218 } else {
00219 info(0, "Connected to: %s", version);
00220 }
00221
00222 return conn;
00223 }
00224
00225
00226 static void oracle_close_conn(void *theconn)
00227 {
00228 struct ora_conn *conn = (struct ora_conn*) theconn;
00229
00230 gw_assert(conn != NULL);
00231
00232 if (conn->svchp != NULL)
00233 oracle_checkerr(conn->errhp, OCILogoff(conn->svchp, conn->errhp));
00234
00235 OCIHandleFree(conn->errhp, OCI_HTYPE_ERROR);
00236 OCIHandleFree(conn->envp, OCI_HTYPE_ENV);
00237
00238
00239 gw_free(conn);
00240 }
00241
00242
00243 static int oracle_check_conn(void *conn)
00244 {
00245 Octstr *sql;
00246 List *res;
00247 int ret;
00248
00249
00250 sql = octstr_create("SELECT 1 FROM DUAL");
00251
00252 ret = oracle_select(conn, sql, NULL, &res);
00253 if (ret != -1 && gwlist_len(res) > 0) {
00254 List *row = gwlist_extract_first(res);
00255 gwlist_destroy(row, octstr_destroy_item);
00256 }
00257 if (ret != -1)
00258 gwlist_destroy(res, NULL);
00259
00260 octstr_destroy(sql);
00261
00262 return ret;
00263 }
00264
00265
00266 static void oracle_conf_destroy(DBConf *theconf)
00267 {
00268 OracleConf *conf = theconf->oracle;
00269
00270 octstr_destroy(conf->username);
00271 octstr_destroy(conf->password);
00272 octstr_destroy(conf->tnsname);
00273
00274 gw_free(conf);
00275 gw_free(theconf);
00276 }
00277
00278
00279 static int oracle_select(void *theconn, const Octstr *sql, List *binds, List **res)
00280 {
00281 List *row;
00282 OCIStmt *stmt;
00283 OCIParam *dparam;
00284 sword status;
00285 ub4 columns;
00286 ub4 i;
00287 struct data_s {
00288 text *data;
00289 ub2 size;
00290 sb2 ind;
00291 ub2 type;
00292 };
00293 struct data_s *data;
00294 struct ora_conn *conn = (struct ora_conn*) theconn;
00295 int binds_len = (binds ? gwlist_len(binds) : 0);
00296
00297 *res = NULL;
00298
00299
00300 status = OCIHandleAlloc(conn->envp, (dvoid**)&stmt, OCI_HTYPE_STMT, 0,0);
00301 if (OCI_SUCCESS != status) {
00302 oracle_checkerr(conn->errhp, status);
00303 return -1;
00304 }
00305
00306 status = OCIStmtPrepare(stmt, conn->errhp, octstr_get_cstr(sql),
00307 octstr_len(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
00308 if (OCI_SUCCESS != status) {
00309 oracle_checkerr(conn->errhp, status);
00310 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00311 return -1;
00312 }
00313
00314
00315 for (i = 0; i < binds_len; i++) {
00316 OCIBind *bndhp = NULL;
00317 Octstr *bind = gwlist_get(binds, i);
00318 status = OCIBindByPos(stmt, &bndhp,
00319 conn->errhp, (i+1), (dvoid *) octstr_get_cstr(bind),
00320 (sword) octstr_len(bind)+1, SQLT_STR, (dvoid *) 0, (ub2 *)0,
00321 (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT);
00322 if (OCI_SUCCESS != status) {
00323 oracle_checkerr(conn->errhp, status);
00324 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00325 return -1;
00326 }
00327 }
00328
00329 status = OCIStmtExecute(conn->svchp, stmt, conn->errhp, 0, 0, NULL, NULL,
00330 OCI_DEFAULT);
00331 if (OCI_SUCCESS != status && OCI_NO_DATA != status) {
00332 oracle_checkerr(conn->errhp, status);
00333 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00334 return -1;
00335 }
00336
00337 status = OCIAttrGet(stmt, OCI_HTYPE_STMT, &columns, 0, OCI_ATTR_PARAM_COUNT,
00338 conn->errhp);
00339 if (status != OCI_SUCCESS) {
00340 oracle_checkerr(conn->errhp, status);
00341 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00342 return -1;
00343 }
00344
00345 debug("dbpool.oracle",0,"SQL has %d columns", columns);
00346
00347
00348 debug("dbpool.oracle",0,"alloc size=%d",sizeof(text*)*columns);
00349 data = gw_malloc(sizeof(struct data_s)*columns);
00350
00351 debug("dbpool.oracle",0,"retrieve data_size");
00352
00353 for (i=0 ; i < columns; i++) {
00354 OCIDefine *defh;
00355
00356 status = OCIParamGet(stmt, OCI_HTYPE_STMT, conn->errhp,
00357 (dvoid**) &dparam, i+1);
00358 if (status != OCI_SUCCESS) {
00359 oracle_checkerr(conn->errhp, status);
00360 columns = i;
00361 for (i = 0; i < columns; i++)
00362 gw_free(data[i].data);
00363 gw_free(data);
00364 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00365 return -1;
00366 }
00367
00368 status = OCIAttrGet(dparam, OCI_DTYPE_PARAM, (dvoid*) &data[i].size,
00369 0, OCI_ATTR_DATA_SIZE, conn->errhp);
00370 if (status != OCI_SUCCESS) {
00371 oracle_checkerr(conn->errhp, status);
00372 columns = i;
00373 for (i = 0; i < columns; i++)
00374 gw_free(data[i].data);
00375 gw_free(data);
00376 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00377 return -1;
00378 }
00379
00380 status = OCIAttrGet(dparam, OCI_DTYPE_PARAM, (dvoid*) &data[i].type,
00381 0, OCI_ATTR_DATA_TYPE, conn->errhp);
00382 if (status != OCI_SUCCESS) {
00383 oracle_checkerr(conn->errhp, status);
00384 columns = i;
00385 for (i = 0; i < columns; i++)
00386 gw_free(data[i].data);
00387 gw_free(data);
00388 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00389 return -1;
00390 }
00391
00392
00393 if (data[i].type != SQLT_DAT) {
00394 data[i].size++;
00395 data[i].type = SQLT_STR;
00396 }
00397
00398 debug("dbpool.oracle",0,"alloc size=%d", data[i].size);
00399 data[i].data = gw_malloc(data[i].size);
00400
00401
00402 status = OCIDefineByPos(stmt, &defh, conn->errhp, i+1, data[i].data,
00403 data[i].size, data[i].type, &data[i].ind,
00404 0, 0, OCI_DEFAULT);
00405 if (status != OCI_SUCCESS) {
00406 oracle_checkerr(conn->errhp, status);
00407 columns = i;
00408 for (i = 0; i <= columns; i++)
00409 gw_free(data[i].data);
00410 gw_free(data);
00411 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00412 return -1;
00413 }
00414 }
00415
00416 *res = gwlist_create();
00417
00418 while ((status = OCIStmtFetch(stmt, conn->errhp, 1,
00419 OCI_FETCH_NEXT, OCI_DEFAULT)) == OCI_SUCCESS ||
00420 status == OCI_SUCCESS_WITH_INFO) {
00421
00422 row = gwlist_create();
00423 for (i = 0; i < columns; i++) {
00424 if (data[i].data == NULL || data[i].ind == -1) {
00425 gwlist_insert(row, i, octstr_create(""));
00426 } else {
00427 gwlist_insert(row, i, octstr_create_from_data(data[i].data, data[i].size));
00428 }
00429
00430
00431 }
00432 gwlist_append(*res, row);
00433 }
00434
00435
00436 if (status != OCI_NO_DATA) {
00437 List *row;
00438 oracle_checkerr(conn->errhp, status);
00439 for (i = 0; i < columns; i++)
00440 gw_free(data[i].data);
00441 gw_free(data);
00442 while ((row = gwlist_extract_first(*res)) != NULL)
00443 gwlist_destroy(row, octstr_destroy_item);
00444 gwlist_destroy(*res, NULL);
00445 *res = NULL;
00446 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00447 return -1;
00448 }
00449
00450 for (i = 0; i < columns; i++)
00451 gw_free(data[i].data);
00452
00453 gw_free(data);
00454 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00455
00456 return 0;
00457 }
00458
00459
00460 static int oracle_update(void *theconn, const Octstr *sql, List *binds)
00461 {
00462 OCIStmt *stmt;
00463 sword status;
00464 ub4 rows = 0, i;
00465 struct ora_conn *conn = (struct ora_conn*) theconn;
00466 int binds_len = (binds ? gwlist_len(binds) : 0);
00467
00468
00469 status = OCIHandleAlloc(conn->envp, (dvoid**)&stmt, OCI_HTYPE_STMT, 0,0);
00470 if (OCI_SUCCESS != status) {
00471 oracle_checkerr(conn->errhp, status);
00472 return -1;
00473 }
00474 debug("dbpool.oracle",0,"OCIStmt allocated");
00475
00476 status = OCIStmtPrepare(stmt, conn->errhp, octstr_get_cstr(sql),
00477 octstr_len(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
00478 if (OCI_SUCCESS != status) {
00479 oracle_checkerr(conn->errhp, status);
00480 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00481 return -1;
00482 }
00483 debug("dbpool.oracle",0,"OCIStmtPrepare done");
00484
00485
00486 for (i = 0; i < binds_len; i++) {
00487 Octstr *bind = gwlist_get(binds, i);
00488 OCIBind *bndhp = NULL;
00489 status = OCIBindByPos(stmt, &bndhp,
00490 conn->errhp, (i+1), (dvoid *) octstr_get_cstr(bind),
00491 (sword) octstr_len(bind)+1, SQLT_STR, (dvoid *) 0, (ub2 *)0,
00492 (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT);
00493 if (OCI_SUCCESS != status) {
00494 oracle_checkerr(conn->errhp, status);
00495 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00496 return -1;
00497 }
00498 }
00499
00500
00501 status = OCIStmtExecute(conn->svchp, stmt, conn->errhp, 1, 0, NULL, NULL,
00502 OCI_COMMIT_ON_SUCCESS);
00503 if (OCI_SUCCESS != status && OCI_NO_DATA != status) {
00504 oracle_checkerr(conn->errhp, status);
00505 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00506 return -1;
00507 }
00508 debug("dbpool.oracle",0,"OCIStmtExecute done");
00509
00510 status = OCIAttrGet(stmt, OCI_HTYPE_STMT, &rows, 0, OCI_ATTR_ROW_COUNT,
00511 conn->errhp);
00512 if (status != OCI_SUCCESS) {
00513 oracle_checkerr(conn->errhp, status);
00514
00515 }
00516 debug("dbpool.oracle",0,"rows processed = %d", rows);
00517
00518 OCIHandleFree(stmt, OCI_HTYPE_STMT);
00519
00520 return (int) rows;
00521 }
00522
00523 static struct db_ops oracle_ops = {
00524 .open = oracle_open_conn,
00525 .close = oracle_close_conn,
00526 .check = oracle_check_conn,
00527 .conf_destroy = oracle_conf_destroy,
00528 .select = oracle_select,
00529 .update = oracle_update
00530 };
00531
00532 #endif
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.