Все оказалось достаточно просто, но много времени ушло на отладку и поиск одной ошибки.
Рабочий код практически описан в документации в OCI в разделе 6 про describe, там в конце пример. Там показывается как из OCIStmt (в нем так же хранится и курсор) получить информацию о том что там за поля и какого они типа и размера. После этого уже можно автоматизировать defineByPos (с помощью абстрацкии типа Field) и делать fetch, чтобы получать данные.
Т.е. сделали запрос, пробежались по курсора добавили в список поля с необходимыми типами данных, именем и размером, сделали define by pos по этому списку, ну а программист по имени поля в курсоре получает его значение, через какую-нибудь абстракцию.
Пример (используется функция принимающая 1 параметр и возращающая курсор) :
Код | #include <stdio.h> #include <string.h> #include <oci.h> #include <stdlib.h>
char* pConnectChar = "SYSDB_mydomen.ru"; char* pUsernameChar = "test"; char* pPasswordChar = "test"; char* sqlCharArray1 = "BEGIN MYPKG.PK_TEST.TEST_CURSOR(:ParamIntIN, :Cursor); END;";
int retval; ub4 parmcnt=0; ub4 pos2=0; text *pcoln[20]; ub4 namelen[20]; char state_key[5]; OCIStmt* pOciStatement; OCIStmt* pOciStatCursor; OCIError* pOciError; OCIEnv* pOciEnviron; OCIServer* pOciServer; OCISession* pOciSession; OCISvcCtx* pOciServiceContext; OCIBind* pOciBind[500]; OCIParam* pOciParam;
int main() { int paramInt = 0;
retval = OCIEnvCreate(&pOciEnviron, OCI_DEFAULT, NULL, NULL, NULL, NULL,0,NULL); retval = OCIEnvInit(&pOciEnviron, OCI_DEFAULT, 0, NULL); retval = OCIHandleAlloc(pOciEnviron, (void **)&pOciError, OCI_HTYPE_ERROR, 0, NULL); retval = OCIHandleAlloc(pOciEnviron, (void **)&pOciServiceContext, OCI_HTYPE_SVCCTX, 0, NULL); retval = OCIHandleAlloc(pOciEnviron, (void **)&pOciStatement, OCI_HTYPE_STMT, 0, NULL); retval = OCIHandleAlloc ((dvoid *)pOciEnviron, (dvoid **)&pOciServer, OCI_HTYPE_SERVER, 0, (dvoid **) 0); retval = OCILogon(pOciEnviron,pOciError,&pOciServiceContext,(unsigned char *)pUsernameChar, strlen(pUsernameChar), (unsigned char *)pPasswordChar, strlen(pPasswordChar), (unsigned char *)pConnectChar,strlen(pConnectChar)); printf("OCILogon retval=%d\n",retval);
retval = OCIStmtPrepare(pOciStatement, pOciError, (unsigned char *)sqlCharArray1,strlen(sqlCharArray1), OCI_NTV_SYNTAX, OCI_DEFAULT); printf("StmtPrepare retval=%d\n",retval); retval = OCIHandleAlloc(pOciEnviron, (void **)&pOciStatCursor, OCI_HTYPE_STMT, 0, NULL); retval = OCIBindByName(pOciStatement,&pOciBind[0], pOciError, (text*)"ParamIntIN", strlen("ParamIntIN"),(void *)¶mInt, (sb4) sizeof(int), SQLT_INT, (void *) 0, (ub2 *) 0, (ub2 *)0,(ub4)0, (ub4 *)0, (ub4) OCI_DEFAULT); printf("BindByName ParamIntIN OCI_HTYPE_STMT retval=%d\n",retval);
retval = OCIBindByName(pOciStatement,&pOciBind[1], pOciError, (text*)"Cursor", strlen("Cursor"), (void *)&pOciStatCursor, (sb4) 0, SQLT_RSET, (void *) 0, (ub2 *) 0, (ub2 *)0,(ub4)0, (ub4 *)0, (ub4) OCI_DEFAULT); printf("BindByName Cursor OCI_HTYPE_STMT retval=%d\n",retval); retval = OCIStmtExecute(pOciServiceContext, pOciStatement, pOciError, (ub4)1, (ub4) 0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, (ub4) OCI_DEFAULT); OCIHandleFree((void*)pOciStatement, OCI_HTYPE_STMT);
printf("StmtExecute retval=%d\n",retval); /* How to get the values of the cursor? */ /* Get number of parameters of the Cursor */ OCIAttrGet((void *) pOciStatCursor, (ub4)OCI_HTYPE_STMT, (void*) &parmcnt,(ub4 *) 0, (ub4)OCI_ATTR_PARAM_COUNT, pOciError);
printf("\nNumber of parameters of the cursor = %d\n",parmcnt); for (int pos = 1; pos <= (int)parmcnt; pos++) { OCIAttrGet((void *) pOciStatCursor, (ub4)OCI_HTYPE_STMT, (void*) &pos2,(ub4 *) 0, (ub4)OCI_ATTR_CURRENT_POSITION, pOciError); retval = OCIParamGet((void *)pOciStatCursor, (ub4)OCI_HTYPE_STMT, pOciError, (void **)&pOciParam, (ub4) pos ); OCIAttrGet((void*) pOciParam, (ub4) OCI_DTYPE_PARAM,(void*) &pcoln[pos-1],(ub4 *) &namelen[pos-1], (ub4) OCI_ATTR_NAME,(OCIError *)pOciError ); } for (int i = 1; i <=(int)parmcnt; i++) printf("Column %i\tNAME = %.*s\n",i,namelen[i-1],pcoln[i-1]);
return 0; }
|
|