Delphi.Forever

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Delphi.Forever » FAQ » FAQ по работе с СУБД


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

Сообщений 1 страница 2 из 2

1

> в данном контексте:
PK (Primary Key) - первичный ключ;
FK (Foreign Key) - ключ;
SP (Stored Procedure) - хранимая процедура;
UDF (User Defined Function) - определенная пользователем процедура, обычно
в виде или в составе выполнимого модуля или скрипта (Rexx, Ticl, Perl etc.).

> сокращения продуктов:
SAW - Sybase SQLAnywhere, бывший Watcom SQL Server
wwwsybase.com, wwwsybase.ru
DB2 - IBM DB2
wwwibm.com, wwwibm.ru
UDB - New generation of DB2, v5 Universal DataBase.
IB - Interbase, В России известен также так IBDatabase
wwwinterbase.com, wwwinprise.com, wwwborland.ru, wwwdemo.ru, ib.demo.ru
MSSQL - MS SQL Server
wwwmicrosoft.com/sqlserver
DESK - "настольные" БД, Paradox и dBase
PDX - Corel Paradox
wwwcorel.com, wwwinprise.com
DBF - xBase
wwwborland.com (Borland Visual dBase)
FIB - FreeIBComponents
BDE - Borland Database Engine

> --- added in v7.0
Q>:
Делаем ApplyUpdates. Если пpи insert(update) пpоизошла ошибка (поле
null, сpаботал check, etc), то BDE всегда говоpит "General SQL Error"
вместо ноpмального сообщения об ошибке :-( Без CU все ноpмально,
pазумеется. Как боpоть этот баг?
A>:
Использyй ноpмальнyю тpансляцию ошибок в Application.OnException.

    Вpоде это.

>== Режем pаз ==<

procedure DBExceptionTranslate(E: EDBEngineError);
  function OriginalMessage: String;
  var
    I: Integer;
    DBErr: TDBError;
    S: String;
  begin
    Result := '';
    for I := 0 to E.ErrorCount - 1 do
    begin
      DBErr := E.Errors[i];
      case DBErr.NativeError of
        -836: { Intebase exception }
          begin
            S := DBErr.Message;
            Result := #13#10 + Copy(S, Pos(#10, S) + 1, Length(S));
            Exit;
          end;
      end;
      S := Trim(DBErr.Message);
      if S <> '' then Result := Result + #13#10 + S;
    end;
  end;
begin
  case E.Errors[0].ErrorCode of
    $2204:
      E.Message := LoadStr(SKeyDeleted);
    $271E,$2734:
      E.Message := LoadStr(SInvalidUserName);
    $2815:
      E.Message := LoadStr(SDeadlock);
    $2601:
      E.Message := LoadStr(SKeyViol);
    $2604:
      E.Message := LoadStr(SFKViolation) + OriginalMessage;
    else begin
      E.Message := Format(LoadStr(SErrorCodeFmt), [E.Errors[0].ErrorCode]) +
OriginalMessage;
    end;
  end;
end;

>== Режем два ==<

Vladimir Gaitanoff
vg@divo.ru
wwwtsinet.ru/~vg
(2:5017/5.69)

Q>:
[IB] Как узнать текущие дату и время в Interbase?
A>:
Дата + время - DATE.
Только дата - TODAY.
Только время - DATE-TODAY.

Сяржук Казачэнка
bamboo7431@hotmail.com

Q>:
[IB]  После снесения через родной uninstall Interbase Server 5.0 для Windows
и желания  поставить 5.1.1 вылетает ошибка: IBCheck. Что делать?
A>:
Решение найдено. Прочитай сам и передай товарищу:
надо запустить regedit, и открыть ключ
HKEY_LOCAL_MACHINE\Environment
там есть строка PATH. Так вот иногда она почему-то становится не
строкой, а еще чем-то. Ее надо убить, и пересоздать как строку,
прописав туда прежнее содержимое (в виде строки).

Dmitry Kuzmenko, Epsylon Technologies.
dima@demo.ru

Q>:
[DBF] Как можно открыть DBF-файл с признаком индекса, если индексный файл
отсутствует?
A>:
С помощью BDE Callbacks. Пpимеp для Delphi 2.0, на пеpвом не пpовеpял:

=== Callback.pas ===
unit Callback;

interface

uses BDE, Classes, Forms, DB, DBTables;

type
  TForm1 = class(TForm)
    Table1: TTable;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    CBack: TBDECallback; // опpеделение BDE CallBack
    CBBuf: CBInputDesc;  // пpосто буфеp
    function CBFunc(CBInfo: Pointer): CBRType; // Callback-функция
  public
  end;

var Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Session.Open; // В это вpемя сессия ещё не откpыта
  CBack := TBDECallback.Create(Session {Напpимеp},nil,cbINPUTREQ,@CBRegBuf,
    SizeOf(CBBuf),CBFunc,False);  // Опpеделили Callback
  Table1.Open;
//^^^^^^^^^^^ - здесь возможна ошибка с индексом, etc.
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  CBack.Free;  // Освобождаем CallBack
end;

function TForm1.CBFunc(CBInfo: Pointer): CBRType;
begin
  with PCBInputDesc(CBInfo)^ do
  case eCbInputId of
    cbiMDXMissing {, cbiDBTMissing - можно ещё и очищать BLOB-поля}:
    begin
      iSelection := 3; // Номеp ваpианта ответа (1-й - откpыть только        //
для чтения, 2-й - не откpывать, 3-й - отсоединить индекс).
        // Возможный источник непpиятностей: а вдpуг в последующих веpсиях
        // BDE номеpа будут дpугими?
      Result := cbrCHKINPUT; // Обpабатывать введённый ответ
    end;
  end;
end;

end.
=== Callback.pas ===

PS: конечно, это лишь пpимеp, делающий минимум необходимого. В pамках данного
письма невозможно дать какое-то описание BDE Callbacks. Инфоpмацию я взял из
BDE32.HLP, BDE.INT и DB.PAS. В VCL.HLP совсем ничего нет по этому поводу.
Вообще, pуки бы отоpвал тем, кто писал спpавку по Дельфям: я неделю мучался с
сабжем, пока случайно не набpёл на Callbacks.

Denis Zaytsev
(2:5011/49.6)

> --- changed in v7.0
Q>:
Как работать из Delphi напрямую с MS ADO (Microsoft Active Data Objects)?
A>:
Итак, хочу поделиться некоторыми достижениями... так на всякий случай. Если у
вас вдруг потребуется сделать в своей программке доступ к базе данных, а BDE
использовать будет неохота (или невозможно) - то есть довольно приятный
вариант: использовать ActiveX Data Objects. Однако с их использованием есть
некоторые проблемы, и одна из них это как передавать Optional параметры,
которые вроде как можно не указывать. Однако, если вы работаете с ADO
по-человечески, а не через тормозной IDispatch.Invoke то это превращается в
головную боль. Вот как от нее избавляться:

var
  OptionalParam: OleVariant;
  VarData: PVarData;
begin
  OptionalParam := DISP_E_PARAMNOTFOUND;
  VarData := @OptionalParam;
  VarData^.VType := varError;

после этого переменную OptionalParam можно  передавать вместо неиспользуемого
аргумента.

Далее, самый приятный способ получения Result sets:

Там есть масса вариантов, но как выяснилось оптимальным является следующий
вариант, который позволяет получить любой желаемый вид курсора (как клиентский
так и серверный)

var
MyConn: _Connection;
MyComm: _Command;
MyRecSet: _Recordset;
prm1: _Parameter;
begin
MyConn := CoConnection.Create;
MyConn.ConnectionString := 'DSN=pubs;uid=sa;pwd=;';
MyConn.Open('','','',-1);
MyCommand := CoCommand.Create;
MyCommand.ActiveConnection := MyConn;
MyCommand.CommandText := 'SELECT * FROM blahblah WHERE BlahID=?'
Prm1 := MyCommand.CreateParameter('Id',adInteger.adParamInput,-1,<value>);
MyCommand.AppendParameter(Prm1);
MyRecSet := CoRecordSet.Create;
MyRecSet.Open(MyCommand,OptionalParam,adOpenDynamic,adLockReadOnly,adCmdText);

... теперь можно фетчить записи. Работает шустро и классно. Меня радует.
Особенно радуют серверные курсоры.

Проверялось на Delphi 3.02 + ADO 1.5 + MS SQL 6.5 sp4. Пашет как зверь.
Из вкусностей ADO - их легко можно использовать во всяких многопоточных
приложениях где BDE порой сбоит, если, конечно, ODBC драйвер грамотно сделан...
ну и еще можно использовать для доступа к данным всяких там "нестандартных" баз
типа MS Index Server или MS Active Directory Services.

Alexey Kopernick
awk@dialup.ptt.ru
ICQ UIN: 3150119
(2:5020/221)

В Delphi (как минимум в 4 версии) существует "константа" EmptyParam, которую
можно подставлять в качестве пустого параметра.

Akzhan Abdulin
(2:5040/55.46)

> --- added in v6
Q>:
Как установить BDE32 на чистой машине (ручками, без IS)?
A>:
Нижеследующий рецепт работает для вариантов D2/BDE351, D3/BDE40,
D3/BDE451, D2/BDE40, D2/BDE451. Список файлов BDE для версии 3.51
(в отличие от 4.x) также не вычислял; считаем, что
необходимы все файлы.

1. Переписать все файлы:
// ========== BDE40 ===================
CHARSET.BLL
OTHER.BLL
USA.BLL
IDAPI32.CFG
BLW32.DLL
IDAPI32.DLL
IDBAT32.DLL
IDPDX32.DLL
IDR20009.DLL
IDSQL32.DLL
BDEADMIN.EXE
// ========== end of BDE40 ===================

2. Прописать в регистри след. значения:
// ==========BDE351 ===================
REGEDIT4

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\BLW32]
"LOCALE_LIB1"="C:\\Program Files\\Borland\\Common Files\\BDE\\USA.BLL"
"BLAPIPATH"="C:\\Program Files\\Borland\\Common Files\\BDE"
"LOCALE_LIB2"="C:\\Program Files\\Borland\\Common
Files\\BDE\\EUROPE.BLL"
"LOCALE_LIB3"="C:\\Program Files\\Borland\\Common
Files\\BDE\\OTHER.BLL"
"LOCALE_LIB4"="C:\\Program Files\\Borland\\Common
Files\\BDE\\CHARSET.BLL"
"LOCALE_LIB5"="C:\\Program Files\\Borland\\Common
Files\\BDE\\CEEUROPE.BLL"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database Engine]
"DLLPATH"="C:\\Program Files\\Borland\\Common Files\\BDE"
"CONFIGFILE01"="C:\\Program Files\\Borland\\Common
Files\\BDE\\IDAPI32.CFG"
"RESOURCE"="Path=BDE_LANGDRV"
"SaveConfig"="WIN31"
"UseCount"="1"
// ========== End of BDE351 ===================
// ========== BDE40 ===================
REGEDIT4

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database Engine]
"DLLPATH"="C:\\APartner\\BDE451\\SQLLinks.40;C:\\APartner\\BDE451"
"RESOURCE"="0009"
"CONFIGFILE01"="C:\\APartner\\BDE451\\IDAPI32.CFG"
"UseCount"="1"
"SaveConfig"="WIN32"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database Engine\Settings]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database Engine\Settings\DRIVERS]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\DBASE]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\DBASE\INIT]
"VERSION"="4.0"
"TYPE"="FILE"
"LANGDRIVER"="db866ru0"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\DBASE\TABLE CREATE]
"LEVEL"="5"
"MDX BLOCK SIZE"="1024"
"MEMO FILE BLOCK SIZE"="1024"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\MSACCESS]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\MSACCESS\DB OPEN]
"DATABASE NAME"="DRIVE:/PATH/DATABASE.MDB"
"USER NAME"=""
"OPEN MODE"="READ/WRITE"
"LANGDRIVER"=""

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\MSACCESS\INIT]
"VERSION"="1.0"
"TYPE"="SERVER"
"DLL32"="IDDAO32.DLL"
"DRIVER FLAGS"=""
"TRACE MODE"="0"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\ORACLE]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\ORACLE\DB OPEN]
"SERVER NAME"="ORA_SERVER"
"USER NAME"="MYNAME"
"NET PROTOCOL"="TNS"
"OPEN MODE"="READ/WRITE"
"SCHEMA CACHE SIZE"="8"
"LANGDRIVER"=""
"SQLQRYMODE"=""
"SQLPASSTHRU MODE"="SHARED AUTOCOMMIT"
"SCHEMA CACHE TIME"="-1"
"MAX ROWS"="-1"
"BATCH COUNT"="200"
"ENABLE SCHEMA CACHE"="FALSE"
"SCHEMA CACHE DIR"=""
"ENABLE BCD"="FALSE"
"ENABLE INTEGERS"="FALSE"
"LIST SYNONYMS"="NONE"
"ROWSET SIZE"="20"
"BLOBS TO CACHE"="64"
"BLOB SIZE"="32"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\ORACLE\INIT]
"VERSION"="4.0"
"TYPE"="SERVER"
"DLL"="SQLD_ORA.DLL"
"DLL32"="SQLORA32.DLL"
"VENDOR INIT"="ORANT71.DLL"
"DRIVER FLAGS"=""
"TRACE MODE"="0"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\PARADOX]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\PARADOX\INIT]
"VERSION"="4.0"
"TYPE"="FILE"
"LANGDRIVER"="ancyrr"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\DRIVERS\PARADOX\TABLE CREATE]
"LEVEL"="4"
"BLOCK SIZE"="2048"
"FILL FACTOR"="95"
"STRICTINTEGRTY"="TRUE"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\REPOSITORIES]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\REPOSITORIES\Borland Data Dictionary]
"DATABASE NAME"="DefaultDD"
"TABLE NAME"="BDESDD"
"LANGUAGE DRIVER"=""
"DESCRIPTION"="Borland Database Engine Sample Data Dictionary"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database Engine\Settings\SYSTEM]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\SYSTEM\FORMATS]

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\SYSTEM\FORMATS\DATE]
"SEPARATOR"="."
"MODE"="1"
"FOURDIGITYEAR"="FALSE"
"YEARBIASED"="TRUE"
"LEADINGZEROM"="FALSE"
"LEADINGZEROD"="FALSE"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\SYSTEM\FORMATS\NUMBER]
"DECIMALSEPARATOR"="."
"THOUSANDSEPARATOR"=" "
"DECIMALDIGITS"="2"
"LEADINGZERON"="TRUE"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\SYSTEM\FORMATS\TIME]
"TWELVEHOUR"="FALSE"
"AMSTRING"="AM"
"PMSTRING"="PM"
"SECONDS"="TRUE"
"MILSECONDS"="FALSE"

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database
Engine\Settings\SYSTEM\INIT]
"VERSION"="4.0"
"LOCAL SHARE"="FALSE"
"MINBUFSIZE"="128"
"MAXBUFSIZE"="2048"
"LANGDRIVER"="ancyrr"
"MAXFILEHANDLES"="48"
"SYSFLAGS"="0"
"LOW MEMORY USAGE LIMIT"="32"
"AUTO ODBC"="FALSE"
"DEFAULT DRIVER"="PARADOX"
"MEMSIZE"="16"
"SHAREDMEMSIZE"="2048"
"SHAREDMEMLOCATION"=""
"DATA REPOSITORY"="Borland Data Dictionary"
"SQLQRYMODE"=""

[HKEY_LOCAL_MACHINE\SOFTWARE\Borland\BLW32]
"BLAPIPATH"="C:\\APartner\\BDE451"
"LOCALE_LIB1"="C:\\APartner\\BDE451\\USA.BLL"
"LOCALE_LIB2"="C:\\APartner\\BDE451\\EUROPE.BLL"
"LOCALE_LIB3"="C:\\APartner\\BDE451\\OTHER.BLL"
"LOCALE_LIB4"="C:\\APartner\\BDE451\\CHARSET.BLL"
"LOCALE_LIB5"="C:\\APartner\\BDE451\\CEEUROPE.BLL"
"LOCALE_LIB6"="C:\\APartner\\BDE451\\FAREAST.BLL"
"LOCALE_LIB7"="C:\\APartner\\BDE451\\JAPAN.BLL"
// ========== End of BDE40 ===================

Serge Sushko
sushko@apartner.aha.ru
http://members.tripod.com/~sushko/

Q>:
Как засунуть в качестве паpаметpа хpанимой пpоцедуpы стpоку длиной
более 255 символов? И вообще, как использовать паpаметpы SP, если
они BLOB?
A>:
"засунуть" длинную строку можно было и раньше, если написать
редактируемый запрос, и воспользоваться операциями Insert/Edit.
Однако это не относится к хранимым процедурам.
В Delphi 3.0 появился новый тип параметра (TBlobField вроде)
и соответственно его поддержка в BDE. Если просто взять BDE 4.01 и
выше, то работать все-равно не будет - нужна соотв. версия VCL (из
Delphi 3.0 или выше)

Dmitry Kuzmenko, Epsylon Technologies.
(095) 535-0319, 913-5608.
http://ib.demo.ru/

Q>:
[PDX] Почему при создании таблицы Paradox с первичным нечувствительным
к регистру индексом вываливается ошибка?
A>:
В Парадоксе первичный индекс всегда CaseSensitive.

<имя автора не сохранилось>

> --- changed in v6
Q>:
[PDX,DBF] Как программно изменить LangDriver для таблиц dBase и Paradox?
A>:

Откpываешь help и смотpишь:

.......
var List:TStrings;
.......
BEGIN
  .......
  List.Add ('LANGDRIVER=db866ru0');
  .......
  Session.ModifyDriver('DBASE',List);
  .......
END;

это действие я пpовожy пеpед откpытием таблицы

Ivan Sboev
(2:5049/36.15)

  Это о "русификации" таблицы. В таблицах dBase и Paradox имеется байт,
который определяет CodePage содержимого таблицы. Раньше он не использо-
вался и был зарезервирован. Тебе нужно его правильно установить. Это
делается через DBD Restructure table. Если хочешь програмно, можешь
воспользоваться следующей процедурой:

uses DbiTypes, DbiProcs, DbiErrs, DB, WinProcs, SysUtils;

procedure ChangeLangDriver(DatabaseName, TableName, LDName: string);
var
  TblExt: string;
  Database: TDatabase;
  TblDesc: CRTblDesc;
  OptDesc: FLDDesc;
  OptData: array [0..250] of Char;
  Cur: hDBICur;
  Rec: CFGDesc;
begin
  if (TableName='') or (LDName='') then
    raise Exception.Create('Unknown TableName or LDName');
  Database:=Session.OpenDatabase(DatabaseName);
  try
    if Database.IsSQLBased then raise Exception.Create('Function
ChangeLangDriver working only with dBase or Paradox tables');
    FillChar(OptDesc, SizeOf(OptDesc), #0);
    FillChar(TblDesc, SizeOf(TblDesc), #0);
    StrCopy(OptDesc.szName, 'LANGDRIVER');
    OptDesc.iLen:=Length(LDName)+1;
    with TblDesc do
    begin
      StrPCopy(szTblName, TableName);
      TblExt:=UpperCase(ExtractFileExt(TableName));
      if TblExt='DBF' then StrCopy(szTblType, szDbase)
      else if TblExt='.DB' then StrCopy(szTblType, szParadox)
      else begin
        AnsiToOEM(StrPCopy(OptData, DatabaseName), OptData);
        if DbiOpenCfgInfoList(nil, dbiREADONLY, cfgPersistent,
          StrPCopy(OptData, '\DATABASES\'+StrPas(OptData)+'\DB INFO\'),
Cur)<>DBIERR_NONE
          then raise Exception.Create('Unknown table type');
        try
          while DbiGetNextRecord(Cur, dbiNOLOCK, @Rec, nil)<>DBIERR_EOF do
            if StrComp(Rec.szNodeName, 'DEFAULT DRIVER')=0 then
            begin
              StrCopy(szTblType, Rec.szValue);
              Break;
            end;
        finally
          Check(DbiCloseCursor(Cur));
        end;
      end;
      iOptParams:=1;
      pfldOptParams:=@OptDesc;
      pOptData:=@OptData;
    end;
    StrPCopy(OptData, LDName);
    Check(DbiDoRestructure(Database.Handle, 1, @TblDesc, nil,
      nil, nil, False));
  finally
    Session.CloseDatabase(Database);
  end;
end;

  Примеры использования:

ChangeLangDriver('DBDEMOS', 'EMPLOYEE', 'ancyrr');
ChangeLangDriver('DBDEMOS', 'EMPLOYEE.DB', 'ancyrr');
ChangeLangDriver('C:\DELPHI\DEMOS\DATA', 'CLIENTS.DBF', 'db866ru0');

  LDName:
    для D1 - имя .LD файла в каталоге IDAPI\LANGDRV
    для D2 и CB - из BDECFG32.HLP поле Short name в табличке по указателю
        language drivers, dBASE или поле Internal в табличке по указателю
        language drivers, Paradox.
    для D3 - не знаю так как у меня ее нет, думаю, что как и в D2.

Farid Zaripov
farid@aduis.kiev.ua
(2:463/201.101)

> --- added in v5.1
Q>:
[Oracle] Поясните, чем в Oracle являются понятия Instance, Database etc.?
A>:
Перевод документации:
------------------------------------------------------------------------------
Q: Что такое ORACLE Database?
A: Это данные которые будут обрабатываться как единое целое. Database состоит
из файлов операционной системы. Физически существуют database files и redo log
files. Логически database files содержат словари, таблицы пользователей и redo
log файлы. Дополнительно database требует одну или более копий control file.
Q: Что такое ORACLE Instance?
A: ORACLE Instance обеспечивает программные механизмы доступа и управления
database. Instance может быть запущен независимо от любой database (без
монтирования или открытия любой database). Один instance может открый только
одну database. В то время как одна database может быть открыта несколькими
Instanse. Instance состоит из:
1) SGA (System Global Area) которая обеспечивает коммуникацию меджу процессами
2) до пяти (в последних версиях больше) бэкграундовых процессов.
-----------------------------------------------------------------------------
От себя добавлю - database включает в себя tablespace, tablespace включает в
себя segments (в одном файле данных может быть один или несколько сегментов,
сегменты не могут быть разделены на несколько файлов). segments включают в себя
extents.

Alex Kravets
(2:5020/904.12)

Q>:
[DB2+UDB] Существует ли средство для вывода определения структуры таблицы?
Я создал таблицу и хочу получить её структуру, чтобы сделать изменённый оператор
создания таблицы.
A>:
Для этого существует утилита DB2LOOK. Она находится в SQLLIB\MISC. Пример
использования:
      CONNECT TO SAMPLE USER xxx USING yyy
      DB2LOOK -d SAMPLE -u xxx -e -t employee
Вывод может быть перенаправлен в файл. Полный синтаксис выдаётся по команде:
DB2LOOK ?

Vadim Rumyantsev
(2:5030/48.400)

Q>:
[DB2+UDB] У меня есть текстовые файлы, которые я хочу использовать в запросах к DB2,
но не хочу создавать из них постоянные таблицы в базе. Что делать?
A>:
Можно воспользоваться табличными функциями (Table Functions). Они позволяют
использовать файлы как таблицы. Примеры приведены в руководстве "Embedded SQL
Programming Guide".

Vadim Rumyantsev
(2:5030/48.400)

> --- added in v5
Q>:
[Oracle] Как заставить Oracle анализировать все таблицы базы данных?
A>:
Конечно, можно использовать DBMS_SQL, DBMS_JOB...
А можно и так:

#!/bin/sh
#
# Analyze all tables
#

SQLFILE=/tmp/analyze.sql
LOGFILE=/tmp/analyze.log

echo @connect dbo/passwd@ > $SQLFILE

$ORACLE_HOME/bin/svrmgrl <<EOF | awk \
'/^TABLE/ { print "ANALYZE TABLE DBO." $2 \
" ESTIMATE STATISTICS"; print "/"; }' >> $SQLFILE
connect dbo/passwd
SELECT 'TABLE', TABLE_NAME FROM all_tables WHERE owner = 'DBO';
EOF

echo exit >> $SQLFILE
cat $SQLFILE > $LOGFILE

cat $SQLFILE | $ORACLE_HOME/bin/svrmgrl >> $LOGFILE

cat $LOGFILE | /usr/bin/mailx -s 'Analyze tables' tlk@nbd.kis.ru

rm $SQLFILE
rm $LOGFILE

Anatoly Kuznetsov
tlk@nbd.kis.ru
(2:5015/4.1)

Q>:
[Oracle] В режиме отладки приложения не разрешается доступ (открытие) базы данных.
Как лечить?
A>:
Необходимо отключить (деинсталлировать через Oracle Installer) Trace Service на
клиенте - совет от ORACLE.
Глюк имеет место быть только под Windows NT 4.xx.

Sergey Klochkovski
(2:5080/60.3)

Q>:
[VCL] При разрушении обьектов, порожденных от TDataSet (TTable, TQuery), не
отрабатывает событие OnBeforeClose. Что делать?
A>:
Сейчас вышел из ситуации так: в TForm.OnClose, т.е. пока ещё все компоненты
формы живы, делаю  CloseDatabases(Self).

Александр Петросян(PAF), Зеленоград.
(2:5020/468.8)

Q>:
[SQL] При попытке выполнения такого оператора SQL -
"DELETE from T39 T39C0 WHERE T39C0.F1LHT35=253291661" SQL-сервер ругается на
недопустимый синтаксис. В чем я неправ?
A>:
В данном случае, видимо, T39C0 расценивается как псевдоним.
Но стандартом SQL-92 такое запрещено в delete. Цитата собственно из этого стандарта
(сборник  из delete и names and identifiers, определение identifier пропущено,
просто набор <simple latin letter> | <digit>, начинается с буквы):

Format
<delete statement: positioned>::=
delete from <table name> where current of <cursor name>

<table name> ::= <qualified name> | <qualified local  name>
<qualified name> ::= [<shema name><period>] [<qualified identifier>]
<qualified identifier> ::=<identifier>
<shema name>::=[<catalog name><period>]<unqualified shema name>
<unqualified shema name>::=<identifier>
<catalog name>::=<identifier>
<qualified local  name>::= MODULE <period><local table name>
<local table name>::=<qualified identifier>

Стандартом запрещено вот такое
select test.a, p_test.a from test p_test;
вот это не по стандарту, хотя MS такое ест.

Lilya Kozlenko
li@relex.ru

Q>:
[VCL] Хочу шапку в TDBGrid. Как сделать?
A>:
Уже реализовано в виде вот этого компонента -
(С) Andre

unit bdbgrid;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,
  Grids, DBGrids, Math;

type
  TOnDrawTitleEvent = procedure(ACol : integer; ARect : TRect; var
TitleText : string)
    of object;

  TBitDBGrid = class(TDBGrid)
  private
   FBitmapBrowse : TBitmap;
   FBitmapEdit : TBitmap;
   FBitmapInsert : TBitmap;
   FBitmapFill : TBitmap;
   FRealTitleFont : TFont;
   FOnDrawTitle : TOnDrawTitleEvent;
   FResizeFlag : boolean;
    { Private declarations }
   procedure SetRealTitleFont(Value : TFont);
   procedure UpdateTitlesHeight;
  protected
   procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState:
TGridDrawState);
        override;
   procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
   procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    { Protected declarations }
  public
    constructor Create(AOwner : TComponent);override;
    destructor Destroy; override;
    { Public declarations }
  published
    property OnDrawTitle : TOnDrawTitleEvent read FOnDrawTitle write
FOnDrawTitle;
    property RealTitleFont : TFont read FRealTitleFont write
SetRealTitleFont;
    { Published declarations }
  end;

procedure Register;

implementation

var DrawBitmap : TBitmap;

function Max(X, Y: Integer): Integer;
begin
  Result := Y;
  if X > Y then Result := X;
end;

procedure WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer;
  const Text: string; Alignment: TAlignment);
//(C) Borland function :)
const
  AlignFlags : array [TAlignment] of Integer =
    ( DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
      DT_RIGHT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
      DT_CENTER or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX );
var
  B, R: TRect;
  I, Left: Integer;
begin
with DrawBitmap, ARect do { Use offscreen bitmap to eliminate flicker
and }
   begin                     { brush origin tics in painting /
scrolling.    }
     Width := Max(Width, Right - Left);
     Height := Max(Height, Bottom - Top);
     R := Rect(DX, DY, Right - Left - 1, Bottom - Top - 1);
     B := Rect(0, 0, Right - Left, Bottom - Top);
    end;
with DrawBitmap.Canvas do
   begin
     DrawBitmap.Canvas.CopyRect(B, ACanvas, ARect);
     Font := ACanvas.Font;
     Font.Color := ACanvas.Font.Color;
     Brush := ACanvas.Brush;
     SetBkMode(Handle, TRANSPARENT);
     DrawText(Handle, PChar(Text), Length(Text), R,
AlignFlags[Alignment]);
    end;
ACanvas.CopyRect(ARect, DrawBitmap.Canvas, B);
end;

constructor TBitDBGrid.Create(AOwner : TComponent);
begin
inherited Create(Aowner);
FRealTitleFont := TFont.Create;
FResizeFlag := false;
end;

destructor TBitDBGrid.Destroy;
begin
FRealTitleFont.Free;
inherited Destroy;
end;

procedure TBitDBGrid.UpdateTitlesHeight;
var Loop : integer;
    MaxTextHeight : integer;
    RRect : TRect;
begin
MaxTextHeight := 0;
for loop := 0 to Columns.Count - 1 do begin
   RRect := CellRect(0, 0);
   RRect.Right := Columns[Loop].Width;
   RRect.Left := 0;
   Canvas.Font := RealTitleFont;
   MaxTextHeight := Max(MaxTextHeight, DrawText(Canvas.Handle,
                         PChar(Columns[Loop].Title.Caption),
                         Length(Columns[Loop].Title.Caption), RRect,
                         DT_CALCRECT + DT_WORDBREAK));
  end;
if TitleFont.Height <> - MaxTextHeight then
   TitleFont.Height := - MaxTextHeight;
end;

procedure TBitDBGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
if MouseCoord(X, Y).Y = 0 then
   FResizeFlag := true;
inherited MouseDown(Button, Shift, X, Y);
end;

procedure TBitDBGrid.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
if FResizeFlag then begin
   FResizeFlag := false;
   UpdateTitlesHeight;
  end;
end;

procedure TBitDBGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState:
TGridDrawState);
var Indicator : TBitmap;
    TitleText : string;
    Al : TAlignment;
begin
if not ((gdFixed in AState) and ((ARow = 0) and (dgTitles in Options)
and (ACol <> 0)))
  then inherited DrawCell(ACol, ARow, ARect, AState)
  else begin
    if DefaultDrawing then begin
      DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_BOTTOMLEFT);
      DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_TOPRIGHT);
      InflateRect(ARect, -1, -1);
      Canvas.Brush.Color := FixedColor;
      Canvas.FillRect(ARect);
     end;
    TitleText := Columns[ACol - 1].Title.Caption;
    if Assigned(OnDrawTitle) then OnDrawTitle(ACol, ARect, TitleText);
    if DefaultDrawing  and (TitleText <> '') then
      begin
        Canvas.Brush.Style := bsClear;
        Canvas.Font := RealTitleFont;
        if ACol > 0 then Al := Columns[ACol - 1].Title.Alignment
          else Al := Columns[0].Title.DefaultAlignment;
        WriteText(Canvas, ARect, 2, 2, TitleText, Al);
       end;
   end;
end;

procedure TBitDBGrid.SetRealTitleFont(Value : TFont);
begin
FRealTitleFont.Assign(Value);
Repaint;
end;

procedure Register;
begin
  RegisterComponents('Andre VCL', [TBitDBGrid]);
end;

initialization
DrawBitmap := TBitmap.Create;

finalization
DrawBitmap.Free;

end.

Ilya Andreev

Q>:
[IB] При обращении к memo-полю из BDE возникает ошибка "Memo too large". Как лечить?
A>:
В BDE есть крутая ошибка, достаточно известная всем, кроме
Borland'a. Поскольку они ее еще с 1й Delphi не исправили.
Этот баг проявляется как Access Violation в программе при
обращении к таблице IB, которая содержит более одного
поля типа VARCHAR (или CHAR) размером > 255. Причем,
первое поле меньшего, а второе большего размера.
Если поменять местами поля или сделать их одного размера, то
все нормально. Эффект имеет место только с IB, вроде.

Вадим Миллер
miller@demo.ru

Q>:
[PDX]  Как сменить пароль (master password) для таблицы Paradox?
A>:
пожалуйста:
var
  db    : TDatabase;
  Desc  : CRTblDesc;
begin
  db := PriceTable.OpenDatabase;
  FillChar( Desc, SizeOf( Desc ), #0 );
  StrCopy( Desc.szTblName, PChar(PriceTable.TableName));
  StrCopy( Desc.szTblType, szParadox );
  StrCopy( Desc.szPassword, 'password' );
  Desc.bProtected := TRUE;
  Check( DbiDoRestructure( db.Handle, 1, @Desc, nil, nil, nil, FALSE ));
end;

Садохин Дмитрий (SDV)
vita@transit.samara.ru

Q>:
[MSSQL] Работаю на D3+BDE+ODBC и если в транзакции изменена какая-то таблица,
то для другого пользователя блокируестя вся таблица, до окончания транзакции.
Как лечить?
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
wwwmedia-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-драйвер (доступен на wwwsybase.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)

0

2

Часть II
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;     
    StrDispose(pszDir);
  end;
end;

Pavel Kulchenko
(2:465/66)

Q>:
Как записать в BLOB поле большой текст (>255) из DELPHI?
A>:
var S: TBlobStream;
    B: pointer;
    c: integer;

Table1.Edit;
S := TBlobStream.Create(Table1BlobField as TBlobField, bmWrite); {кажется, так}
C := S.Write(B, C);
Table1.Post;
S.Destroy;

или так

var S: TMemoryStream;
    B: pointer;
    C: integer;

S := TMemoryStream.Create;
...
Table1.Edit;
S.Clear;
S.SetSize(C);
C := S.Write(B,C);
(Table1BlobField as TBlobField).LoadFromStream(S);
S.Clear;
Table1.Post;
...
S.Destroy;

Alexey Kats
(2:463/201.9)

Q>:
(DBF) Как открыть индексированную таблицу dBase, если нет файла *.MDX?
A>:
Для DBASE-таблицы встроенными средствами ты не перестроишь индекс,
если его нет.  Для этой цели мне пришлось написать процедуру для
физического удаления признака индексации в самом dbf файле и после ее
применения добавлять индексы заново. Для этого в заголовок файла dbf
по смещению 28(dec) записываешь 0. По другому никак не выходит(я долго
бился)- вот для Paradox таблиц все Ok.

Олег (GOS)
oleg@avia.cmw.ru

Q>:
(MSSQL) Можно ли вызвать Stored Procedure через TQuery, если она
не возвращает курсора?
A>:
В случае MS SQL нужно написать:
Query1.Sql:='declare @res'+#13#10+'exec MyFunc :Param1,:Param2,@res OUTPUT';
Query1.Open;
Result:=Query1.FieldByName('Column1').Value;
Query1.Close;

Konstantin Suslov
(2:5020/300.16)

Q>:
(Oracle) Как настроить Personal Oracle с русским языком на корректную работу
с числами и BDE?
A>:
прописать в \HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE параметр:
NLS_NUMERIC_CHARACTERS = '.,'
или
после соединения с ORACLE выполнить
ALTER SESSION SET NLS_NUMERIC_CHARACTERS = '.,'

Aleksei Alekseenko
(2:5030/548.2)
Voice phone: 007-812-694-8625

Q>:
(MSSQL) Как настроить MS SQL Server 6.5 на корректную работу
с числами и BDE при выполнении UPDATE?
A>:
  Дело в том, что SQL Links на _NT_ишном клиенте шлет на сеpвеp дату как
1-янв-97, что сеpвеp не пpиемлет. Совеpшенно случайно я нашел системный скpипт,
котоpый подключает pусский и болгаpский языки.

   - выполни sp_configure и убедись, что у тебя default sortorder id==106 (rus
case insens) или 105 (rus case sens). Если нет - пеpеставь сеpвеp.

   - найди в каталоге c:\mssql\install скpипт instlang.sql и запусти его.

   - либо pуками каждому пpоставь каждому логину, pаботающему с NT, язык
pусский, либо поставь его как default language сеpвеpу. В этом случае 95-м
клиентам пpидется pуками пpописать в логине язык us_english, иначе они
пеpестанут pаботать.

   Для установки russian как default надо выполнить скpипт:

   exec sp_configure 'default language', 2
   go
   reconfigure
   go

Vadim Shcolin
vadim@vsh.spb.su
(2:5030/87.91)

Q>:
Как научить VCL делать Refresh для запросов правильно?
Особенно интересует Refresh для связки Master-Detail.
A>:
(IB?)
Старо как мир, и нет ничего военного:

=== Cut ===
procedure  RefreshQuery (Query : TQuery; F : boolean);
var B : TBookMark;
begin
with Query do
   if Query.Active then
   begin
     B:=GetBookMark;
     try
       Close;
       Unprepare;  {Если не поставить этого, то если используется select
SP, то иногда последующая операция вешает сервер.
                    Кто скажет почему?!}
       Active:=True;
       if F then begin
         try
           GotoBookMark(B)
         except
           on EDatabaseError do First;
         end
       end
       else First;
     finally
       FreeBookmark(B);
     end;
   end;
end;
=== Cut ===

Eugene Zhilkin
(2:461/88)

Уфф! Кажется, лyчше yже не сделать. :)

dbtables можно опционально пpопатчить (см.в конце), чтобы иметь такой вот
pyлезный Detail query.

>== Режем pаз ==<

Update for dbtables.pas

    New interface function DoRefreshQuery can Refresh TQuery component in
master-detail scheme and alone.
    TQuery.RefreshParams should be updated

function GetFieldNamesStr(DataSet: TDataSet): String;
var
  I: Integer;
begin
  Result := '';
  with DataSet do
    for I := 0 to FieldCount - 1 do
      Result := Result + Fields[i].FieldName + ';';
end;

procedure DoRefreshQuery(Query: TQuery; KeyFields: String; BookMarkSearch:
Boolean);
var
  Fields: TList;
  KeyValues: Variant;
  KeyNames: String;
  Bmk: TBookmark;
  I: Integer;
  BookmarkFound: Boolean;
  CanLocate: Boolean;
begin
  Fields := TList.Create;
  if KeyFields = '' then KeyFields := GetFieldNamesStr(Query);
  try
    Query.GetFieldList(Fields, KeyFields);
    for I := Fields.Count - 1 downto 0 do
      with TField(Fields[i]) do
        if Calculated or Lookup then Fields.Delete(I);
    CanLocate := Fields.Count > 0;
    if CanLocate then
    begin
      if Fields.Count = 1 then
        KeyValues := TField(Fields[0]).Value
      else begin
        KeyValues := VarArrayCreate([0, Fields.Count - 1], varVariant);
        KeyValues[0] := TField(Fields[0]).Value;
      end;
      KeyNames := TField(Fields[0]).FieldName;
      for I := 1 to Fields.Count - 1 do
      begin
        KeyNames := KeyNames + ';' + TField(Fields[i]).FieldName;
        KeyValues[i] := TField(Fields[i]).Value;
      end;
    end;
  finally
    Fields.Free;
  end;
  with Query do
  begin
    Bmk := nil;
    DisableControls;
    try
      BookmarkFound := False;
      if BookMarkSearch then
        Bmk := GetBookmark;
      Close;
      Open;
      if Assigned(Bmk) then
      try
        GotoBookMark(Bmk);
        BookmarkFound := True;
      except  end;
      if not BookmarkFound and CanLocate then
        Locate(KeyNames, KeyValues, []);
    finally
      EnableControls;
      Screen.Cursor := crDefault;
      FreeBookmark(Bmk);
    end;
  end;
end;

procedure TQuery.RefreshParams;
var
  DataSet: TDataSet;
begin
  DisableControls;
  try
    if FDataLink.DataSource <> nil then
    begin
      DataSet := FDataLink.DataSource.DataSet;
      if DataSet <> nil then
        if DataSet.Active and (DataSet.State <> dsSetKey) then
          DoRefreshQuery(Self, GetFieldNamesStr(Self), False);
    end;
  finally
    EnableControls;
  end;
end;

>== Режем два ==<

Vladimir Gaitanoff
(2:5020/880.5)

Q>:
Как пересчитать все Calculated Fields без переоткрытия TDataSet?
A>:
    Resync([rmExact, rmCenter])

Vladimir Gaitanoff
(2:5020/880.5)

Q>:
(Oracle) Как в Oracle создать sequence с некоторого номера?
A>:
create sequence minvalue 10;

Andrey V. Petrow
(2:5030/53.334)

Q>:
Как создать текстовую таблицу с поддержкой русских букв?
A>:
Делай pаз - create database ... без всяких default character set
Делай два - запускай BDE Config и создавай алиас
Делай тpи - делай настpойки:

стpаница   паpаметp        значение         Пpимечание
Drivers    LANGDRIVER      'ascii' ANSI     У INTERBASE
Alias      LANGDRIVER      пусто
System     LANGDRIVER      'ascii' ANSI
System     DEFAULT DRIVER  ASCIIDRV

Alexey Malinin
(2:5057/19.18)

Q>:
(Oracle) Как решать некоторые вопросы при подключении к Oracle?
A>:

DD> 1. Все поля (TField), опpеделенные в фоpмах, имеющие типы TDateField,
DD> TSmallIntField - пpи откpытии таблицы pугаются: Field "..." is not of
DD> expected type. Посмотpел - пpи пеpеопpеделении их под Oracle'ом они

     Чтобы "увидеть" integer-поля нужно в настройке Alias'а Oracle в BDE
установить Enable Integers -> True (и напрочь будет потерян Locate по этим якобы
int/smallint полям).  С датами, возможно, тоже надо разбираться
через настройки Win & Oracle. У меня в Win дата формата "дд.мм.гггг", в Oracle
NLS_LANG -> AMERICAN_AMERICA.CL8MSWIN1251 и с датами все гут.

DD> 2. Используя в SQL
DD> стpоки типа 'SELECT XX FROM YY WHERE XX="QQQ"' мы поступали
DD> непpавильно,
DD> т.к. двойные кавычки в Oracle обpабатывабтся не так, как в Btrieve.
DD> Тут мы

    Oracle в данном случае не причем. Это глюк BDE. Лечилось просто - вместо
обрамления двойными кавычками строкового значения, нужно обрамлять его с
помощью #39, примерно так

      MySQLString:='SELECT XX FROM YY WHERE XX='+#39+'QQQ'+#39;

Belsky Roman
(2:450/94.75)

SS> У кого-нибудь есть опыт по настройке BDE ? Откликнитесь плиз! При
SS> попытке соединиться с базой вылезает ошибка: Vendor failed init!
SS> Delphi запускаю под 95. На всякий случай пути к \BDE и ORAWIN\BIN я
SS> проставил! orant71.dll (родной или переименнованый ora72win.dll)
SS> закидывал куда угодно, но.... все равно вылетает ошибка BDE Error
SS> 15879 Vendor failed init :-(

   Клиент у тебя NT, как я понял?
   ora7x.dll - 32bit клиент для win95
   orant7x.dll - 32bit клиент для NT
   ora7xwin.dll - 16bit клиент для win

   т.е. ora7xwin в Delphi3 вообще ставить бесполезно (16bit для 32bit appl).
  ora*71.dll у меня изначально к ORACLE 7.2 не коннектился - они там как-то
  резко сменили OCI. Правда потом ora72win.dll с Pers. Oracle 7.3 работал,
  но все равно лучше, наверное, чтобы номер версии dll был не ниже версии
  сервера.

    А вообще я 32bit дельфях в Vendor Init давно прописываю OCIW32.dll -
  он всегда для последней версии сервера с которым ты работаешь.

  Это IMHO. Но у меня Delphi3 и Delphi1 коннектятся как с Oracle 7.1 на
  Unix'е, так и с Pers. Oracle 7.3

Alex Mironov
http://WWW.MEB.RU/igorvl.html
(2:5020/238.46)

Q>:
Как заставить BDE сохранять в БД поле времени с сотыми долями секунды?
A>:
Если руками, то в BDE Administrator. Если в в инсталлялке, то -

В пункте Make Registry Changes InstallShield'а создай ключ
HKEY_LOCAL_MACHINE\SOFTWARE\Borland\Database Engine\Settings\SYSTEM\
FORMATS\TIME\MILSECONDS=TRUE

Alexey Yashin
(2:5020/62.31)

Q>:
Как создать Calculated Fields в RunTime?
A>:
See book "Developing Custom Delphi Components" by Ray Konopka.

This is little bit corrected example from this book:

function TMyClass.CreateCalcField( const AFieldName:string;
AFieldClass:TFieldClass; ASize:Word ) : TField;
begin
  Result := FDataSet.FindField(AFieldName); // Field may already exists!
  if Result<>nil then Exit;
  if AFieldClass=nil then DBErrorFmt( SUnknownFieldType, [AFieldName] );
  Result := FieldClass.Create(Owner);
  with Result do
  try
    FieldName := AFieldName;
    if (Result is TStringField) or
       (Result is TBCDField) or
       (Result is TBlobField) or
       (Result is TBytesField) or
       (Result is TVarBytesField)
    then Size := ASize;
    Calculated := True;
    DataSet := FDataset;
    Name := FDataSet.Name+AFieldName;
  except
    Free;  // We must release allocated memory on error!
    raise;
  end;
end;

Alex Konshin
(2:5030/217.217)

Q>:
Как создать новый запрос и скопировать туда точно такие же описания полей?
A>:
Копируешь FieldDefs. Проходишь циклом по FieldDefs.Items[i].CreateField(Owner);

Alex Konshin
(2:5030/217.217)

Q>:
(DB2) Почему DB2 ругается на Create Trigger?
A>:
  Я тут писал по поводу того, что у меня не pаботали тpиггеpы. Все дело
оказалось в пpавиле написания команды "create trigger". Если все остальные
команды коppектно воспpинимаются на любом pегистpе, то эта только набpанная
одними большими буквами.

Aleksey Sushko
(2:4615/7.32)

Q>:
(IB) Как заставить Interbase принять COLLATE PXW_CYRL по умолчанию?
(AA: Это очень полезно при прямой работе с IB из PowerDesigner)
A>:
Чтобы не писать каждый раз COLLATE я сделал следующее:

1) Создал сохраненную процедуру

create procedure fix_character_sets
as
begin
  update rdb$character_sets
    set rdb$default_collate_name = 'PXW_CYRL'
    where rdb$character_set_name = 'WIN1251' and
        rdb$default_collate_name = 'WIN1251';
end

2) Запустил ее один раз.

3) Создаю таблицы без COLLATE.

4) После восстановления из архива, запускаю еще раз.

Кудрин Олег, АТС-55, Красноярск.
oleg@ats.telecom.krasnoyarsk.su

Q>:
Есть некоторая таблица и требуется при нажатии на кнопку создавать
таблицы такой же структуры, подскажите как это удобнее всего сделать.
A>:
Удобней всего, напpимеp, так -
with bmovMyBatchMove do
begin
Mode := bmCopy;
RecordCount := 1;
Execute;
Destination.Delete;
end;

Akzhan Abdulin
(2:5040/55.46)

  Неправда Ваша! ;) Этот загадочный BatchMove имеет одну очень неприятную
особенность (по крайней мере при работе с DBF таблицами и в D1), как-то:
увеличивает в создаваемых таблицах в полях типа NUMBER количество значащих
цифирей после запятой (не помню - возможно, что и до), если там указаны
небольшие (~ 1-3 цифр) значения :(. Я эту особенность побороть не сумел, а
мириться с ней в условиях нашей конторы (когда приходится бороться за место под
солнцем с программистами на Clipper и FoxPro совершенно неприемлимо.
  Кроме того, в предложенном выше варианте еще и запись удалять приходится...:)
  Решалась же эта проблема следующим способом:

>============  Cut Begin  Myutils.Pas ====================

procedure CopyStruct(SrcTable,DestTable: TTable; cpyFields: array of string);
var
  i: Integer;
  bActive: Boolean;
  SrcDatabase,DestDatabase: TDatabase;
  iSrcMemSize,iDestMemSize: Integer;
  pSrcFldDes: PFldDesc;
  CrtTableDesc: CRTblDesc;
  bNeedAllFields: Boolean;
begin
  SrcDatabase:=Session.OpenDatabase(SrcTable.DatabaseName);
  try
    DestDatabase:=Session.OpenDatabase(DestTable.DatabaseName);
    try
      bActive:=SrcTable.Active;
      SrcTable.FieldDefs.Update;
      iSrcMemSize:=SrcTable.FieldDefs.Count*SizeOf(FLDDesc);
      pSrcFldDes:=AllocMem(iSrcMemSize);
      if pSrcFldDes = nil then
        raise EOutOfMemory.Create('=х iтрEрхE ярь Eш!');
      try
        SrcTable.Open;
        Check(DbiGetFieldDescs(SrcTable.Handle,pSrcFldDes));
        SrcTable.Active:=bActive;
        FillChar(CrtTableDesc,SizeOf(CrtTableDesc),0);
        with CrtTableDesc do
        begin
          StrPcopy(szTblName,DestTable.TableName);
          StrPcopy(szTblType,'DBASE');
          if(Length(cpyFields[0]) = 0) or (cpyFields[0] = '*') then
          begin
            bNeedAllFields:=True;
            SrcTable.FieldDefs.Update;
            iFldCount:=SrcTable.FieldDefs.Count;
          end
          else
          begin
            bNeedAllFields:=False;
            iFldCount:=High(cpyFields)+1;
          end;
          iDestMemSize:=iFldCount*Sizeof(FLDDesc);
          CrtTableDesc.pFLDDesc:=AllocMem(iDestMemSize);
          if CrtTableDesc.pFLDDesc = nil then
            raise EOutOfMemory.Create('=х iтрEрхE ярь Eш!');
        end;
        try
          if bNeedAllFields then
            for i:=0 to CrtTableDesc.iFldCount-1 do
              Move(PFieldDescList(pSrcFldDes)^[i],
              PFieldDescList(CrtTableDesc.pFLDDesc)^[i],SizeOf(FldDesc))
          else
            for i:=0 to CrtTableDesc.iFldCount-1 do
              Move(PFieldDescList(pSrcFldDes)^[SrcTable.FieldDefs.Find(cpyField
s[i]).FieldNo-1],
              PFieldDescList(CrtTableDesc.pFLDDesc)^[i],SizeOf(FldDesc));
          Check(DbiCreateTable(DestDatabase.Handle,True,CrtTableDesc));
        finally
          FreeMem(CrtTableDesc.pFLDDesc,iDestMemSize);
        end;
      finally
        FreeMem(pSrcFldDes,iSrcMemSize);
      end;
    finally
      Session.CloseDatabase(DestDatabase);
    end;
  finally
    Session.CloseDatabase(SrcDatabase);
  end;
end;

>============   Cut End   ====================

Vlad Fillippov
(2:5055/34.3)

Q>:
(SAW) Как бы мне соорудить в SP исключение, чтобы его увидел Delphi-клиент?
A>:

SS>   sqlstate='99999' не подходит, т.к. хочется на клиенте видеть код
SS> исключения.

  Используй RAISERROR с кодом >20000. Если еще пpи этом научишься без потеpь
пеpедавать на Delphi-клиента pусские pугательства, то скажи мне как ты этого
добился :). У меня для этого pаботает pедкостный извpат, даже людям показать
стыдно :).

Alexander Tesanov
(2:5015/23.5)

0


Вы здесь » Delphi.Forever » FAQ » FAQ по работе с СУБД