Test Code: In the code below, each event may be comprised of different number of segments(details). Each event is a row in the "events" table and the details are stored in the blob column. In real life, we may have upto 100 details per event. Table Structure --------------- create table events ( event_id integer NOT NULL, start_time date NULL, end_time date NULL, details blob NULL, PRIMARY KEY (event_id) ); /******************* TEST C Code Begin ***************/ typedef struct mDetailRec { long lDetailID; long lStart; long lEnd; short shType; } mDETAILREC; typedef struct EventRec { ub4 lEventID; OCIDate pEventStart; OCIDate pEventEnd; mDETAILREC *pDetRec; } EVENTREC; #define MAX_BATCH_COUNT 1000 #define MAX_DETAIL_SIZE 100 static int GetNextEvent( int i, EVENTREC *pEventRec ); static int FillDetailArray( int i, long lEventID, mDETAILREC *hDetRecList, int nMaxSize); // The Main Function int SaveEventDetails() { OCISvcCtx *pSvch = NULL; OCIStmt *pStmt; char zSQL[1024]; EVENTREC hEventRec; EVENTREC pEventArray[MAX_BATCH_COUNT]; OCIBind *aDef[4]; ub4 MaxBlobLen; int DetCount=0; ub4 i=0, j=0, byte_amt=0; mDETAILREC hDetRecList[MAX_DETAIL_SIZE]; ub2 rcode=0; dvoid *hdlptr = (dvoid *) 0; ub4 hdltype = OCI_HTYPE_BIND, iter=0, idx=0; ub1 piece = OCI_ONE_PIECE; ub1 in_out = 0; sb2 indptr = 0; int RetCode = TRUE; MaxBlobLen = sizeof(DETAILREC) * MAX_DETAIL_SIZE; checkerr(errhp, OCISessionGet(envhp, errhp, &pSvch, pAuth, zdbConnStr, strlen(zdbConnStr), NULL, 0, NULL, NULL, NULL, OCI_DEFAULT)); strcpy( zSQL, "UPDATE events " "SET start_time = :1, end_time = :2, details = :3 " "WHERE event_id = :4" ); // Initialize pointers for ( i = 0; i < MAX_BATCH_COUNT; i++ ) pEventArray[i].pDetRec = hDetRecList; checkerr(errhp, OCISessionGet(envhp, errhp, &pSvch, pAuth, zdbConnStr, strlen(zdbConnStr), NULL, 0, NULL, NULL, NULL, OCI_DEFAULT)); checkerr(errhp, OCIStmtPrepare2(pSvch, &pStmt, errhp, (const OraText *) zSQL, strlen(zSQL), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT)); if ( !checkerr(errhp, OCIBindByPos(pStmt, &aDef[0], errhp, 1, (void *) &pEventArray[0].pEventStart, (sb4)sizeof(pEventArray[0].pEventStart), SQLT_ODT, 0, 0, 0, 0, 0, OCI_DEFAULT)) || !checkerr(errhp, OCIBindByPos(pStmt, &aDef[1], errhp, 2, (void *) &pEventArray[0].pEventEnd, (sb4)sizeof(pEventArray[0].pEventEnd), SQLT_ODT, 0, 0, 0, 0, 0, OCI_DEFAULT)) || !checkerr(errhp, OCIBindByPos(pStmt, &aDef[2], errhp, 3, (void *) pEventArray[0].pDetRec, (sb4)MaxBlobLen, SQLT_BIN, (void*)NULL,(ub2*)0, 0, 0, 0, (ub4) OCI_DATA_AT_EXEC)) || !checkerr(errhp, OCIBindByPos(pStmt, &aDef[3], errhp, 4, (dvoid *) &pEventArray[0].lEventID, (sb4)sizeof(pEventArray[0].lEventID), SQLT_INT, 0, 0, 0, 0, 0, OCI_DEFAULT)) ) { RetCode = FALSE; goto CleanUp; } for (j = 0; j < 4 ; j++) { checkerr(errhp, OCIBindArrayOfStruct(aDef[j], errhp, sizeof(pEventArray[0]), 0, 0, 0)); } // Fill event array with data for ( i = 0; i < MAX_BATCH_COUNT; i++ ) { // Fill Event Headers without the details GetNextEvent( i, &pEventArray[i] ); } i = 0; while (1) { RetCode = OCIStmtExecute( pSvch, pStmt, errhp, MAX_BATCH_COUNT, 0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT ); if ( RetCode != OCI_NEED_DATA) break; // Go Fill the details array for the next event DetCount = 0L; DetCount = FillDetailArray( i, pEventArray[i].lEventID, hDetRecList, MAX_DETAIL_SIZE ); byte_amt = sizeof(mDETAILREC) * DetCount; // Flush the details to the table if (!checkerr(errhp, OCIStmtGetPieceInfo( pStmt, errhp, &hdlptr, &hdltype, &in_out, &iter, &idx, &piece ) )) { RetCode = FALSE; goto CleanUp; } if (!checkerr(errhp, OCIStmtSetPieceInfo( (dvoid *)hdlptr, (ub4)hdltype, errhp, (dvoid *)hDetRecList, &byte_amt, OCI_ONE_PIECE, &indptr, &rcode))) { RetCode = FALSE; goto CleanUp; } i++; } CleanUp: checkerr(errhp, OCIStmtRelease(pStmt,errhp, (OraText *) NULL, 0, OCI_DEFAULT)); checkerr(errhp, OCISessionRelease( pSvch, errhp, NULL, 0, OCI_DEFAULT)); return RetCode; } static int GetNextEvent( int i, EVENTREC *pEventRec ) { pEventRec->lEventID = i; SetDateTime_OCI( 20081002, 1340, &pEventRec->pEventStart ); SetDateTime_OCI( 20081102, 2240, &pEventRec->pEventEnd ); return TRUE; } static int FillDetailArray( int i, long lEventID, mDETAILREC *hDetRecList, int nMaxSize) { int j, k; j = i % 10 + 1; for ( k = 0; k < j; k++ ) { (hDetRecList+k)->lDetailID = i; (hDetRecList+k)->lStart = 1000 + i; (hDetRecList+k)->lEnd = 1000 + i + 10; (hDetRecList+k)->shType = j; } return j; } /******************* TEST C Code End ***************/