/* * libdbi - database independent abstraction layer for C. * Copyright (C) 2001-2004, David Parker and Mark Tobenkin. * http://libdbi.sourceforge.net * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * dbd_oracle.c: Oracle database support * Copyright (C) 2003-2004, Christian M. Stamgren * http://libdbi-drivers.sourceforge.net * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE /* we need asprintf */ #include #include #include #include #include #include #include #include #include "dbd_oracle.h" #include "oracle_charsets.h" /* declarations of optional external functions */ #ifndef HAVE_ASPRINTF int asprintf(char **result, const char *format, ...); #endif static const dbi_info_t driver_info = { "Oracle", "Oracle database support (using Oracle Call Interface)", "Ashish Ranjan ", "http://libdbi-drivers.sourceforge.net", "dbd_Oracle v" VERSION, __DATE__ }; static const char *custom_functions[] = {NULL}; static const char *reserved_words[] = ORACLE_RESERVED_WORDS; void _translate_oracle_type(int fieldtype, ub1 scale, unsigned short *type, unsigned int *attribs); void _get_field_info(dbi_result_t *result); void _get_row_data(dbi_result_t *result, dbi_row_t *row, unsigned long long rowidx); unsigned long long _oracle_query_to_longlong(dbi_conn_t *conn, const char *sql_cmd); void _checkerr(OCIError * errhp, sword status); static size_t oracle_escape_string(char *to, const char *from, size_t length); int _oradate_to_dtx(const char *obuff, dbi_datetimex dtx); void dbd_register_driver(const dbi_info_t **_driver_info, const char ***_custom_functions, const char ***_reserved_words) { *_driver_info = &driver_info; *_custom_functions = custom_functions; *_reserved_words = reserved_words; } int dbd_initialize(dbi_driver_t *driver) { /* this indicates the driver can be safely unloaded when libdbi is shut down. Change the value to '0' (zero) if the driver, or a library it is linked against, installs exit handlers via atexit() */ _dbd_register_driver_cap(driver, "safe_dlclose", 1); /* this indicates the database engine supports transactions */ _dbd_register_driver_cap(driver, "transaction_support", 1); /* this indicates the database engine supports savepoints */ _dbd_register_driver_cap(driver, "savepoint_support", 1); return OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, (dvoid * (*)(dvoid *, size_t)) 0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, (void (*)(dvoid *, dvoid *)) 0 ); } int dbd_finalize(dbi_driver_t *driver) { /* perform any database-specific client library shutdown. * this is called right before dlclose()ing the driver. * return -1 on error, 0 on success. */ return 0; } int dbd_connect(dbi_conn_t *conn) { Oraconn *Oconn = malloc( sizeof( Oraconn )); const char *username = dbi_conn_get_option(conn, "username"); const char *password = dbi_conn_get_option(conn, "password"); const char *sid = dbi_conn_get_option(conn, "dbname"); sword status; if(! sid ) sid = getenv("ORACLE_SID"); /* OCI Environment Allocation */ if(OCIEnvCreate ((OCIEnv **) &(Oconn->env), OCI_DEFAULT, (dvoid *)0, 0, 0, 0, (size_t)0, (dvoid **)0)) { _dbd_internal_error_handler(conn, "Connect::Unable to initialize environment", 0); return -2; } /* OCI ERROR HANDLE */ if( (OCIHandleAlloc( (dvoid *) Oconn->env, (dvoid **) &(Oconn->err), OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0))) { _dbd_internal_error_handler(conn, "Connect::Unable to allocate ERROR handlers.", 0); return -2; } /* OCI SERVICE HANDLE */ if( (OCIHandleAlloc( (dvoid *) Oconn->env, (dvoid **) &(Oconn->svc), OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0))) { _dbd_internal_error_handler(conn, "Connect::Unable to allocate SERVICE handlers.", 0); return -2; } if( (status = OCILogon(Oconn->env, Oconn->err, &(Oconn->svc), (CONST OraText*) username, strlen(username),(CONST OraText*) password, strlen(password), sid, strlen(sid)))) { _checkerr(Oconn->err, status); _dbd_internal_error_handler(conn, "Connect::Unable to login to the database.", 0); return -2; } conn->connection = (void *)Oconn; if (sid) conn->current_db = strdup(sid); return 0; } int dbd_disconnect(dbi_conn_t *conn) { Oraconn *Oconn = conn->connection; if (Oconn) { OCILogoff(Oconn->svc, Oconn->err); OCIHandleFree((dvoid *) Oconn->svc, OCI_HTYPE_SVCCTX); OCIHandleFree((dvoid *) Oconn->err, OCI_HTYPE_ERROR); free(conn->connection); } conn->connection = NULL; return 0; } int dbd_fetch_row(dbi_result_t *result, unsigned long long rowidx) { dbi_row_t *row = NULL; if (result->result_state == NOTHING_RETURNED) return -1; if (result->result_state == ROWS_RETURNED) { row = _dbd_row_allocate(result->numfields); _get_row_data(result, row, rowidx); _dbd_row_finalize(result, row, rowidx); } return 1; } int dbd_free_query(dbi_result_t *result) { if (result->result_handle) OCIHandleFree((dvoid *)result->result_handle, OCI_HTYPE_STMT); result->result_handle = NULL; return 0; } int dbd_goto_row(dbi_result_t *result, unsigned long long rowidx, unsigned long long currowidx) { /* no-op */ return 1; } int dbd_get_socket(dbi_conn_t *conn) { return 0; /* Oracle can't do that.. */ } /* * Use this function with care... It might bite you. * There can be N-type columns in queries that have a diffrent Charset, * a session might be altered to use another charset as output or * there might be values converted using the Oracle convert() function in the query. */ const char *dbd_get_encoding(dbi_conn_t *conn){ OraText buf[OCI_NLS_MAXBUFSZ]; sword ret; int i = 0; Oraconn *Oconn = conn->connection; if( (ret = OCINlsGetInfo(Oconn->env, Oconn->err, buf, OCI_NLS_MAXBUFSZ, OCI_NLS_CHARACTER_SET)) != OCI_SUCCESS) { _checkerr(Oconn->err, ret); } if (!buf) return NULL; else { while (*oracle_encoding_hash[i]) { if (!strcmp(oracle_encoding_hash[i], buf)) { return oracle_encoding_hash[i+1]; } i += 2; } } return "UTF-16"; } char *dbd_get_engine_version(dbi_conn_t *conn, char *versionstring) { /* todo: query db engine for version "select version from v$instance" should do the trick */ *versionstring = '\0'; return versionstring; } dbi_result_t *dbd_list_dbs(dbi_conn_t *conn, const char *pattern) { return NULL; /* Oracle can't do that */ } dbi_result_t *dbd_list_tables(dbi_conn_t *conn, const char *db, const char *pattern) { dbi_result_t *res; char *sql_cmd; /* * We just ignore the db param, * Oracle can't read from diffrent databases at runtime. */ if (pattern == NULL) { asprintf(&sql_cmd, "SELECT table_name FROM user_tables"); res = dbd_query(conn, sql_cmd); free(sql_cmd); return res; } else { asprintf(&sql_cmd, "SELECT table_name FROM user_tables WHERE table_name LIKE '%s'",pattern); res = dbd_query(conn, sql_cmd); free(sql_cmd); return res; } } size_t dbd_quote_string(dbi_driver_t *driver, const char *orig, char *dest) { size_t len; const char *escaped = "\'\"\\"; strcpy(dest, "'"); len = oracle_escape_string(dest+1, orig, strlen(orig)); strcat(dest, "'"); return len+2; } dbi_result_t *dbd_query_null(dbi_conn_t *conn, const char unsigned *statement, size_t st_length) { OCIStmt *stmt; OCIDefine *defnp; ub2 stmttype = 0; ub4 numfields = 0; dbi_result_t *result; ub4 numrows = 0, affectedrows = 0; Oraconn *Oconn = conn->connection; sword status; ub4 cache_rows = 0; char *notused; unsigned int idx = 0; unsigned short fieldtype; unsigned int fieldattribs; OCIParam *param; ub4 otype; text *col_name; sb1 scale; ub4 col_name_len; char* col_name_dbi; OCIHandleAlloc( (dvoid *) Oconn->env, (dvoid **) &stmt, OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0); if( OCIStmtPrepare(stmt, Oconn->err, (char *) statement, (ub4) st_length, (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)) { OCIHandleFree(stmt, OCI_HTYPE_STMT); return NULL; } OCIAttrGet(stmt, OCI_HTYPE_STMT, (dvoid *) &stmttype, (ub4 *) 0, (ub4) OCI_ATTR_STMT_TYPE, Oconn->err); status = OCIStmtExecute(Oconn->svc, stmt, Oconn->err, (ub4) (stmttype == OCI_STMT_SELECT ? 0 : 1), (ub4) 0, (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, stmttype == OCI_STMT_SELECT ? MY_OCI_STMT_SCROLLABLE_READONLY : OCI_COMMIT_ON_SUCCESS); if( status != OCI_SUCCESS) { OCIHandleFree(stmt, OCI_HTYPE_STMT); return NULL; } if( stmttype == OCI_STMT_SELECT) { OCIAttrGet (stmt, OCI_HTYPE_STMT, (dvoid *) &numfields, (ub4 *) 0, (ub4) OCI_ATTR_PARAM_COUNT, Oconn->err); /* * To find out how many rows there is in a result set we need to call * OCIStmtFetch2() with OCI_FETCH_LAST and then use OCIAttrGet() * with MY_OCI_ATTR_CURRENT_POSITION, This is really not that great * because it might be very very very slow..... But It's the only way I know. * It would be really great if libdbi didn't have to know how large a result set is * at this early point. */ /* dummy define .. * We need to have atleast one define before fetching. Duh!!! */ OCIDefineByPos(stmt, &defnp, Oconn->err, 1, (dvoid *) ¬used, (sword) sizeof(sword), SQLT_CHR, (dvoid *) 0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT); status = OCIStmtFetch2(stmt, Oconn->err, (ub4)1, OCI_FETCH_LAST, 0, OCI_DEFAULT); status = OCIAttrGet (stmt, OCI_HTYPE_STMT, (dvoid *) &numrows, (ub4 *) 0, (ub4) MY_OCI_ATTR_CURRENT_POSITION, Oconn->err); _checkerr(Oconn->err, status); /* cache should be about 20% of all rows. */ if(dbi_conn_get_option_numeric(conn, "oracle_prefetch_rows")) { cache_rows = (ub4)numrows/5; OCIAttrSet(stmt, OCI_HTYPE_STMT, &cache_rows, sizeof(cache_rows), OCI_ATTR_PREFETCH_ROWS, Oconn->err); } /* howto handle affectedrows? */ } result = _dbd_result_create(conn, (void *)stmt, numrows , affectedrows); _dbd_result_set_numfields(result, numfields); while (idx < result->numfields) { scale = 0; OCIParamGet(stmt, OCI_HTYPE_STMT, Oconn->err, (dvoid **)¶m, (ub4) idx+1); OCIAttrGet(param, (ub4) OCI_DTYPE_PARAM, &otype,(ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE, (OCIError *) Oconn->err ); OCIAttrGet((dvoid*) param, (ub4) OCI_DTYPE_PARAM, (dvoid**) &col_name,(ub4 *) &col_name_len, (ub4) OCI_ATTR_NAME, (OCIError *) Oconn->err ); if(otype == 2) { /* we got SQLT_NUM */ OCIAttrGet((dvoid*) param, (ub4) OCI_DTYPE_PARAM, (dvoid**) &scale,(ub4 *) 0, (ub4) OCI_ATTR_SCALE, (OCIError *) Oconn->err ); } /*bug fixing , it is necessary to copy it to earlier as in many cases it is not giving a properly terminated string, which gives malformed col name */ col_name_dbi = calloc(col_name_len + 1,sizeof(char) ); strncpy( col_name_dbi, (char *) col_name, col_name_len); _translate_oracle_type(otype, scale, &fieldtype, &fieldattribs); _dbd_result_add_field(result, idx, col_name_dbi, fieldtype, fieldattribs); free(col_name_dbi); idx++; } //end-code block1 return result; } dbi_result_t *dbd_query(dbi_conn_t *conn, const char *statement) { return dbd_query_null(conn, statement, strlen(statement)); } int dbd_transaction_begin(dbi_conn_t *conn) { if (dbd_query(conn, "SET TRANSACTION") == NULL) { return 1; } else { return 0; } } int dbd_transaction_commit(dbi_conn_t *conn) { if (dbd_query(conn, "COMMIT") == NULL) { return 1; } else { return 0; } } int dbd_transaction_rollback(dbi_conn_t *conn) { if (dbd_query(conn, "ROLLBACK") == NULL) { return 1; } else { return 0; } } int dbd_savepoint(dbi_conn_t *conn, const char *savepoint) { char* query; if (!savepoint) { return 1; } asprintf(&query, "SAVEPOINT %s", savepoint); if (dbd_query(conn, query) == NULL) { free(query); return 1; } else { free(query); return 0; } } int dbd_rollback_to_savepoint(dbi_conn_t *conn, const char *savepoint) { char* query; if (!savepoint) { return 1; } asprintf(&query, "ROLLBACK TO SAVEPOINT %s", savepoint); if (dbd_query(conn, query) == NULL) { free(query); return 1; } else { free(query); return 0; } } int dbd_release_savepoint(dbi_conn_t *conn, const char *savepoint) { /* apparently not used by Oracle */ return 0; } const char *dbd_select_db(dbi_conn_t *conn, const char *db) { /* todo: PostgreSQL can't do it either, but there's a workaround */ return NULL; /* Oracle can't do that .... */ } int dbd_geterror(dbi_conn_t *conn, int *err_no, char **errstr) { char errbuf[1024]; int errcode = 0; Oraconn *Oconn = conn->connection; *err_no = 0; if (!conn->connection) { *errstr = strdup("Unable to connect to database."); return 2; } else { OCIErrorGet((dvoid *)Oconn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); *errstr = strdup(errbuf); *err_no = errcode; } return 3; } unsigned long long dbd_get_seq_last(dbi_conn_t *conn, const char *sequence) { unsigned long long retval = 0; char *sql_cmd = NULL; if( ! sequence) return 0; asprintf(&sql_cmd, "SELECT %s.currval FROM dual", sequence); retval = _oracle_query_to_longlong(conn, sql_cmd); if(sql_cmd) free(sql_cmd); return retval; } unsigned long long dbd_get_seq_next(dbi_conn_t *conn, const char *sequence) { unsigned long long retval = 0; char *sql_cmd = NULL; if( ! sequence) return 0; asprintf(&sql_cmd, "SELECT %s.nextval FROM dual", sequence); retval = _oracle_query_to_longlong(conn, sql_cmd); if(sql_cmd) free(sql_cmd); return retval; } int dbd_ping(dbi_conn_t *conn) { unsigned long long retval = 0; char *sql_cmd = NULL; /* Oraconn *Oconn = conn->connection; */ asprintf(&sql_cmd, "SELECT 1 from dual"); retval = _oracle_query_to_longlong(conn, sql_cmd); if(sql_cmd) free(sql_cmd); if(!retval) { /* We need to reconnect! */ dbd_disconnect(conn); retval = dbd_connect(conn); return (retval ? 0 : retval); } return retval; } /* CORE ORACLE DATA FETCHING STUFF */ void _translate_oracle_type(int fieldtype, ub1 scale, unsigned short *type, unsigned int *attribs) { unsigned int _type = 0; unsigned int _attribs = 0; switch (fieldtype) { case SQLT_INT: case SQLT_LNG: _type = DBI_TYPE_INTEGER; _attribs |= DBI_INTEGER_SIZE8; break; case SQLT_FLT: _type = DBI_TYPE_DECIMAL; _attribs |= DBI_DECIMAL_SIZE8; break; case SQLT_NUM: /* * We use size8 becouse we don't know if it * can be smaller :( */ if(scale > 0) { _type = DBI_TYPE_DECIMAL; _attribs |= DBI_DECIMAL_SIZE8; } else { _type = DBI_TYPE_INTEGER; _attribs |= DBI_INTEGER_SIZE8; } break; case SQLT_BIN: case SQLT_LBI: _type = DBI_TYPE_BINARY; break; case SQLT_DAT: _type = DBI_TYPE_DATETIME; break; case SQLT_AFC: case SQLT_STR: case SQLT_CHR: case SQLT_VNU: case SQLT_VCS: default: _type = DBI_TYPE_STRING; break; } *type = _type; *attribs = _attribs; } void _get_field_info(dbi_result_t *result) { unsigned int idx = 0; unsigned short fieldtype; unsigned int fieldattribs; OCIParam *param = NULL; ub4 otype; text *col_name; sb1 scale; ub4 col_name_len; char* col_name_dbi; Oraconn *Oconn = (Oraconn *)result->conn->connection; OCIStmt *stmt = (OCIStmt *) result->result_handle; while (idx < result->numfields) { scale = 0; OCIParamGet((dvoid *)stmt, OCI_HTYPE_STMT, Oconn->err, (dvoid **)¶m, (ub4) idx+1); OCIAttrGet((dvoid*) param, (ub4) OCI_DTYPE_PARAM, (dvoid*) &otype,(ub4 *) 0, (ub4) OCI_ATTR_DATA_TYPE, (OCIError *) Oconn->err ); OCIAttrGet((dvoid*) param, (ub4) OCI_DTYPE_PARAM, (dvoid**) &col_name,(ub4 *) &col_name_len, (ub4) OCI_ATTR_NAME, (OCIError *) Oconn->err ); if(otype == 2) { /* we got SQLT_NUM */ OCIAttrGet((dvoid*) param, (ub4) OCI_DTYPE_PARAM, (dvoid**) &scale,(ub4 *) 0, (ub4) OCI_ATTR_SCALE, (OCIError *) Oconn->err ); } /*bug fixing , it is necessary to copy it to earlier as in many cases it is not giving a properly terminated string, which gives malformed col name */ col_name_dbi = calloc(col_name_len + 1,sizeof(char) ); strncpy( col_name_dbi, (char *) col_name, col_name_len); _translate_oracle_type(otype, scale, &fieldtype, &fieldattribs); _dbd_result_add_field(result, idx, col_name_dbi, fieldtype, fieldattribs); free(col_name_dbi); idx++; } } void _get_row_data(dbi_result_t *result, dbi_row_t *row, unsigned long long rowidx) { OCIStmt *stmt = result->result_handle; OCIDefine *defnp = (OCIDefine *) 0; OCIParam *param; Oraconn *Oconn = result->conn->connection; unsigned int curfield = 0; size_t length = 0; size_t slen; unsigned int sizeattrib; dbi_data_t *data; char *ptr, *cols[result->numfields]; sword status; /* * Prefetch all cols as char *'s * This might not be all that good ... lets revisit * this when some Oracle guru starts sending in patches. */ while(curfield < result->numfields) { length = 0; OCIParamGet(stmt, OCI_HTYPE_STMT, Oconn->err, (dvoid **)¶m, (ub4) curfield+1); OCIAttrGet((dvoid*) param, (ub4) OCI_DTYPE_PARAM, (dvoid*) &length,(ub4 *) 0, (ub4) OCI_ATTR_DATA_SIZE, (OCIError *) Oconn->err ); cols[curfield] = malloc(length + 1); if (result->field_types[curfield] == DBI_TYPE_DATETIME){ OCIDefineByPos(stmt, &defnp, Oconn->err, curfield+1, cols[curfield], (sword) length+1, SQLT_DAT, (dvoid *) 0, (ub2 *)0 , (ub2 *)0, OCI_DEFAULT); } else { OCIDefineByPos(stmt, &defnp, Oconn->err, curfield+1, cols[curfield], (sword) length+1, SQLT_STR, (dvoid *) 0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT); } if(length < 0 ) _set_field_flag( row, curfield, DBI_VALUE_NULL, 1); switch (result->field_types[curfield]) { case DBI_TYPE_BINARY: case DBI_TYPE_STRING: case DBI_TYPE_XDECIMAL: row->field_sizes[curfield] = length; break; default: row->field_sizes[curfield] = 0; break; } curfield++; } status = OCIStmtFetch2(stmt, Oconn->err, 1, OCI_FETCH_ABSOLUTE, rowidx+1, OCI_DEFAULT); curfield = 0; while (curfield < result->numfields) { data = &row->field_values[curfield]; switch (result->field_types[curfield]) { case DBI_TYPE_INTEGER: sizeattrib = _isolate_attrib(result->field_attribs[curfield], DBI_INTEGER_SIZE1, DBI_INTEGER_SIZE8); switch (sizeattrib) { case DBI_INTEGER_SIZE1: case DBI_INTEGER_SIZE2: case DBI_INTEGER_SIZE3: case DBI_INTEGER_SIZE4: case DBI_INTEGER_SIZE8: default: data->d_longlong = (long long) strtoll(cols[curfield],NULL,10); break; } break; case DBI_TYPE_DECIMAL: sizeattrib = _isolate_attrib(result->field_attribs[curfield], DBI_DECIMAL_SIZE4, DBI_DECIMAL_SIZE8); switch (sizeattrib) { case DBI_DECIMAL_SIZE4: case DBI_DECIMAL_SIZE8: default: data->d_double = (double) strtod(cols[curfield], NULL); //fprintf(stderr, "Double: %s:%f\n", cols[curfield], data->d_double); break; } break; case DBI_TYPE_STRING: case DBI_TYPE_XDECIMAL: slen = row->field_sizes[curfield]; data->d_string = malloc(row->field_sizes[curfield]+1); memcpy(data->d_string, cols[curfield],row->field_sizes[curfield]); data->d_string[slen] = '\0'; if (dbi_conn_get_option_numeric(result->conn, "oracle_chop_blanks") == 1) { ptr = data->d_string; if(ptr != NULL && *ptr != '\0') while(slen && ptr[slen - 1] == ' ') --slen; ptr[slen] = '\0'; /* Chop blanks */ row->field_sizes[curfield] = slen; /* alter field length */ } break; case DBI_TYPE_BINARY: data->d_string = malloc(row->field_sizes[curfield]); memcpy(data->d_string, cols[curfield],row->field_sizes[curfield]); break; case DBI_TYPE_DATETIME: _oradate_to_tm(cols[curfield], &data->d_datetimex); break; } if (cols[curfield]) free(cols[curfield]); curfield++; } } unsigned long long _oracle_query_to_longlong(dbi_conn_t *conn, const char *query) { OCIStmt *stmt = NULL; sword val = 0; OCIDefine *defnp = NULL; Oraconn *Oconn = conn->connection; OCIHandleAlloc( (dvoid *) Oconn->env, (dvoid **) &stmt, OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0); OCIStmtPrepare(stmt, Oconn->err, (char *) query, (ub4) strlen(query), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT); OCIDefineByPos(stmt, &defnp, Oconn->err, 1, (dvoid *) &val, (sword) sizeof(sword), SQLT_INT, (dvoid *) 0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT); OCIStmtExecute(Oconn->svc, stmt, Oconn->err, (ub4) 1, (ub4) 0, (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT); OCIStmtFetch(stmt, Oconn->err, (ub4) 1, (ub4) OCI_FETCH_NEXT, (ub4) OCI_DEFAULT); (void) OCIHandleFree((dvoid *) stmt, OCI_HTYPE_STMT); return (unsigned long long) (val ? val : 0); } void _checkerr(OCIError * errhp, sword status) { text errbuf[512]; /* ub4 buflen; */ ub4 errcode; switch (status) { case OCI_SUCCESS: break; case OCI_SUCCESS_WITH_INFO: (void) fprintf(stderr,"Error - OCI_SUCCESS_WITH_INFO\n"); break; case OCI_NEED_DATA: (void) fprintf(stderr, "Error - OCI_NEED_DATA\n"); break; case OCI_NO_DATA: (void) fprintf(stderr,"Error - OCI_NODATA\n"); break; case OCI_ERROR: (void) OCIErrorGet (errhp, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); (void) fprintf(stderr,"Error - %s Code: %d\n", errbuf, errcode); break; case OCI_INVALID_HANDLE: (void) fprintf(stderr,"Error - OCI_INVALID_HANDLE\n"); break; case OCI_STILL_EXECUTING: (void) fprintf(stderr,"Error - OCI_STILL_EXECUTE\n"); break; default: break; } } const char *dbd_encoding_from_iana(const char * iana_encoding ) { return iana_encoding; } const char *dbd_encoding_to_iana(const char * iana_encoding ) { return iana_encoding; } /* taken from sqlite3 driver */ size_t dbd_quote_binary (dbi_conn_t *conn, const unsigned char *orig, size_t from_length, unsigned char **ptr_dest ) { unsigned char *temp; size_t len; if ((temp = malloc(from_length * 2)) == NULL) { return 0; } strcpy(temp, "\'"); if (from_length) { len = _dbd_encode_binary(orig, from_length, temp+1); } else { len = 0; } strcat(temp, "'"); *ptr_dest = temp; return len+2; } size_t dbd_conn_quote_string (dbi_conn_t *conn, const char *orig, char *dest ) { return dbd_quote_string(conn->driver, orig, dest); } /* This function is stolen from MySQL,Sqlite3. The quoting was changed to the SQL standard, i.e. single and double quotes are escaped by doubling, not by a backslash. Newlines and carriage returns are left alone */ static size_t oracle_escape_string(char *to, const char *from, size_t length) { const char *to_start=to; const char *end; for (end=from+length; from != end ; from++) { switch (*from) { case 0: /* Must be escaped for 'mysql' */ *to++= '\\'; *to++= '0'; break; case '\'': *to++= '\''; /* double single quote */ *to++= '\''; break; case '\032': /* This gives problems on Win32 */ *to++= '\\'; *to++= 'Z'; break; default: *to++= *from; } } *to=0; return (size_t) (to-to_start); } int _oradate_to_tm(const char *obuff, dbi_datetimex *dtx) { struct tm *tmt = &dtx->tm; /* char stime[101], *cp = NULL; */ /* memset(stime, 0, sizeof(stime)); */ /* sprintf(stime, "%04d%02d%02d%02d%02d%02d", */ /* // | YYYY | */ /* (obuff[0]-100)*100 + (obuff[1]-100), */ /* // | month | day | */ /* obuff[2], obuff[3], */ /* // | HH | MM | SS | */ /* obuff[4]-1, obuff[5]-1, obuff[6]-1); */ /* cp = strptime(stime, "%Y%m%d%H%M%S", &tmt); */ memset(tmt, 0, sizeof(*tmt)); tmt->tm_sec = obuff[6]-1; tmt->tm_min = obuff[5]-1; tmt->tm_hour = obuff[4]-1; tmt->tm_mday = obuff[3]; tmt->tm_mon = obuff[2]; tmt->tm_year = (obuff[0]-100)*100 + (obuff[1]-100); return 0; }