Nyní si předvedeme, jak jednoduše převést DBF tabulku do MDB databáze. Využity jsou i dvě API funkce ODBC pro zjištění několika informací pro založení MDB databáze. Na MDB databázi se vždy připojuje přes název ODBC driveru.
Vstupními parametry jsou: alias DBF souboru - lcAlias, umístění + název cílového MDB souboru - lcMDB a umístění + název exstujícího MDB souboru - lcVMDB.
Třetí parametr není potřeba, pokud MDB soubor existuje a nebude se znovu vytvářet.
Celý přenos řídí čtyři proměnné:
LPARAM lcAlias,lcMDB,lcVMDB * lcAlias - Alias otevřené DBF tabulky * lcMDB - Cesta a název MDB souboru kam se vytvoří tabulka * lcVMDB - Cesta a název MDB vzorového souboru (může být jakýkoliv, ale musí existovat). * - Slouží pro otestování verze ODBC driveru MS Access * Návratové konstanty #DEFINE __DBF2MDB_ErrOK 0 && #DEFINE __DBF2MDB_ErrConnectionFailed -1 && Nepodařilo se otevřír spojení na MDB soubor #DEFINE __DBF2MDB_ErrMDBNotCreated -2 && Nepodařilo se vytvořit MDB soubor #DEFINE __DBF2MDB_ErrFewParameters -3 && Málo parametrů #DEFINE __DBF2MDB_ErrNoTables -4 && Nepodařilo se získat seznam tabulek #DEFINE __DBF2MDB_ErrCannotCTable -5 && Nepodařilo se vytvořit tabulku #DEFINE __DBF2MDB_ErrCannotDTable -6 && Nepodařilo se smazat tabulku #DEFINE __DBF2MDB_ErrNotaTable -7 && Tabulka je pohled nebo systémová tabulka #DEFINE __DBF2MDB_ErrNotInsert -8 && Nepodařilo se založit větu #DEFINE __DBF2MDB_ErrNotDelete -9 && Nepodařilo se smazat věty #DEFINE __DBF2MDB_ErrAliasNotOpen -10 && Alias není otevřený * Konstanty pro ODBC #DEFINE SQL_DRIVER_VER 7 IF FILE(lcMDB) AND PCOUNT()<2 OR !FILE(lcMDB) AND PCOUNT()<3 AND !FILE(lcVMDB) RETURN __DBF2MDB_ErrFewParameters ENDIF IF !USED(lcAlias) RETURN __DBF2MDB_ErrAliasNotOpen ENDIF * Potřebné ODBC API fukce DECLARE Integer SQLConfigDataSource in odbccp32.dll Integer, Integer,String, String DECLARE INTEGER SQLGetInfo IN odbc32.dll INTEGER,INTEGER, STRING @,INTEGER,INTEGER @ LOCAL lcSQL,lihdbc,liErr,liODBChdbc,lcPom,lii,lcMDBVersion,lcCRKey,lcTable,; lcATables,llExists,lcSQLI,; llReCreate,llReFill,liFormat,llMDBReCreate LOCAL ARRAY laFields(1) llMDBReCreate=.F. && Má se znovu vytvořit MDB soubor? llReCreate=.T. && Má se tabulka znovu vytvořit, pokud existuje? llReFill=.F. && Má se tabulka znova naplnit? liFormat=1 && Formát/verze MDB souboru (1 - MS Access 2.0, 2 - MS Access 95/97, 3 - MS Access 2000)
Pokud není databázový soubor založen, či se má znovu vytvořit, musí se nejdříve zjistit, jaká verze ODBC driveru pro MS Acces databázi je nainstalován. Novější verze používá jiná klíčová slova pro vytvoření MDB souboru (viz. MSDN - Q126606). Aby se dala zjistit verze ODBC ovladače, je nutno otevřít spojení na existující MS Access databázi (jedno jakou, třeba i prázdnou). Pak se pomocí ODBC funkce SQLGetInfo() zjistí verze ODBC driveru a dle ní a proměnné liFormat se vygeneruje klíčové slovo pro určení verze nově vytvořené MS Access databáze. Ta se vytvoří pomocí ODBC funkce SQLConfigDataSource().
IF !FILE(lcMDB) OR llMDBReCreate * Zjištění verze ODBC driveru pro MS Access * protože klíčová slova pro vytvoření MDB souboru jsou pro různé verze jiná lihdbc=SQLSTRINGCONNECT("driver={Microsoft Access driver (*.mdb)};dbq="+lcVMDB) IF lihdbc=0 RETURN __DBF2MDB_ErrConnectionFailed ENDIF liODBChdbc=SQLGETPROP(lihdbc,"ODBChdbc") && Zjisti ODBC hdbc lcVersion=SPACE(254) && Nastav buffer lii=0 =SQLGetInfo(liODBChdbc,SQL_DRIVER_VER,@lcVersion,LEN(lcVersion),@lii) && Načti verzi driveru =SQLDISCONNECT(lihdbc) lcVersion=LTRIM(STR(VAL(LEFT(lcVersion,AT(".",lcVersion)-1)),3)) lcCRKey = IIF(lcVersion="3",IIF(liFormat=1,"CREATE_V2DB","CREATE_DB"),; IIF(liFormat=1,"CREATE_DBV2",IIF(liFormat=2,"CREATE_DBV3","CREATE_DBV4"))) IF FILE(lcMDB) && Pokud existuje DELE FILE (lcMDB) && Smaž jej ENDIF * Vytvoření databáze IF SQLConfigDataSource(0,1,"Microsoft Access Driver (*.mdb)",lcCRKey+"="+lcMDB)#1 * Selhalo vytvoření MDB souboru RETURN __DBF2MDB_ErrMDBNotCreated ENDIF ENDIF
Když je MS Access databáze vytvořena, pak se na ni připojíme.
Nastavíme synchronní přenos, automatické transakce a aby se nezobrazoval přihlašovací dialog.
Pokud by byl vlastní přenos pomalý, pak lze nastavit ruční transakce, ale po skončení smyčky je pak nutno zavolat funkce SQLCOMMIT() nebo SQLROLLBACK() dle toho, zda se podařilo všechny věty přenést.
Takovýto způsob (ruční transakce) je sice rychlý, ale zase zajišťuje buď všechna data nebo nic, bohužel, při potvrzení nebo vrácení změn může nastat delší časová odmlka.
Název tabulky je odvozen přímo z názvu DBF souboru.
Kontroluje se, zda vytvářená tabulka již neexistuje jako pohled či systémová tabulka.
Pokud ano, pak se přenos přeruší. Při definici SQL příkazu pro vytvoření tabulky se krom názvu a typu položky též přebírá i příznak .NULL. hodnoty.
SQL příkaz pro založení věty se generuje tak, aby byl vlastní přenos nejrychlejší a umožňoval přenášet velké memo položky a General pole - INSERT INTO TABLE myTable (pol1,pol2) VALUES (?Alias.pol1,?Alias.pol2) - používají se parametry.
Pokud se má tabulka znovu vytvořit, tak se nejdříve pomocí SQL příkazu DROP TABLE ... smaže a pak se založí.
* Připojení na MDB soubor * Vytvoření a naplnění tabulky lihdbc=SQLSTRINGCONNECT("Driver={Microsoft Access Driver (*.mdb)};DBQ="+lcMDB) IF lihdbc<=0 RETURN __DBF2MDB_ErrConnectionFailed ENDIF =SQLSETPROP(lihdbc,"Asynchronous",.F.) && Nastav Asynchronní provoz =SQLSETPROP(lihdbc,"Transactions",1) && Nastav Automatické transakce =SQLSETPROP(lihdbc,"DispLogin",3) && Nikdy nezobrazuj dialog při přihlášení lcPom=DBF(lcAlias) lii=RAT("\",lcPom) lcTable=IIF(lii>0,SUBS(lcPom,lii+1),lcPom) lii=RAT(".",lcTable) lcTable=IIF(lii>0,LEFT(lcTable,lii-1),lcTable) llDal=.T. && Nastav příznak, že je vše OK * Zjisti, zda tabulka již existuje lcATables=SYS(2015) && Pracovní kurzor IF SQLTABLES(lihdbc,"'TABLE','VIEW','SYSTEM TABLE'",lcATables)<=0 liErr=__DBF2MDB_ErrNoTables llDal=.F. ENDIF IF llDal STORE "" TO lcSQL,lcPom,lcSQLI * Načti seznam položek FOR lii=1 TO AFIELDS(laFields,lcAlias) lcSQL=lcSQL+" "+laFields(lii,1)+" "+; IIF(laFields(lii,2)='C',"TEXT ("+LTRIM(STR(laFields(lii,3),11))+")",; IIF(laFields(lii,2)='M',"LONGTEXT",; IIF(laFields(lii,2)='Y',"CURRENCY",; IIF(laFields(lii,2)='F',"FLOAT",; IIF(laFields(lii,2)='B',"DOUBLE",; IIF(laFields(lii,2)='I',"INTEGER",; IIF(laFields(lii,2)='N',"SINGLE" ,; IIF(laFields(lii,2)$'D,T',"DATETIME",; IIF(laFields(lii,2)='G',"LONGBINARY","BIT")))))))))+" "+IIF(laFields(lii,5),"NULL,","NOT NULL,") lcSQLI=lcSQLI+laFields(lii,1)+", " lcPom=lcPom+"?"+lcAlias+"."+laFields(lii,1)+", " NEXT lcSQL="CREATE TABLE "+lcTable+" ("+LEFT(lcSQL,LEN(lcSQL)-1)+")" lcSQLI="INSERT INTO "+lcTable+" ("+LEFT(lcSQLI,LEN(lcSQLI)-2)+") VALUES ("+LEFT(lcPom,LEN(lcPom)-2)+")" SELE (lcATables) LOCATE FOR UPPER(ALLT(TABLE_NAME))==UPPER(lcTable) llExists=FOUND() IF llExists AND llReCreate AND UPPER(ALLT(TABLE_TYPE))=='VIEW' OR UPPER(ALLT(TABLE_TYPE))=='SYSTEM TABLE' llDal=.F. liErr=__DBF2MDB_ErrNotaTable ENDIF ENDIF IF llDal AND (!llExists OR llReCreate) IF llExists AND SQLEXEC(lihdbc,"DROP TABLE "+lcTable)<=0 llDal=.F. liErr=__DBF2MDB_ErrCannotDTable ENDIF IF llDal AND SQLEXEC(lihdbc,lcSQL)<=0 llDal=.F. liErr=__DBF2MDB_ErrCannotCTable ENDIF ENDIF IF USED(lcATables) && Pokud je pracovní kurzor otevřen USE IN (lcATables) && Pak jej uzavři ENDIF
Pokud se mají původní data smazat, pak se na to použije SQL příkaz DELETE FROM myTable. Vlastní přenos je také urychlen tím, že se SQL příkaz nejdříve předpřipraví pomocí funkce SQLPREPARE() (ODBC driver si SQL příkaz předkompiluje a při každém zavolání fukce SQLEXEC() převezme parametry).
* Smaž věty, pokud tabulka existuje a nebyla znovu vytvořena a má se naplnit IF llDal AND llExists AND !llReCreate AND llReFill AND SQLEXEC(lihdbc,"DELETE FROM "+lcTable)<=0 liErr=__DBF2MDB_ErrNotDelete llDal=.F. ENDIF IF llDal liErr=__DBF2MDB_ErrOK SELE (lcAlias) =SQLPREPARE(lihdbc,lcSQLI) SCAN ALL IF SQLEXEC(lihdbc,lcSQLI)<=0 liErr=__DBF2MDB_ErrNotInsert EXIT ENDIF ENDSCAN * Pokud jsou nastaveny ruční transakce, pak buď potvrď změny, nebo je zruš =IIF(SQLGETPROP(lihdbc,"Transactions")=2,IIF(liErr=__DBF2MDB_ErrOK,SQLCOMMIT(lihdbc),SQLROLLBACK(lihdbc)),.T.) ENDIF =SQLDISCONNECT(lihdbc) && Uzavři spojení RETURN liErr