📄 orafns.c
字号:
append_oci_error(db->errmsg, db->err); return db->success = 0; } /* Set pre-fetch rows to some very large value. Oracle will clamp this down automatically to what will fit in PREFETCH_MEMORY. It's not documented if that would be what happens if we set PREFETCH_MEMORY to some buffer size, but left PREFETCH_ROWS at, say, zero -- a reasonable convenction for "use as much as in PREFETCH_MEMORY". Oracle seems to behave that way, but don't rely on it. The "clamp down" behavior is documented. */ attval = 1000000; status = OCIAttrSet(db->stmt, OCI_HTYPE_STMT, &attval, 0, OCI_ATTR_PREFETCH_ROWS, db->err); if ( status != OCI_SUCCESS ) { sprintf(db->errmsg, "Error settgin prefetch row count:\n"); append_oci_error(db->errmsg, db->err); return db->success = 0; } /* Connected successfully */ return db->success = 1;}/* ------------------------------------------------------------------------------------------------------------- *//* Get a parameter attribute, checking errors */static int get_param_attr(CONST dvoid * param, int ncol, struct db_conn * db, dvoid * attrib, ub4 * sizep, char *prompt, ub4 attrtype){ sb4 attr_status = OCI_SUCCESS; attr_status = OCIAttrGet((dvoid *) param, OCI_DTYPE_PARAM, attrib, sizep, attrtype, db->err); if ( attr_status != OCI_SUCCESS ) { /* Error getting param info */ sprintf(db->errmsg, "Error getting column %s for col %d:\n", prompt, ncol); append_oci_error(db->errmsg, db->err); return db->success = 0; } /* Success */ return db->success = 1;}/* ------------------------------------------------------------------------------------------------------------- *//* Append Oracle error to our specific error */static void append_oci_error(char *errbuf, OCIError * err){ sword status = 0; char *dummy = 0; sb4 errcode = 0; char buf[50000]; /* If Oracle message begins with this, it means we cannot locate error messages. Probably issue with ORACLE_HOME */ /* Hack: this is highly language dependent */ char * leading = "Error while trying to retrieve text for error"; status = OCIErrorGet(err, 1, dummy, &errcode, buf, sizeof buf, OCI_HTYPE_ERROR); if ( status ) return; /* Append Oracle error */ strcat(errbuf, buf); /* See if having trouble getting error text */ if ( 0 == strncmp(buf, leading, strlen(leading)) ) { char reason[1000]; char * home = getenv("ORACLE_HOME"); if ( ! home ) strcpy(reason, "ORACLE_HOME is not set."); else if ( ! *home ) strcpy(reason, "ORACLE_HOME is set to the empty string."); else sprintf(reason, "ORACLE_HOME value '%s' is possibly not valid.", home); strcat(errbuf, "Cannot get Oracle error message text. Check ORACLE_HOME environment variable.\n"); strcat(errbuf, reason); }}/* ------------------------------------------------------------------------------------------------------------- *//* Decode data type code */static char * decode_data_type(int dtype) { static char buf[100]; switch (dtype) { case 1: return "VARCHAR2"; case 2: return "NUMBER"; case 3: return "INTEGER"; case 4: return "FLOAT"; case 8: return "LONG"; case 11: return "ROWID"; case 12: return "DATE"; case 23: return "RAW"; case 24: return "LONG RAW"; case 96: return "CHAR"; case 104: return "ROWID DESC"; case 105: return "MLSLABEL"; case 108: return "User defined"; case 111: return "REF"; case 112: return "CLOB"; case 113: return "BLOB"; } sprintf("<Unknown type %d>", buf); return buf;}/* Get appropriate length for fetch into on output define variable */static int fetch_data_len(int dtype, int dlen){ static char buf[100]; /* We get everything as a string (SQLT_STR). So for numbers, use the largest buffer that would ever be used by an Oracle number, for dates a reasonable limit for formatted dates (e.g., "Wednesday, November 23, 2005") and for chars, just that length, plus one for the null terminator. With all this, we should not be getting Oracle truncation due to deficiencies in our buffer size (i.e., our buffer should always accomodate the Oracle data). */ switch (dtype) { case 1: /* VARCHAR2 */ case 96: /* CHAR */ return dlen + 1; case 2: /* NUMBER */ case 3: /* INTEGER */ case 4: /* FLOAT */ return 50; case 8: /* LONG */ return 70000; case 12: /* DATE */ return 50; } return SQLT_STR;}/* ------------------------------------------------------------------------------------------------------------- *//* Free contents of a column */static void free_column(struct column * c){ free_if_non_null(c->name); free_if_non_null(c->data); if ( c->def ) OCIHandleFree(c->def, OCI_HTYPE_DEFINE);}/* ------------------------------------------------------------------------------------------------------------- */static void free_if_non_null(void *p) { if ( p ) free(p); }/* ------------------------------------------------------------------------------------------------------------- */static int disconnect(struct db_conn * db){ if ( ! db ) return 0; free_columns(db); /* This should cause Oracle to free up all other handles created under it */ if ( db->env ) OCIHandleFree(db->env, OCI_HTYPE_ENV); free_if_non_null(db->user); free_if_non_null(db->schema); free_if_non_null(db->sid); free_if_non_null(db->sql); free_if_non_null(db->errmsg); reset_db_conn(db); return db->success = 1;}/* ------------------------------------------------------------------------------------------------------------- *//* Free column info */static void free_columns(struct db_conn * db){ int i; /* Clear out internal column struct */ if ( db->columns ) { for ( i=0; i < db->ncol; i++ ) free_column(&db->columns[i]); free(db->columns); db->columns = 0; } /* Free externally visible row and column structures */ if ( db->sqlcols ) { for ( i=0; i < db->ncol; i++ ) free_if_non_null(db->sqlcols[i]); free(db->sqlcols); db->sqlcols = 0; } if ( db->currow ) { for ( i=0; i < db->ncol; i++ ) free_if_non_null(db->currow[i]); free(db->currow); db->currow = 0; }}/* Reset a db_conn struct */static void reset_db_conn(struct db_conn * db){ db->env = 0; db->err = 0; db->svc = 0; db->prefetch_bytes = -1; db->auto_commit = 1; db->stmt = 0; db->sql = 0; db->is_command = 0; db->params = 0; db->nparam = 0; db->columns = 0; db->sqlcols = 0; db->currow = 0; db->ncol = 0; db->rows_affected = 0; db->eof = 0; db->success = 0; db->errmsg = 0;}/* ------------------------------------------------------------------------------------------------------------- *//* Do checks prior to operations that are relevant only for an active SQL statement */static int check_active_statement(struct db_conn * db, char * action){ /* Clear out results */ *db->errmsg = '\0'; db->success = 0; /* Make sure we have a connection, and an active SQL statement */ if ( ! db->env || ! db->svc ) { sprintf(db->errmsg, "Attempt to %s while not connected.\n", action); return 0; } else if ( ! db->stmt ) { sprintf(db->errmsg, "Attempt to %s before SQL statement executed.\n", action); return 0; } return 1;}/* Do checks prior to operations that are relevant only for SELECT query */static int check_active_select(struct db_conn * db, char * action){ /* First check active SQL */ if ( ! check_active_statement(db, action) ) return 0; else if ( db->is_command ) { sprintf(db->errmsg, "Attempt to %s on non-SELECT SQL statement:\n%s\n", action, db->sql); return 0; } /* If have statement, but not column info, probably had an invalid statement or other error. */ else if ( ! db->sqlcols ) { sprintf(db->errmsg, "Attempt to %s on invalid SQL statement:\n%s\n", action, db->sql); return 0; } return 1;}/* ------------------------------------------------------------------------------------------------------------- *//* Get number of columns in SELECT query, or zero if error. */static int ncol(struct db_conn * db){ if ( ! check_active_select(db, "get number of SELECT columns") ) return 0; return db->ncol;}/* Get EOF status of SELECT query */static int eof(struct db_conn * db){ /* Make sure have an active SELECT */ if ( ! check_active_select(db, "get fetch EOF status") ) return db->success = 0; /* Make sure did a fetch and have db->currow */ if ( ! db->currow ) { sprintf(db->errmsg, "Attempt to get EOF status before first fetch.\n"); return db->success = 0; } db->success = 1; return db->eof;}/* Get success status of last operation */static int success(struct db_conn * db){ return db->success;}/* Get column info for SELECT result */static struct sqlcol ** column_info(struct db_conn * db){ if ( ! check_active_select(db, "get column info for SELECT results") ) return 0; db->success = 1; return db->sqlcols;}/* Get row values for most recent fetch */static struct sqlval ** row_values(struct db_conn * db){ int n; /* Make sure have an active SELECT */ if ( ! check_active_select(db, "get row values for SELECT results") ) { db->success = 0; return 0; } /* Make sure did a fetch and have db->currow */ if ( ! db->currow ) { sprintf(db->errmsg, "Attempt to get row values before first fetch.\n"); db->success = 0; return 0; } /* Make sure not at EOF */ if ( db->eof ) { sprintf(db->errmsg, "Attempt to get row values at EOF.\n"); db->success = 0; return 0; } /* printf("\n"); for (n=0; n < db->ncol; n++) { if ( db->currow[n]->is_null ) printf("sqlval[%d]->data is NULL\n", n); else printf("sqlval[%d]->data is '%s'\n", n, db->currow[n]->data); } printf("terminator is '%d'\n", db->currow[n]); */ db->success = 1; return db->currow;}/* Get no. of rows affected (no. insert/update/delete, or no. fetched so far) */static int rows_affected(struct db_conn * db){ /* Make sure have an active SELECT */ if ( ! check_active_statement(db, "get number of affected rows") ) return db->success = 0; db->success = 1; return db->rows_affected;}/* Set auto_commit flag (returns what it was before) */static int set_auto_commit(struct db_conn * db, int auto_commit){ int old_value = db->auto_commit; db->auto_commit = auto_commit; return old_value;}/* Is string NULL empty? */static int empty(char * s) { return !s || !*s; }/* Map NULL to empty string */static char * valid_string(char * s) { return s ? s : ""; }/* ------------------------------------------------------------------------------------------------------------- *//* Wrapper routines - these are part of the "void *" based interface that are straight-through calls to the equivalent routines in this module. More functions (e.g., to get column info and data) are implemented in the interface module.*/void * oracle_connect(char * user, char * schema, char * password, char * sid, int prefetch_bytes, int auto_commit){ return (void *) connect(user, schema, password, sid, prefetch_bytes, auto_commit); }int oracle_disconnect(void * db){ return disconnect((struct db_conn *) db); }int oracle_exec_sql(void * db, char * sql, struct sqlparam ** params, int is_command){ return exec_sql((struct db_conn *) db, sql, params, is_command); }int oracle_fetch_row(void * db){ return fetch_row((struct db_conn *) db); }int oracle_ncol(void * db){ return ncol((struct db_conn *) db); }int oracle_eof(void * db){ return eof((struct db_conn *) db); }int oracle_success(void * db){ return success((struct db_conn *) db); }struct sqlcol ** oracle_column_info(void * db){ return column_info((struct db_conn *) db); }struct sqlval ** oracle_row_values(void * db){ return row_values((struct db_conn *) db); }int oracle_rows_affected(void * db){ return rows_affected((struct db_conn *) db); }int oracle_commit(void * db){ return commit((struct db_conn *) db); }int oracle_rollback(void * db){ return rollback((struct db_conn *) db); }int oracle_set_auto_commit(void * db, int auto_commit){ return set_auto_commit((struct db_conn *) db, auto_commit); }/* ------------------------------------------------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -