Я могу вызвать хранимую процедуру через OCI с помощью курсора ref, а затем перебрать результаты, используя вызов OCIStmtFetch2() каждый раз. Мой вопрос в том, как я могу перебирать ряд строк, поэтому мне не нужно каждый раз вызывать OCIStmtFetch2()? Предположим, что ответ будет что-то с OCI_ATTR_PREFETCH_ROWS, но я не могу заставить это работать, поскольку доступ к файлам создается каждый раз, когда я вызываю OCIStmtExecute.
http://www.sqlines.com/oracle/oci/array_fetch работает для операторов select, но я хочу использовать его для курсора, который разбивается на мою реализацию. Извините за длину кода, но вот полная функция:
OCIError* pOciError;
OCIStmt* pOciStatement;
char* sqlCharArray = "BEGIN fxt.fxt_get_risk_trns('SOD', '29-SEP-2014', :refCursor ); END;";
OCIEnv* g_pOciEnvironment = NULL;
OCIServer* g_pOciServer = NULL;
OCISession* g_pOciSession = NULL;
OCISvcCtx* g_pOciServiceContext = NULL;
sb2* pIndicator=0;
OCIDefine* pOciDefine2;
OCIBind* pBind;
OCIStmt* cursor;
int answer = OCIEnvCreate((OCIEnv **)&g_pOciEnvironment, (ub4)OCI_THREADED ,
(void *)0, (void * (*)(void *, size_t))0,
(void * (*)(void *, void *, size_t))0,
(void (*)(void *, void *))0,
(size_t)0, (void **)0);
<snip boilerplate code>
const int prefetchSize(PREFETCH_ROWS_SIZE);
answer = OCIHandleAlloc(g_pOciEnvironment , (void **)(&pOciStatement), OCI_HTYPE_STMT, 0, NULL);
answer = OCIAttrSet(pOciStatement, OCI_HTYPE_STMT, (void*)&prefetchSize, sizeof(int), OCI_ATTR_PREFETCH_ROWS, pOciError);
answer = OCIStmtPrepare(pOciStatement, pOciError, (unsigned char *)sqlCharArray, strlen(sqlCharArray),OCI_NTV_SYNTAX, OCI_DEFAULT);
answer = OCIHandleAlloc(g_pOciEnvironment, (void **)(&cursor), OCI_HTYPE_STMT, 0, NULL);
answer = OCIBindByPos(pOciStatement, &pBind, pOciError, 1, &cursor, 0, SQLT_RSET, pIndicator, 0, NULL, 0, 0, OCI_DEFAULT);
// Fetched data indicators, lengths and codes
char dealSTSCode[PREFETCH_ROWS_SIZE][4000];
sb2 dealSTSCode_ind[PREFETCH_ROWS_SIZE];
ub2 dealSTSCode_len[PREFETCH_ROWS_SIZE], dealSTSCode_code[PREFETCH_ROWS_SIZE];
answer = OCIAttrSet(cursor, OCI_HTYPE_STMT, (void*)&prefetchSize, sizeof(int), OCI_ATTR_PREFETCH_ROWS, pOciError);
// Unhandled exception thrown here, Access violation reading location xxx
answer = OCIStmtExecute(g_pOciServiceContext, pOciStatement, pOciError, PREFETCH_ROWS_SIZE, 0, NULL, NULL, OCI_DEFAULT);
answer = OCIDefineByPos(cursor,&pOciDefine2, pOciError,6, (void*)&dealSTSCode, 4000, SQLT_STR, dealSTSCode_ind, dealSTSCode_len, dealSTSCode_code,OCI_DEFAULT);
if (answer == 0)
{
int rowsFetched = 0;
do
{
if (!OCIStmtFetch2(cursor, pOciError, 100, OCI_FETCH_NEXT,0,OCI_DEFAULT))
{
OCIAttrGet(cursor, OCI_HTYPE_STMT, (void*)&rowsFetched, NULL, OCI_ATTR_ROWS_FETCHED, pOciError);
for (int i = 0; i != rowsFetched; ++i)
{
// process row
}
}
}
while (rowsFetched > 0);
}
Я нашел решение этого. Нужно было попробовать еще несколько комбинаций звонков, но в итоге попало туда. Я исправил исходный код, чтобы отразить правильное решение.
Главное - определить атрибут prefetch rows на самом курсоре, а не указатель оператора.