Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Embedded SQL via ODBC / 11 сообщений из 11, страница 1 из 1
20.10.2003, 12:56
    #32298280
gardenman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
Уважаемые! Давайте поговорим о ESQL и ODBC.
Кто что юзает? в чем преимущества и в чем недостатки этих подходов?
У кого есть опыт работы в Embedded SQL?
...
Рейтинг: 0 / 0
20.10.2003, 15:23
    #32298582
NewYear
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
но что здесь может быть интересно?

ESQL это для дибиту. я много чего написал using embedded sql для DB2 Workstaton/ OS/400 / OS/390. не уверен, стоит ли его использовать с другими базами.

я пробовал ESQL с Microsoft SQL Server, так ESQL там очень убогой и через задницу. bnd-шник представляет собой хранимую процедуру на SQL, а в программе на host language просто подставляются вызовы SP. в качестве host language мохно использовать исключительно С.

ESQL различается для баз. даже при портировании программы между различными дибиту, приходится вносить исправления.
...
Рейтинг: 0 / 0
21.10.2003, 02:17
    #32299207
tchingiz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
при использовании ESQL - не надо настраивать odbc драйвер.

теоретически система получается проще и быстрее.
использовал ESQL в C для доступа к Sybase ASA (6.x, 7.x, 8.x), Oracle 8.x.
что бы не писать select, insert, update для каждой таблице использую
sqlda - область.

переносимость ессно будет ни к черту.
пробовал работать с FB.
даже sqlda- области в ASA и FB отличаются сильно.
а толком использовть ESQL от FB так и не удалось.
...
Рейтинг: 0 / 0
21.10.2003, 16:09
    #32300134
gardenman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
Меня еще интересует вот такой вопрос:
Как в других базах данных и насколько хорошо поддерживается
Embedded SQL/C++
Например, можно ли хост перевнные инициализировать по ссылке, через указатель, делать их членами класса. Я знаю что всё это отлично поддерживается в DB2. В Sybase к сожалению такие возможности отсутствуют.
А как обстоят дела по этому вопросу у Oracle?
вроде эта фишка называется PRO*C.
...
Рейтинг: 0 / 0
21.10.2003, 23:10
    #32300578
tchingiz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
в оракле действительно называется PRO*C

--
хост перевнные инициализировать по ссылке, через указатель, делать их членами класса

В Sybase к сожалению такие возможности отсутствуют.
------------


ой, млин, а я не знал, что у Sybase такие траблы.

поэтому, переменные для обмена с бд у меня живут как члены класса

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
// u_mkSDE have been started, debug is false
// u_mkSDE have been finished after   0  secs of work. 
//	rc/position= 0 /Ok/create
// Table/View to SDE - convertor is here: func/struct = true;tbl=Indicator;prf=GSAU
struct GSAU_RIndicator : ASAI_TSde{
	TStr    note;
	TULong    messageNo;
	TULong    index_;
	TULong    id_;
	TChar    get_set;
 private:
    x_bool    isGood;
 public: 
    friend GSAU_API GSAU_RIndicator * WINAPI GSAU_iniIndicator( GSAU_RIndicator * r)
    ;
   ....


таблица вот такая

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
create                                    
table GSAU.Indicator (                         
  id        UNSIGNED INTEGER not null
                default Autoincrement,   
  messageNo   UNSIGNED INTEGER,
  index_       UNSIGNED INTEGER,
  id_          UNSIGNED INTEGER,
  get_set     CHAR( 1 ) NOT NULL DEFAULT 'n' REFERENCES db.TNoYes(id),
  note        VARCHAR( 512 ) DEFAULT '', 
  primary key (id)
);






структура ASAI_TSde представляет собой список

который в кишках программы связывается с область SQLDA - она и играет роль
хост переменных


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
char *    //  asai_ins: ASAI_TSde ->  "insert into table (...) values (...)" 
asai_linkI(
    const ASAI_TSde    * rec,
    const ASAI_TId     * id,
    const x_bool        useAux,
    const ulong          aux,
    void               * sqlda

)
{
long rc= 0 ;
char * _me =  "asai_linkI" ;


SQLDA * da = (SQLDA *)sqlda  ; /// <<<<!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


uint     nFlds  =  0 ;     // actual number of fields in sde to be exchanged
char       comma = ' ';
TField    * f =  0 ;
char * t =  0 , * v =  0 ;
TChar     *  c =  0 ;
TTiny     * tn =  0 ;  TLong   * ln  =  0 ; TULong * ul =  0 ; TUShort * us = 0 ;
TShort    * sh =  0 ;  TDouble * tdb =  0 ; TStr   * st =  0 ;

ASAI_TDT      * dt =  0 ;

DECL_DATETIME * ddt =  0 ; // sybase struct
ASAI_TDateTime     * mdt =  0 ;     //my struct



ASAI_TSde *sde = ( ASAI_TSde *) rec;   // <<<< список хост переменных



ASAI_TDB        * asai = sde->database;

x_bool     useId = (id && *rec->id)?true:false ;
uint  msecs= 0 , secs= 0 ;
char * values =  ") values (" ;
x_sprintf (asai->bufP(),  "insert into %s (" , sde->fullName());

t =  x_addStr (t, asai->bufP());
v =  x_addStr (v, values);
if (useId ) {
    t  = x_addStr (t, sde->id);
    v  = x_addStr (v,  ":?" );
    comma = ',';


                                 // заполнение SQLDA  "хост"  переменными


    if (id->t == ASAI_I_ulong){
         da->sqlvar[nFlds].sqltype = DT_UNSINT;
         da->sqlvar[nFlds].sqllen  = sizeof(ulong);
         da->sqlvar[nFlds].sqldata = (void *)  &(id->v.u);
    }
    else if (id->t == ASAI_I_uhuge){
        ; // NRD
    }
    else{
         da->sqlvar[nFlds].sqltype = DT_STRING | DT_FIXCHAR;;
         da->sqlvar[nFlds].sqllen  = ASAI_KEY_SZ;
         da->sqlvar[nFlds].sqldata = (void *)&(id->v.c);
    }
    nFlds++;
}
for (f = sde->get(false);
        f !=  0 ;
             f = sde->get(true)){
//    asai->print(_me,  "adr of field/rc/name/type: %lu/%ld/%s/%hu" , 
//                          (ulong)f, rc, f->name, f->type);
    switch (f->type) {


                                 // заполнение SQLDA  "хост"  переменными


    case SDE_fKey:  
        if (asai->debug)
            x_printf( "\n...%s: name of fKey: %s" ,_me, f->name);
        x_sprintf (asai->bufP(),  "%c %s" , comma, f->name);
        t = x_addStr(t, asai->bufP());
        x_sprintf(asai->bufP(),  "%c :?" , comma);
        v = x_addStr(v, asai->bufP());
        comma     = ',';
        da->sqlvar[nFlds].sqltype = DT_UNSINT;
        da->sqlvar[nFlds].sqllen  = sizeof(ulong);
        da->sqlvar[nFlds].sqldata = (ulong *)f->field;
        nFlds++;
        break;
    .....


пример создания инсерта

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
        SQLDA * da =  0 ;
        da = alloc_sqlda(sde->fields->len+(useId? 1 : 0 )+(useAux? 1 : 0 ));// столько полей живет в записи
        if(da) {
            _bf = asai_linkI(sde, useId?id: 0 , useAux, asai->aux,  da);
            if (_bf) {
                long rc1 = _OK;
                asai->print(_me,  "new insert= ->%s<-" ,  _bf);
                EXEC SQL PREPARE S3 FROM  :_bf;
                EXEC SQL EXECUTE S3 USING  DESCRIPTOR da; 
                rc = asai_sqlEr(_me, _bf,  ca);
                rc1 = asai_unLink(da,  0 , asai, true); // отвязал строчки от sqlda
                x_free(_bf);
            }
            free_sqlda(da);
        }
        else
            rc = _NOTMEM;



...
Рейтинг: 0 / 0
22.10.2003, 05:15
    #32300633
c127
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
ИМХО ESQL-программы получаются проще и понятнее чем их ODBC аналоги. Правда в ODBC программирование я сильно не зарывался. Универсальность ODBC - фикция, так что смело начинай работать с ESQL, при переходе на другой SQL сервер все равно придется подправлять руками что ODBC что ESQL. К тому же ODBC драйвера далеко не безгрешны, так что имеем дополнительный источник ошибок.
...
Рейтинг: 0 / 0
22.10.2003, 10:37
    #32300904
gardenman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
2 tchingiz
)) Все примерно правильно, но я говорил немножко о другом:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
class CMyRec {
public:
   EXEC SQL BEGIN DECLARE SECTION;
   long id;
   char name[ 31 ];
   EXEC SQL END DECLARE SECTION;

   EXEC SQL DECLARE CMyRec CURSOR FOR
      SELECT id,name FROM MyTable WHERE name>=:name
           ORDER BY name OPTIMIZE FOR  50  ROWS;
// -- Единственный метод
 
   bool fetch() {
       EXEC SQL FETCH CMyRec INTO :id,:name;
       if (SQLCODE!= 100 ) return true;
       return false;
   }
};
...
vector<CMyRec> vmyrec;
...
EXEC SQL OPEN CMyRec;
for(;;){
   CMyRec therec;
   if (!therec.fetch()) break;
   vmyrec.push_back(therec);
}
EXEC SQL CLOSE CMyRec;



Причем определение класса CMyRec можно вставлять в заголовочный файл
а затем инклудить его:

EXEC SQL INCLUDE 'CMyRec.h';

Вот это я и называю настоящей поддержкой C++

А можно вообще fetch вызывать в конструкторе, тогда имеем такую фишку:

EXEC SQL OPEN CMyRec;
CMyRec* mv=new CMyRec[1000];
EXEC SQL CLOSE CMyRec;

В результате выполнения такой конструкции
получаем сразу массив уже заполненных структур;
Единственный вопрос: Размер массива должен соответвовать количеству
выбираемых записей, в противном случае нужно подумать об обработке
исключений;

Сравни теперь свой код, по длине и по ясности с моим, не говоря уж об
ODBC. И еще такая вещь - всё что я написал - это статический SQL,
который естественно выполняется быстрее динамического. И былее эффективен при частых вызовах, более безопасен, и не требует больших накладных расходов при администрировании.
...
Рейтинг: 0 / 0
23.10.2003, 00:25
    #32302332
tchingiz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
2gardeman

гы ну ясное дело что статический быстрее и понятнее.
со статического я начал тоже.
только это уже другая тема
попишешь для каждой новой таблицы новый код может о другой теме задумаешься (и перейдешь на sqlda).

все что я привел - я уже не пишу. ;)
а либо написал давно (два года назад), либо генерирую программой sql2C++ под любую таблицу, обзор (до сохраненок руки не дошли).

поэтому код достаточно сложный
(кстати
с поддержкой индикатора для хранения NULL
и возврата ошибок в поле, чего нет у тебя
)

а собственно оператор insert выглядит так
Код: plaintext
1.
2.
3.
4.
5.
6.
 
            GSAU_RCmd4Pmp  Cmd4Pmp  (database);
                 // тут можно присвоение перегрузить, что сделано в поздних версиях
                 // Cmd4Pmp.uid = c;
            Cmd4Pmp.uid.strTo(c, db->buf);  // uid  into the record, db->buf buffer
            rc = Cmd4Pmp.Insert(&p);          // timestamp'll setup by sql server


в поле для уида записи структуры для работы с таблицей Cmd4Pmp из заданной базы данных
ложится новый уникальный идентификотор из строки с
и строчка вставляется в таблицы. в p возвращается id записи.



более того я сознательно избегаю создавать сложные обьекты и дополнительные
буфера для записей, а работаю с одной строчкой в буфере sql-сервера.

/*
кстати о ESQL в FB/Iterbase - оказалось, что там нет перемещения назад и произвольного позиционирования в буферу SQL сервера.
в Oracle и ASA есть.
поэтому в FB без собственного промежуточного буфера (и проблем синхронизации собственно буфера и буфера SQL сервера) не обойтись.
:(((

*/
...
Рейтинг: 0 / 0
24.10.2003, 10:06
    #32303913
gardenman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
Говоришь генерируешь?) это хорошо! Это правильно...)) Я тоже генерирую
А на счет NULL величин - эт вы меня зря так обижаете.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
EXEC SQL BEGIN DECLARE SECTION;
   char somefield[ 51 ];
   short somefield_ind;
EXEC SQL END DECLARE SECTION;
...
EXEC SQL DECLARE C1 CURSOR FOR ...
EXEC SQL OPEN C1;
EXEC SQL FETCH C1 INTO :somefield:somefield_ind, .... ;


вот таким образом и будет тебе индикаторная переменная.
А вот на счет генерации, у db2 есть классная утилитка db2dclgn, которая генерит структуру любой таблицы в любом формате - С,COBOL,FORTRAN...
в результате работы получается заголовочный файл, ну например:
Код: plaintext
1.
2.
3.
4.
create table test (
   id integer,
   name char( 30 )
)

запускаем db2dclgn -d {database} -t test -i
в результате имеем заголовочный файл


Код: plaintext
1.
2.
3.
4.
5.
6.
struct 
{
   long id;
   name char[ 31 ];
} test;
test_ind[ 2 ];


test_ind - Это будет массив индексных переменных
а дальше прописываем примерно такую структуру:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
class CTest {
public:
   EXEC SQL BEGIN DECLARE SECTION;
   EXEC SQL INCLUDE 'test.h';
   EXEC SQL END DECLARE SECTION;
   bool fetch();
};

и, пользуясь тем что db2 может грузить зяпись прямо в структуру
имеем возможность написать так в методе fetch():


Код: plaintext
1.
2.
3.
    EXEC SQL DECLARE CURSOR ctest FOR  SELECT * FROM test;
    EXEC SQL OPEN ctest;
    EXEC SQL FETCH ctest INTO :test INDICATOR :test_ind;


Заметь - запись находится сразу в структуре, которая является членом класса. Имеется массив индикаторных переменных, показывающих где NULL величины, и всё генерится автоматом. Получили класс - можем использовать шаблоны.
Результат - все очень хорошо структарировано, и в случае изменения структуры таблиц - генерится за 1 секунду.
...
Рейтинг: 0 / 0
24.10.2003, 11:39
    #32304051
NewYear
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
о, а я тоже код генерирую. код кончно не такой понятный, но в него смотреть не надо (само работает).



// Babylon C++ Generator
// C++ generated for Application TESTPRG
//
// Date generated: 24.10.2003
// Time generated: 11:34:56
// Generator version: HptBuildDate:020124
// Trace / Comments: Dictionary(false false false false ) / false

#define SQLDB2_H
#include <fcwrcl.h>
EXEC SQL INCLUDE SQLCA;

struct rcdXXX_ : public MSQLRecord
{
SQLCHA EZE1_ ; // HHH --> EZE1_

rcdXXX_ () : MSQLRecord ( "XXX" , 14 ) ,
EZE1_ ( *this , Leaf , 1, 0, 0, 14 )
{};
};

EXEC SQL BEGIN DECLARE SECTION;
struct {
short len;
unsigned char data[10];
} *hvXXX_EZE1_;

short *nidXXX_EZE1_;
EXEC SQL END DECLARE SECTION;

class appTESTPRG_ : public FCWMainApp
{
private:
enum {
cs_TESTAPP_MF_ = 0
} CtlState ;

rcdXXX_ XXX_;

public:

appTESTPRG_ () ;
~appTESTPRG_ () ;
void Start ();

void fncTESTAPP_MF_ ();
void fncX_ERROR_LOG_ ();
void optX_ERROR_LOG_ ();
};

appTESTPRG_ :: appTESTPRG_() : FCWMainApp ( "TESTPRG", NULL, NULL, ByPassKeys( ), Key :: None, NULL, InEdit :: All, NonSegmented )
{

Init( key_dbms, val_db2 );
XXX_.Setup();

CtlState = cs_TESTAPP_MF_;
}

appTESTPRG_ :: ~appTESTPRG_()
{
}

void appTESTPRG_ :: Start ()
{
do {
CtlMode = cm_normalFlow;
switch (CtlState) {

case cs_TESTAPP_MF_:
fncTESTAPP_MF_();
if (CtlMode == cm_End || CtlMode == cm_Goto)
continue;

CtlMode = cm_End;
break;

default:
break;

}
} while ( CtlMode != cm_End );
}

void appTESTPRG_ :: fncTESTAPP_MF_ ()
{
PrcPush("TESTAPP_MF_");
EZEFEC = 1;
fncX_ERROR_LOG_( );
if ( CtlMode != cm_normalFlow )
{
PrcPop();
return;
}
PrcPop();
return;
}

void appTESTPRG_ :: fncX_ERROR_LOG_ ()
{
PrcPush("X_ERROR_LOG_");
XXX_.EZE1_ = "XXX";
optX_ERROR_LOG_( );
if ( CtlMode != cm_normalFlow )
{
PrcPop();
return;
}
if ( EZEREPLY == 1 )
EZECOMIT( OPT_REPLY );
else
EZECOMIT( OPT_NOREPLY );
PrcPop();
return;
}

void appTESTPRG_ :: optX_ERROR_LOG_ ( )
{
if ( !XXX_.BeginAdd(2, NO_EXEC_TIME_BLD | NO_HOST_VAR_TABLE_NAME , 1 , 0 ) )
{
XXX_.SetParm( 1, (AHVPTR) &hvXXX_EZE1_, (AHVPTR) &nidXXX_EZE1_, XXX_.EZE1_, 453, False );
EXEC SQL INSERT INTO XSXX (HHH)
VALUES( :*hvXXX_EZE1_ :*nidXXX_EZE1_ ) ;
XXX_.EndAdd ( &sqlca );
}
}

extern "C" int SYSCALL TESTPRG()
{
appTESTPRG_ App ;
App.Start();
return(0);
}

// C++ Application Generation complete. elapsedTime = 0.02 secs. bytesPerSec = 130250,00
...
Рейтинг: 0 / 0
25.10.2003, 06:31
    #32305015
tchingiz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Embedded SQL via ODBC
2 NewYear
я понил - капец ODBC

gardeman> db2 может грузить зяпись прямо в структуру

все на db2


ну все могут грузить запись(си) прямо в структуру(ры) через (массив)sqlda.
/*
чем я занимаюсь тоже, я писал пример с insert, так как он первый попался
для цикла тоже с fetch тоже есть
*/
я почти уверен, если ты посмотришь текст после препроцессора
db2 там будет такая структура.
;))
хотя как у db2 - легче и понятнее, чем явно трахаться с sqlda
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Embedded SQL via ODBC / 11 сообщений из 11, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]