I have written before about our project to record channel archive data in Oracle. Channel archive data has to do with the status of the accelerator. We just started taking data on a klystron design which gloms together eight of the amplifiers to begin to meet the power needs for the Next Linear Collider.
We have a multi-threaded OCI direct path program which works quite well under Oracle 9i, but returns a 1403 error under Oracle 8i. The respective versions are 9.0.1.3 and 8.1.6.3. If we can get this program to work, it will be used at various high -energy physics labs around the world. One of the most interested labs is BESSY, Berliner Elektronenspeicherring-Geselschaft fur Synchrotronstralung mbH. They are not ready to implement 9i yet and want us to get it running against 8i. When I say us, I mean the developers. I've written lots of C programs, but none were multithreaded and nearly all were Pro*C. There are two files involved the first sets up the environment. ------------------------------------------------------------------------------------------------------------------------ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/time.h> #include "oci.h" #include "oracle_defs.h" #include "oci_defs.h" /* #ifdef DEBUG */ GLOBAL int db_init(char *instance, ALL_OCI_HANDLES *all_oci_handles, ALL_OCI_HANDLES *thread_oci_handles) { int sts; #ifdef DEBUG fprintf(stderr, "instance = %s\n", instance); #endif memset(all_oci_handles, 0, sizeof(ALL_OCI_HANDLES)); #ifdef ORACLE_9I_OR_HIGHER sts = OCIInitialize((ub4) OCI_THREADED, (dvoid *) 0, (dvoid * (*) (dvoid *, size_t)) 0, (dvoid * (*) (dvoid *, dvoid *, size_t)) 0, (void (*)(dvoid *, dvoid *)) 0 ); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIInitialize = %d\n", sts); return(ERROR); } #else sts = OCIInitialize((ub4) OCI_OBJECT, (dvoid *) 0, (dvoid * (*) (dvoid *, size_t)) 0, (dvoid * (*) (dvoid *, dvoid *, size_t)) 0, (void (*)(dvoid *, dvoid *)) 0 ); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIInitialize = %d\n", sts); return(ERROR); } #endif sts = OCIEnvInit( (OCIEnv **) &all_oci_handles->EnvH, OCI_DEFAULT, (size_t) 0, (dvoid **) 0 ); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIEnvInit = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIEnvInit( (OCIEnv **) &thread_oci_handles->EnvH, OCI_DEFAULT, (size_t) 0, (dvoid **) 0 ); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIEnvInit = %d\n", sts); return(ERROR); } #endif sts = OCIHandleAlloc( (dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->ErrH, OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #1 = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIHandleAlloc( (dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->ErrH, OCI_HTYPE_ERROR, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #1 = %d\n", sts); return(ERROR); } #endif /* Server contexts. ------------------- */ sts = OCIHandleAlloc( (dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->SrvH, OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #2 = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIHandleAlloc( (dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->SrvH, OCI_HTYPE_SERVER, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #2 = %d\n", sts); return(ERROR); } #endif sts = OCIHandleAlloc( (dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->SvcH, OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #3 = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIHandleAlloc( (dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->SvcH, OCI_HTYPE_SVCCTX, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #3 = %d\n", sts); return(ERROR); } #endif sts = OCIServerAttach(all_oci_handles->SrvH, all_oci_handles->ErrH, (text *)instance, strlen(instance), 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIServerAttach = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIServerAttach(thread_oci_handles->SrvH, thread_oci_handles->ErrH, (text *)instance, strlen(instance), 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIServerAttach = %d\n", sts); return(ERROR); } #endif /* Set attribute context in the service context. ------------------------------------------------ */ sts = OCIAttrSet( (dvoid *) all_oci_handles->SvcH, OCI_HTYPE_SVCCTX, (dvoid *) all_oci_handles->SrvH, (ub4) 0, OCI_ATTR_SERVER, (OCIError *) all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIAttrSet( (dvoid *) thread_oci_handles->SvcH, OCI_HTYPE_SVCCTX, (dvoid *) thread_oci_handles->SrvH, (ub4) 0, OCI_ATTR_SERVER, (OCIError *) thread_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet = %d\n", sts); return(ERROR); } #endif sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->SesH, (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #4 = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIHandleAlloc((dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->SesH, (ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #4 = %d\n", sts); return(ERROR); } #endif sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->SelectStmt, (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #5 = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIHandleAlloc((dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->SelectStmt, (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #5 = %d\n", sts); return(ERROR); } #endif sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->InsertStmt, (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #6 = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIHandleAlloc((dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->InsertStmt, (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #6 = %d\n", sts); return(ERROR); } #endif sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->UpdateStmt, (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #6 = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIHandleAlloc((dvoid *) thread_oci_handles->EnvH, (dvoid **) &thread_oci_handles->UpdateStmt, (ub4) OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #6 = %d\n", sts); return(ERROR); } #endif return(SUCCESS); } --------------------------------------------------------------------------------------------------------------------------- Note the different calls to OCIInitialize. If we use OCI_THREADED instead of OCI_OBJECT the 8.1.6 database it leads to trouble. =========================================================================================================================== Here is the program which does the work --------------------------------------------------------------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/time.h> #include "oci.h" #include "oracle_defs.h" #include "oci_defs.h" GLOBAL int float_table_init(ALL_OCI_HANDLES *all_oci_handles, int direct_path_buf_rows) { int sts; int i; int pos; int stat; char float_table_name[] = "arch_data_f"; char float_table_schema_name[] = ""; char float_table_col_names[FLOAT_TABLE_NCOL_TBL][MAX_NAME_COL_LEN + 1] = {"pv_id", "value", "timestamp", "nanosecs", "stat", "sevr", "ostat"}; int float_table_col_exttyp[FLOAT_TABLE_NCOL_TBL] = {SQLT_INT, SQLT_FLT, SQLT_DAT, SQLT_INT, SQLT_INT, SQLT_INT, SQLT_INT}; int float_table_maxlen_fld[FLOAT_TABLE_NCOL_TBL] = {38, 15, 7, 9, 8, 8, 16}; int float_table_precision[FLOAT_TABLE_NCOL_TBL] = {38, 15, 0, 9, 8, 8, 16}; int float_table_scale[FLOAT_TABLE_NCOL_TBL] = {0, 5, 0, 0, 0, 0, 0}; TABLE_INFO float_table_info; COL_INFO *colp; FLD_INFO *fldp; OCIParam *colDesc; ub2 num_cols; ub2 exttyp_col; ub2 csid_col; ub1 prec_col; sb1 scale_col; ub4 maxlen_fld; ub4 buf_size = 300000; ub4 num_rows; text Error[512]; sb4 ErrorCode; /***Logic begins */ num_rows = direct_path_buf_rows; /* Step 1 (performing the OCI initialization) has been done previously. Step 2 is to allocate a direct path context handle and set the attributes. ------------------------------------------------------------------------ */ sts = OCIHandleAlloc((dvoid *) all_oci_handles->EnvH, (dvoid **) &all_oci_handles->FloatTableDirPathCtxH, (ub4) OCI_HTYPE_DIRPATH_CTX, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #1 = %d\n", sts); OCIErrorGet(all_oci_handles->ErrH, (ub4) 1, (text *) NULL, &ErrorCode, Error, (ub4) sizeof(Error), OCI_HTYPE_ERROR); fprintf(stderr, "Error: %s\n", Error); return(ERROR); } sts = OCIAttrSet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (ub4) OCI_HTYPE_DIRPATH_CTX, (dvoid *) &buf_size, (ub4) 0, (ub4) OCI_ATTR_BUF_SIZE, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #1 = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIAttrSet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (ub4) OCI_HTYPE_DIRPATH_CTX, (dvoid *) &num_rows, (ub4) 0, (ub4) OCI_ATTR_NUM_ROWS, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #2 = %d\n", sts); OCIErrorGet(all_oci_handles->ErrH, (ub4) 1, (text *) NULL, &ErrorCode, Error, (ub4) sizeof(Error), OCI_HTYPE_ERROR); fprintf(stderr, "Error: %s\n", Error); return(ERROR); } #endif /* Fill in the float_table_info data structure, which describes the table to be loaded using the direct path API. This data structure includes information about each column of the table. --------------------------------------------------------------------- */ strcpy(float_table_info.name_tbl, float_table_name); float_table_info.ncol_tbl = FLOAT_TABLE_NCOL_TBL; float_table_info.col_tbl = (COL_INFO *) malloc(FLOAT_TABLE_NCOL_TBL * sizeof(COL_INFO)); if (float_table_info.col_tbl == NULL) { fprintf(stderr, "Unable to allocate float_table_info.col_tbl\n"); return(ERROR); } float_table_info.fld_tbl = (FLD_INFO *) malloc(FLOAT_TABLE_NCOL_TBL * sizeof(FLD_INFO)); if (float_table_info.fld_tbl == NULL) { fprintf(stderr, "Unable to allocate float_table_info.fld_tbl\n"); return(ERROR); } for (i = 0, colp = float_table_info.col_tbl, fldp = float_table_info.fld_tbl; i < FLOAT_TABLE_NCOL_TBL; i++, colp++, fldp++) { colp->id_col = 0; strcpy(colp->name_col, float_table_col_names[i]); colp->exttyp_col = float_table_col_exttyp[i]; strcpy(colp->datemask_col, ""); colp->prec_col = float_table_precision[i]; colp->scale_col = float_table_scale[i]; colp->csid_col = 0; fldp->maxlen_fld = float_table_maxlen_fld[i]; } /* Step 3 is to supply the name of the object (in this case, the name of a table) to be loaded. ---------------------------------------------------------------- */ sts = OCIAttrSet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (ub4) OCI_HTYPE_DIRPATH_CTX, (dvoid *) float_table_name, (ub4) strlen((const char *) float_table_name), (ub4) OCI_ATTR_NAME, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #3 = %d\n", sts); return(ERROR); } #ifdef ORACLE_9I_OR_HIGHER sts = OCIAttrSet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (ub4) OCI_HTYPE_DIRPATH_CTX, (dvoid *) float_table_schema_name, (ub4) strlen((const char *) float_table_schema_name), (ub4) OCI_ATTR_SCHEMA_NAME, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #4 = %d\n", sts); return(ERROR); } #endif /* Step 4 is to describe the external data types of the table columns. ---------------------------------------------------------------------- */ num_cols = (ub2) float_table_info.ncol_tbl; sts = OCIAttrSet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (ub4) OCI_HTYPE_DIRPATH_CTX, (void *) &num_cols, (ub4) 0, (ub4) OCI_ATTR_NUM_COLS, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #5 = %d\n", sts); return(ERROR); } sts = OCIAttrGet((dvoid *) all_oci_handles->FloatTableDirPathCtxH, OCI_HTYPE_DIRPATH_CTX, (dvoid *) &all_oci_handles->FloatTableColLstDesc, (ub4 *) 0, OCI_ATTR_LIST_COLUMNS, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrGet #1 = %d\n", sts); return(ERROR); } for (i = 0, pos = 1, colp = float_table_info.col_tbl, fldp = float_table_info.fld_tbl; i < FLOAT_TABLE_NCOL_TBL; i++, pos++, colp++, fldp++) { sts = OCIParamGet((dvoid *) all_oci_handles->FloatTableColLstDesc, (ub4) OCI_DTYPE_PARAM, (dvoid *) all_oci_handles->ErrH, (dvoid **) &colDesc, pos); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIParamGet = %d\n", sts); return(ERROR); } colp->id_col = i; sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM, (dvoid *) colp->name_col, (ub4) strlen((const char *)colp->name_col), (ub4) OCI_ATTR_NAME, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #6 = %d\n", sts); return(ERROR); } exttyp_col = (ub2) colp->exttyp_col; sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM, (dvoid *) &exttyp_col, (ub4) 0, (ub4) OCI_ATTR_DATA_TYPE, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #7 = %d\n", sts); return(ERROR); } maxlen_fld = (ub4) fldp->maxlen_fld; sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM, (dvoid *) &maxlen_fld, (ub4) 0, (ub4) OCI_ATTR_DATA_SIZE, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #8 = %d\n", sts); return(ERROR); } if (strlen(colp->datemask_col) > 0) { sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM, (dvoid *) colp->datemask_col, (ub4) strlen((const char *) colp->datemask_col), (ub4) OCI_ATTR_DATEFORMAT, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #9 = %d\n", sts); return(ERROR); } } if (colp->prec_col) { prec_col = (ub1) colp->prec_col; sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM, (dvoid *) &prec_col, (ub4) 0, (ub4) OCI_ATTR_PRECISION, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #10 = %d\n", sts); return(ERROR); } } if (colp->scale_col) { scale_col = (sb1) colp->scale_col; sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM, (dvoid *) &scale_col, (ub4) 0, (ub4) OCI_ATTR_SCALE, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #11 = %d\n", sts); return(ERROR); } } if (colp->csid_col) { csid_col = (ub2) colp->csid_col; sts = OCIAttrSet((dvoid *) colDesc, (ub4) OCI_DTYPE_PARAM, (dvoid *) &csid_col, (ub4) 0, (ub4) OCI_ATTR_CHARSET_ID, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrSet #12 = %d\n", sts); return(ERROR); } } sts = OCIDescriptorFree((dvoid *) colDesc, OCI_DTYPE_PARAM); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIDescriptorFree = %d\n", sts); return(ERROR); } } free(float_table_info.col_tbl); free(float_table_info.fld_tbl); #ifdef ORACLE_9I_OR_HIGHER sts = lock_table(all_oci_handles, float_table_name); if (sts != SUCCESS) { fprintf(stderr, "error return from lock_table\n"); return(sts); } #endif /* Step 5 is to prepare the direct path interface. -------------------------------------------------- */ sts = OCIDirPathPrepare(all_oci_handles->FloatTableDirPathCtxH, all_oci_handles->SvcH, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIDirPathPrepare = %d\n", sts); OCIErrorGet(all_oci_handles->ErrH, (ub4) 1, (text *) NULL, &ErrorCode, Error, (ub4) sizeof(Error), OCI_HTYPE_ERROR); fprintf(stderr, "Error: %s\n", Error); /***TESTING return(ERROR); */ exit(0); } sts = commit_trans(all_oci_handles); if (sts != SUCCESS) { fprintf(stderr, "error return from commit_trans\n"); return(sts); } /* Step 6 is to allocate a column array. ---------------------------------------- */ sts = OCIHandleAlloc((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (dvoid **) &all_oci_handles->FloatTableColArrayH, (ub4) OCI_HTYPE_DIRPATH_COLUMN_ARRAY, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #2 = %d\n", sts); return(ERROR); } /* Step 7 is to allocate a direct path stream. ---------------------------------------------- */ sts = OCIHandleAlloc((dvoid *) all_oci_handles->FloatTableDirPathCtxH, (dvoid **) &all_oci_handles->FloatTableDirPathStreamH, (ub4) OCI_HTYPE_DIRPATH_STREAM, (size_t) 0, (dvoid **) 0); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIHandleAlloc #3 = %d\n", sts); return(ERROR); } /* Get the number of rows and columns in the column array just allocated. ------------------------------------------------------------------------- */ sts = OCIAttrGet(all_oci_handles->FloatTableColArrayH, (ub4) OCI_HTYPE_DIRPATH_COLUMN_ARRAY, &all_oci_handles->FloatTableNumRows, 0, OCI_ATTR_NUM_ROWS, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrGet #2 = %d\n", sts); return(ERROR); } sts = OCIAttrGet(all_oci_handles->FloatTableColArrayH, (ub4) OCI_HTYPE_DIRPATH_COLUMN_ARRAY, &all_oci_handles->FloatTableNumCols, 0, OCI_ATTR_NUM_COLS, all_oci_handles->ErrH); if (sts != SUCCESS) { fprintf(stderr, "Error returned from OCIAttrGet #3 = %d\n", sts); return(ERROR); } #ifdef DEBUG fprintf(stderr, "FloatTableNumRows = %d\n", all_oci_handles->FloatTableNumRows); fprintf(stderr, "FloatTableNumCols = %d\n", all_oci_handles->FloatTableNumCols); #endif return(SUCCESS); } ----------------------------------------------------------------------------------------------------------------------- The program has the main thread doing direct path inserts and some DML operations while a second thread using another connection does some updates. As I said it works well in 9i, but if we multithread the 8i version a 1403 error occurs on the call to OCIHANDLEALLOC with the argument OCI_HTYPE_DIRPATH_CTX ------------------------------------------------------------------------------------------------------------------------- I imagine we are on the hemorrhaging edge doing this with 8i. Is anybody doing anything similar. Have you been successful with 8i. If so what version. I tried to relate the problem to an OCI bug, but was could not. If it would run under the latest 8.1.7 release, that might be acceptable to the folks in Germany. To be fair it ain't the Germans that are insistent, but the project leader here. Ian MacGregor Stanford Linear Accelerator Center ian@SLAC -- Please see the official ORACLE-L FAQ: http://www.orafaq.com -- Author: MacGregor, Ian A. INET: [EMAIL PROTECTED] Fat City Network Services -- (858) 538-5051 FAX: (858) 538-5051 San Diego, California -- Public Internet access / Mailing Lists -------------------------------------------------------------------- To REMOVE yourself from this mailing list, send an E-Mail message to: [EMAIL PROTECTED] (note EXACT spelling of 'ListGuru') and in the message BODY, include a line containing: UNSUB ORACLE-L (or the name of mailing list you want to be removed from). You may also send the HELP command for other information (like subscribing).