(*****************************************************************************
* DbUtils.pas
*
* Утилита для работы с базами данных
*
* Создана 09/20/96
*****************************************************************************)
unit Dbutils;
(****************************************************************************)
(****************************************************************************)
interface
(****************************************************************************)
(****************************************************************************)
uses DbTables;
function DbGetVersion(table: TTable): LongInt;
(****************************************************************************)
(****************************************************************************)
implementation
(****************************************************************************)
(****************************************************************************)
uses Db, DbiProcs, DbiTypes, {DbiErrs,} SysUtils;
{---------------------------------------------------------------------------}
(*
* Цель: определение номера версии структуры таблицы
* Параметры: table (I) – интересующая нас таблица
* Возвращаемая величина: номер версии
* Исключительная ситуация: EDatabaseError
*)
function DbGetVersion(table: TTable): LongInt;
var
hCursor : hDBICur;
tableDesc: TBLFullDesc;
cName : array[0..255] of char;
begin
{ копируем имя таблицы в строку 'с' }
StrPCopy(cName, table.TableName);
{ просим BDE создать запись, содержащую информацию об определенной таблице }
Check(DbiOpenTableList(table.DBHandle, True, False, cName, hCursor));
{ получаем запись, содержащую информацию о структуре }
Check(DbiGetNextRecord(hCursor, dbiNOLOCK, @tableDesc, nil));
{ возвращаем поле записи, содержащее номер версии структуры нашей таблицы }
Result:= tableDesc.tblExt.iRestrVersion;
Check(DbiCloseCursor(hCursor));
end;
end.
Перемещение таблиц
Здесь я привожу примеры программ, которые я использую для копирования и удаления таблиц. Необходимые для работы модули: DB, DBTables, DbiProcs,DbiErrs, и DbiTypes. Вам всего лишь необходимо указать каталог расположения, исходное имя таблицы, каталог назначения и имя таблицы, куда будет скопирована исходная таблица и BDE скопирует таблицу целиком со всеми индексами. Процедура удаления в качестве входных параметров использует каталог расположения и имя таблицы, при этом BDE удаляет как саму таблицу, так и все файлы, связанные с ней (индексы и т.п.). Для тестирования данные процедуры были помещены в новое приложение и мне пришлось их немного отредактировать, чтобы удалить некоторые зависимости, которые были связаны с главной формой приложения. Теперь процедуры являются полностью автономными и могут быть помещены в отдельный модуль. (Не забудьте включить его в список используемых модулей). Пользуйтесь на здоровье!
procedure TConvertForm.CopyTable(FromDir, SrcTblName, ToDir, DestTblName: String);
var
DBHandle: HDBIDB;
ResultCode: DBIResult;
Src, Dest, Err: Array[0..255] of char;
SrcTbl, DestTbclass="underline" TTable;
begin
SrcTbclass="underline" = TTable.Create(Application);
DestTbclass="underline" = TTable.Create(Application);
try
SrcTbl.DatabaseName:= FromDir;
SrcTbl.TableName:= SrcTblName;
SrcTbl.Open;
DBHandle:= SrcTbl.DBHandle;
SrcTbl.Close;
ResultCode:= DbiCopyTable(DBHandle,false,
StrPCopy(Src,FromDir + '\' + SrcTblName), nil, StrPCopy(Dest,ToDir + '\' + DestTblName));
if (ResultCode <> DBIERR_NONE) then begin
DbiGetErrorString(ResultCode,Err);
raise EDatabaseError.Create('При копировании ' + FromDir + '\' + SrcTblName + ' в ' + ToDir + '\' + DestTblName + ' ,' + 'BDE сгенерировал ошибку ''' + StrPas(Err) + '''');
end;
finally
SrcTbl.Free;
DestTbl.Free;
end;
end;
procedure TConvertForm.DeleteTable(Dir, TblName: String);
var
DBHandle: HDBIDB;
ResultCode: DBIResult;
tbl, Err: Array[0..255] of char;
SrcTbl, DestTbclass="underline" TTable;
SrcTbclass="underline" = TTable.Create(Application);
try
SrcTbl.DatabaseName:= Dir;
SrcTbl.TableName:= TblName;
SrcTbl.Open;
DBHandle:= SrcTbl.DBHandle;
SrcTbl.Close;
ResultCode:= DbiDeleteTable(DBHandle, StrPCopy(Tbl,Dir + '\' + TblName), nil);
if (ResultCode <> DBIERR_NONE) then begin
DbiGetErrorString(ResultCode,Err);
raise EDatabaseError.Create('Удаляя ' + Dir + '\' + TblName + ', BDE ' + 'сгенерировал ошибку ''' + StrPas(Err) + '''');
end;
finally
SrcTbl.Free;
end;
end;
Прокрутка таблицы: хитрость PeekMessage()
На днях я решил поиграть с API-функцией PeekMessage(). Функция работает, но ловить ее нужно следующим образом.
Я прокручиваю таблицу, связанную с набором данных. "Поиск" в наборе данных замедляет процесс скролирования (условимся называть "поиском" синхронное перемещение табличного курсора в процессе скроллирования, при котором текущей записью становится запись, ближайшая к нажимаемой кнопке полосы прокрутки). Возникла задача: необходимо отменить "поиск" (процесс слежения) и переместить указатель на необходимую запись только в случае остановки пользователем процесса скроллирования, другими словами – пока пользователь осуществляет скроллирование, "поиск" необходимо отменить. Итак, ко мне в голову пришла мысль, что с помощью PeekMessage() можно выловить определенное сообщение и тем самым отменить поиск во время прокрутки. Звучит просто, но на самом деле все оказалось наоборот.
Я установил фильтр поиска сообщений на WM_MOUSEFIRST/LAST. Ситуация: пользователь непрерывно прокручивает DBGrid вниз, т.е. держит нажатой нижнюю кнопку скроллирования. В результате PeekMessage() возвращает False – нас это не устраивает, это не то, что мы хотим. Положительный результат можно получить только в случае сверхскоростных манипуляций мышью.