Delphi 3. Библиотека программиста

       

Упаковка таблиц Paradox и dBASE


Дневник №16, 20 марта. В детстве мама все время заставляла меня убирать разнообразный хлам, не используемый в проектах, над которыми я тогда работал. Фразу: «Убирай за собой!»мне приходилось слышать по крайней мере раз в день. Наверное, у моего клиента была похожая мама — может быть, именно поэтому он обратился ко мне с просьбой изобрести легкий способ освобождения неиспользуемого места в таблицах Paradox и dBASE из приложений Delphi.

Наверное, мне пришла в голову та же мысль, что и моему странному клиенту — я предположил, что для этого должен существовать специальный метод компонента TTable. Это было бы вполне логично, потому что возможность упаковки предусмотрена и в dBASE, и в Paradox. Однако команда разработ чиков Delphi, видимо, стремилась мыслить глобально и обеспечить поддержку больших баз данных с архитектурой клиент/сервер, которые не воспринимают таких команд.

Хотя разработчики Delphi не предусмотрели непосредственной возможно сти для упаковки таблиц, они все же оставили средства для того, чтобы вы могли «залезть внутрь» и работать со средствами низкого уровня. Речь идет не только о внутреннем сервисе Windows, а о любом старом API, который пожелает стать доступным для программ — в том числе и Borland Database Engine (BDE).

Механизм BDE предоставляет программам множество низкоуровневых услуг. На нем основана работа компонентов Delphi, связанных с базами данных. Модули BDE доступны для любой Delphi-программы.

Небольшой поиск в Internet вознаградил меня процедурой, которая средствами BDE выполняет упаковку таблиц Paradox и dBASE. К сожалению, автор процедуры неизвестен, и я не могу должным образом поблагодарить его. Я слегка изменил код, чтобы преобразовать его в модуль и организовать обработку ошибок. Измененная версия процедуры содержится в файле PAKTABLE.PAS (см. листинг 14.5).

Листинг 14.5.

Модуль для упаковки таблиц Paradox и dBASE {——————————————————————————————————————————————————————} { Упаковка таблиц (демонстрационная программа) } { PAKTABLE.PAS : Главный модуль } { Автор: Эйс Брейкпойнт, N.T.P. } { При содействии Дона Тейлора } { } { Модуль, содержащий специализированную процедуру } { для упаковки таблиц Paradox и dBASE и удаления } { пустых записей } { } { Написано для *High Performance Delphi 3 Programming* } { Copyright (c) 1997 The Coriolis Group, Inc. } { Дата последней редакции 22/4/97 } {————————} unit PakTable; interface uses SysUtils, Dialogs, DBTables, DBiTypes, DBiProcs, DBiErrs; function PackTable(var ATable : TTable) : Boolean; implementation type EDBPackMisc = class(Exception); var ActiveStatus : Boolean; ExclusiveStatus : Boolean; Error : DBiResult; ErrorMsg : DBiMsg; pTableDesc : pCRTblDesc; AHandle : hDBiDB;

{ PackTable упаковывает записи в таблицах Paradox и dBASE (а в случае таблиц dBASE также производит фактическое удаление записей, ранее помеченных как удаленные). Свойство TableType упаковываемой таблицы должно быть равно либо ttParadox, либо ttDBase; ttDefault не подходит. Кроме того, таблица не должна больше никем использоваться, поскольку ее необходимо перевести в режим монопольного доступа. } function PackTable(var ATable : TTable) : Boolean; begin Result := False; try with ATable do begin { Сохраняем текущее состояние таблицы } ActiveStatus := Active; ExclusiveStatus := Exclusive; { Разрываем связь таблицы с элементами и устанавливаем монопольный режим } DisableControls; Active := False; Exclusive := True; end; { with } try { Упаковываем таблицу в зависимости от ее типа } case ATable.TableType of ttParadox : begin { Создаем таблицу с описанием и готовим ее к использованию } GetMem(pTableDesc, SizeOf(CRTblDesc)); FillChar(pTableDesc^, SizeOf(CRTblDesc), 0); with pTableDesc^ do begin StrPCopy(szTblName, ATable.TableName); StrPCopy(szTblType, szParadox); bPack := True; end; { with } { Получаем логический номер базы данных для таблицы } with ATable do begin Active := True; AHandle := ATable.DBHandle; Active := False; end; { with } try { Попытаемся реструктурировать/упаковать таблицу и обработать ошибки } Error := DBiDoRestructure(AHandle, 1, pTableDesc, nil, nil, nil, False); if Error = DBIERR_NONE then Result := True else begin DBiGetErrorString(Error, ErrorMsg); raise EDBPackMisc.Create(ErrorMsg); end; finally FreeMem(pTableDesc, SizeOf(CRTblDesc)); end; { try } end; ttDBase : with ATable do begin Active := True; Error := DBiPackTable(DBHandle, Handle, nil, nil, True); if Error = DBIERR_NONE then Result := True else raise EDBPackMisc.Create ("Could not pack this dBASE table"); end; else raise EDBPackMisc.Create ("Cannot pack this table type"); end; { case } except on E:EDBPackMisc do MessageDlg(E.Message, mtError, [mbOK], 0); end; { try } finally { Восстанавливаем исходное состояние таблицы } with ATable do begin Active := False; Exclusive := ExclusiveStatus; Active := ActiveStatus; EnableControls; end; { with } end; { try } end; end.

В Paradox и dBASE используются несколько отличающиеся способы удаления записей. Когда dBASE «удаляет» запись, она не уничтожается на физическом уровне. Запись всего лишь помечается как удаленная, для чего ее первый байт заменяется символом *. Преимущество такого подхода заключается в том, что удаленную запись можно легко «восстановить», а недоста ток — в том, что удаление записи не приводит к освобождению места на диске. С другой стороны, Paradox действительно уничтожает запись физически и повторно использует освободившееся место при добавлении новых записей.

Для упаковки таблиц этих двух видов также применяются различные

механизмы. Таблицы dBASE упаковываются командой DBiPackTable. Упаковка таблиц Paradox выполняется в процессе реструктурирования таблицы (таким образом становится понятно, почему возможность упаковки включена в диалоговое окно Restructure Table программы Paradox).
Большинство махинаций, выполняемых в PackTable, связано с фиксацией состояния таблицы (чтобы при выходе ее можно было восстановить) и приведением таблицы в должный вид перед обращением к BDE API. PackTable различает таблицы двух видов по значению свойства TableType. При установке свойств таблицы необходимо выбрать значение ttParadox или ttDBase; стандарт ное значение ttDefault не подойдет. Не важно, к какому типу относится упаковываемая таблица — она должна находиться в монопольном режиме. Никто не сможет обратиться к ней, пока выполняется операция упаковки.



Содержание раздела