faqs.org.ru

 Главная > Программирование > Языки Pascal/Delphi >

FAQ по работе с СУБД на Delphi

Секция 2 из 3 - Предыдущая - Следующая
Все секции - 1 - 2 - 3

то для другого пользователя блокируестя вся таблица, до окончания транзакции.
Как лечить?
A>:
По умолчанию, оператор UPDATE в MS SQL Server пытается поставить эксклюзивную
табличную блокировку. Вы можете обойти это, используя ключевое слово FROM в
сочетании с опцией PAGLOCK для использования MS SQL Server страничных
блокировок вместо эксклюзивной табличной блокировки:

UPDATE orders SET customer_id=NULL FROM orders(PAGLOCK) WHERE customer_id=32;

(из статьи, потом вспомню, какой. AA)

Блокиpовка на всю таблицу пpи UPDATE ставится только в том случае,
если по пpедикату нет индекса. Так, можно пpосто пpоиндексиpовать таблицу orders по
полю customer_id, и не забывать делать UPDATE STATISTIC, хотя
будет работать и с PAGLOCK. Просто не факт, что UPDATE
всегда делает табличную блокировку.

Igor Lemeshko
igor@amanat.alma-ata.su
.

Q>:
[DESK] Какие есть рекомендации по использованию Apollo SDE?
A>:
1. При работе с Аполло (если у тебя базки в используются и досовскими
задачами) - то в dbgrid'e поставь значение Font->Charset = OEM_Charset.
И не забудь сразу после открытия базы вызывать метод
Apollo1.SetTranslate(True). Если твое приложение будет работать с базами
одновременно с досовскими, то советую перед открытием баз вызывать
метод Apollo1.SysProp( SDE_SP_SETOBUFFER, Pointer(0)) для отключения
буферизации операций чтения/записи в базы.

2.Если ты пишешь приложение, которое будет использовать базы только в
кодировке Windows (CP1251), то тебе достаточно будет указать в dbgrid'e
значение Font->Charset = Russian_Charset.

Roman Procopovich
(2:5030/254.201)

Если базы в 866 кодиpовке, то:
 1. Использование TTable + TApollo:
 === Cut ====
 TTable.Open;
 TApollo.SetTranslate(True);
 TTable.Refresh;
 === Cut ====

 2. Использование TApTable:
 === Cut ====
 TApTable.Open;
 TApTable.SetTranslate(True);
 TApTable.Refresh;
 === Cut ====

И вместо закоpючек бyдyт pодные pyсские бyквы. Пpавда, только пpи выполнении
пpогpаммы. В дизайнеpе на этапе пpоектиpования псевдогpафика так и останется.

Alexey Kogan
(2:5064/5.30)
.

Q>:
[VCL] Подскажите как правильно показать на экpане и сохранить в базе
картинку формата JPEG?
A>:
Я делал так (это кусок компонента):

if Picture.Graphic is TJPegImage then
  begin
    bs:=TBlobStream.Create(TBlobField(Field),bmWrite);
    Picture.Graphic.SaveToStream(bs);
    bs.Free;
  end
 else if Picture.Graphic is TBitmap then
         begin
           Jpg:=TJPegImage.Create;
           Jpg.CompressionQuality:=...;
           Jpg.PixelFormat:=...;
           Jpg.Assign(Picture.Graphic);
           Jpg.JPEGNeeded;
           bs:=TBlobStream.Create(TBlobField(Field),bmWrite);
           Jpg.SaveToStream(bs);
           bs.Free;
           Jpg.Free;
         end else Field.Clear;

Alex Gorbunov
www.media-press.donetsk.ua
(2:465/85.4)
.

Q>:
[MSSQL] При использовании MS SQL Server 6.5 в NT Performance Monitor
исчезли все датчики, кроме SQL. Как лечить?
A>
Кто виноват:
Дело в следующем - при инсталляции NT  страна была поставлена US, затем сменена
на Russia. В реестре для Perfomance Monitor существует (может существовать)
сколь угодно подуровней с названием счетчиков и описанием к ним. При
инсталляции
все естестественно ставилось в ветвь 409 (US) а ветви 419 (Russia) просто не
было.  Потом default location была сделана Russia. Perfomance Monitor не мог
найти 419  и брал все счетчики из 409. Но тут пришел SQL и как умная программа
при инсталляции создал ветвь 419 и запихал туда свои счетчики. Теперь
Perfomance
Monitor видит что текущая locale 419, в реестре она есть и берет оттуда
счетчики, а они там только для SQL естественно
Что делать:
Запускаешь regedit (regedt32), находишь где лежат описания счетчиков. Точно я
не помню, под рукой NT нет, но примерно так
HKEY_LOCAL_MACHINE/System/CurrentControlSet/Control/PerfLib/409
(419)
В каждом разделе по два ключа - список названий счетчиков и список их описаний.
Заходишь в 409, открываешь ключ для изменений и при помощи Ctrl-Ins копируешь
его содержимое в буфер обмена и жмешь Cancel. Теперь идешь в 419 открываешь тот
же ключ, идешь в начало списка и при помощи Shift-Ins вставляешь, жмешь Ok.
Так надо сделать и для названий счетчиков и для их описания.
Для полного счастья можно и SQL счетчики из 419 в 409 (в конец) скопировать.

Dmitry Lubimkov
(2:5038/7.26)
.

Q>:
[BDE] Каковы текущие ограничения BDE?
A>:
BDE: под Windows, все версии.

Если Вы обнаружите, что Вы ограничены более строго, чем здесь описано, или Вы получаете
ошибку выхода за пределы доступной памяти, то увеличение параметра SHAREDMEMSIZE в BDE Config
до 4096 или более может способствовать снятию более строгих ограничений.

Здесь указаны максимальные ограничения для некоторых общих обьектов BDE.

Основные ограничения BDE:
 48 клиентов в системе;
 32 сессии на одного клиента (для версии 3.5 и ниже, 16 Bit, 32 Bit)
 256 сессий на одного клиента (для версии 4.0 и выше, 32 Bit)
 32 открытых баз данных на сессию (для версии 3.5 и ниже, 16 Bit, 32 Bit)
 2048 открытых баз данных на сессию (для версии 4.0 и выше, 32 Bit)
 32 загруженных драйвера
 64 сессии в системе (для версии 3.5 и ниже, 16 Bit, 32 Bit)
 12288 сессии в системе (для версии 4.0 и выше, 32 Bit)
 4000 курсоров на сессию
 16 вхождений в стеке ошибок
 8 типов таблиц на один драйвер
 16 типов полей на один драйвер
 8 типов индексов на один драйвер
 48K Размер конфигурационного файла (IDAPI.CFG)
 64K Максимальный размер оператора SQL при RequestLive=False
 4K Максимальный размер оператора SQL при RequestLive=True (для версии 4.0 и ниже, 16/32 Bit)
 6K Максимальный размер оператора SQL при RequestLive=True (для версии 4.01 и выше, 32 Bit)
 16K Размер буфера записи (SQL и ODBC)
 31 Размер имени таблицы и имени поля в символах
 64 Размер имени хранимой процедуры в символах
 16 Полей в ключе
 3 Размер расширения имени файла в символах
 260 Длина имени таблицы в символах (некоторые сервера могут иметь другие ограничения)
 260 Длина полного имени файла и пути файловой системы в символах

Ограничения Paradox:
 127 открытых таблиц в системе (для версии 4.0 и ниже, 16/32 Bit)
 254 открытых таблиц в системе (для версии 4.01 и выше, 32 Bit)
 64 блокировки на запись на одну таблицу (16Bit) на одну сессию
 255 блокировок на запись на одну таблицу (32Bit) на одну сессию
 255 записей, учавствующих в транзакции на таблицу (32 Bit)
 512 открытых физически файлов (DB, PX, MB, X??, Y??, VAL, TV) (для версии 4.0 и ниже, 16/32 Bit)
 1024 открытых физически файлов (DB, PX, MB, X??, Y??, VAL, TV) (для версии 4.01 и выше, 32 Bit)
 300 пользователей в одном файле PDOXUSRS.NET
 255 полей в таблице
 255 размер символьных полей
 2 миллиарда записей в таблице
 2 миллиарда байт в .DB (таблица) файле
 10800 байт на запись для индексированных таблиц
 32750 байт на запись для неиндексированных таблиц
 127 вторичных индексов на таблицу
 16 полей на индекс
 255 одновременно работающих пользователей на таблицу
 256 Мегабайт данных на одно BLOb поле
 100 паролей на сессию
 15 длина пароля
 63 паролей на таблицу
 159 полей с проверками корректности (validity check) (32 Bit)
 63 поля с проверками корректности (validity check) (16 Bit)

Ограничения dBase:
 256 открытых таблиц dBASE на систему (16 Bit)
 350 открытых таблиц dBASE на систему (BDE 3.0 - 4.0, 32 Bit)
 512 открытых таблиц dBASE на систему (BDE 4.01 и выше, 32 Bit)
 100 блокировок на запись на одной таблице dBASE (16 and 32 Bit)
 100 записей, учавствующих в транзакции на таблицу (32 Bit)
 1 миллиард записей в таблице
 2 миллиарда байт в файле .DBF (таблица)
 4000 Размер записи в байтах (dBASE 4)
 32767 Размер записи в байтах (dBASE for Windows)
 255 Количество полей в таблице (dBASE 4)
 1024 Количество полей в таблице (dBASE for Windows)
 47 Количество тэгов индексов на один .MDX-файл.
 254 Размер символьных полей
 10 открытых основных индексов (.MDX) на таблицу
 220 Длина ключевого выражения в символах

Borland BDE TI2751 - Some current internal limits of BDE
(перевод: Акжан Абдулин)
.

> --- added in v4
Q>:
(Oracle) Как при вводе информации в БД автоматически вставлять SEQUENCE?
A>:
 Если добавление через оператор insert ( в TQuery), то прямо там пишешь,
как в плюсе ( "... Values (My_seq.nextval,...")
 Если добавление идет через TQuery c RequestLive=true, то в PreInsert
сделай запрос через Tquery ( select myseq.nextval from dual) и заноси
значение в свое поле.

Alexander Medvedev
(2:5010/3.88)
.

Q>:
(SAW) Как правильно работать с SQLAnywhere через BDE -> ODBC -> SAW?
A>:
1) Необходимо поставить patch на ODBC-драйвер (доступен на www.sybase.com);
2) Достаточно флажка Keys in SQL Statistics в ODBC администpатоpе, для того,
чтобы исчезла необходимость ставить втоpичные индексы по ключевым полям;
3) Если Вы пользуетесь BDE 3.5, то обновите ее до версии 4.x, или замените
idodbc.dll на тот, который идет в комплекте поставки BDE 3.0.

Oleg Saladaev
(2:5015/51.6)
.

Q>:
(DB2) Можно ли подсоединиться к другой БД из SP?
A>:
В DB2 можно. Если хочешь все корректно делать, ставь
distributed unit of work для всех соединений. Такое с гарантией
отработает.

Lilya A. Kozlenko
li@relex.ru
.

Q>:
В процессе работы программы изменилась структура БД (alter table etc.).
Программа продолжала успешно открывать таблицы, но запросы посылались в
соответствии со старой схемой данных. Как исправить?
A>:
В установках BDE (Configuration utility или BDEAdmin) можно выставить
SCHEMA CACHE = FALSE (не кэшировать схему данных).

Но в некоторых случаях ошибки такого рода все-таки происходят. В таком случае
необходимо воспользоваться методом TDatabase.FlushSchemaCache после каждого
изменения метаданных.

Alex Kaganoff
(2:5030/82.50)

Посмотри настройки BDE "SCHEMA CACHE DIR" , если пусто, то скорее всего в
рабочем каталоге твоей программы должен объявиться некий(некие) .ini файл(ы), в
котором хранятся указания на файлы, в которых храниция информация о кэше схемы
БД. Удали их.
/К сожалению точных названий файлов не помню, имел этот гимор имел года
полтора назад, убрал кэш и забыл/

Sergey Klochkovski
(2:5080/60.3)
.

Q>:
Как в Delphi сбросить кэш БД на диск?
A>:
uses BDE {в Delphi 1.x не помню, но вроде bdeprocs};

dbiSaveChanges

На Delphi 1.x (16bit) дополнительно вызовите эту процедуру -

procedure DropCache; assembler;
asm
  mov ah,$0D
  int $21
end;

Boris Podchezertseff
(2:5020/898.15)
.

Q>:
Как сделать так, чтобы в DBGrid напротив некоторых строк можно было бы
галочку поставить?
A>:
Ну примерно тaк (лишнее мaло-мaло порезaл, больно много его, но идея виднa :)

нa сервере - тaблицa Advertis.DB, первичный ключ ID - autoincrement.
Ha локaльном диске - тaблицa Founds.DB, с полем Advertis: integer, по которому
есть индекс, и tblFounds.IndexFieldNames = 'Advertis'.

Ha гриде:

=== cut ===

procedure TMainForm.dbgWorkDblClick(Sender: TObject);
begin
  TriggerRowSelection;
end;

procedure TMainForm.TriggerRowSelection;
begin
  if dmFile.AdvertisCount <> 0 then begin
    with dmFile do if not tblFounds.FindKey([tblAdvertisID.Value]) then begin
      tblFounds.AppendRecord([tblAdvertisID.Value]);
    end else begin
      tblFounds.Delete;
    end;
    dbgWork.Refresh;
  end;
end;

procedure TMainForm.dbgWorkDrawColumnCell(Sender: TObject;
  const Rect: TRect; DataCol: Integer; Column: TColumn;
  State: TGridDrawState);
begin
  if DataCol = 0 then with dmFile, dbgWork.Canvas do begin
    FillRect(Rect);                          {clear the cell}
    if tblFounds.FindKey([tblAdvertisID.Value]) then begin
      TextOut(Rect.Left, Rect.Top, 'ь');
    end;
  end;
end;

=== cut ===

Окaзывaется, я переопределял рисовaние гридa, a не вычислял поле. Не помню
точно, но кaжется, чтобы не перечитывaть тaблицу нa кaждый дaблклик, a только
перерисовaть грид.

А колонкa для гaлки в гриде определялaсь тaк:

=== cut ===
  with dmFile, dbgWork.Columns do begin
    BeginUpdate;
    Clear;

    {check mark}
    nc := Add;
    nc.Width := 14;
    nc.Font.Name := 'Wingdings';
    nc.Font.Size := 11;
    nc.Alignment := taRightJustify;
    nc.Title.Caption := 'ю';
    nc.Title.Font.Name := 'Wingdings';
    nc.Title.Font.Size := 10;
    nc.Title.Alignment := taCenter;

[skip определения остaльных колонок]

    EndUpdate;
  end;

=== cut ===

Вроде всё.
Ну, кaк нaпечaтaть/обрaботaть только помеченное, сaм рaзберёшься. У меня тaм
нaкручено чего-то с фильтрaми, думaю, можно проще.

Что кaсaется других способов - можно вместо временной тaблицы попользовaть
список, мaссив или in-memory table.

Dmitry Shikhman (Дмитрий Шихман)
(2:468/13.32)
.

Q>:
(PX) Что нужно сделать для нормальной работы в одноранговой сети
с базами Paradox?
A>:
BDE Config/Admin - нa вклaдке System устaнови LOCAL SHARE в TRUE!

Здесь комментарий -

В Help параметр LOCAL SHARE описан как:
AA> === Cut ===
AA> The ability to share access to local data between an active BDE
AA> application and an active non-BDE application.  Set to TRUE if you need to
AA> work with the same files through both a BDE and a non-BDE application at
AA> the same time.  (It is not necessary to set LOCAL SHARE to TRUE if you do
AA> not need to have both applications open at the same time.)  Default: FALSE.
AA> === Cut ===

Дaк читaл я вышеизложенное, и рaсценивaю его кaк тумaнопускaтельство. А
подозревaю, что просто у BDE для скорости есть свой внутренний кэш (или, может,
мехaнизм блокировок в пaмяти), и для двух приложений _нa_одном_компьютере_ оно
всё делaет хорошо, a вот если приложение нaходится нa другом компьютере (и
лезет в БД через другую копию BDE), то у него есть доступ только к фaйлaм нa
диске (кaк и у non-BDE application).

Скорее всего, борлaнд отключaет эти хитрости у сетевых дисков. Но для
_локaльного_ дискa, который рaсшaрен по сети, он этого, похоже, не сделaл :(
И BDE нa фaйл-сервере не зaботится о прaвильных индексaх и блокировкaх нa диске
(т.е. не ожидaет, что кто-то мог испрaвить индекс, покa оно ворон считaло).

А этa устaновкa _зaстaвляет_ его рaботaть по стaрым пaрaдоховым соглaшениям.

Что и требовaлось.

PS Инaче говоря, следует считaть, что network is non-BDE application, и тогдa
это не есть бaгa :)

Dmitry Shikhman (Дмитрий Шихман)
(2:468/13.32)
.

Q>:
(IB) При попытке регистрации UDF возникает ошибка (udf not defined).
Что не так?
A>:
1) Располагайте DLL в каталоге Interbase/Bin, или в одном из каталогов,
в которых ОС обязательно будет произведен поиск этой библиотеки
(для Windows это %SystemRoot% и %Path%);
2) При декларировании функции не следует указывать расширение модуля (в Windows
по умолчанию DLL):

declare external function f_SubStr
  cstring(254), integer, integer
 returns
  cstring(254)
 entry_point "Substr" module_name "UDF1"

Где UDF1 - UDF1.DLL.

Alexey Malinin
(2:5057/19.18)
.

Q>:
При выполнении некоторых живых запросов, возвращающих единственную запись,
BDE ругается "multiple records found, but only one was expected". Как лечить?
A>:
Запросы вида

  SELECT c, b, a, q FROM T WHERE b = :b,

где ключ c, но Дельфы посчитали ключом  a. Интересный запрос, да? Такое
впечатление, что, поскольку ключом в исходной таблице являлсь третья колонка,
то Дельфы посчитали ключом третью колонку. Перестановкой SELECT a, b, c, q...
все исправилось. Я решил теперь использовать в таких (live) запросах только
SELECT *.

Victor V. Metelitsa
(2:5077/13)
.

Q>:
Требуется информация о принципе и порядке работы с TUpdateSQL
для работы с неживыми запросами.
A>:
Кидаешь UpdateSQL на форму, после чего в том SQL, который ты собираешься
редактировать, устанавливаешь в UpdateObject имя этого UpdateSQL. После этих
дел по дабл-клику на UpdateSQL выдаётся редактор, в котором ты должен для
каждой из таблиц,входящих в твой запрос, указать набор полей, являющихся
уникальным ключём _таблицы_, и набор полей, которые требуется редактировать.
В общем случае возможны глюки с редактированием, если в числе изменяемых полей
будут элементы ключа. Указав все поля, давишь кнопку Generate SQL и в
результате у тебя генерятся запросы на редактирование, добавление и удаление,
которые прописываются в том же UpdateSQL. Обычно эти запросы никакого
дополнительного редактирования не требуют. После всех
этих дел ты можешь нормально редактировать запрос, как обычную таблицу.

Некоторые моменты.

Для того, чтобы всё это нормально работало, нужно, чтобы в TQuery были включены
RequestLive и CashedUpdates. Соответственно, для подтверждения изменений нужно
вызывать TQuery.ApplyUpdates и TQuery.CommitUpdates, либо
TDatabase.ApplyUpdates, а для отмены - CancelUpdates.

Если меняешь структуру таблиц, то не забывай менять  списки полей в UpdateSQL,
иначе можешь получить неприятный сюрприз - будешь долго сидеть и думать,
почему при редактировании/добавлении некоторые поля не прописываются :-).

-- Отрезано --

Насчёт CachedUpdates.
Сия хреновина придумана для того, чтобы обеспечить сохранение/отмену
редактирования/добавления/удаления сразу нескольких записей. Принцип
совершенно элементарен: если CachedUpdates  включен, то все производимые
изменения в датасете по команде Post фиксируются не в базе, а во временном
файле на винте клиента. Для того, чтобы прописать изменения в таблице
(физически), необходимо вызвать для соответствующего запроса последовательно
методы ApplyUpdates и CommitUpdates, а для отмены ВСЕХ изменений (начиная от
последнего выполненного CommitUpdates), вызвать CancelUpdates.
Кроме того, метод ApplyUpdates у TDataBase. Этому методу нужен список
датасетов, и он производит их обновление в одной транзакции.

Практическое применение, например, такое: на форме редактирования с
гридом и набором кнопок Добавить, Удалить, Редактировать, ОК, Отмена,
вешаешь на первые три кнопки обработчики с Insert, Delete и Edit
соответственно,на ОК - такой примерно обработчик:

with DataSet do begin
  if State in [dsEdit,dsInsert] then Post;
  ApplyUpdates;
  CommitUpdates;
end;

а на Отмену такой:

with DataSet do begin
  if State in [dsEdit,dsInsert] then Cancel;
  CancelUpdates;
end;

В результате юзер может редактировать хоть всю таблицу, но если
успеет спохватиться, то может отменить все свои художества.
Только желательно на выходе из формы проверить, сохранены ли
изменения,и если нет, то напомнить/переспросить.

Ivan Kudryashov
jony@chat.ru
.

Q>:
(DB2) Как заставить работать DB2 через протокол IPX?
A>:
=== begin DB2IPX.TXT ===
Связь Win-клиента c DB2 в сети Netware

           Настройка доступа к DB2
         --------------------------

  1. Связь с использованием протокола IPX/SPX.
-----------------------------------------------

Возможны два варианта доступа:
        - через сервер NETWARE;
        - прямая адресация.

  1.1. Конфигурация для доступа через сервер.
------------------------------------------------------

Замечание. Проверялся доступ через сервера NW 3.11 и 3.12.
           Для 4.х нужно еще разобраться.

  1.1.1.  DB2 Сервер.
---------------------

- должна быть установлена OS/2 Warp или OS/2 Warp Connect.

- включена поддержка NETWARE;

- в CONFIG.SYS в переменную среды DB2COMM добавить (через запятую) IPXSPX и
перезагрузить систему;

- создать командный файл DBIPXSET.CMD :
  |------------------------------------------------------------------
  |db2 update dbm cfg using fileserver <NWSERVER> objectname dbserver
  |------------------------------------------------------------------
        где - <NWSERVER> - имя сервера;

- выполнить командный файл DBIPXSET.CMD ;

- перестартовать сервер базы данных;

- создать командный файл DBIPXREG.CMD :
  |----------------------------------------------------------------
  |db2 register nwbindery user <USERNAME>
  |----------------------------------------------------------------
        где - <USERNAME> - имя пользователя, обладающего правами
администратора на сервере <NWSERVER> ;

- выполнить командный файл DBIPXREG.CMD ;

- ответить на запрос пароля.


  1.1.2. WINDOWS - клиент.
--------------------------

- установить WINDOWS 3.1 или WfWG 3.11;

- установить клиента NETWARE от версии 4.х
- при установке влючить поддержку WINDOWS;
- установить клиента DB2 для WINDOWS;
- используя программу Client Setup описать новый узел - сервер базы
данных :
        Name - <любое имя>
        Protocol - IPX/SPX
        File server - <NWSERWER>
        Object name - dbserver
- описать базу данных и разрешить доступ к ней через ODBC.


  1.2. Конфигурация для доступа через прямую адресацию
----------------------------------------------------------

  1.2.1.  DB2 Сервер.
---------------------

- см. п 1.1.1.

- найти в директории x:\sqllib\misc программу  DB2IPXAD.EXE и
выполнить ее;
- записать полученный адрес.


  1.2.2. WINDOWS - клиент.
--------------------------

- см. п. 1.1.2. (первые три);
- используя программу Client Setup описать новый узел - сервер базы
данных :
        Name - <любое имя>
        Protocol - IPX/SPX
        File server - *
        Object name - <адрес полученный от DB2IPXAD.EXE>
-  описать базу данных и разрешить доступ к ней через ODBC.

=== end DB2IPX.TXT ===

Sergei Babain
(2:5058/88.23)
.

Q>:
Можно ли в TDBGrid pазpешить только опеpации UPDATE записей
и запpетить INSERT/DELETE ? И как это сделать?
A>:
А я делаю так. а DataSource к которому прицеплен Grid вешаю Event OnStateChange
при ентом обрабатываю

if DBGrid1.DataSource.DataSet.State in [dsEdit, dsInsert] then
   DBGrid1.Options:=DBGrid1.Options+goRowSelect
else
   DBGrid1.Options:=DBGrid1.Options-goRowSelect;

Дело в том что если у Grid'а стоит опция goRowSelect из Grid'а невозможно
добавить запись. у а когда програмно вызываешь редактирование то курсор
принимает обычный вид и все Ok Ob.

Denis Kim
(2:5020/799.2)

Лучше "not State in dsEditModes"

Max Belugin
(2:5020/484.28)
belugin@bsd.lanit.ru
.

Q>:
(MSSQL) Как поймать свой RAISEERROR в Delphi?
A>:
Отлавливать нужно NativeCode напpимеp так:

procedure TFDMUtils.GeneralError(DataSet: TDataSet; E: EDatabaseError;
  var Action: TDataAction);
  var i: Word;
      ExtInfo : String;
begin
  ExtInfo := '';

if (E is EDBEngineError) then begin
  if (EDBEngineError(E).Errors[0].NativeError = 0) then begin // Local Error
         if EDBEngineError(E).Errors[0].Errorcode = 9732 then
            ExtInfo := DataSet.FieldByName(trim(copy(E.Message,
29,20))).DisplayLabel;
.......................................
      end else begin       // Remote SQL Server error
          ExtInfo := ExtractFieldLabels(DataSet, E.Message);
          case EDBEngineError(E).Errors[0].NativeError of
               233, 515 :
                 Alert('Ошибка','Не все поля заполнены ! '+ExtInfo );
               547      :
                 if (StrPos(PChar(E.Message), PChar('DELETE')) <> nil ) then
                     Alert('Ошибка пpи удалении','Имеются подчиненные записи,
удаление (изменение) невозможно! '+ExtInfo )
                 else
                 if (StrPos(PChar(E.Message), PChar('INSERT')) <> nil ) then
                    Alert('Ошибка пpи вставке','Отсутствует запись в
МАСТЕР-таблице! '+ExtInfo )
                 else
                 if (StrPos(PChar(E.Message), PChar('UPDATE')) <> nil ) then
                    Alert('Ошибка пpи обновлении','Отсутствует запись в
МАСТЕР-таблице! '+ExtInfo );
               2601     :
                 Alert('Ошибка','Такая запись уже есть!' );
               else
                 Alert('Ошибка','Неизвестная ошибка, код - '+
                        inttostr(EDBEngineError(E).Errors[0].NativeError)
+ExtInfo);
          end;
      end;
  end;
end;
------------------------------------------------------
Этот код был заточен под MSSQL, но не нужно пытаться его использовать, а лучше
по этому пpимеpу написать свою.

Sergey Gristchuk
gristchuk@usa.net
(2:463/209.31)
.

> --- added in v3
Q>:
Как заставить компонент реагировать на изменения в TDataSource?
A>:
TFieldDataLink. За D2 не скажу, а в D1 в Help'е его нет, pеализован в
\DELPHI\SOURCE\VCL\DBTABLES.PAS.

 VV>   Более конкретный вопрос: Как заставить произвольные объекты
 VV> (предположительно формы) реагировать на изменения в каком-то DataSource?

type
  TMyForm = class(TForm)
    {...}
    Table1: TTable;
    DataSource1: TDataSource;
  private
    FDL : TFieldDataLink;
    procedure RecChange(Sender: TObject);
  public
    {...}
  end;

procedure TMyForm.FormCreate(Sender: TObject);
begin
  FDL:=TFieldDataLink.Create;
  FDL.OnDataChange:=RecChange;
  FDL.DataSource:=DataSource1;
  FDL.FieldName:='MyFieldName';
end;

procedure TTabEditDlg.FormDestroy(Sender: TObject);
begin
  FDL.Free;
end;

procedure TTabEditDlg.MasterChange(Sender: TObject);
begin
  {... тут pеагиpуй на изменения ...}
end;

Eugene Polkin
(2:5001/12.3)
.

Q>:
В Delphi 3 ползунок TDBGrid иногда может находится не только в трех
фиксированных позициях. Что для этого нужно?
A>:
Здесь отрывки из исходников VCL -

==========
unit DBGrids;
procedure TCustomDBGrid.UpdateScrollBar;
var
  SIOld, SINew: TScrollInfo;
begin

[skipped]

>      if IsSequenced then

      begin
        SINew.nMin := 1;
        SINew.nPage := Self.VisibleRowCount;
        SINew.nMax := RecordCount + SINew.nPage -1;
        if State in [dsInactive, dsBrowse, dsEdit] then
          SINew.nPos := RecNo;  // else keep old pos
      end
      else
      begin
        SINew.nMin := 0;
        SINew.nPage := 0;
        SINew.nMax := 4;
        if BOF then SINew.nPos := 0
        else if EOF then SINew.nPos := 4
        else SINew.nPos := 2;
      end;

[skipped]

unit dbtables;
function TBDEDataSet.IsSequenced: Boolean;
begin
  Result := (FRecNoStatus = rnParadox) and (not Filtered);
end;
==========

Ilya Andreev
(2:5030/55.28)


То есть, к примеру, все будет работать "красиво" на таблицах BDE, если они:
 а) таблицы Paradox;
 б) на них не установлен фильтр.
TClientDataSet в режиме singletier (briefcase) также работает "красиво".
.

Q>:
(Desktop) Можно ли использовать результаты выполнения одного TQuery для другого TQuery?
A>:
Если Вы работаете с локальными БД, то Вам поможет -

DbiMakePermanent(SourceQuery.Handle, RName, false);

Ilya Andreev
(2:5030/55.28)
Sergey Sukhanov
(2:5019/1.32)
.

Q>:
(DB2/NT) Как создать БД в кодировке CP1251?
A>:
     Вот такая конструкция проходит на DB2 2.1.2/NT и UDB5/NT...

=== Cut ===
CREATE  DATABASE Efes2
 USING CODESET 1251 TERRITORY RU
 COLLATE USING IDENTITY;
=== Cut ===

Ilia Starkov
(2:5061/2.21)
.

Q>:
(Oracle) Подскажите, как на Oracle 7.3.2.3 (Solaris x86) поменять compatible на
7.3.2.3 (c 7.1.0.0)?
A>:
Ставить в initmybase.ora
 compatible = "7.3.2.3"
и после старта с новым параметром сделать
ALTER DATABASE RESET COMPABILITY;
И рестартовать базу.

Alexander Medvedev
(2:5010/3.88)
.

Q>:
(IB) Как получить результирующим полем разницу между хранимой датой и текущей
датой?
A>:
   SELECT CAST((поле_с_датой -"NOW") AS INTEGER)
   FROM MyBase

Получишь результат в днях.

Andrey K.Yazev
(aky@infra.sar.nnov.ru)
.

Q>:
(D3) Как добится верной работы фильтра на запросах и на неиндексированных таблицах?
(Т.е. при работе программы наблюдалась следующая картина:
в результате очередной фильтрации оставалось
видно 4 записи из восьми. Добавляем букву к фильтру, остается, допустим,
две. Убираем букву, которую только что добавили, в гриде все равно видно
только две записи.)
A>:
Эта проблема была в D3 только на TQuery, а в D3.01 появилась и в TTable.
Лечится так (простой пример):

procedure TMainForm.Edit1Change(Sender: TObject);
begin
  if length(Edit1.Text) > 0 then begin
    Table1.Filtered := TRUE;
    UpdateFilter(Table1);
  end
  else Table1.Filtered := FALSE;
end;

procedure TMainForm.UpdateFilter(DataSet: TDataSet);
var
  FR: TFilterRecordEvent;
begin
  with DataSet do begin
    FR := OnFilterRecord;
    if Assigned(FR) and Active then begin
      DisableControls;
      try
        OnFilterRecord := nil;
        OnFilterRecord := FR;
      finally
        EnableControls;
      end;
    end;
  end;
end;

Pavel Krasikov
(2:5005/7)
.

> --- changed in v3
Q>:
(PX, DBF) Подскажите, плз, как упаковать базу (dBase,Paradox) в runtime?
A>:
Для dBase:

 uses
   DbiProcs;

 with Table do
 begin
   OldState := Active; Close;
   Exclusive := True; Open;

   DbiPackTable(DBHandle, Handle, nil, nil, True);
   {^ здесь можно добавить check()}

   Close; Exclusive := False;
   Active := OldState;
   { при желании можно сохранить закладку }
 end;

 Для Paradox:

 DbiDoRestructure(DBHandle, 1, ?, nil, nil, nil, False); { см. dbiProcs.int }

 Вместо ? указатель на массив длинных таких структур с описанием
реструктуризации. Кто делал на Px, я думаю, дадут пример.

Pavel Kulchenko
(2:465/66)

Это насчет упаковки db (может что-то и лишнее, что-то можно
сделать по-дpугому, но pаботает )

Пpимеp для Paradox:

Uses BDE; // for D3, для D2 непомню (что-то типа DbiProc и еще что-то)

// для пpимеpа
tLog : TTable; // таблица юзающая d:\db\log.db

var
     TblDesc:  CRTblDesc;
     rslt   :  DBIResult;
     Dir    :  String; //имеется в виду huge string т.е. {$H+}
     hDb    :  hDbiDb;

begin
  tLog.Active:=False; //деактивиpуем TTable


  SetLength(Dir, dbiMaxNameLen + 1);
  DbiGetDirectory(tLog.DBHandle, False, PChar(Dir));
  SetLength(Dir, StrLen(PChar(Dir)));

  DbiOpenDatabase(nil, nil, dbiReadWrite, dbiOpenExcl, nil, 0, nil, nil, hDb);

  DbiSetDirectory(hDb, PChar(Dir));

  FillChar(TblDesc, sizeof(CRTblDesc), 0);
  StrPCopy(TblDesc.szTblName, 'd:\db\log.db');
                              // здесь должно быть полное имя файла
                              //котоpое можно: а) ввести pуками;
                              //б) вытащить из пpопеpтей таблицы;
                              //в) вытащить из алиаса;
                              //г) см. FAQ
  StrCopy(TblDesc.szTblType, szParadox);
                             //BTW тут может и szDBase стоять

  TblDesc.bPack := TRUE;

  DbiDoRestructure(hDb, 1, @TblDesc, nil, nil, nil, False);
  DbiCloseDatabase(hDb);

end;

// можно еще чеки ввести, но облом :-)

Robert Gluvchinskiy
(2:463/102.108)
.

> --- added in v2
Q>:
Неожиданно возник следующий вопрос :
Каким образом можно узнать где физически располагается локальная база
данных, если известно имя Alias-а ?
A>:
1. По таблице (фактически по Database) получить физическое местонахождение.
 Прим. Database можно создать явно, если нет, Дельфи сама его создаст, доступ
по Table(Query).Database

uses
  DbiProcs;

function GetDirByDatabase(Database: TDatabase): string;
var
  pszDir: PChar;
begin
  pszDir := StrAlloc(255);
  try
    DbiGetDirectory(Database.Handle, True, pszDir);
    Result := StrPas(pszDir);
  finally
    StrDispose(pszDir);
  end;
end;

2. По алиасу.

function GetPhNameByAlias(sAlias: string): string;
var
  Database: TDatabase;
  pszDir: PChar;
begin
  Database := TDatabase.Create(nil);                 {allocate memory}
  pszDir := StrAlloc(255);
  try
    Database.AliasName := sAlias;
    Database.DatabaseName := 'TEMP';   {requires a name -- is ignored}
    Database.Connected := True;    {connect without opening any table}
    DbiGetDirectory(Database.Handle, True, pszDir);     {get the dir.}
    Database.Connected := False;                          {disconnect}
    Result := StrPas(pszDir);                    {convert to a string}
  finally
    Database.Free;                                       {free memory}
    StrDispose(pszDir);
  end;
end;

Pavel Kulchenko
(2:465/66)
.

Q>:
Как записать в BLOB поле большой текст (>255) из DELPHI?
A>:

Секция 2 из 3 - Предыдущая - Следующая

Вернуться в раздел "Языки Pascal/Delphi" - Обсудить эту статью на Форуме
Главная - Поиск по сайту - О проекте - Форум - Обратная связь

© faqs.org.ru