Rozdział 26
Borland Database Engine (BDE)
Borland Database Engine (BDE) (mechanizm dostępu do baz danych) jest
zestawem bibliotek DLL, przy pomocy których Delphi realizuje dostęp do baz
danych. Interfejs BDE jest używany nie tylko przez Delphi. Posługują się nim
również inne programy firmy Borland (takie jak Paradox for Windows, Visual
dBASE, Borland C++ Builder itd). W niektórych pakietach programowych tej
firmy, BDE występuje pod starą nazwą IDAPI (Independent Database Application
Programming Interface). Początkowo IDAPI miał być interfejsem otwartych baz
danych, ale na tym polu przegrał z ODBC firmy Microsoft.
Delphi, poprzez swoje komponenty przeznaczone do obsługi baz danych, zawiera
prawie wszystkie właściwości funkcjonalne BDE, toteż niezwykle rzadko zachodzi
konieczność bezpośredniej współpracy z BDE. Metody oferowane przez Delphi są
bez porównania łatwiejsze i bardziej odporne na błędy, niż bezpośrednie
wywołania BDE. Zastosowanie tych komponentów nie redukuje (wbrew pozorom)
efektywności aplikacji.
Stosując bezpośrednie odwołania BDE należy pamiętać o kilku sprawach. Po
pierwsze - nie jest dostępny mechanizm obsługi wyjątków, który biblioteka Delphi
- VCL - zapewnia podczas dostępu do bazy danych. Należy dokładnie sprawdzać
kody zwracane przez funkcje BDE i odpowiednio na nie reagować. Po drugie -
z uwagi na fakt, iż komponenty bazy danych Delphi nie będą świadome niskiego
poziomu dostępu, musimy się liczyć z koniecznością ponownej synchronizacji
z bazą danych. W pewnych sytuacjach może to wymagać tylko wywołania metody
Refresh (odświeżania), w innych - zamknięcia i ponownego otwarcia objektu
DataSet.
W tym rozdziale przyjrzymy się wykorzystaniu BDE, w celu rozszerzenia dostępu
do baz danych w stosunku do zakresu oferowanego przez bibliotekę Delphi - VCL.
Nie traktujemy tutaj BDE jako alternatywy dla VCL, a jedynie jako jej
rozszerzenie. Omówimy podstawową strukturę BDE i funkcje BDE (w zakresie
wymaganym przez twórców aplikacji) oraz metody jednoczesnego stosowania
komponentów Delphi i odwołań BDE API.
BDE kontra ODBC
W zasadzie sterowniki BDE, na tle swych odpowiedników ODBC, wypadają
korzystniej - są szybsze i charakteryzują się lepszymi właściwościami
746 Część IV
użytkowymi. Do wielu sterowników nie można ponadto uzyskać dostępu bez
wykonywania bezpośrednich odwołań ODBC API - nie są one obsługiwane przez
większość narzędzi poza tymi, które pretendują do zgodności z ODBC.
Inaczej jest w przypadku BDE. Z zasady, oparte o BDE sterowniki SQL Link
obsługują platformy bazy danych w sposób kompleksowy. Ich funkcjonalność
potwierdza się w pracy komponentów baz danych Delphi. Np. serwery baz danych
SQL dysponują mechanizmem kontroli transakcji, który umożliwia grupowanie
porcji zmian w bazie danych z zachowaniem (lub bez) ich kompletności. Składnia
SQL wymaga zapoczątkowania zmian grupy transakcji z serwera do serwera.
Z drugiej strony tabele lokalne nie pozwalają na stosowanie przetwarzania
transakcyjnego. Mimo sprzeczności między producentami w zakresie składni SQL
i mimo braku obsługi transakcji w tabelach lokalnych, BDE zapewnia pojedyncze
odwołanie API do rozpoczęcia transakcji na dowolnej platformie:
DbiBeginTran. Ta właściwość znajduje nawet zastosowanie dla tabel
lokalnych; BDE tworzy dla nich swój własny mechanizm kontroli transakcji.
Delphi zawiera to odwołanie BDE API w metodzie BeginTransaction
swojego komponentu TDatabase, co pozwala na zainicjowanie transakcji na
platformie serwera, bez odwoływania się do tabeli aktualnej. Tym samym można
stosować przetwarzanie transakcyjne tabel lokalnych, bez względu na
ograniczenia. BDE zapewnia jednolity interfejs API, bez względu na rodzaj
stosowanego systemu zarządzania bazą danych (DBMS).
Architektura
Architektura BDE bazuje na sterownikach - dla każdego stosowanego systemu
obsługi baz danych (DBMS) wymagany jest oddzielny sterownik. Czasami
pojedynczy sterownik obsługuje wiele wersji platform DBMS (np. istnieje jeden
sterownik dla platformy dBASE, bez względu na to, czy mamy do czynienia
z dBASE III, IV lub V, FoxPro lub systemem Clipper).
Rozważając to zagadnienie, lepiej zrozumiemy architekturę BDE. Dostęp z Delphi
do obiektu bazy danych realizowany jest następująco:
1. Odwołanie się do komponentu bazy danych Delphi.
2. Komponent wywołuje BDE.
3. BDE wywołuje swoją lokalną bazę danych lub sterownik SQL Links.
4. Jeśli używany jest sterownik lokalny, wówczas udostępnia on tabele bazy
danych
5. Jeśli używany jest sterownik SQL Links, wywołuje on sterownik klienta
producenta DBMS.
Rozdzial 26 Borland Database Engine (BDE) 747
BDE jest zorientowany obiektowo - charakteryzuje się wygodną obsługą
i łatwością rozszerzania. Jeśli zachodzi potrzeba uzyskania dostępu do platformy
DBMS, dla której BDE nie zapewnia pełnej obsługi, należy po prostu zainstalować
- dedykowany dla tej platformy - sterownik BDE lub ODBC. Jest mało
prawdopodobne, aby trzeba było przerabiać BDE, by mógł obsługiwać nowe
platformy.
BDE jest przygotowany do pracy w trybie klient/serwer - obsługuje wszystkie
zaawansowane funkcje, których użytkownicy oczekują od DBMS typu
klient/serwer. Mamy tutaj na myśli m.in.: przetwarzanie transakcji, aktualizowanie
kursorów, obsługę procedur pamiętanych i inne. Zamiast stosować metodę
najmniejszego wspólnego mianownika do obsługi baz danych, BDE dysponuje
interfejsem API, który jest superzestawem funkcji dostępnych na wszystkich,
obsługiwanych przez niego platformach. Ponieważ sterowniki i API nie są z sobą
w powiązane w BDE, przejście z platformy na platformę nigdy nie było łatwiejsze.
Skalowanie związane z przejściem z tabel lokalnych na platformy typu
klient/server jest tak łatwe, jak zmiana aliasu bazy danych, stosowanego przez
aplikację do wskazania nowej platformy.
Usługi współdzielone
Mocna strona BDE wynika z faktu, iż oferuje on usługi, które mogą być
współdzielone przez sterowniki baz danych. Często dzięki temu nie trzeba
ustanawiać oddzielnych usług dla każdego sterownika. Ma to pozytywny wpływ na
ogólną efektywność aplikacji i zapewnia zgodność pomiędzy driverami.
Usługi systemu operacyjnego (OS)
Ponieważ BDE udostępnia swoim sterownikom pełny zestaw usług, izolując je od
bezpośredniego kontaktu z systemem operacyjnym i siecią, jest on w dużej mierze
od niego niezależny.
Menadżer bufora
Pierwszą usługą systemu operacyjnego jest Współdzielony menadżer bufora,
oparty na priorytetach i umożliwiający współdzielenie tego samego dynamicznego
obszaru bufora przez wszystkie sterowniki BDE. Aczkolwiek stosowanie obszaru
dynamicznego nie jest konieczne, sterowniki wykorzystujące wspólny obszar
dynamiczny oszczędzają zasoby systemu.
748 Część IV
Menadżer pamięci
Aby zwiększyć wydajność przydziału mniejszych obszarów pamięci, BDE
dysponuje swoim własnym mechanizmem przydziału pomocniczego. Dzięki niemu
sterowniki nie muszą każdorazowo odwoływać się do systemu operacyjnego, gdy
potrzebują małej ilości pamięci. BDE przydziela większe fragmenty pamięci RAM
i następnie przekazuje je klientowi zgłaszającemu żądania jej przydziału.
Bufor danych typu BLOB
W celu przyspieszenia dostępu do obiektów typu BLOB, BDE zapewnia bufor
danych BLOB. Pamięć ta uwalnia programistów od konieczności zakładania
własnych buforów. Umożliwia ponadto swobodny dostęp do informacji typu
BLOB - tak, by użytkownicy BDE nie musieli się zajmować zapisywaniem
zawartości tego typu danych do pliku zewnętrznego. Ten swobodny dostęp
realizowany jest nawet na platformach, które - ze swojej strony - nie zapewniają
dostępu do danych tego typu.
Mechanizm sortowania
BDE zapewnia szybki mechanizm sortowania, wykorzystywany przez mechanizm
zapytań, sterowniki dBASE i Paradoxa. Firma Borland posiada dwa różne patenty
na architekturę tych mechanizmów sortowania.
Mechanizm zapytań
Aparat zapytań BDE jest mocnym, pełnowartościowym procesorem zapytań, który
szybko wytwarza pełne zestawy wynikowe. Mechanizm ten obsługuje zarówno
metody Zapytanie przez przykład (QBE- Query By Example) i bezpośrednio
metody SQLa - zapytywania baz danych za pośrednictwem każdego,
obsługiwanego przezeń sterowników. SQL można np. wykorzystywać do zapytania
tabel dBASE, nawet w przypadku tabel lokalnych, pozbawionych właściwej
obsługi przetwarzania zapytań SQL.
Generator SQL
Jak już wspomniano, BDE umożliwia tworzenie zapytań baz danych przy pomocy,
znanej z Paradoxa, metody QBE lub używając tradycyjnych instrukcji SQL. Gdy
zapytanie QBE przesyłane jest do serwera SQL, tłumaczone jest najpierw przez
BDE na SQL.
Rozdzial 26 Borland Database Engine (BDE) 749
Restrukturyzacja
Usługa współdzielona Restrukturyzacja umożliwia wykonanie modyfikacji
struktur tabel dBASE i Paradox, bez konieczności zaznajamiania się z szczegółami
tego procesu. Obsługuje ona automatyczne tworzenie tymczasowych tabel lub
zapisywanie i ponowne ładowanie danych.
Usługa translacji danych
BDE dostarcza usługę realizującą translację danych pomiędzy różnymi formatami.
Właściwość ta pozwala funkcjom i usługom na operacje między bazami danych.
W przypadku konwersji pomiędzy podobnymi formatami, usługa określa najlepszą
metodę konwersji i wykonuje ją.
Funkcje integralnej obsługi tabel
BDE zapewnia potężny mechanizm służący do przenoszenia danych z jednego
formatu na inny oraz do obsługi łączenia podobnych do siebie tabel. Usługa ta jest
podstawą komponentu Delphi - TBatchMove i programu narzędziowego Data
Pump.
Tabele w pamięci
Podobnie w przypadku, gdy mamy do czynienia z wieloma platformami DBMS
klient/serwer, BDE obsługuje tabele tymczasowe, które istnieją tylko w pamięci.
Usługa ta przyspiesza dostęp do danych, zwiększa efektywność sortowania
i zapewnia niezbędne podstawy dla uaktualnień buforowanych.
Kursory łączone
BDE obsługuje kursory łączone na poziomie mechanizmu, zaspakajając potrzebę
VCL Delphi, uwalnia jednocześnie projektanta aplikacji od zajmowania się tym
problemem. Aączenie jednego kursora z innym powoduje przejście
przemieszczanie się jednego kursora w czasie zmian drugiego. Zwykle kursor
łączony stosowany jest podczas ustanawiania związków ogólny/szczegółowy
między tabelami.
Usługi sterowników SQL
Dla sterowników bazujących na SQL dostarczana jest seria mini usług - m.in.
translacja komend nawigacyjnych do SQL-a (dzięki czemu dysponować możemy
750 Część IV
łatwiejszym dostępem do tabel lokalnych i SQL), słownik danych i usługi
katalogowe obiektów oraz manipulacja buforowanymi polami typu BLOB.
Menadżer systemu
W razie konieczności Menadżer systemu dla BDE ładuje sterowniki i zwalnia
zasoby, gdy nie są one już dłużej potrzebne.
Menadżer konfiguracji
Usługa zarządzania konfiguracją BDE umożliwia klientom odczyt i zapis
informacji dotyczącej konfiguracji sterownika. Menadżer umożliwia tworzenie
aliasów, zapytań o parametry sterowników itd.
Sterowniki językowe
Dzięki sterownikom językowym BDE, twórcy aplikacji nie muszą się martwić
o zachowanie BDE w przypadku zmiany języka.
BDE API
BDE API jest interfejsem użytkownika API, zapewniającym pojedynczy
i zunifikowany zestaw odwołań API, zarówno dla zasobów baz danych opartych
o ISAM, jak i zdalnych. Każdy typ bazy danych ma dedykowany sobie interfejs
API. Stąd nawet, gdyby dwukierunkowa nawigacja pomiędzy obiektami bazy
danych serwera SQL nie była właściwie obsługiwana przez producentów DBMS,
Delphi zapewnia ją (w obu kierunkach) w zdalnych zbiorach wynikowych (czego
moglibyśmy oczekiwać normalnie od tabel lokalnych, ale nie od zdalnych). Co
więcej - mimo, iż dBASE i Paradox, jako formaty plików lokalnych, nie posiadają
wbudowanej obsługi transakcji, BDE zapewnia dla nich mechanizm kontroli
transakcji, który wykorzystuje te same odwołania API jak platformy, które te
transakcje obsługują.
BDE API (co można odczytać jedynie pozytywnie) nie obsługuje wszelkich
elementów właściwych każdej platformie DBMS, dla której pracuje. Stąd np.
indeksy systemu Clipper są teraz obsługiwane przez sterownik BDE dBASE,
indeksy pierwotne natomiast - przez sterownik systemu Paradox. Procedury
pamiętane obsługiwane są na tych platformach SQL, które mają je wbudowane itd.
Rozdzial 26 Borland Database Engine (BDE) 751
Minimalne właściwości funkcjonalne
Na platformach, dla których dostępny jest rodzimy sterownik BDE lub ODBC,
dostępne będą zawsze następujące funkcje:
Otwieranie/zamykanie baz danych
Pobieranie/nadawanie wartości właściwości w obiektach baz danych
Odczytywanie/zapisywanie danych w obiektach baz danych
Tworzenie obiektów baz danych, takich jak tabele i indeksy
Wykonywanie operacji między bazami danych - jak kopiowanie jednej bazy do
innej
Podstawowe struktury BDE
Aby stworzyć aplikację współpracującą z BDE, powinniśmy znać podstawowe,
wykorzystywane przez ten mechanizm, struktury danych (tabela 26.1):
Tabela 26.1 Podstawowe struktury danych BDE
Struktura Opis
BATTb1Desc
Integralny deskryptor tabeli
CANHdr
Nagłówek klasy węzła filtra
CBPROGRESSDesc
Procedura zwrotna wskaznika postępu
RESTcbDESC
Procedura zwrotna restrukturyzacji tabeli
CFGDesc
Deskryptor konfiguracji
CLIENTInfo
Informacja o aplikacji klienta
CRTb1Desc
Deskryptor atrybutów tabeli
DBDesc
Deskryptor bazy danych
DBIEnumFld
Pole wyliczeniowe
DBIEnv
Deskryptor środowiska BDE
DBIErrInfo
Deskryptor informacji o błędzie
DBIQryProgress
Wskaznik statusu zapytania
DRVType
Deskryptor informacji o sterowniku
FILEDesc
Deskryptor pliku
752 Część IV
Struktura Opis
FILTERInfo
Deskryptor informacji o filtrze
FLDDesc
Deskryptor pola
FLDType
Deskryptor typu pola
FMLDesc
Deskryptor sterownika języka
FMTBcd
Format liczby dziesiętnej kodowanej dwójkowo
FMTDate
Format danej
FMTNumber
Format liczby
FMTTime
Format czasu
DbiFUNCArgDesc
Deskryptor argumentu funkcji zdalnego zasobu
danych
DbiFUNCDesc
Deskryptor funkcji zdalnego zasobu danych
IDXDesc
Deskryptor indeksu
IDXType
Deskryptor typu indeksu
LDDesc
Deskryptor sterownika języka
LOCKDesc
Deskryptor blokady
RECProps
Deskryptor własności rekordu
RINTDesc
Deskryptor integralności
SECDesc
Deskryptor ochrony
SESInfo
Deskryptor informacji o sesji
SPDesc
Deskryptor procedury standardowej
SPParamDesc
Deskryptor parametrów procedury standardowej
SYSConfig
Deskryptor informacji o konfiguracji systemu
SYSInfo
Deskryptor statusu systemu BDE
SYSVersion
Deskryptor informacji o wersji systemu BDE
TBLBaseDesc
Deskryptor informacji o tabeli podstawowej
TblExtDesc
Deskryptor informacji o tabeli dodatkowej
TBLFullDesc
Deskryptor informacji o tabeli pełnej
TBLType
Deskryptor możliwości tabeli
Rozdzial 26 Borland Database Engine (BDE) 753
Struktura Opis
USERDesc
Deskryptor użytkownika
VCHKDesc
Deskryptor sprawdzenia ważności
XInfo
Deskryptor transakcji
Oprócz tych struktur BDE definiuje obiekty podane w tabeli 26.2.
Tabela 26.2 Obiekty definiowane przez BDE
Obiekt Typ Opis
hDBICur hDBIObj
Uchwyt kursora
hDBIDb hDBIObj
Uchwyt bazy danych
hDBIObj UINT32
Uchwyt obiektu nieokreślonego
hDBIQry hDBIObj
Uchwyt zapytania
hDBISes hDBIObj
Uchwyt sesji
hDBIStmt hDBIObj
Uchwyt instrukcji zapytania
hDBIXact UINT32
Uchwyt transakcji
hDBIXlt hDBIObj
Uchwyt translacji
phDBICfg
^hDBICfg
Wskaznik uchwytu konfiguracji
phDBICur
^hDBICur
Wskaznik uchwytu kursora
phDBIDb
^hDBIDb
Wskaznik uchwytu bazy danych
phDBIObj
^hDBIObj
Wskaznik uchwytu nieokreślonego obiektu
phDBIQry
^hDBIQry
Wskaznik uchwytu zapytania
phDBISes
^hDBISes
Wskaznik uchwytu sesji
phdbistmt
^hdbistmt
Wskaznik uchwytu instrukcji
phDBIXact
^hDBIXact
Wskaznik uchwytu transakcji
phDBIXlt
^hDBIXlt
Wskaznik uchwytu translacji
Najczęściej w aplikacjach używane są zmienne: hDBIDb i hDBICur. Zmienna
hDBIDb zwracana jest przy otwieraniu bazy danych, hDBICur - przy otwieraniu
tabeli. Odpowiada to właściwościom DBHandle i Handle tabel TDBDataSet
i TBDEDataSet.
754 Część IV
Budowanie aplikacji BDE
Najprawdopodobniej nie będziemy autorami aplikacji, stworzonej wyłącznie przy
pomocy odwołań BDE (tj. z pominięciem komponentów bazodanowych Delphi).
Niemniej jednak wiedza o wymaganiach takiej aplikacji może być pożyteczna,
ponieważ pomaga zrozumieć procesy, w wyniku których Delphi zapewnia dostęp
do bazy danych. Aby stworzyć aplikacje stosując tylko odwołania BDE API,
powinniśmy wykonać 12 podstawowych kroków:
1. Zainicjować mechanizm BDE.
2. Ustawić warstwę analizy programu (debug layer).
3. Otworzyć bazę danych.
4. Ustawić katalog roboczy.
5. Ustawić katalog tymczasowy.
6. Otwierając tabelę stworzyć kursor.
7. Pobrać właściwości tabeli
8. Ulokować obszar bufora rekordu.
9. Przesunąć kursor na pożądany rekord.
10. Pobrać rekord z kursora.
11. Pobrać żądane pole z rekordu.
12. Zwolnić wszystkie przydziały zasobów.
Listing 26.1 ilustruje powyższe 12 kroków. W tym przykładzie dokonywana jest
konwersja aplikacji wzorcowej (pobranej z Helpa BDE) - z języka C na Object
Pascal. Po zakończeniu konwersji, aplikacja jest wstawiana do zdarzenia
OnClick komponentu przycisku.
Listing 26.1. Aplikacja wzorcowa BDE Help przepisana w Object
Pascalu i poddana konwersji na obsługę zdarzenia OnClick
przycisku.
{*******************************************************}
{ }
{ BDE Template Program }
{ }
{ Copyright (c) 1996 Borland International }
{ }
{*******************************************************}
{
Conversion to Object Pascal by Ken Henderson.
Rozdzial 26 Borland Database Engine (BDE) 755
}
unit bdetemp;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Ą' Controls, Forms, Dialogs,
StdCtrls, ToolWin, ComCtrls, BDE;
type
TForm1 = class(TForm)
ToolBar1: TToolBar;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
hDb : hDBIDb; // Handle to the Database
hCur : hDBICur; // Handle to the cursor (table)
szTblName : String;
szTblType : String;
CursorProps : CURProps; // Properties of the cursor
pRecBuf : pBYTE; // Pointer to the record buffer
EmpNo : integer;
isBlank : BOOL;
function Chk(ErrorValue : DBIResult) : DBIResult;
var
dbi_status : string;
dbi_string : string;
ErrInfo : DBIErrInfo;
count : integer;
begin
dbi_status:= ;
dbi_string:= ;
if (ErrorValue <> DBIERR_NONE) then begin
DbiGetErrorInfo(TRUE, ErrInfo);
756 Część IV
if (ErrInfo.iError = ErrorValue) then begin
dbi_status:= ERROR + ErrInfo.szErrCode;
With ErrInfo do
for count:=low(szContext) to high(szContext) do
if (strcomp(ErrInfo.szContext[count],
Ą' )<>0) then
dbi_status := dbi_status+ + ErrInfo.
Ą' szContext[count];
end else begin
SetLength(dbi_string, DBIMAXMSGLEN);
DbiGetErrorString(ErrorValue, PChar
Ą' (dbi_string));
dbi_status := ERROR +dbi_string;
end;
MessageBox(0, PChar(dbi_status), BDE Error , MB_OK
Ą' or MB_ICONEXCLAMATION);
end;
result:=ErrorValue;
end;
begin
hDb := nil;
hCur := nil;
ShowMessage( Initialize engine );
Chk(DbiInit(nil)); // Step 2
ShowMessage( Set debug layer options );
DbiDebugLayerOptions(DEBUGON or OUTPUTTOFILE or
Ą' FLUSHEVERYOP, TRACE.TXT );// Step 3
ShowMessage( Open database );
Chk(DbiOpenDatabase( // Step 4
nil, // Database name - nil for standard
Ą' database
nil, // Database type - nil for standard
Ą' database
dbiREADWRITE, // Open mode - Read/Write or Read only
dbiOPENSHARED, // Share mode - Shared or Exclusive
nil, // Password - not needed for the
Ą' STANDARD database
0, // Number of optional parameters
nil, // Field Desc for optional parameters
nil, // Values for the optional parameters
hDb)); // Handle to the database
ShowMessage( Set table directory );
Rozdzial 26 Borland Database Engine (BDE) 757
Chk(DbiSetDirectory( // Step 5
hDb, // Handle to the database which
Ą' is being modified
C:\Program Files\Borland\Delphi 3.0\Demos\Data ));
Ą' // The new working directory
ShowMessage( Set private directory );
Chk(DbiSetPrivateDir( // Step 6
c:\temp )); // Select a directory on
Ą' a local drive not used
// by other applications.
szTblName:= EMPLOYEE ;
szTblType:=szPARADOX;
ShowMessage( Open table );
Chk(DbiOpenTable( // Step 7
hDb, // Handle to the standard
Ą' database
PChar(szTblName), // Name of the table
PChar(szTblType), // Type of the table - only
Ą' used for local tables
nil, // Index Name - Optional
nil, // IndexTagName - Optional.
Ą' Only used by dBASE
0, // IndexId - 0 = Primary.
dbiREADWRITE, // Open Mode - Read/Write or
Ą' Read Only
dbiOPENSHARED, // Shared mode - SHARED or EXCL
xltFIELD, // Translate mode - Almost
Ą' always xltFIELD
FALSE, // Unidirectional cursor
Ą' movement.
nil, // Optional Parameters.
hCur)); // Handle to the cursor
ShowMessage( Get cursor properties );
Chk(DbiGetCursorProps( // Step 8
hCur, // Handle to the cursor
CursorProps)); // Properties of the cursor
Ą' (table)
ShowMessage( Allocate a record buffer );
GetMem(pRecBuf,CursorProps.iRecBufSize * sizeof(BYTE));
Ą' // Step 9
if (pRecBuf = nil) then
ShowMessage( Error allocating buffer )
else begin
758 Część IV
ShowMessage( Set cursor to the crack before the
Ą' first record );
Chk(DbiSetToBegin(hCur)); // Step 10
Ą' // Position the specified cursor to the crack
Ą' // before the first record
ShowMessage( Get the next record );
Chk(DbiGetNextRecord( // Step 11
hCur,
Ą' // Cursor from which to get the record.
dbiNOLOCK, // Lock Type
pRecBuf,
Ą' // Buffer to store the record
nil));
Ą' // Record properties - don t need in this case
ShowMessage( Get a field out of the record buffer );
Chk(DbiGetField(
hCur, // Cursor which contains the record
1, // Field Number of the EmpNo
Ą' field.
pRecBuf, // Buffer containing the record
@EmpNo, // Variable for the EmpNo
isBlank)); // Is the field blank?
ShowMessage( The retrieved field
value is + IntToStr(EmpNo));
end;
ShowMessage( Clean-up );
if (pRecBuf <> nil) then
freemem(pRecBuf); // Free the record buffer
if (hCur <> nil) then
Chk(DbiCloseCursor(hCur)); // Close the cursor
if (hDb <> nil) then
Chk(DbiCloseDatabase(hDb)); // Close the database
DbiExit; // Close the BDE.
end;
end.
Rozdzial 26 Borland Database Engine (BDE) 759
Jak można zauważyć kod jest dołączany do przycisku zdarzenia OnClick na
formularzu Delphi. Kod ten można wpisać do własnego zdarzenia OnClick - by
sprawdzić jego działanie. Należy zauważyć, że moduł ten powoduje otwarcie
tabeli EMPLOYEE w katalogu: C:\Program Files\Borland\Delphi
3.0 \Demos\Data. W związku z tym należy zadbać, aby tabela ta zaistniała
przed uruchomieniem modułu.
W klauzuli Uses modułu należy odnotować wykorzystanie modułu BDE. Zawiera
wszystkie informacje o procedurach i typach danych dla mechanizmu bazy danych.
Aby były one dostępne bezpośrednio dla BDE należy dodać je do polecenia Uses.
Aczkolwiek większość twórców aplikacji Delphi nigdy nie buduje aplikacji, która
realizuje dostęp do bazy danych wyłącznie przy pomocy odwołań BDE API,
powyższy kod traktować możemy jako pewien szablon, przy pomocy którego
można tego dokonać.
Dostęp do BDE z aplikacji Delphi
Najbardziej prawdopodobny jest scenariusz zakładający, iż prawie cały dostęp do
bazy danych realizowany będzie przy pomocy wbudowanych komponentów
Delphi (z wykonywaniem niektórych specjalizowanych funkcji poprzez
bezpośrednie odwołania BDE). Ilustracją tego typu podejścia jest komponent
LiveQuery (opisany szczegółowo w rozdziale 27), stosujący - w celu
wykonania zapytania w zdarzeniu BeforeOpen potomka TTable - funkcję
BDE DBiQExecDirect. Kod zródłowy podano w listingu 26.2.
Listing 26.2 Komponent LiveQuery wykorzystuje funkcję BDE
o nazwie DBiQExecDirect
(
Komponent Delphi LiveQuery
Obsługuje edycję zbiorów wynikowych servera SQL przy pomocy
tymczasowych perspektyw (views). Umożliwia to uaktualnienie
każdego modyfikowalnego zbioru wynikowego przez użytkownika,
który stworzył go jako perspektywę na serwerze. Dlatego
obsługiwane są wszystkie modyfikacje, które mogłyby być
obsługiwane przez serwer za pośrednictwem perspektyw.
Napisał Ken Henderson.
Copyright 1995 by Ken Henderson
Kilka zastrzeżeń:
1) Sztuczka ta jest wykonywana przy pomocy tymczasowych
perspektyw i w związku z tym:
760 Część IV
a) Ponieważ pewne platformy, jak Sybase, nie obsługują
tymczasowych perspektyw, musiałem skonstruować nazwę
tymczasową (temp name) oraz stworzyć i opuścić
perspektywę. Nazwa powstała na podstawie daty i czasu,
w związku z tym kolizje z innymi użytkownikami są
praktycznie niemożliwe. Patrz kod zródłowy. Możliwa
jest obsługa ewentualnych wyjątków. Jeśli taka sytuacja
zdarzy się, ponownie wydawane jest polecenie Open ....
b) Oczywiście twoi użytkownicy nadal będą potrzebowali
zezwolenia na tworzenie perspektyw.
c) Ponieważ komponent ten tworzy perspektywy, jest tylko
użyteczny na serwerach, które je obsługują (tj.:
serwerach zdalnych) - nie można go używać z tabelami
dBASE i Paradox.
Po stronie korzyści:
1) Do opisu modyfikowalnych perspektyw możemy użyć dowolnej
składni, która jest obsługiwana przez komputer. Składnia ta
powinna zapewniać:
a) dowolną, żądaną liczbę tabel za pośrednictwem złączeń
b) klauzule (clauses)
Pozwoli to na ulokowanie całego obciążenia na serwerze, gdzie
moim zdaniem powinno się znajdować. Oznacza to także, że
wykonywane polecenia SQL będą najpierw kompilowane, co jest
bardziej efektywne. Jeśli serwer nie akceptuje modyfikacji
która ma być wykonana, wystąpi oczywiście wyjątek.
}
unit Liveqry;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes,
Ą' Graphics, Controls,
Forms, Dialogs, DB, DBTables, BDE;
const
DEFAULTCREATEVIEWSQL = CREATE VIEW %s AS ;
DEFAULTDROPVIEWSQL = DROP VIEW %s ;
DEFAULTTABLENAMEFORMAT = TV%s ;
type
TLiveQuery = class(TTable)
private
{ Private declarations }
FCreateViewSQL : String;
FDropViewSQL : String;
Rozdzial 26 Borland Database Engine (BDE) 761
FTableNameFormat : TFileName;
FSQL : TStrings;
procedure SetQuery(Value: TStrings);
protected
{ Protected declarations }
procedure CreateTemporaryView;
procedure DropTemporaryView;
procedure DoBeforeOpen; override;
procedure DoAfterClose; override;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
{ Published declarations }
property CreateViewSQL : String read FCreateViewSQL
Ą' write FCreateViewSQL;
property DropViewSQL : String read FDropViewSQL
Ą' write FDropViewSQL;
property SQL : TStrings read FSQL write SetQuery;
property TableNameFormat : TFileName read
Ą' FTableNameFormat write FTableNameFormat;
end;
procedure Register;
implementation
constructor TLiveQuery.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FSQL := TStringList.Create;
FCreateViewSQL := DEFAULTCREATEVIEWSQL;
FDropViewSQL := DEFAULTDROPVIEWSQL;
FTableNameFormat := DefaultTableNameFormat;
end;
destructor TLiveQuery.Destroy;
begin
If Active then begin
Close;
DropTemporaryView;
end;
SQL.Free;
inherited Destroy;
end;
procedure TLiveQuery.SetQuery(Value: TStrings);
begin
CheckInActive;
762 Część IV
SQL.Assign(Value);
end;
procedure TLiveQuery.CreateTemporaryView;
var
TemporaryDB : TDatabase;
WorkSQL : TStrings;
begin
WorkSQL := TStringList.Create;
WorkSQL.AddStrings(SQL);
TableName:=Format(TableNameFormat,[FormatDateTime( yymmdd
Ą' hhnnss ,Now)]);
WorkSQL.Insert(0,Format(CreateViewSQL,[TableName]));
TemporaryDB:=Session.OpenDatabase(DatabaseName);
If (TemporaryDB<>nil) then
try
If (TemporaryDB.IsSQLBased) then begin
If (DbiQExecDirect(TemporaryDB.
Ą' Handle,qrylangSQL,
PChar(WorkSQL.Text),nil)<>DBIERR_NONE) then
raise EDatabaseError.Create( Error creating
Ą' temporary view );
end else
raise EDatabaseError.Create( Cannot use this
Ą' component with local tables )
finally
Session.CloseDatabase(TemporaryDB);
WorkSQL.Free;
end;
end;
procedure TLiveQuery.DoBeforeOpen;
begin
inherited DoBeforeOpen;
CreateTemporaryView;
end;
procedure TLiveQuery.DropTemporaryView;
var
TemporaryDB : TDatabase;
WorkSQL : TStrings;
begin
try
WorkSQL:=TStringList.Create;
WorkSQL.Add(Format(DropViewSQL,[TableName]));
TemporaryDB:=Session.OpenDatabase(DatabaseName);
If (TemporaryDB<>nil) then begin
If (TemporaryDB.IsSQLBased) then begin
Rozdzial 26 Borland Database Engine (BDE) 763
If (DbiQExecDirect(TemporaryDB.Handle,
Ą' qrylangSQL, PChar(WorkSQL.Text),nil)
Ą' <>DBIERR_NONE) then
raise EDatabaseError.Create( Error dropping
Ą' temporary view );
end else
raise EDatabaseError.Create( Cannot use this
Ą' component with local tables )
finally
Session.CloseDatabase(TemporaryDB);
WorkSQL.Free;
end;
end;
end;
procedure TLiveQuery.DoAfterClose;
begin
DropTemporaryView;
inherited DoAfterClose;
end;
procedure Register;
begin
RegisterComponents( Data Access , [TLiveQuery]);
end;
end.
Zwróćmy uwagę na funkcję DBiQExecDirect. Zaraz po zbudowaniu procedurą
polecenia SQL WorkSQL, jest ono gotowe do przetworzenia. Z uwagi na fakt, iż
stosowany jest komponent potomny Table, nie ma prostej możliwości realizacji
utworzonego wyrażenia SQL. Jeśli LiveQuery był potomkiem komponentu
Query, wówczas możliwy byłby dostęp do procedury ExecSQL (ale tak nie jest).
Tak dzieje się, gdy w grę wchodzi funkcja DBiQExecDirect. W celu
wykonania zapytania SQL tworzony jest tymczasowy obiekt hDBIDb, przesyłany
następnie, wraz z zawartością WorkSQL, do funkcji DBiQExecDirect.
UWAGA
Jeśli nie osiągnięto zgodności z Serwerem SQL, wtedy - zamiast tymczasowego
połączenia bazy danych (które zostało stworzone przez komponent) - możemy
skorzystać z własności DBHandle komponentu LiveQuery. Serwer zakazuje
inicjowania nowego zapytania w czasie, gdy wyniki poprzedniego zapytania
pozostają nierozstrzygnięte - stąd stosowanie LiveQuery.Database.Handle
z funkcją DBiQExecDirect w środowisku SQL Serwer nie ma uzasadnienia.
764 Część IV
Należy zauważyć, że trzeci parametr funkcji DbiQExecDierct wymaga typu
danych PChar. Aańcuchy Pchar stanowią pascalową wersję łańcucha char*
w C i C++. Począwszy od Delphi 2.0, translacja łańcuchów pascalowych na
łańcuchy C/C++ ogranicza się do ich wpisania. Aańcuchy pascalowe są teraz
zakończone pustym znakiem (NULL) i twórcy aplikacji także tym nie muszą się
martwić. Co więcej - łańcuchy w Pascalu także zawierają pole długości, dzięki
czemu nie trzeba przeszukiwać łańcucha (ze względu na pusty znak) - by odczytać
ich długość, jak dzieje się to w przypadku języka C.
Wykonywanie odwołań do DBMS
BDE umożliwia również dostęp do bezpośredniej obsługi dla konkretnego DBMS.
Taka właściwość pozwala na wykonanie odwołań do funkcji w bibliotekach
klienta danego DBMS, z całkowitym pominięciem komponentów baz danych
Delphi i BDE. W pewnych okolicznościach poprawi to wydajność, umożliwiając
ponadto funkcjonalne pominięcie BDE.
Do pobrania uchwytu połączenia rodzimego do danej DBMS należy użyć funkcji
DbiGetProp.
W tabeli 26.3 zebrano typy informacji, dostępne na każdej platformie.
Tabela 26.3 Informacje platformy DBMS zwracane przez DbiGetProp.
Platforma Typ uchwytu Długość
gds_db_handle
InterBase 4
DBPROCESS NEAR *
Sybase 2
LDA
Oracle 64
HDBC
ODBC Socket 4
Poniższy fragment kodu zawiera pewien przykład składni, której można użyć na
platformie Sybase - by pobrać nazwy aktualnej bazy danych:
type
DBPROCESS = Pointer;
var
Form1: TForm1;
DBProc: DBPROCESS;
Size DBProc: Word;
function dbname(DBOros: DBPROCESS) : Pchar; external
Ą' LIBSYBDB ;
Rozdzial 26 Borland Database Engine (BDE) 765
implementation
{$R *.DFM)
Procedure TForm1.Button1Click(sender: Tobject);
begin
biGetProp(hDBiObj (Table1.DBHandle),dbNATIVEHNDL,
DBProc, SizeOf(DBProc), SizeDBProc;
Edit1.Text:=dbname(DBProc);
end;
W tym przykładzie funkcja dbname z biblioteki DB-Library jest odnoszona
zewnętrznie w LIBSYBDB DLL. Takie połączenie wymaga pojedynczego
parametru bieżącego połączenia uchwytu DBPROCESS. Uchwyt ten jest
pobierany poprzez wywołanie DbiGetProp i przekazywany następnie do
parametru dbNATIVEHNDL.
Pobieranie informacji charakterystycznych dla danej
platformy poprzez BDE
Jeśli zamiarem twórcy aplikacji jest umożliwienie użytkownikowi budowania
zapytań podczas wykonania programu, wówczas należy zapewnić sobie - na
wybranej platformie DBMS - możliwość listowania nie tylko tabel i kolumn, ale
także funkcji, które platforma obsługuje podczas zapytania o dane. Koniecznym
może okazać się wyświetlanie takich elementów, jak łańcuchy, dane i funkcje
numeryczne itd. Funkcją BDE, realizującą powyższe zadania, jest
DbiOpenFunctionList. Otwiera ona kursor w liście funkcji obsługiwanej
przez skojarzoną platformę DBMS. Aby pobrać kolejno każdą obsługiwaną nazwę
funkcji należy wywołać DBiGetNextRecord. Listingi 26.3 do 26.5 ilustrują
prosty program Delphi, wykorzystujący - do listowania tabeli obiektów obecnych
na aktualnej platformie DBMS oraz funkcji obsługiwanych przez platformę -
funkcję DbiOpenFunctionList
Program przedstawia listę rozwijalną aliasów BDE, które można wybrać i zapytać
o informacje dotyczące funkcji i tabeli.
Listing 26.3 Plik zródłowy projektu dla programu
przykładowego funkcji BDE DbiOpenFunctionList, FuncEx.
program funcex;
uses
Forms,
funcex"" in 'funcex"".pas' {Form1};
{$R*.RES}
766 Część IV
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Applicatiob.Run;
end.
Listing 26.4 Plik zródłowy modułu dla FuncEx00.PAS, tylko
moduł w programie przykładowym BDE DbiOpenFunctionList,
FuncEx.
unit funcex00;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, DBTables, StdCtrls, BDE;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
ListBox1: TListBox;
ComboBox1: TComboBox;
ListBox2: TListBox;
Database1: TDatabase;
procedure ComboBox1Change(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.ComboBox1Change(Sender: TObject);
function Chk(ErrorValue : DBIResult) : DBIResult;
var
dbi_status : string;
dbi_string : string;
ErrInfo : DBIErrInfo;
count : integer;
Rozdzial 26 Borland Database Engine (BDE) 767
begin
dbi_status:= ;
dbi_string:= ;
if (ErrorValue <> DBIERR_NONE) then begin
DbiGetErrorInfo(TRUE, ErrInfo);
if (ErrInfo.iError = ErrorValue) then begin
dbi_status:= ERROR + ErrInfo.szErrCode;
With ErrInfo do
for count:=low(szContext) to high(szContext) do
if (strcomp(ErrInfo.szContext[count],
Ą' )<>0) then
dbi_status := dbi_status+ +
Ą' ErrInfo.szContext[count];
end else begin
SetLength(dbi_string, DBIMAXMSGLEN);
DbiGetErrorString(ErrorValue,
Ą' PChar(dbi_string));
dbi_status := ERROR +dbi_string;
end;
MessageBox(0, PChar(dbi_status), BDE Error , MB_OK
Ą' or MB_ICONEXCLAMATION);
end;
result:=ErrorValue;
end;
var
hCur : hDBiCur;
FuncInfo : DBiFUNCDESC;
Counter : integer;
begin
With Database1 do begin
Connected:=False;
ListBox2.Items.Clear;
DatabaseName:=ComboBox1.Items[ComboBox1.ItemIndex];
Open;
Session.GetTableNames(DatabaseName, ,False, False,
Ą' ListBox1.Items);
end;
counter:=0;
If (Chk(DbiOpenFunctionList(Database1.Handle, [ic:ccc}
Ą' fnListINCL_USER_DEF, @hcur)) = DBIERR_NONE) then begin
if (hCur<>nil) then begin
while (DBiGetNextRecord(hCur,dbinolock,@FuncInfo,
Ą' nil)<>DBIERR_EOF) and (counter <50) do begin
ListBox2.Items.Add(FuncInfo.szName);
inc(counter);
end;
768 Część IV
DbiCloseCursor(hCur);
ListBox2.Sorted:=True;
end else ShowMessage( Error opening cursor );
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Session.GetDatabaseNames(ComboBox1.Items);
ComboBox1.ItemIndex:=0;
end;
end.
Listing 26.5 Plik formularza (.DFM) dla FuncEx00.PAS,
pojedynczy moduł w programie przykładowym BDE
DbiOpenFunctionList, FuncEx.
object Form1: TForm1
Left = 200
Top = 108
Width = 544
Height = 375
Caption = Form1
Font.Color = clWindowText
Font.Height = -11
Font.Name = MS Sans Serif
Font.Style = []
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 33
Top = 0
Width = 36
Height = 13
Caption = Aliases:
end
object Label2: TLabel
Left = 32
Top = 40
Width = 35
Height = 13
Caption = Tables:
end
object Label3: TLabel
Left = 216
Top = 40
Width = 98
Height = 13
Caption = Supported functions:
end
Rozdzial 26 Borland Database Engine (BDE) 769
object ListBox1: TListBox
Left = 32
Top = 56
Width = 177
Height = 209
ItemHeight = 13
TabOrder = 0
end
object ComboBox1: TComboBox
Left = 32
Top = 14
Width = 177
Height = 21
Style = csDropDownList
ItemHeight = 13
TabOrder = 1
OnChange = ComboBox1Change
end
object ListBox2: TListBox
Left = 216
Top = 56
Width = 177
Height = 209
ItemHeight = 13
TabOrder = 2
end
object Database1: TDatabase
DatabaseName = DBDEMOS
SessionName = Default
Left = 496
end
end
770 Część IV
Rysunek 26.1
Aplikacja FuncEX
pokazuje tabele
i funkcje dostępne
na platformie
DBMS.
Indeksy wyrażeniowe
Jedna z największych korzyści wynikających z faktu, że BDE obsługuje indeksy
oparte na wyrażeniach dBASE jest to, że wywodzący się z dBASE mechanizm
obliczania wartości (ewaluator) wyrażeń możemy wykorzystać we własnych
aplikacjach. Pozwala to na włączenie ewaluatora wyrażeń, wraz z bogactwem
indeksów dBASE, do aplikacji Delphi. Ewaluator obsługiwałby wyrażenia
zawierające wszystkie operacje i funkcje dostępne w indeksach dBASE.
Aby uzyskać dostęp do ewaluatora wyrażeń BDE należy stworzyć indeks
wyrażeniowy w oparciu o fikcyjną tabelę DBF dBASE. W tym celu powinniśmy
utworzyć jednowierszową tabelę dBASE (struktura nie ma znaczenia) oraz
umożliwić aplikacji wprowadzenie wyrażenia (które nie musi operować na tabeli).
Tabelę użyjemy tylko do stworzenia indeksu - by obliczyć wyrażenie. Gdy
wyrażenie jest wprowadzane do aplikacji, należy stworzyć indeksowanie tabeli na
bazie wprowadzonego wyrażenia (jako klucza). Wystarczy wówczas przełączyć
nowy indeks tak, aby stał się bieżącym indeksem tabeli i - wykorzystując funkcję
BDE DbiExtractKey - powrócić do głównej (lub obliczonej) wartości klucza..
Poniżej przedstawiliśmy fragment kodu z aplikacji stosującej opisaną technikę.
procedure TForm1.Button1Click(Sender: TObject);
var
IndexDesc : IDXDesc;
KeyString : String;
begin
Rozdzial 26 Borland Database Engine (BDE) 771
With Table1 do begin
If not Active then Open;
AddIndex('EXPEVAL',Edit.Text,[ixExpression]);
Close
IndexName:='EXPEVAL';
Open;
DbiGetIndexDesc(Table1.Handle,",IndexDesc);
SetLenght(KeyString,IndexDesc.iKeyLen);
DbiExtractKey(Tablee1.Handle, nil,
Ą' PChar(KeyString));
Edit2.Text:=KeyString;
Close;
DeleteIndex('EXPEVAL');
IndexName:='DUMMY';
end;
end;
Najważniejsza jest tutaj procedura DbiExtractKey, która zwraca poddaną
translacji lub wyliczoną - na podstawie indeksu. - wartość klucza Ta pożyteczna
właściwość umożliwia dodanie do skompilowanej aplikacji Delphi
przypominającego interpreter narzędzia, pozwalającego wyliczyć wartość
wyrażenia. Na rysunku 26.2 przedstawiono aplikację, wykorzystującą funkcję
DbiExtract do obliczenia wyrażenia złożonego.
Rysunek 26.2.
Aplikacja
z mechanizmem
kalkulacji wyrażeń
- funkcjąi BDE
DbiExtractKey
772 Część IV
Optymalizacja BDE
Optymalizacja BDE może być trudnym procesem. Wskazówki podane poniżej nie
stanowią "cudownego leku", ale pozwalają ocenić, czy mechanizm jest
dostatecznie szybki (i czy nie wymaga dodatkowej kosmetyki).
Modyfikacje danych są spowalniane przez liczne indeksy zewnętrzne.
W związku z tym należy ograniczyć je do niezbędnych. Może okazać się, że
będzie szybciej opuścić indeksy i przebudować je po wstawieniu danych.
Tabele powinniśmy otwierać jedynie w trybie wyłącznego dostępu.
miarę możliwości unikać manipulowania wierszami - lepiej operować na
W
porcjach BDE.
Stosując funkcję DbiWriteBlock powinniśmy starać się pracować
z blokami fizycznymi o różnej wielkości.
Funkcji DbiAcqPersistTableLock można użyć w stosunku fikcyjnej
tabeli - by wymusić stworzenie pliku .LCK, który - przy otwieraniu i zamykaniu
tabel - nie byłby kasowany i ponownie tworzony w trakcie otwierania
i zamykania tabel.
używać tabel tworzonych w pamięci operacyjnej, a nie na dysku
Należy
twardym. Nie wolno nam jednak zapominać o tym, iż tabel przechowywanych
w pamięci operacyjnej nie można indeksować, kopiować lub zapisywać
w sposób trwały.
Optymalizacja dostępu BDE do SQL
Optymalizacja SQL-a została omówiona dokładniej w rozdziale 24 i 25. W tym
miejscu ograniczyliśmy się do kilku ogólnych wskazówek związanych z dostępem
BDE do SQL.
Wykonując serię modyfikacji na serwerze SQL, należy stosować transakcje
jawne, unikając rozpoczynania i kończenia transakcji niejawnych dla każdej
modyfikacji.
Przygotować złożone zapytania i procedury pamiętane dla bezpośrednich
odwołań SQL (PassThrough SQL). W rezultacie BDE dostarczy, możliwie
najszybciej, nasze zapytania SQL do serwera, pozwalając nam na stosowanie
dowolnego SQL, wspieranego przez mechanizmy serwera.
Jak już wspominaliśmy, istnieje możliwość - dzięki informacjom przekazanym
przez funkcję IDAPI DbiGetProps - realizacji wywołań rodzimych dla
DBM.
Rozdzial 26 Borland Database Engine (BDE) 773
Wykonać pierwszy człon zapytania, co pozwoli zmniejszyć jego zbiór
wynikowy - a po zredukowaniu (w maksymalnym stopniu) zestawu wyników -
grupowanie lub złączenie .
pewnych przypadkach zalecane jest kopiowanie wyników zapytania do
W
lokalnej tabeli.
Funkcje DbiAddFilter, DbiSetRange i DbiSetFieldMap pomagają
zredukować ilość aktualnie dostępnych danych. Efektem każdorazowej redukcji
danych pierwotnych (przeznaczonych do przetwarzania) będzie przyspieszenie
pracy aplikacji. Zauważmy, że wszystkie te właściwości obsługiwane są
bezpośrednio przez kontrolki Delphi DataSet
Tworzenie indeksów zstępujących dla tabel, na których wykonywane jest
często przewijanie wsteczne, pozwala istotnie zaoszczędzić czas pracy serwera.
znajdujemy się w środku dużej tabeli lub jeśli tabela zawiera indeks
Gdy
złożony, powinniśmy unikać stosowania DbiSetToEnd i DbiSetToKey.
Wywołanie tych funkcji w nieodpowiednim momencie może spowodować
sekwencyjne przeglądanie przez aplikację znacznej liczbę wierszy.
Wyszukiwarka
Podobne podstrony:
27 rozdział 26 mjtwzr7c54hzzud5imqogonzh5caxp5cu7ky6eyTom I rozdziały 26 32Tom II rozdziały 26 30Bestia Zachowuje się Źle Shelly Laurenston Rozdział 26rozdział 26 LegomonizmRozdział 26Rozdział 26 Złożenie do grobuDom Nocy 09 Przeznaczona rozdział 26 TŁUMACZENIE OFICJALNERozdział 2626 27 10 arkusz AON I09 Rozdzial 27 30więcej podobnych podstron