Přístup na vzdálená data

Vzdálená data - skoro každý už o tom slyšel, ale ti začínající si kladou otázky:
- Jak na to ?
- Jaké tam jsou podrazy ?
- Vyplatí se to ?

Na vzdálená data se dá přistupovat pomocí nativní vrstvy pro podporu ODBC ve VFP nebo pomocí objektů DAO a OLE-DB. V samotné VFP lze na RD přistupovat programově pomocí SPT (SQL Pass Through) či spojení a pohledy definovat visuálně v DBC konteineru.

Část první - Použití SPT a visuálního návrhu

Nebudu se zde zabývat jak visuálně definovat spojení a pohledy na RD, či otevírat spojení a tahat data pomocí SPT. Hodlám poukázat na rozdíly mezi visuálním návrhem a SPT a na různé špeky.

Obecné výhody visuálního návrhu:

Obecné nevýhody visuálního návrhu:

Obecné výhody SPT:

Obecné nevýhody SPT:

1) Definice spojení

1a) Obecný popis:
Definice spojení mezi visuálním návrhem a SPT se nijak neliší. V obou případech se lze odkazovat na DSN či přímo definovat ConnectString. V samotném ConnectString-u lze definovat DSN nebo přímo ODBC driver.

Spojení uložené v DBC konteineru lze otevřít pomocí funkce SQLCONNECT(), kde se jako parametr použije název spojení v DBC konteineru.

Spojení přes SPT se otevírá pomocí funkcí



Ukázka:
* Otevření spojení z DBC konteineru
LOCAL lihdbc
lihdbc=SQLCONNECT("MOJE_SPOJENI_V_DBC_KONTEINERU")

* Otevření spojení přes SPT
lihdbc=SQLCONNECT("MOJE_DSN","Uziv1","heslo1")

* Otevření spojení přes SPT pomocí definovaného ConnectStringu přes DSN
lihdbc=SQLSTRINGCONNECT("DSN=MOJE_DSN;uid=Uziv1;pwd=Heslo1;")

* Otevření spojení přes SPT pomocí definovaného ConnectStringu přes určení ODBC driveru
lihdbc=SQLSTRINGCONNECT("driver={Microsoft Access driver (*.mdb)};dbq=rdatab.mdb;uid=Uziv1;pwd=Heslo1")


Nejpodporovanější elementy jsou: DSN,driver,uid,pwd,dbq.

Většina ODBC driverů má specifické elementy ConnectStringu:

SQL server:
Microsoft ODBC Driver for Oracle,Microsoft ODBC for Oracle:
Oracle ODBC driver,Oracle73:
Microsoft dBASE Driver (*.dbf):

1b) Vlastnosti spojení:
Následující tabulka ukazuje seznam nastavitelných vlastností spojení. Jak již bylo řečeno výše, některé vlastnosti se dají nastavit pouze tak, že se aplikují na 0. spojení a VFP následně tyto vlastnosti přebere pro nově otevřené spojení (takové vlastnosti mají ve 4. sloupci Ano) - SQLSETPROP(0,"IdleTimeOut",0).

Název Deaultní hodnota Popis Nutné nastavit
na 0. spojení
Poznámka
IdleTimeOut 0 Čas v minutách+1, po kterém VFP automaticky ukončí ODBC spojení.
Po použití ODBC handlu VFP automaticky ODBC spojení obnoví.
Ano Pokud je 0, spojení se nikdy neukončí.
Toto však bohužel přestává korektně fungovat po nainstalování MDAC 2.0 a vyšší.
Tato činnost je však nyní přímo implemetována jako součást Poolingu v ODBC manageru.
PacketSize 4096 Velikost paketu v bytes v síťovém provozu Ano Většinou je toto nastavení ingorováno, neb si jej nastaví sám databázový server.
DispLogin 1 Způsob zobrazení přihlašovacího dialogu. Ano Tato volba umožňuje říci, zda se má spustit přihlašovací dialog ODBC driveru , pokud nějaké důležité údaje chybí.
ConnectTimeOut 15 Čas v sekundách, po kterém se vyhlásí time-out error. Ano Pokud se tato vlastnost nastaví (>0), aplikace nezatuhne.
QueryTimeOut 0 Čas v sekundách, po kterém se vyhlásí generální time-out error. Ano Pokud se tato vlastnost nastaví (>0), aplikace nezatuhne.
WaitTime 600 Čas v ms po ketrém VFP kontroluje, zda již byl příkaz vykonán. Ano Čím větší čas, tím menší komunikace mezi klientem a serverem a tím pádem i méně přetížená síť.
Asynchronous .F. Příznak zda je spojení v režimu asynchronním. Ne Pokud je .T., pak VFP umožňuje na takto více nastavených spojení naráz spuštět SQL příkazy a otevírat pohledy.
DispWarnings .F. Příznak, zda se mají zobrazovat varovná hlášení ODBC driveru při nastavování vlastností. Ne Pokud je nastaveno .T., pak u starších ODBC driverů nedošlo ke spojení
Abych pravdu řek, většinou tyto hlašení v ostrém provozu lidi rozčilujou.
BatchMode .T. Příznak, zda funkce SQLEXEC() vrátí výsledky vícenásobného SQL příkazu najednou či postupně pomocí funkce SQLMORERESULT(). Ne Doporučuji ponechat defaultní nastavení .F., ušetříte si tím spoustu starostí.
Transactions 1 Příznak , zda jsou transakce automatické či ruční. Ne Na většinu případů stačí automatické transakce (ukládání jedné věty v pohledu). Pokud je však nutno provést změny ve více tabulkách a nejde to pomocí uložených procedur (třeba v takovým MS Accessu je to vo hubu) pak se nastaví ruční transakce.
Pro potvrzení změn se použije funkce SQLCOMMIT() a pro zrušení změn SQLROLLBACK().

1c) Batch processing (provedení více SQL příkazů pomocí funkce SQLEXEC()):
1ca) Vlastnost BatchMode = .T.
  Pokud proběhly všechny SQL příkazy v pořádku, funkce SQLEXEC() 1. Pokud jsou v SQL příkazu pouze SELECTy pak, vrátí počet provedených SELECTů (nebo vytvořených VFP kurzorů).

* Vyvolání dvou SELECTů najednou
SQLEXEC(1,"SELECT * FROM XXT001;SELECT * FROM XXT002","test")

* Vyvolání dvou UPDATEů najednou
SQLEXEC(1,"UPDATE XXT001 SET XX002 = 0 WHERE XX001='A';UPDATE XXT002 SET XX002 = 0 WHERE XX001='B'")
  Pokud je spouštěno několik SELECTů, pak VFP vytvoří kurzory jejichž název vychází z uvedeného 3. parametru (pokud nebyl zadán, pak první kurzor má název SQLResult a další SQLResult1,SQLResult2 ...).
  Musí se dodržet jedna zásada - nesmí se najednou spouštět SQL příkazy, které vracejí a nevracejí výsledky např. SELECT a UPDATE, VFP potom vyhlásí chybu.

Poznámka: Pokud je nastaveno Asynchronní spojení, pak funkce SQLEXEC() vrací 0 tak dlouho dokud není SQL příkaz kompletně vykonán. Pokud došlo ke stáhnutí posledních dat, návratová hodnota odpovídá popisu výše uvedenému.


1cb) Vlastnost BatchMode = .F.
  V tomto případě funkce SQLEXEC() vrátí/vykoná pouze 1. SQL příkaz (návratová hodnota je 1 pokud to je v pořádku). Další SQL příkazy se vykonají pomocí funkce SQLMORERESULT(), kde návratová hodnota je 1 pokud se povedlo provést SQL příkaz a 2 pokud byl proveden poslední SQL příkaz.

  Pokud jsou najednou použity příkazy které vrací a nevrací data (SELECT,UPDATE), pak VFP vyhlásí chybu a některé SQL příkaz se nemusejí provést, resp. se to celé chová podivně. Proto platí pravidlo uvedené výše - nemíchat dohromady.

Poznámka: Pokud je nastaveno Asynchronní spojení, pak funkce SQLEXEC() vrací 0 tak dlouho dokud není SQL příkaz kompletně vykonán. Funkce SQLMORERESULT() vrací 1 tak dlouho dokud nejsou vykonány (návratová hodnota je 2) kompletně všechny SQL příkazy takže nelze rozlišit zda již byl konktrétní SQL příkaz kompletně vykonán.

1d) Asynchronní/Synchronní provoz:
Pokud nedošlo ke zmeně vlastnosti Asynchronous na 0. spojení (DE,Runtime), nebo ke změně nastavení VFP (DE), pak je spojení otevíráno v režimu synchronním. Velice dobrý popis rozdílů mezi asynchronním a synchronním režimem je v samotném helpu VFP.

Synchronní režim se používá pokud je potřeba co nejrychleji vykonat SQL příkaz a nevadí, že po tu dobu bude aplikace zablokovaná.
Funkce SQLEXECUTE() či SQLMORERESULT() vrací 1 pokud nic neselhalo, -1 pokud selhal SQL příkaz či -2 pokud došlo k chybě na úrovni spojení.

Asynchronní režim se používá pokud je potřeba postupně načítat data na pozadí či na požádání nebo spouštět naráz více SQL příkazů na různých spojení (všechna musí být v asynchronním režimu).
Funkce SQLEXECUTE() vrací 0 dokud není SQL příkaz komletně vykonán, 1 pokud je SQL příkaz kompletně vykonán a nic neselhalo, -1 pokud selhal SQL příkaz či -2 pokud došlo k chybě na úrovni spojení (chování fukce SQLMORERESULT() je popsáno v části 1c) Batch processing).

1e) Transakce:
Standardně jsou na spojení nastaveny automatické transakce, to znamená, že po vykonaní každého příkazu INSERT,UPDATE či DELETE jsou změny nevratné.Pokud by bylo potřeba jednu větu větu založit, další opravit a smazat nějaký blok dat a při selhání jednoho z oněch příkazů vrátit zpět původní stav, pak se musí nastavit na spojení ruční transakce.

* Spojení je už otevřeno, v synchronním režimu
=SQLSETPROP(lihdbc,"Transactions",2) && Nastav ruční transakce

* Proveď INSERT,UPDATE,DELETE
liErr=SQLEXEC(lihdbc,"INSERT INTO XXT001 (XX001,XX002) VALUES ('AAAA','BBBBB')")
IF liErr=1
   liErr=SQLEXEC(lihdbc,"UPDATE XXT001 SET XX002='BBBBB'  WHERE XX001='AAAA'")
ENDIF
IF liErr=1
   liErr=SQLEXEC(lihdbc,"DELETE FROM XXT001 WHERE XX001='AAAA'")
ENDIF
* Pokud došlo k chybě musí se vrátit změny
IF liErr<0
   =SQLROLLBACK(lihdbc)
ELSE
   * Jinak se musejí potvrdit
   liErr=SQLCOMMIT(lihdbc) && i tato funkce může vrátit -1 nebo -2
   IF liErr#1
      * Zatím se mi nestalo, že by to takhle dopadlo, takže je to tady jen pro jistotu
      =SQLROLLBACK(lihdbc)
   ENDIF
ENDIF
* Nastavení automatických transakcí
=SQLSETPROP(lihdbc,"Transactions",1)


Poznámka:
Na některé SQL příkazy se nevztahují transakce.

Slovníček pojmů a zkratek:
ConnectString - - Spojovací řetězec , jehož některé elementy můžou být specifické pro určitý ODBC driver, ale většina odpovídá standardu ODBC
ODBC driver - - Specifický driver pro konkrétní datový zdroj
DSN - Data Source Name - Název datového zdroje definovaného v ODBC manažeru
DAO - Data Access Object - Objektové rozhraní pro přístup k RD
SPT - -viz SQL Pass Through
SQL Pass Through - - Technologie pro vykonaní nativních příkazů pro datový server
ODBC - Open database connectivity - Univerzální rozhraní pro přístup k různým datovým zdrojům
RD - - Vzdálená data
DE - Developmen Environment - Vývojové prostředí
Runtime - -
OLE-DB - -
ADO - -