Поиск:

Ответ в темуСоздание новой темы Создание опроса
> OCI : DefineByName 
V
    Опции темы
Torsten
Дата 30.3.2012, 10:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 10.6.2008
Где: Pskov

Репутация: нет
Всего: 7



Приветствую. Столкнулся с проблемой нужно для курсора реализовать DefineByName, но я не уверен что это вообще возможно, т.к. во всех example используется только define by pos, и гугл по запросу define by name - ничего нужно не выдает. Однако, например, в php есть функция oci_define_by_name. Я попробовал поизучать исходники пыхи, но реализацию найти не удалось, она где-то спрятана под тонной макросов ZEND_***. 

Цель очень простая. Сделать возможность обработки результата процедуры через курсор и получать доступ к полям курсора по имени, чтобы в случае изменения кол-ва параметров в курсоре не требовалось менять маппинг полей в приложении. Таким образом не будет требоватся синхронное обновление базы и приложений, в случае добавление в новых параметров в курсор.

Это сообщение отредактировал(а) Torsten - 30.3.2012, 10:29
--------------------
We have no begining, we have no end. We are infinite.
PM MAIL   Вверх
Torsten
Дата 5.4.2012, 17:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 10.6.2008
Где: Pskov

Репутация: нет
Всего: 7



Все оказалось достаточно просто, но много времени ушло на отладку и поиск одной ошибки.

Рабочий код практически описан в документации в 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 *)&paramInt,
    (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;
}



Это сообщение отредактировал(а) Torsten - 5.4.2012, 17:19
--------------------
We have no begining, we have no end. We are infinite.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C++: Базы данных"
chipset

Данный форум предназначен для обсуждения вопросов прямым образом связанных с C++ и БД. Так, вопросы только по C++ следует задавать в C++:Общие вопросы а вопросы по абстрактным БД в Базах данных или в соответствующих под-форумах.

Благодарим за понимание.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, chipset.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Базы данных | Следующая тема »


 




[ Время генерации скрипта: 0.0738 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.