//Advanced Delphi Systems Code: ads_Db
Unit ads_Db;
{Copyright(c)2016 Advanced Delphi Systems

 Richard Maley
 Advanced Delphi Systems
 12613 Maidens Bower Drive
 Potomac, MD 20854 USA
 phone 301-840-1554
 dickmaley@advdelphisys.com

 The code herein can be used or modified by anyone.  Please retain references
 to Richard Maley at Advanced Delphi Systems.  If you make improvements to the
 code please send your improvements to dickmaley@advdelphisys.com so that the
 entire Delphi community can benefit.  All comments are welcome.
}
(*
UnitIndex Master Index Implementation Section Download Units
Description: ads_Db.pas
This unit contains the following routines.

AddTables   CreateTableFromQuery   DBAddQueryToTable   DBAddTables   DBCopyFieldAToB   DBCopyTable   DBCopyTableAToB   DBCopyTableToServer   DBCreateTableBorrowStr   DBCreateTableFromQuery   DBCreateTableFromTTable   DBDeleteTable   DBDropTable   DBEmptyTable   DBFieldNameByNo   DBFieldNamesCommonToString   DBFieldNamesCommonToTStrings   DBFieldNamesToTStrings   DBFieldNo   DBFieldSize   DBFieldType   DBFieldTypeByNo   DBGlobalStringFieldChange   DBGlobalStringFieldChangeWhere   DBGlobalStringFieldChangeWhere2   DBInsertMatchingFields   DBKeyFieldNamesToTStrings   DBLookUpDialog   DBMedianSingle   DBMoveTable   DBNextAlphaKey   DBNextInteger   DBNFields   DBParadoxCreateNKeys   DBRecordMove   DBReNameTable   DBSchemaSame   DBSessionCreateNew   DBSqlValueQuoted   DBSubtractTable   DBTrimBlanksLeft   DBTrimBlanksRight   DBUpdateMatchingFields   DeleteTable   DialogDBLookUp   DialogLookup   DialogLookupDetail   DropTable   EmptyTable   ErrorMeaning   FieldNo   FieldSize   FieldType   FieldTypeFromDataSet   IsEmptyDataSource   IsEmptyTable   IsEmptyTQuery   IsEmptyTTable   IsField   IsFieldKeyed   IsRecord   IsSchemaSame   IsStructureSame   IsTable   IsTableKeyed   LookupDialog   MoveTable   NFields   SubtractTable   TableAdd   TableCreateFromQuery   TableMove   TableSubtract   TEditKeyFilter.OnlyAToZ   TEditKeyFilter.OnlyNumbers   TEditKeyFilter.OnlyNumbersAbsolute   TPanel_Cmp_Sec_ads.ResizeShadowLabel  TypeField   TypeFieldFromDataSet  

*)
Interface
Uses DBTables, Classes, ExtCtrls, DB;

Function DBCreateTableFromTTable(
            Table: TTable;
            NewTableName,
            TableDatabaseName: String): Boolean;



{!~ Add source table to destination table}
Function AddTables(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;

{!~ Creates a new table from a Query.
 Complex joins can be output to a new table.}
Function CreateTableFromQuery(
            Query: TQuery;
            NewTableName,
            TableDatabaseName: String): Boolean;

{!~ Add source query to destination table}
Procedure DBAddQueryToTable(
      DataSet : TQuery;
      const
      DestDatabaseName,
      DestinationTable: string);

{!~ Add source table to destination table}
Function DBAddTables(
      const
      SourceDatabaseName,
      SourceTable,
      DestDatabaseName,
      DestinationTable: string): Boolean;

{!~ Copies Field A To Field B.}
function DBCopyFieldAToB(
            DatabaseName,
            TableName,
            SourceField,
            DestField: String): Boolean;

{!~ Copies SourceTable To DestTable.
If DestTable exists it is deleted}
Function DBCopyTable(
            SourceDatabaseName,
            SourceTable,
            DestDatabaseName,
            DestTable: String): Boolean;

{!~ Copies Table A To Table B.  If Table B exists it
is emptied}
Function DBCopyTableAToB(
            SourceDatabaseName,
            SourceTable,
            DestDatabaseName,
            DestTable: String): Boolean;

{!~ Copies a table from the source to the destination.
If the destination table exists the function will not
throw an error, the existing table will be replaced with the new
table.}
Function DBCopyTableToServer(
  SourceDatabaseName   : String;
  SourceTableName      : String;
  DestDatabaseName     : String;
  DestTableName        : String): Boolean;

{!~ Creates an empty table with indices by borrowing the structure
of a source table. Source and destination can be remote or local
tables.  If the destination table exists the function will not
throw an error, the existing table will be replaced with the new
table.}
Function DBCreateTableBorrowStr(
  SourceDatabaseName   : String;
  SourceTableName      : String;
  DestDatabaseName     : String;
  DestTableName        : String): Boolean;

{!~ Creates a new table from a Query.
 Complex joins can be output to a new table.}
Function DBCreateTableFromQuery(
            Query: TQuery;
            NewTableName,
            TableDatabaseName: String): Boolean;

{!~ Deletes A Table}
Function DBDeleteTable(const DatabaseName, TableName : string):Boolean;

{!~ Drops A Table}
Function DBDropTable(const DatabaseName, TableName : string):Boolean;

{!~ Empties a table of all records}
Function DBEmptyTable(
           const DatabaseName,
           TableName : string): Boolean;

{!~ Returns the field Name as a String.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason '' is returned.}
Function DBFieldNameByNo(
  DatabaseName  : String;
  TableName     : String;
  FieldNo       : Integer): String;

{!~ Returns Field Names shared by 2 tables as a string.
Fields are separated by commas with no trailing comma.}
Function DBFieldNamesCommonToString(
  DatabaseName1 : String;
  TableName1    : String;
  DatabaseName2 : String;
  TableName2    : String): String;

{!~ Copies Field Names shared by 2 tables to a TStrings object.
Returns true if successful.  If there
is an error, the DatabaseName doesn't exist, the table doesn't
exist or some other reason False is returned.  }
Function DBFieldNamesCommonToTStrings(
  DatabaseName1 : String;
  TableName1    : String;
  DatabaseName2 : String;
  TableName2    : String;
  Strings       : TStrings): Boolean;

{!~ Copies Table Field Names to a TStrings object, e.g.,
ListBox1.Items, Memo1.Lines.

Returns the true if successful.  If there
is an error, the DatabaseName doesn't exist, the table doesn't
exist or some other reason False is returned.  }
Function DBFieldNamesToTStrings(
  DatabaseName : String;
  TableName    : String;
  Strings      : TStrings): Boolean;

{!~ Returns the field Number as an integer.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason -1 is returned.}
Function DBFieldNo(DatabaseName, TableName, FieldName: String): Integer;

{!~ Returns the database field Size as an integer.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason 0 is returned.}
Function DBFieldSize(DatabaseName, TableName, FieldName: String): Integer;

{!~ Returns the database field type as a string.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason a null string is returned.}
Function DBFieldType(DatabaseName, TableName, FieldName: String): String;

{!~ Returns the database field type as a string.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason a null string is returned.}
Function DBFieldTypeByNo(DatabaseName, TableName: String; FieldNo: Integer): String;

{!~ Replace all the values in a field that match a
condition value with a new value}
procedure DBGlobalStringFieldChange(
  const DatabaseName,
  TableName,
  FieldName,
  NewValue : string);

{!~ Replace all the values in a field with a new value}
procedure DBGlobalStringFieldChangeWhere(
  const DatabaseName,
  TableName,
  FieldName,
  CurrentValue,
  NewValue : string);

{!~ Replace values in a field (NewValueField) with NewValue
based on a where condition in CurrentValueField with a value
of CurrentValue}
procedure DBGlobalStringFieldChangeWhere2(
  const DatabaseName,
  TableName,
  NewValueField,
  NewValue,
  CurrentValueField,
  CurrentValue: string);

{!~ Inserts matching fields in a destination table.
Source Table records are deleted if the record was inserted properly.
Records unsuccessfully inserted are retained and the problems recorded
in the ErrorField.}
Function DBInsertMatchingFields(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable,
           ErrorField: string): Boolean;

{!~ Copies Table Key Field Names to a TStrings object.
Returns the true if successful.  If there
is an error, the DatabaseName doesn't exist, the table doesn't
exist or some other reason False is returned.  }
Function DBKeyFieldNamesToTStrings(
  DatabaseName : String;
  TableName    : String;
  Strings      : TStrings): Boolean;

{!~ Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
Function DBLookUpDialog(
  Const DataBaseName  : String;
  Const TableName     : String;
  Const FieldName     : String;
  Const SessionName   : String;
  Const DefaultValue  : String;
  const DialogCaption : string;
  const InputPrompt   : string;
  const DialogWidth   : Integer
  ): String;

{!~ Returns the median value for a column in a table
as type single}
Function DBMedianSingle(
      const DatabaseName,
      TableName,
      FieldName,
      WhereString
      : string): Single;

{!~ Moves SourceTable From SourceDatabaseName
 To DestDatabasename.  If a table exists
 with the same name at DestDatabaseName it
 is overwritten.}
Function DBMoveTable(
            SourceTable,
            SourceDatabaseName,
            DestDatabaseName: String): Boolean;

{!~ Returns the number of fields in a table}
Function DBNFields(DatabaseName, TableName: String): Integer;

{!~ Returns the next key value when the table keys are
numbers as strings, e.g., '   12' key would return
'   13'}
Function DBNextAlphaKey(DatabaseName, TableName, FieldName: String):String;

{!~ Returns the next key value when the table keys are
integers, e.g., 12 key would return 13}
Function DBNextInteger(
  DatabaseName,
  TableName,
  FieldName: String):LongInt;

{!~ ReKeys a Paradox Table to the first N fields}
Function DBParadoxCreateNKeys(
  DatabaseName : String;
  TableName    : String;
  NKeys        : Integer): Boolean;

{!~ ReNames a table}
Function DBReNameTable(
  DatabaseName,
  TableNameOld,
  TableNameNew: String): Boolean;

{!~ Applies BatchMode Types As Appropriate To
Source and Destination Tables}
Function DBRecordMove(
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestTable: String;
           BMode: TBatchMode): Boolean;

{!~ Returns True If The Tables Have Identical Structures, False Otherwise.
If 1 Local Table is involved then Indices are ignored!!!!!!}
Function DBSchemaSame(const
           DatabaseName1,
           Table1,
           DatabaseName2,
           Table2: string): Boolean;

{!~ Creates a new TSession object.}
{$IFDEF WIN32}
Function DBSessionCreateNew: TSession;
{$ENDIF WIN32}

{!~ Returns a value for use in a sql where clause with the
appropriate Quoting of the value based on its datatype.  If
an error occurs the original string value is returned unchanged}
Function DBSqlValueQuoted(
  const
  DatabaseName,
  TableName,
  FieldName,
  FieldValue: string): String;

{!~ Subtracts the records in the source
 table from the destination table}
Function DBSubtractTable(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;

{!~ Trims blank spaces from the Left of the string}
Function DBTrimBlanksLeft(
  DatabaseName : String;
  TableName    : String;
  FieldName    : String): Boolean;

{!~ Trims blank spaces from the right of the string}
Function DBTrimBlanksRight(
  DatabaseName : String;
  TableName    : String;
  FieldName    : String): Boolean;

{!~ Updates matching fields in a destination table.
Source Table records are deleted if the record was updated properly.
Records unsuccessfully updated are retained and the problems recorded
in the ErrorField.}
Function DBUpdateMatchingFields(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable,
           ErrorField: string;
           MsgPanel: TPanel;
           FilePath: String): Boolean;

{!~ Deletes A Table}
Function DeleteTable(const DatabaseName, TableName : string):Boolean;

{!~ Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
Function DialogDBLookUp(
  Const DataBaseName  : String;
  Const TableName     : String;
  Const FieldName     : String;
  Const SessionName   : String;
  Const DefaultValue  : String;
  const DialogCaption : string;
  const InputPrompt   : string;
  const DialogWidth   : Integer
  ): String;

{!~ Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
Function DialogLookup(
  const DialogCaption : string;
  const InputPrompt   : string;
  const DefaultValue  : string;
  const Values        : TStringList
  ): string;

{!~ Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
Function DialogLookupDetail(
  Const DialogCaption   : string;
  Const InputPrompt     : string;
  Const DefaultValue    : string;
  Const Values          : TStringList;
  Const ButtonSpacing   : Integer;
  Const SpacerHeight    : Integer;
  Const TopBevelWidth   : Integer;
  Const PromptHeight    : Integer;
  Const FormHeight      : Integer;
  Const FormWidth       : Integer;
  Const Hint_OK         : string;
  Const Hint_Cancel     : string;
  Const Hint_ListBox    : string;
  Const ListSorted      : Boolean;
  Const AllowDuplicates : Boolean
  ): string;

{!~ Drops A Table}
Function DropTable(const DatabaseName, TableName : string):Boolean;

{!~ Empties a table of all records}
Function EmptyTable(
           const DatabaseName,
           TableName : string): Boolean;

{!~ Returns the meaning of the given result code.  Error codes are for
Delphi 1.0.}
function ErrorMeaning (ResultCode: Integer): string;

{!~ Returns the field Number as an integer.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason 0 is returned.}
Function FieldNo(DatabaseName, TableName, FieldName: String): Integer;

{!~ Returns the database field Size as an integer.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason 0 is returned.}
Function FieldSize(DatabaseName, TableName, FieldName: String): Integer;

{!~ Returns the database field type as a string.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason a null string is returned.}
Function FieldType(DatabaseName, TableName, FieldName: String): String;

{!~ Returns the database field type as a string.  If there
is an error a null string is returned.}
Function FieldTypeFromDataSet(DataSet: TDataSet; FieldName: String): String;

{!~ Tests whether a TDataSource is empty, i.e., has no records }
Function IsEmptyDataSource(DS: TDataSource): Boolean;

{!~ Tests whether a TQuery is empty, i.e., has no records }
Function IsEmptyTQuery(Query: TQuery): Boolean;

{!~ Tests whether a TTable is empty, i.e., has no records }
Function IsEmptyTTable(Table: TTable): Boolean;

{!~ Tests whether a table is empty, i.e., has no records }
Function IsEmptyTable(DatabaseName, TableName: String): Boolean;

{!~ Returns True If DatabaseName:TableName:FieldName Exists,
False Otherwise}
Function IsField(DatabaseName, TableName, FieldName: String): Boolean;

{!~ Returns True If DatabaseName:TableName:FieldName
 Exists and is Keyed, False Otherwise}
Function IsFieldKeyed(DatabaseName, TableName, FieldName: String): Boolean;

{!~ Returns True If The Record Exists, False Otherwise}
Function IsRecord(
  DatabaseName : String;
  TableName    : String;
  TableKeys    : TStringList;
  KeyValues    : TStringList): Boolean;

{!~ Returns True If The Tables Have Identical Structures, False Otherwise.
If 1 Local Table is involved then Indices are ignored!!!!!!}
Function IsSchemaSame(const
           DatabaseName1,
           Table1,
           DatabaseName2,
           Table2: string): Boolean;

{!~ Returns True If The Tables Have Identical Structures, False Otherwise.
If 1 Local Table is involved then Indices are ignored!!!!!!}
Function IsStructureSame(const
           DatabaseName1,
           Table1,
           DatabaseName2,
           Table2: string): Boolean;

{!~ Returns True If The Table Exists, False Otherwise.
This procedure needs to be improved.
Please give recommendations or new code.}
Function IsTable(DatabaseName, TableName: String): Boolean;

{!~ Returns True If DatabaseName:TableName
Exists and has a primary key, False Otherwise}
Function IsTableKeyed(DatabaseName, TableName: String): Boolean;

{!~ Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
Function LookupDialog(
  const DialogCaption : string;
  const InputPrompt   : string;
  const DefaultValue  : string;
  const Values        : TStringList
  ): string;

{!~ Moves SourceTable From SourceDatabaseName
 To DestDatabasename.  If a table exists
 with the same name at DestDatabaseName it
 is overwritten.}
Function MoveTable(
            SourceTable,
            SourceDatabaseName,
            DestDatabaseName: String): Boolean;

{!~ Returns the number of fields in a table}
Function NFields(DatabaseName, TableName: String): Integer;

{!~ Subtracts the records in the source
 table from the destination table}
Function SubtractTable(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;

{!~ Add source table to destination table}
Function TableAdd(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;

{!~ Creates a new table from a Query.
 Complex joins can be output to a new table.}
Function TableCreateFromQuery(
            Query: TQuery;
            NewTableName,
            TableDatabaseName: String): Boolean;

{!~ Moves SourceTable From SourceDatabaseName
 To DestDatabasename.  If a table exists
 with the same name at DestDatabaseName it
 is overwritten.}
Function TableMove(
            SourceTable,
            SourceDatabaseName,
            DestDatabaseName: String): Boolean;

{!~ Subtracts the records in the source
 table from the destination table}
Function TableSubtract(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;

{!~ Returns the database field type as a string.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason a null string is returned.}
Function TypeField(DatabaseName, TableName, FieldName: String): String;

{!~ Returns the database field type as a string.  If there
is an error a null string is returned.}
Function TypeFieldFromDataSet(DataSet: TDataSet; FieldName: String): String;

implementation


Uses ads_Strg, StdCtrls, Controls, Forms, SysUtils, Dialogs;

Type

{!~
TPanel_Cmp_Sec_ads
}
TPanel_Cmp_Sec_ads = class(TPanel)
Public
  procedure ResizeShadowLabel(Sender: TObject);
End;

{!~
TPanel_Cmp_Sec_ads.ResizeShadowLabel
}
//
Unit Description UnitIndex Master Index
procedure TPanel_Cmp_Sec_ads.ResizeShadowLabel(
  Sender     : TObject);
Var
  PH, PW : Integer;
  LH, LW : Integer;
begin
  PH := TPanel(Sender).Height;
  PW := TPanel(Sender).Width;
  LH := TLabel(Controls[0]).Height;
  LW := TLabel(Controls[0]).Width;
  TLabel(Controls[0]).Top  := ((PH-LH) div 2)-3;
  TLabel(Controls[0]).Left := ((Pw-Lw) div 2)-3;
End;

Type

{!~
TEditKeyFilter
}
TEditKeyFilter = Class(TEdit)
Published
  {!~ Throws away all keys except 0-9,-,+,.}
  Procedure OnlyNumbers(Sender: TObject; var Key: Char);

  {!~ Throws away all keys except 0-9}
  Procedure OnlyNumbersAbsolute(Sender: TObject; var Key: Char);

  {!~ Throws away all keys except a-z and A-Z}
  Procedure OnlyAToZ(Sender: TObject; var Key: Char);

End;

{!~
TEditKeyFilter.OnlyNumbers

Throws away all keys except 0-9,-,+,.}
//
Unit Description UnitIndex Master Index
Procedure TEditKeyFilter.OnlyNumbers(Sender: TObject; var Key: Char);
Begin
  KeyPressOnlyNumbers(Key);
End;

{!~
TEditKeyFilter.OnlyNumbersAbsolute

Throws away all keys except 0-9}
//
Unit Description UnitIndex Master Index
Procedure TEditKeyFilter.OnlyNumbersAbsolute(Sender: TObject; var Key: Char);
Begin
  KeyPressOnlyNumbersAbsolute(Key);
End;

{!~
TEditKeyFilter.OnlyAToZ

Throws away all keys except a-z and A-Z}
//
Unit Description UnitIndex Master Index
Procedure TEditKeyFilter.OnlyAToZ(Sender: TObject; var Key: Char);
Begin
  KeyPressOnlyAToZ(Key);
End;

{!~
AddTables

Add source table to destination table}
//
Unit Description UnitIndex Master Index
Function AddTables(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;
Var
  BMode : TBatchMode;
Begin
  If IsTableKeyed(DestDatabaseName,DestinationTable) Then
  Begin
    If IsTableKeyed(SourceDatabaseName,SourceTable) Then
    Begin
      BMode := BatAppendUpdate;
    End
    Else
    Begin
      BMode := BatAppend;
    End;
  End
  Else
  Begin
    BMode := BatAppend;
  End;

  Result := DBRecordMove(SourceDatabaseName,SourceTable,
                         DestDatabaseName,DestinationTable,BMode);
End;

{!~
CreateTableFromQuery

Creates a new table from a Query.
Complex joins can be output to a new table.}
//
Unit Description UnitIndex Master Index
Function CreateTableFromQuery(
            Query: TQuery;
            NewTableName,
            TableDatabaseName: String): Boolean;
Begin
  Result := DBCreateTableFromQuery(Query,NewTableName,TableDatabaseName);
End;

{!~
DBAddQueryToTable

Add source query to destination table}
//
Unit Description UnitIndex Master Index
Procedure DBAddQueryToTable(
      DataSet : TQuery;
      const
      DestDatabaseName,
      DestinationTable: string);
var
  DTable : TTable;
  BMove  : TBatchMove;
begin
  DTable := TTable.Create(nil);
  BMove  := TBatchMove.Create(nil);
  Try
    DataSet.Active         := True;
    DTable.DatabaseName    := DestDatabaseName;
    DTable.TableName       := DestinationTable;
    DTable.Active          := True;
    BMove.AbortOnKeyViol   := False;
    BMove.AbortOnProblem   := False;
    BMove.ChangedTableName := 'CTable';
    BMove.Destination      := DTable;
    BMove.KeyViolTableName := 'KTable';
    BMove.Mode             := batAppend;
    BMove.ProblemTableName := 'PTable';
    BMove.Source           := DataSet;
    BMove.Execute;
  Finally
    DTable.Active            := False;
    DTable.Free;
    BMove.Free;
  End;
End;

{!~
DBAddTables

Add source table to destination table}
//
Unit Description UnitIndex Master Index
Function DBAddTables(
      const
      SourceDatabaseName,
      SourceTable,
      DestDatabaseName,
      DestinationTable: string): Boolean;
begin
  Result := AddTables(SourceDatabaseName,SourceTable,
                      DestDatabaseName,DestinationTable);
End;

{!~
DBCopyFieldAToB

Copies Field A To Field B.}
//
Unit Description UnitIndex Master Index
function DBCopyFieldAToB(
            DatabaseName,
            TableName,
            SourceField,
            DestField: String): Boolean;
var
  Query     : TQuery;
  CursorWas : TCursor;
  Sess      : TSession;
begin
  CursorWas         := Screen.Cursor;
  Sess              := DBSessionCreateNew;
  Sess.Active       := True;
  Query             := TQuery.Create(sess);
  Query.SessionName := Sess.SessionName;
  Sess.Active       := True;
  Query.Active      := False;
  Query.RequestLive := True;
  try
    Result := False;
    Query.DatabaseName := DatabaseName;
    Query.SQL.Clear;
    Query.SQL.Add('Select ');
    Query.SQL.Add(SourceField+',');
    Query.SQL.Add(DestField);
    Query.SQL.Add('From '+TableName);
    Query.Open;
    Query.First;
    While Not Query.EOF Do
    Begin
      //ProgressScreenCursor;
      Try
        Query.Edit;
        Query.FieldByName(DestField).AsString :=
          Query.FieldByName(SourceField).AsString;
        Query.Post;
      Except
      End;
      Query.Next;
    End;
    Result := True;
  finally
    Query.Free;
    Screen.Cursor := CursorWas;
    Sess.Active   := False;
  end;
End;

{!~
DBCopyTable

Copies SourceTable To DestTable.
If DestTable exists it is deleted}
//
Unit Description UnitIndex Master Index
Function DBCopyTable(
            SourceDatabaseName,
            SourceTable,
            DestDatabaseName,
            DestTable: String): Boolean;
Begin
  Result := DBRecordMove(SourceDatabaseName,SourceTable,
                         DestDatabaseName,DestTable,batCopy);
End;

{!~
DBCopyTableAToB

Copies Table A To Table B.  If Table B exists it
is emptied}
//
Unit Description UnitIndex Master Index
Function DBCopyTableAToB(
            SourceDatabaseName,
            SourceTable,
            DestDatabaseName,
            DestTable: String): Boolean;
begin
  Result :=
    DBCopyTable(
      SourceDatabaseName,
      SourceTable,
      DestDatabaseName,
      DestTable);
End;

{!~
DBCopyTableToServer

Copies a table from the source to the destination.
If the destination table exists the function will not
throw an error, the existing table will be replaced with the new
table.

example:
  This is a very powerful migration utility.
  It can be used to copy tables from and to any location.
  The following example copies the DBDemos "Customer.db" table to
  a Sybase client server database.

  DBCopyTableToServer(
    'DBDemos',
    'Customer.Db',
    'SybaseDb',
    'Customer');
}
//
Unit Description UnitIndex Master Index
Function DBCopyTableToServer(
  SourceDatabaseName   : String;
  SourceTableName      : String;
  DestDatabaseName     : String;
  DestTableName        : String): Boolean;
Begin
  Result := False;
  Try
    If DBCreateTableBorrowStr(
         SourceDatabaseName,
         SourceTableName,
         DestDatabaseName,
         DestTableName)
    Then
    Begin
      If  AddTables(
            SourceDatabaseName,
            SourceTableName,
            DestDatabaseName,
            DestTableName)
      Then
      Begin
        Result := True;
      End;
    End;
  Except
    On E : Exception Do
    Begin
      ShowMessage('DBCopyTableToServer Error: '+E.Message);
      Result := False;
    End;
  End;
End;

{!~
DBCreateTableBorrowStr

Creates an empty table with indices by borrowing the structure
of a source table. Source and destination can be remote or local
tables.  If the destination table exists the function will not
throw an error, the existing table will be replaced with the new
table.

example:
  This is a very powerful migration utility.
  The function creates an empty table with indices by borrowing the
  structure of a source table. Source and destination can be remote
  or local tables.  If the destination table exists the function will not
  throw an error, the existing table will be replaced with the new
  table.

  The following example creates an empty version of the DBDemos
  "Customer.Db" table on a Sybase Client Server Database.

  DBCreateTableBorrowStr(
    'DBDemos',
    'Customer.Db',
    'SybaseDb',
    'Customer');
}
//
Unit Description UnitIndex Master Index
Function DBCreateTableBorrowStr(
  SourceDatabaseName   : String;
  SourceTableName      : String;
  DestDatabaseName     : String;
  DestTableName        : String): Boolean;
Var
  S             : TTable;
  D             : TTable;
  i             : Integer;
  j             : Integer;
  IMax          : Integer;
  IndexName     : String;
  IndexFields   : String;
  IndexFields2  : String;
  Q             : TQuery;
  IDXO          : TIndexOptions;
Begin
  S := TTable.Create(nil);
  D := TTable.Create(nil);
  Try
    Try
      S.Active       := False;
      S.DatabaseName := SourceDatabaseName;
      S.TableName    := SourceTableName;
      S.TableType    := ttDefault;
      S.Active       := True;
      D.DatabaseName := DestDatabaseName;
      D.TableName    := DestTableName;
      D.TableType    := ttDefault;
      D.FieldDefs.Assign(S.FieldDefs);
      D.CreateTable;
      {Similar method could be used to create the indices}
      {D.IndexDefs.Assign(S.IndexDefs);}
      S.IndexDefs.Update;
      D.IndexDefs.Update;
      D.IndexDefs.Clear;
      D.IndexDefs.Update;
      For i := 0 To S.IndexDefs.Count - 1 Do
      Begin
        If Pos('.DB',UpperCase(DestTableName)) > 0 Then
        Begin
          {Paradox or DBase Tables}
          If S.IndexDefs.Items[i].Name = '' Then
          Begin
            If Pos('.DB',UpperCase(DestTableName)) = 0 Then
            Begin
              IndexName := DestTableName+IntToStr(i);
            End
            Else
            Begin
              IndexName := '';
            End;
          End
          Else
          Begin
            IndexName := DestTableName+IntToStr(i);
          End;
          IndexFields := S.IndexDefs.Items[i].Fields;
          D.AddIndex(IndexName,IndexFields,S.IndexDefs.Items[i].Options);
          D.IndexDefs.Update;
        End
        Else
        Begin
          {Non Local Tables}
          Q := TQuery.Create(nil);
          Try
            S.IndexDefs.Update;
            D.IndexDefs.Update;
            D.IndexDefs.Clear;
            D.IndexDefs.Update;
            IMax := S.IndexDefs.Count - 1;
            For j := 0 To IMax Do
            Begin
              Q. Active      := False;
              Q.DatabaseName := DestDatabaseName;
              IndexName      := DestTableName+IntToStr(j);
              IndexFields    := S.IndexDefs.Items[j].Fields;
              IndexFields2   :=
                ReplaceCharInString(IndexFields,';',',');
              Q.SQL.Clear;
              Q.SQL.Add('Create');
              If ixUnique in S.IndexDefs.Items[j].Options Then
              Begin
                Q.SQL.Add('Unique');
              End;
              If ixDescending in S.IndexDefs.Items[j].Options Then
              Begin
                Q.SQL.Add('Desc');
              End
              Else
              Begin
                Q.SQL.Add('Asc');
              End;
              Q.SQL.Add('Index');
              Q.SQL.Add(IndexName);
              Q.SQL.Add('On');
              Q.SQL.Add(DestTableName);
              Q.SQL.Add('(');
              Q.SQL.Add(IndexFields2);
              Q.SQL.Add(')');
              Try
                Q.ExecSql;
                D.IndexDefs.Update;
                D.AddIndex(IndexName,IndexFields,S.IndexDefs.Items[j].Options);
                D.IndexDefs.Update;
              Except
                On E : EDBEngineError Do
                Begin
                  If E.Message = 'Invalid array of index descriptors.' Then
                  Begin
                    Try
                      D.IndexDefs.Update;
                      D.DeleteIndex(IndexName);
                      D.IndexDefs.Update;
                    Except
                    End;
                  End
                  Else
                  Begin
                    Try
                      D.IndexDefs.Update;
                      IDXO := D.IndexDefs.Items[j].Options;
                    Except
                    End;
                    {Msg('DBCreateTableBorrowStr Error: '+E.Message);}
                  End;
                End;
              End;
            End;
          Finally
            Q.Free;
          End;
        End;
      End;
      S.Active       := False;
      Result := True;
    Finally
      S.Free;
      D.Free;
    End;
  Except
    On E : Exception Do
    Begin
      ShowMessage('DBCreateTableBorrowStr Error: '+E.Message);
      Result := False;
    End;
  End;
End;

{!~
DBCreateTableFromQuery

Creates a new table from a Query.
Complex joins can be output to a new table.}
//
Unit Description UnitIndex Master Index
Function DBCreateTableFromQuery(
            Query: TQuery;
            NewTableName,
            TableDatabaseName: String): Boolean;
var
  D         : TTable;
  ActiveWas : Boolean;
begin
  D := nil;
  try
    {The Source Table}
    ActiveWas      := Query.Active;
    Query.Active   := true;

    {Create The Destination Table}
    D              := TTable.Create(nil);
    D.Active       := False;
    D.DatabaseName := TableDatabaseName;
    D.TableName    := NewTableName;
    D.ReadOnly     := False;

    {Make the table copy}
    D.BatchMove(Query,batCopy);
    Query.Active := ActiveWas;
    Result := True;
  finally
    D.Free;
  end;
End;

//
Unit Description UnitIndex Master Index
Function DBCreateTableFromTTable(
            Table: TTable;
            NewTableName,
            TableDatabaseName: String): Boolean;
var
  D         : TTable;
  ActiveWas : Boolean;
begin
  D := nil;
  try
    {The Source Table}
    ActiveWas      := Table.Active;
    Table.Active   := true;

    {Create The Destination Table}
    D              := TTable.Create(nil);
    D.Active       := False;
    D.DatabaseName := TableDatabaseName;
    D.TableName    := NewTableName;
    D.ReadOnly     := False;

    {Make the table copy}
    D.BatchMove(Table,batCopy);
    Table.Active := ActiveWas;
    Result := True;
  finally
    D.Free;
  end;
End;



{!~
DBDeleteTable

Deletes A Table}
//
Unit Description UnitIndex Master Index
Function DBDeleteTable(const DatabaseName, TableName : string):Boolean;
Begin
  Try
    If Not IsTable(DatabaseName, TableName) Then
    Begin
      Result := False;
      Exit;
    End;
    Result := DBDropTable(DatabaseName, TableName);
  Except
    Result := False;
  End;
End;

{!~
DBDropTable

Drops A Table}
//
Unit Description UnitIndex Master Index
Function DBDropTable(const DatabaseName, TableName : string):Boolean;
var Query : TQuery;
begin
  Result := False;
  If Not IsTable(DatabaseName, TableName) Then
  Begin
    Exit;
  End;
  Query := TQuery.Create(nil);
  try
    Query.DatabaseName := DatabaseName;
    Query.SQL.Clear;
    Query.SQL.Add('Drop Table ');
    If (Pos('.DB', UpperCase(TableName)) > 0) Or
       (Pos('.DBF',UpperCase(TableName)) > 0) Then
    Begin
      Query.Sql.Add('"'+TableName+'"');
    End
    Else
    Begin
      Query.Sql.Add(TableName);
    End;
    Result := True;
    Try
      Query.ExecSQL;
    Except
      Result := False;
    End;
  finally
    Query.Free;
  end;
End;

{!~
DBEmptyTable

Empties a table of all records}
//
Unit Description UnitIndex Master Index
Function DBEmptyTable(
           const DatabaseName,
           TableName : string): Boolean;
var Query : TQuery;
begin
  Query := TQuery.Create(nil);
  try
    Query.DatabaseName := DatabaseName;
    Query.SQL.Clear;
    If Pos('.DB',UpperCase(TableName)) > 0 Then
      Query.SQL.Add('DELETE FROM "'+TableName+'"')
      Else
      Query.SQL.Add('DELETE FROM '+TableName);
    Query.ExecSQL;
    Result := True;
  finally
    Query.Free;
  end;
End;

{!~
DBFieldNameByNo

Returns the field Name as a String.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason '' is returned.

example:
  Returns the field Name as a String.  If there
  is an error, the table doesn't exist, the field doesn't
  exist or some other reason '' is returned.

  The field number is zero based so the first column would
  be 0, the 2nd column 1 etc.

  This example returns "Company" as the name of the 2nd
  column in the table. "1" is entered as the column
  number because it is zero based.

    FieldName :=
      DBFieldNameByNo(
        'DBDemos',
        'Customer.Db',
        1);
}
//
Unit Description UnitIndex Master Index
Function DBFieldNameByNo(
  DatabaseName  : String;
  TableName     : String;
  FieldNo       : Integer): String;
Var
  Table      : TTable;
Begin
  Result := '';
  If Not IsTable(DatabaseName, TableName) Then Exit;
  If FieldNo < 0 Then Exit;
  If FieldNo >= DBNFields(DatabaseName, TableName) Then Exit;
  Table := TTable.Create(nil);
  Try
    Try
      Table.Active       := False;
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active       := True;
      Result := Table.FieldDefs[FieldNo].Name;
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
DBFieldNamesCommonToString

Returns Field Names shared by 2 tables as a string.
Fields are separated by commas with no trailing comma.}
//
Unit Description UnitIndex Master Index
Function DBFieldNamesCommonToString(
  DatabaseName1 : String;
  TableName1    : String;
  DatabaseName2 : String;
  TableName2    : String): String;
Var
  List1 : TStringList;
  List2 : TStringList;
  i     : Integer;
  Suffix: String;
Begin
  Result := '';
  List1  := TStringList.Create();
  List2  := TStringList.Create();
  Try
    DBFieldNamesToTStrings(
      DatabaseName1,
      TableName1,
      List1);
    For i := 0 To List1.Count - 1 Do
    Begin
      List1[i] := UpperCase(List1[i]);
    End;
    DBFieldNamesToTStrings(
      DatabaseName2,
      TableName2,
      List2);
    For i := 0 To List2.Count - 1 Do
    Begin
      List2[i] := UpperCase(List2[i]);
    End;
    For i := 0 To List1.Count - 1 Do
    Begin
      If Result = '' Then
      Begin
        Suffix := '';
      End
      Else
      Begin
        Suffix := ', ';
      End;
      If List2.IndexOf(List1[i]) <> -1 Then
      Begin
        Result := Result + Suffix + List1[i];
      End;
    End;
  Finally
    List1.Free;
    List2.Free;
  End;
End;

{!~
DBFieldNamesCommonToTStrings

Copies Field Names shared by 2 tables to a TStrings object.
Returns true if successful.  If there
is an error, the DatabaseName doesn't exist, the table doesn't
exist or some other reason False is returned.  }
//
Unit Description UnitIndex Master Index
Function DBFieldNamesCommonToTStrings(
  DatabaseName1 : String;
  TableName1    : String;
  DatabaseName2 : String;
  TableName2    : String;
  Strings       : TStrings): Boolean;
Var
  List1 : TStringList;
  List2 : TStringList;
  i     : Integer;
Begin
{  Result := False;}{zzz}
  List1  := TStringList.Create();
  List2  := TStringList.Create();
  Try
    Strings.Clear;
    DBFieldNamesToTStrings(
      DatabaseName1,
      TableName1,
      List1);
    For i := 0 To List1.Count - 1 Do
    Begin
      List1[i] := UpperCase(List1[i]);
    End;
    DBFieldNamesToTStrings(
      DatabaseName2,
      TableName2,
      List2);
    For i := 0 To List2.Count - 1 Do
    Begin
      List2[i] := UpperCase(List2[i]);
    End;
    For i := 0 To List1.Count - 1 Do
    Begin
      If List2.IndexOf(List1[i]) <> -1 Then
      Begin
        Strings.Add(List1[i]);
      End;
    End;
    Result := True;
  Finally
    List1.Free;
    List2.Free;
  End;
End;

{!~
DBFieldNamesToTStrings

Copies Table Field Names to a TStrings object, e.g.,
ListBox1.Items, Memo1.Lines.

Returns true if successful.  If there
is an error, the DatabaseName doesn't exist, the table doesn't
exist or some other reason False is returned.

example:
  DBFieldNamesToTStrings copies Table Field Names to a TStrings object, e.g.,
  ListBox1.Items, Memo1.Lines.

  It returns true if successful, False otherwise.  If there
  is an error, the DatabaseName doesn't exist, the table doesn't
  exist or some other reason False is returned.

  In this example the DBDemos "Customer.Db" table Field Names
  populate a TStringList that is passed as a parameter to the
  procedure.

    Procedure TForm1.GetFieldNames(
      DatabaseName : String;
      TableName    : String;
      TSL          : TStrings);
    Begin
      DBFieldNamesToTStrings(
        DatabaseName,
        TableName,
        TSL);
    End;

    Procedure TForm1.FormCreate(
    Begin
      TSL := TStringList.Create();
      GetFieldNames(
        'DBDemos',
        'Customer.Db',
        TSL);
    End;
}
//
Unit Description UnitIndex Master Index
Function DBFieldNamesToTStrings(
  DatabaseName : String;
  TableName    : String;
  Strings      : TStrings): Boolean;
Var
  Table      : TTable;
  FieldNo    : Integer;
Begin
  Result := False;
  If Not IsTable(DatabaseName, TableName) Then Exit;
  Table := TTable.Create(nil);
  Try
    Try
      Table.Active       := False;
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active       := True;
      Strings.Clear;
      For FieldNo := 0 To Table.FieldDefs.Count -1 Do
      Begin
        Strings.Add(Table.FieldDefs[FieldNo].Name);
      End;
      Result := True;
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
DBFieldNo

Returns the field Number as an integer.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason -1 is returned.}
//
Unit Description UnitIndex Master Index
Function DBFieldNo(DatabaseName, TableName, FieldName: String): Integer;
Var
  Table      : TTable;
  FieldIndex : Integer;
  FieldNumber: Integer;
Begin
  Result := -1;
  If Not IsTable(DatabaseName, TableName) Then Exit;
  If Not IsField(DatabaseName, TableName, FieldName) Then Exit;
  Table := TTable.Create(nil);
  Try
    Try
      Table.Active       := False;
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active       := True;
      FieldIndex         :=
        Table.FieldDefs.IndexOf(FieldName);
      FieldNumber        :=
        Table.FieldDefs[FieldIndex].FieldNo;
      Result := FieldNumber;
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
DBFieldSize

Returns the database field Size as an integer.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason 0 is returned.}
//
Unit Description UnitIndex Master Index
Function DBFieldSize(DatabaseName, TableName, FieldName: String): Integer;
Var
  Table      : TTable;
  FieldIndex : Integer;
  FieldSize  : Integer;
Begin
  Result := 0;
  If Not IsTable(DatabaseName, TableName) Then Exit;
  If Not IsField(DatabaseName, TableName, FieldName) Then Exit;
  Table := TTable.Create(nil);
  Try
    Try
      Table.Active       := False;
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active       := True;
      FieldIndex         :=
        Table.FieldDefs.IndexOf(FieldName);
      FieldSize          :=
        Table.FieldDefs[FieldIndex].Size;
      Result := FieldSize;
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
DBFieldType

Returns the database field type as a string.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason a null string is returned.}
//
Unit Description UnitIndex Master Index
Function DBFieldType(DatabaseName, TableName, FieldName: String): String;
Begin
  Result := TypeField(DatabaseName, TableName, FieldName);
End;

{!~
DBFieldTypeByNo

Returns the database field type as a string.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason a null string is returned.}
//
Unit Description UnitIndex Master Index
Function DBFieldTypeByNo(DatabaseName, TableName: String; FieldNo: Integer): String;
Var
  Table      : TTable;
  FieldIndex : Integer;
  FieldType  : TFieldType;
Begin
  Result := '';
  If Not IsTable(DatabaseName, TableName) Then Exit;
  Table := TTable.Create(nil);
  Try
    Try
      Table.Active       := False;
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active       := True;
      FieldIndex         := FieldNo;
      Try
        FieldType          :=
          Table.FieldDefs[FieldIndex].DataType;
      Except
        FieldType        := ftUnknown;
      End;
      {TFieldType Possible values are
      ftUnknown, ftString, ftSmallint,
      ftInteger, ftWord, ftBoolean,
      ftFloat, ftCurrency, ftBCD, ftDate,
      ftTime, ftDateTime, ftBytes, ftVarBytes,
      ftBlob, ftMemo or ftGraphic}
      If FieldType=ftUnknown  Then Result := 'Unknown';
      If FieldType=ftString   Then Result := 'String';
      If FieldType=ftSmallInt Then Result := 'SmallInt';
      If FieldType=ftInteger  Then Result := 'Integer';
      If FieldType=ftWord     Then Result := 'Word';
      If FieldType=ftBoolean  Then Result := 'Boolean';
      If FieldType=ftFloat    Then Result := 'Float';
      If FieldType=ftCurrency Then Result := 'Currency';
      If FieldType=ftBCD      Then Result := 'BCD';
      If FieldType=ftDate     Then Result := 'Date';
      If FieldType=ftTime     Then Result := 'Time';
      If FieldType=ftDateTime Then Result := 'DateTime';
      If FieldType=ftBytes    Then Result := 'Bytes';
      If FieldType=ftVarBytes Then Result := 'VarBytes';
      If FieldType=ftBlob     Then Result := 'Blob';
      If FieldType=ftMemo     Then Result := 'Memo';
      If FieldType=ftGraphic  Then Result := 'Graphic';
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
DBGlobalStringFieldChange

Replace all the values in a field that match a
condition value with a new value}
//
Unit Description UnitIndex Master Index
procedure DBGlobalStringFieldChange(
  const DatabaseName,
  TableName,
  FieldName,
  NewValue : string);
begin
  DBGlobalStringFieldChangeWhere(
    DatabaseName,
    TableName,
    FieldName,
    '',
    NewValue);
End;

{!~
DBGlobalStringFieldChangeWhere

Replace all the values in a field with a new value}
//
Unit Description UnitIndex Master Index
procedure DBGlobalStringFieldChangeWhere(
  const DatabaseName,
  TableName,
  FieldName,
  CurrentValue,
  NewValue : string);
var
  Query : TQuery;
begin
  Query := TQuery.Create(nil);
  Try
    Query.Active       := False;
    Query.DatabaseName := DatabaseName;
    Query.RequestLive  := True;
    Query.RequestLive  := True;
    Query.Sql.Clear;
    Query.Sql.Add('UpDate');
    Query.Sql.Add('"'+TableName+'"');
    Query.Sql.Add('Set');
    Query.Sql.Add(
      '"'+TableName+'"."'+FieldName+'"'+
      ' = '+
      '"'+NewValue+'"');
    Query.Sql.Add('Where');
    Query.Sql.Add(
      '"'+TableName+'"."'+FieldName+'"'+
      ' <> '+
      '"'+NewValue+'"');
    If Not (CurrentValue = '') Then
    Begin
      Query.Sql.Add('And ');
      Query.Sql.Add(
        '"'+TableName+'"."'+FieldName+'"'+
        ' = '+
        '"'+CurrentValue+'"');
    End;
    Query.ExecSql;
    Query.Active := False;
  Finally
    Query.Free;
  End;
End;

{!~
DBGlobalStringFieldChangeWhere2

Replace values in a field (NewValueField) with NewValue
based on a where condition in CurrentValueField with a value
of CurrentValue}
//
Unit Description UnitIndex Master Index
procedure DBGlobalStringFieldChangeWhere2(
  const DatabaseName,
  TableName,
  NewValueField,
  NewValue,
  CurrentValueField,
  CurrentValue: string);
var
  Query        : TQuery;
  CValueQuoted : String;
begin
  Query := TQuery.Create(nil);
  Try
    CValueQuoted := DBSqlValueQuoted(
                      DatabaseName,
                      TableName,
                      CurrentValueField,
                      CurrentValue);
    Query.Active       := False;
    Query.DatabaseName := DatabaseName;
    Query.RequestLive  := True;
    Query.RequestLive  := True;
    Query.Sql.Clear;
    Query.Sql.Add('UpDate');
    Query.Sql.Add('"'+TableName+'"');
    Query.Sql.Add('Set');
    Query.Sql.Add(
      '"'+TableName+'"."'+NewValueField+'"'+
      ' = '+
      '"'+NewValue+'"');
    If Not (CurrentValue = '') Then
    Begin
      Query.Sql.Add('Where');
      Query.Sql.Add(
        '"'+TableName+'"."'+CurrentValueField+'"'+
        ' = '+
        CValueQuoted);
    End;
    {Query.Sql.SaveToFile(ExtractFileNameNoExt(TableName)+'.sql');}
    Query.ExecSql;
    Query.Active := False;
  Finally
    Query.Free;
  End;
End;

{!~
DBInsertMatchingFields

Inserts matching fields in a destination table.
Source Table records are deleted if the record was inserted properly.
Records unsuccessfully inserted are retained and the problems recorded
in the ErrorField.}
//
Unit Description UnitIndex Master Index
Function DBInsertMatchingFields(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable,
           ErrorField: string): Boolean;
Var
  S              : TTable;
  T              : TTable;
  D              : TQuery;
  i,j,K          : Integer;
  Keys           : TStringList;
  KeyValues      : TStringList;
  CommonFields   : TStringList;
  {WhereAnd       : String;}{zzz}
  {CurField       : String;}{zzz}
 {CurValue_S     : String;}{zzz}
  {DFieldType     : String;}{zzz}
  EMessage       : String;
  ESuccess       : String;
Begin
  Result       := False;
  ESuccess     := 'Successful';
  S            := TTable.Create(nil);
  D            := TQuery.Create(nil);
  T            := TTable.Create(nil);
  Keys         := TStringList.Create();
  CommonFields := TStringList.Create();
  KeyValues    := TStringList.Create();
  Try
    Try
      D.Active       := False;
      D.DatabaseName := DestDatabaseName;

      DBKeyFieldNamesToTStrings(
        SourceDatabaseName,
        SourceTable,
        Keys);
      DBFieldNamesCommonToTStrings(
        SourceDatabaseName,
        SourceTable,
        DestDatabaseName,
        DestinationTable,
        CommonFields);

      S.Active := False;
      S.DatabaseName := SourceDatabaseName;
      S.TableName    := SourceTable;
      S.Active       := True;
      S.First;
      While Not S.EOF Do
      Begin
        Try

          {Capture the key field values}
          KeyValues.Clear;
          For j := 0 To Keys.Count - 1 Do
          Begin
            KeyValues.Add(S.FieldByName(Keys[j]).AsString);
          End;

          If IsRecord(
               DestDatabaseName,
               DestinationTable,
               Keys,
               KeyValues)
          Then
          Begin
            {The record already exists in the destination table}
            Try
              S.Edit;
              S.FieldByName(ErrorField).AsString :=
                'Error-Insert-Record already exists in destination table';
              S.Post;
            Except
            End;
            S.Next;
            Continue;
          End
          Else
          Begin
            {The record does not exist in the destination table}
            Try
              EMessage := ESuccess;
              S.Edit;
              S.FieldByName(ErrorField).AsString := EMessage;
              S.Post;
            Except
            End;
          End;
          Try
            T.Active       := False;
            T.DatabaseName := DestDatabaseName;
            T.TableName    := DestinationTable;
            T.Active       := True;
            T.Insert;
            For i := 0 To CommonFields.Count - 1 Do
            Begin
              T.FieldByName(CommonFields[i]).AsString :=
                S.FieldByName(CommonFields[i]).AsString;
            End;
            T.Post;
          Except
            If EMessage = ESuccess Then
            Begin
              EMessage := 'Error-Insert- Keys:';
              For K := 0 To Keys.Count -1 Do
              Begin
                EMessage := EMessage + Keys[K]+'='+S.FieldByName(Keys[K]).AsString+', ';
              End;
            End;
            Try
              S.Edit;
              S.FieldByName(ErrorField).AsString := EMessage;
              S.Post;
            Except
            End;
          End;
        Except
          If EMessage = ESuccess Then
          Begin
            EMessage := 'Error-Insert- Keys:';
            For K := 0 To Keys.Count -1 Do
            Begin
              EMessage := EMessage + Keys[K]+'='+S.FieldByName(Keys[K]).AsString+', ';
            End;
          End;
          Try
            S.Edit;
            S.FieldByName(ErrorField).AsString := EMessage;
            S.Post;
          Except
          End;
        End;
        S.Next;
      End;
      If Not IsField(SourceDatabaseName, SourceTable, ErrorField) Then
      Begin
        ShowMessage('Cannot delete records from '+
          SourceTable+' table because '+ErrorField+
          ' Field does not exist');
      End
      Else
      Begin
        D.Active       := False;
        D.RequestLive  := True;
        D.DatabaseName := SourceDatabaseName;
        D.Sql.Clear;
        D.Sql.Add('Delete From '+SourceTable);
        D.Sql.Add('Where');
        D.Sql.Add(ErrorField+' = "'+ESuccess+'"');
        D.ExecSql;
        D.Active := False;
      End;
      Result := True;
    Except
      If EMessage = ESuccess Then
      Begin
        EMessage := 'Error-Process Level- Keys:';
        For K := 0 To Keys.Count -1 Do
        Begin
          EMessage := EMessage + Keys[K]+'='+S.FieldByName(Keys[K]).AsString+', ';
        End;
      End
      Else
      Begin
        EMessage := EMessage + 'Process Error Also';
      End;
      Try
        S.Edit;
        S.FieldByName(ErrorField).AsString := EMessage;
        S.Post;
      Except
      End;
    End;
  Finally
    S.Free;
    D.Free;
    T.Free;
    Keys.Free;
    CommonFields.Free;
    KeyValues.Free;
  End;
End;

{!~
DBKeyFieldNamesToTStrings

Copies Table Key Field Names to a TStrings object.
Returns the true if successful.  If there
is an error, the DatabaseName doesn't exist, the table doesn't
exist or some other reason False is returned.  }
//
Unit Description UnitIndex Master Index
Function DBKeyFieldNamesToTStrings(
  DatabaseName : String;
  TableName    : String;
  Strings      : TStrings): Boolean;
Var
  Table      : TTable;
  FieldNo    : Integer;
Begin
  Result := False;
  If Not IsTable(DatabaseName, TableName) Then Exit;
  Table := TTable.Create(nil);
  Try
    Try
      Table.Active       := False;
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active       := True;
      Strings.Clear;
      For FieldNo := 0 To Table.FieldDefs.Count -1 Do
      Begin
        If IsFieldKeyed(
             DatabaseName,
             TableName,
             Table.FieldDefs[FieldNo].Name) Then
        Begin
          Strings.Add(Table.FieldDefs[FieldNo].Name);
        End;
      End;
      Result := True;
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
DBLookUpDialog

Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
//
Unit Description UnitIndex Master Index
Function DBLookUpDialog(
  Const DataBaseName  : String;
  Const TableName     : String;
  Const FieldName     : String;
  Const SessionName   : String;
  Const DefaultValue  : String;
  const DialogCaption : string;
  const InputPrompt   : string;
  const DialogWidth   : Integer
  ): String;
Begin
  Result :=
    DialogDBLookUp(
      DataBaseName,
      TableName,
      FieldName,
      SessionName,
      DefaultValue,
      DialogCaption,
      InputPrompt,
      DialogWidth
      );
End;

{!~
DBMedianSingle

Returns the median value for a column in a table
as type single}
//
Unit Description UnitIndex Master Index
Function DBMedianSingle(
      const DatabaseName,
      TableName,
      FieldName,
      WhereString
      : string): Single;
Var
  Query    : TQuery;
  NRecords : LongInt;
  NMedian  : LongInt;
  Value1   : Single;
  Value2   : Single;
Begin
  Query := TQuery.Create(nil);
  Try
    {Get the number of values}
    Query.Active := False;
    Query.DatabaseName := DatabaseName;
    Query.SQL.Clear;
    Query.SQL.Add('Select Count(*)');
    Query.SQL.Add('From');
    If (Pos('.DB', UpperCase(TableName)) > 0) Or
       (Pos('.DBF',UpperCase(TableName)) > 0) Then
    Begin
      Query.Sql.Add('"'+TableName+'"');
    End
    Else
    Begin
      Query.Sql.Add(TableName);
    End;
    Query.SQL.Add('Where');
    Query.SQL.Add(FieldName+' is not null');
    If Not (WhereString = '') Then
    Begin
      Query.SQL.Add('And');
      Query.SQL.Add(WhereString);
    End;
    Query.Active := True;
    NRecords := Query.Fields[0].AsInteger;
    NMedian  := NRecords div 2;

    {Get the median value}
    Query.Active := False;
    Query.DatabaseName := DatabaseName;
    Query.SQL.Clear;
    Query.SQL.Add('Select');
    Query.SQL.Add(FieldName);
    Query.SQL.Add('From');
    If (Pos('.DB', UpperCase(TableName)) > 0) Or
       (Pos('.DBF',UpperCase(TableName)) > 0) Then
    Begin
      Query.Sql.Add('"'+TableName+'"');
    End
    Else
    Begin
      Query.Sql.Add(TableName);
    End;
    Query.SQL.Add('Where');
    Query.SQL.Add(FieldName+' is not null');
    If Not (WhereString = '') Then
    Begin
      Query.SQL.Add('And');
      Query.SQL.Add(WhereString);
    End;
    Query.SQL.Add('Order By');
    Query.SQL.Add(FieldName);
    Query.Active := True;
    Query.First;

    If Odd(NRecords) Then
    Begin
      {Odd Number of records}
      Query.MoveBy(NMedian);
      Result := Query.FieldByName(FieldName).AsFloat;
    End
    Else
    Begin
      {Even Number of records}
      Query.MoveBy(NMedian-1);
      Value1 := Query.FieldByName(FieldName).AsFloat;
      Query.Next;
      Value2 := Query.FieldByName(FieldName).AsFloat;
      Result := (Value1+Value2)/2;
    End;
  Finally
    Query.Free;
  End;
End;

{!~
DBMoveTable

Moves SourceTable From SourceDatabaseName
 To DestDatabasename.  If a table exists
 with the same name at DestDatabaseName it
 is overwritten.}
//
Unit Description UnitIndex Master Index
Function DBMoveTable(
            SourceTable,
            SourceDatabaseName,
            DestDatabaseName: String): Boolean;
Begin
  Result := True;
  Try
    {First Copy The Source Table To The New Table}
    If Not DBCopyTable(
             SourceDatabaseName,
             SourceTable,
             DestDatabaseName,
             SourceTable) Then
    Begin
      Result := False;
      Exit;
    End;

    {Now Drop The Source Table}
    If Not DBDropTable(SourceDatabaseName, SourceTable) Then
    Begin
      Result := False;
      Exit;
    End;
  Except
    Result := False;
  End;
End;

{!~
DBNFields

Returns the number of fields in a table}
//
Unit Description UnitIndex Master Index
Function DBNFields(DatabaseName, TableName: String): Integer;
Begin
  Result := NFields(DatabaseName, TableName);
End;

{!~
DBNextAlphaKey

Returns the next key value when the table keys are
numbers as strings, e.g., '   12' key would return
'   13'}
//
Unit Description UnitIndex Master Index
Function DBNextAlphaKey(DatabaseName, TableName, FieldName: String):String;
Var
  Query : TQuery;
  CurrentMax_S : String;
  CurrentLen_I : Integer;
  CurrentMax_I : LongInt;
  NewMax_S     : String;
  NewMax_I     : LongInt;
  Counter      : Integer;
Begin
  Result := '';
  Query := TQuery.Create(nil);
  Try
    Result       := '1';
    CurrentMax_S := '';
    CurrentMax_I := 0;
    CurrentLen_I := 0;
    NewMax_S     := '1';
    Query.DatabaseName := DatabaseName;
    Query.SQL.Clear;
    Query.SQL.Add('Select ');
    Query.SQL.Add('Max('+FieldName+')');
    Query.SQL.Add('From '+TableName);
    Query.Open;
    Try
      CurrentMax_S := Query.Fields[0].AsString;
    Except
    End;
    Try
      CurrentLen_I := Length(CurrentMax_S);
    Except
    End;
    Try
      CurrentMax_I := StrToInt(CurrentMax_S);
    Except
    End;
    NewMax_I := CurrentMax_I + 1;
    NewMax_S := IntToStr(NewMax_I);
    For Counter := 1 To CurrentLen_I Do
    Begin
      If Length(NewMax_S) >= CurrentLen_I Then Break;
      NewMax_S := ' '+NewMax_S;
    End;
    Result := NewMax_S;
  Finally
    Query.Free;
  End;
End;

{!~
DBNextInteger

Returns the next key value when the table keys are
integers, e.g., 12 key would return 13}
//
Unit Description UnitIndex Master Index
Function DBNextInteger(
  DatabaseName,
  TableName,
  FieldName: String):LongInt;
Var
  Query : TQuery;
  CurrentMax   : LongInt;
  NewMax       : LongInt;
Begin
  CurrentMax   := 0;
  Query := TQuery.Create(nil);
  Try
    Query.DatabaseName := DatabaseName;
    Query.SQL.Clear;
    Query.SQL.Add('Select ');
    Query.SQL.Add('Max('+FieldName+')');
    Query.SQL.Add('From ');
    If (Pos('.DB', UpperCase(TableName)) > 0) Or
       (Pos('.DBF',UpperCase(TableName)) > 0) Then
    Begin
      Query.Sql.Add('"'+TableName+'"');
    End
    Else
    Begin
      Query.Sql.Add(TableName);
    End;
    Query.Open;
    Try
      CurrentMax := Query.Fields[0].AsInteger;
    Except
    End;
    NewMax   := CurrentMax + 1;
    Result   := NewMax;
  Finally
    Query.Free;
  End;
End;

{!~
DBParadoxCreateNKeys

ReKeys a Paradox Table to the first N fields}
//
Unit Description UnitIndex Master Index
Function DBParadoxCreateNKeys(
  DatabaseName : String;
  TableName    : String;
  NKeys        : Integer): Boolean;
Var
  T          : TTable;
  T2         : TTable;
  i          : Integer;
  TempDBName : String;
  TempTblNam : String;
  TempTblStub: String;
  KeysString : String;
Begin
  Result := False;
  {Select a temporary table name}
  TempTblStub := 'qrz';
  TempDBName  := DatabaseName;
  TempTblNam  := '';
  For i := 1 To 100 Do
  Begin
    TempTblNam := TempTblStub+StringPad(IntToStr(i),'0',3,False)+'.Db';
    If Not IsTable(TempDBName,TempTblNam) Then
    Begin
      Break;
    End
    Else
    Begin
      If i = 100 Then
      Begin
        DBDeleteTable(
          TempDBName,
          TempTblNam);
      End;
    End;
  End;
  T  := TTable.Create(nil);
  T2 := TTable.Create(nil);
  Try
    Try
      T.Active       := False;
      T.DatabaseName := DatabaseName;
      T.TableName    := TableName;
      T.Active       := True;

      T2.Active       := False;
      T2.DatabaseName := TempDBName;
      T2.TableName    := TempTblNam;
      T2.FieldDefs.Assign(T.FieldDefs);
      T2.IndexDefs.Clear;
      KeysString := '';

      For i := 0 To NKeys - 1 Do
      Begin
        If i > 0 Then
        Begin
          KeysString := KeysString + ';';
        End;
        KeysString :=
          KeysString +
          DBFieldNameByNo(
            DatabaseName,
            TableName,
            i);
      End;
      T2.IndexDefs.Add('',KeysString,[ixPrimary]);
      T2.CreateTable;
      T2.Active := False;
      T.Active        := False;
      AddTables(
        DatabaseName,
        TableName,
        TempDBName,
        TempTblNam);
      DBDeleteTable(DatabaseName,TableName);
      T2.Active      := True;
      T.DatabaseName := DatabaseName;
      T.TableName    := TableName;
      T.FieldDefs.Assign(T2.FieldDefs);
      T.IndexDefs.Clear;
      T.IndexDefs.Add('',KeysString,[ixPrimary]);
      T.CreateTable;
      T2.Active      := False;
      T.Active       := False;
      AddTables(
        TempDBName,
        TempTblNam,
        DatabaseName,
        TableName);
      DBDeleteTable(
        TempDBName,
        TempTblNam);
      Result := True;
    Except
      ShowMessage('Error in Function DBParadoxCreateNKeys');
    End;
  Finally
    T.Free;
    T2.Free;
  End;
End;

{!~
DBReNameTable

ReNames a table}
//
Unit Description UnitIndex Master Index
Function DBReNameTable(
  DatabaseName,
  TableNameOld,
  TableNameNew: String): Boolean;
Begin
  Result := True;
  Try
    If Not IsTable(DatabaseName, TableNameOld) Then
    Begin
      Result := False;
      Exit;
    End;

    {First Copy The Source Table To The New Table}
    If Not DBCopyTable(
             DatabaseName,
             TableNameOld,
             DatabaseName,
             TableNameNew) Then
    Begin
      Result := False;
      Exit;
    End;

    {Now Drop The Source Table}
    If Not DBDropTable(DatabaseName, TableNameOld) Then
    Begin
      Result := False;
      Exit;
    End;
  Except
    Result := False;
  End;
End;

{!~
DBRecordMove

Applies BatchMode Types As Appropriate To
Source and Destination Tables}
//
Unit Description UnitIndex Master Index
Function DBRecordMove(
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestTable: String;
           BMode: TBatchMode): Boolean;
var S : TTable;
    D : TTable;
    B : TBatchMove;
begin
  S := TTable.Create(nil);
  D := TTable.Create(nil);
  B := TBatchMove.Create(nil);
  try
    {Create The Source Table}
    S.Active       := False;
    S.DatabaseName := SourceDatabaseName;
    S.ReadOnly     := False;
    S.TableName    := SourceTable;
    S.Active := true;

    {Create The Destination Table}
    D.Active       := False;
    D.DatabaseName := DestDatabaseName;
    D.TableName    := DestTable;
    D.ReadOnly     := False;

    {Make the table copy}
    B.AbortOnKeyViol := False;
    B.AbortOnProblem := False;
    B.Destination    := D;
    B.Source         := S;
    B.Mode           := BMode;
    Try
      B.Execute;
    Except
    End;

    Result := True;
  finally
    S.Free;
    D.Free;
    B.Free;
  end;
End;

{!~
DBSchemaSame

Returns True If The Tables Have Identical Structures, False Otherwise.
If 1 Local Table is involved then Indices are ignored!!!!!!}
//
Unit Description UnitIndex Master Index
Function DBSchemaSame(const
           DatabaseName1,
           Table1,
           DatabaseName2,
           Table2: string): Boolean;
Begin
  Result := IsStructureSame(DatabaseName1,Table1,DatabaseName2,Table2);
End;

{!~
DBSessionCreateNew

Creates a new TSession object.}
{$IFDEF WIN32}
//
Unit Description UnitIndex Master Index
Function DBSessionCreateNew: TSession;
{$ENDIF WIN32}
{$IFDEF WIN32}
Var
  List : TStringList;
  Seed : String;
  i    : Integer;
  Ses  : String;
Begin
  Seed := 'Session';
  Ses  := Seed+'0';
  List := TStringList.Create;
  Try
    Sessions.GetSessionNames(List);
    For i := 0 To 1000 Do
    Begin
      Ses := Seed + IntToStr(i);
      If List.IndexOf(Ses) = -1 Then Break;
    End;
    Result := Sessions.OpenSession(Ses);
  Finally
    List.Free;
  End;
End;
{$ENDIF}

{!~
DBSqlValueQuoted

Returns a value for use in a sql where clause with the
appropriate Quoting of the value based on its datatype.  If
an error occurs the original string value is returned unchanged}
//
Unit Description UnitIndex Master Index
Function DBSqlValueQuoted(
  const
  DatabaseName,
  TableName,
  FieldName,
  FieldValue: string): String;
Var
  DataType : String;
Begin
  Result := FieldValue;
  Try
    DataType := DBFieldType(DatabaseName, TableName, FieldName);
    If
      (DataType = 'String')
      Or
      (DataType = 'DateTime')
      Or
      (DataType = 'Date')
      Or
      (DataType = 'Time')
    Then
    Begin
      If DataType <> 'String' Then
      Begin
        If FieldValue = '' Then
        Begin
          Result := ' null ';
        End
        Else
        Begin
          Result := '"'+FieldValue+'"';
        End;
      End
      Else
      Begin
        Result := '"'+FieldValue+'"';
      End;
    End
    Else
    Begin
      Result := FieldValue;
    End;
  Except
  End;
End;

{!~
DBSubtractTable

Subtracts the records in the source
 table from the destination table}
//
Unit Description UnitIndex Master Index
Function DBSubtractTable(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;
Begin
  Result := SubtractTable(SourceDatabaseName,SourceTable,
                      DestDatabaseName,DestinationTable);
End;

{!~
DBTrimBlanksLeft

Trims blank spaces from the Left of the string}
//
Unit Description UnitIndex Master Index
Function DBTrimBlanksLeft(
  DatabaseName : String;
  TableName    : String;
  FieldName    : String): Boolean;
Var
  Q : TQuery;
  S : String;
Begin
{  Result := False;}{zzz}
  Q := TQuery.Create(nil);
  Try
    Q.Active       := False;
    Q.DatabaseName := DatabaseName;
    Q.RequestLive  := True;
    Q.Sql.Clear;
    Q.Sql.Add('Select');
    Q.Sql.Add('*');
    Q.Sql.Add('From');
    Q.Sql.Add('"'+TableName+'"');
    Q.Active := True;
    Q.First;
    While Not Q.EOF Do
    Begin
      S := Q.FieldByName(FieldName).AsString;
      S := TrimBlanksLeft(S);
      S := TrimBlanksLeft(S);
      Q.Edit;
      Q.FieldByName(FieldName).AsString := S;
      Q.Post;
      Q.Next;
    End;
    Result := True;
  Finally
    Q.Free;
  End;
End;

{!~
DBTrimBlanksRight

Trims blank spaces from the right of the string}
//
Unit Description UnitIndex Master Index
Function DBTrimBlanksRight(
  DatabaseName : String;
  TableName    : String;
  FieldName    : String): Boolean;
Var
  Q : TQuery;
  S : String;
Begin
{  Result := False;}{zzz}
  Q := TQuery.Create(nil);
  Try
    Q.Active       := False;
    Q.DatabaseName := DatabaseName;
    Q.RequestLive  := True;
    Q.Sql.Clear;
    Q.Sql.Add('Select');
    Q.Sql.Add('*');
    Q.Sql.Add('From');
    Q.Sql.Add('"'+TableName+'"');
    Q.Active := True;
    Q.First;
    While Not Q.EOF Do
    Begin
      S := Q.FieldByName(FieldName).AsString;
      S := TrimBlanksRight(S);
      S := TrimBlanksRight(S);
      Q.Edit;
      Q.FieldByName(FieldName).AsString := S;
      Q.Post;
      Q.Next;
    End;
    Result := True;
  Finally
    Q.Free;
  End;
End;

{!~
DBUpdateMatchingFields

Updates matching fields in a destination table.
Source Table records are deleted if the record was updated properly.
Records unsuccessfully updated are retained and the problems recorded
in the ErrorField.}
//
Unit Description UnitIndex Master Index
Function DBUpdateMatchingFields(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable,
           ErrorField: string;
           MsgPanel: TPanel;
           FilePath: String): Boolean;
Var
  S              : TTable;
  D              : TQuery;
  U              : TQuery;
  i,j,K,m        : Integer;

  Keys           : TStringList;
  KeysType       : TStringList;
  KeysQuotes     : TStringList;
  KeysSpaces     : TStringList;
  KeysWhere1     : TStringList;
  KeysUpdate1    : TStringList;
  KeysWhere2     : TStringList;
  KeyWhere1      : String;
  KeyWhere2      : String;
  KeyUpdate1     : String;
  NonKeys        : TStringList;
  NonKeysType    : TStringList;
  NonKeysQuotes  : TStringList;
  NonKeysSpaces  : TStringList;
  NonKeysStr     : TStringList;

  NonKeysString  : String;

  CommonFields   : TStringList;

  UpdateString   : String;
  WhereAnd       : String;
  CurField       : String;
  CurValue_S     : String;
  CurString      : String;
  CurStrings     : String;
  DFieldType     : String;
  EMessage       : String;
  ESuccess       : String;
  DFromString    : String;
  TimeLog        : TStringList;
  SetString      : String;
Begin
  ESuccess     := 'Successful';
  S            := TTable.Create(nil);
  D            := TQuery.Create(nil);
  U            := TQuery.Create(nil);
  Keys         := TStringList.Create();
  KeysSpaces   := TStringList.Create();
  KeysType     := TStringList.Create();
  KeysQuotes   := TStringList.Create();
  TimeLog      := TStringList.Create();
  CommonFields := TStringList.Create();
  NonKeys      := TStringList.Create();
  NonKeysQuotes:= TStringList.Create();
  NonKeysType  := TStringList.Create();
  NonKeysSpaces:= TStringList.Create();
  NonKeysStr   := TStringList.Create();
  KeysWhere1   := TStringList.Create();
  KeysUpdate1  := TStringList.Create();
  KeysWhere2   := TStringList.Create();
  NonKeysString:= '';
  SetString    := 'Set ';
  TimeLog.Clear;
  Try
    Try
      DBFieldNamesCommonToTStrings(
        SourceDatabaseName,
        SourceTable,
        DestDatabaseName,
        DestinationTable,
        CommonFields);
      For i := 0 To CommonFields.Count - 1 Do
      Begin
        CommonFields[i] := UpperCase(CommonFields[i]);
      End;
      D.Active       := False;
      D.DatabaseName := DestDatabaseName;
      U.Active       := False;
      U.DatabaseName := DestDatabaseName;
      UpdateString   := 'Update ';
      If Pos('.DB',UpperCase(DestinationTable)) > 0 Then
      Begin
        UpdateString := UpDateString + '"'+DestinationTable+'"';
      End
      Else
      Begin
        UpdateString := UpDateString + DestinationTable + '';
      End;
      DBKeyFieldNamesToTStrings(SourceDatabaseName,SourceTable,Keys);
      KeysSpaces.Clear;
      KeysType.Clear;
      KeysQuotes.Clear;
      For i := 0 To Keys.Count - 1 Do
      Begin
        Keys[i] := UpperCase(Keys[i]);
        If Pos(' ',Keys[i]) > 0 Then
        Begin
          KeysSpaces.Add('YES');
        End
        Else
        Begin
          KeysSpaces.Add('NO');
        End;
        DFieldType :=
          DBFieldType(
            SourceDatabaseName,
            SourceTable,
            Keys[i]);
        KeysType.Add(DFieldType);
        If
          (DFieldType = 'String')
          Or
          (DFieldType = 'DateTime')
          Or
          (DFieldType = 'Date')
          Or
          (DFieldType = 'Time')
        Then
        Begin
          KeysQuotes.Add('YES');
        End
        Else
        Begin
          KeysQuotes.Add('NO');
        End;
      End;
      NonKeys.Clear;
      NonKeysQuotes.Clear;
      NonKeysType.Clear;
      NonKeysSpaces.Clear;
      For i := 0 To CommonFields.Count - 1 Do
      Begin
        If Keys.IndexOf(CommonFields[i]) = -1 Then
        Begin
          NonKeys.Add(CommonFields[i]);
          DFieldType :=
            DBFieldType(
              SourceDatabaseName,
              SourceTable,
              CommonFields[i]);
          NonKeysType.Add(DFieldType);
          If
            (DFieldType = 'String')
            Or
            (DFieldType = 'DateTime')
            Or
            (DFieldType = 'Date')
            Or
            (DFieldType = 'Time')
          Then
          Begin
            NonKeysQuotes.Add('YES');
          End
          Else
          Begin
            NonKeysQuotes.Add('NO');
          End;
          If Pos(' ',CommonFields[i]) > 0 Then
          Begin
            NonKeysSpaces.Add('YES');
            NonKeysStr.Add('"'+CommonFields[i]+'"');
          End
          Else
          Begin
            NonKeysSpaces.Add('NO');
            NonKeysStr.Add(CommonFields[i]);
          End;
        End;
      End;
      S.Active := False;
      S.DatabaseName := SourceDatabaseName;
      S.TableName    := SourceTable;
      S.Active       := True;
      S.First;
      m := 0;

      NonKeysString := '';
      For i := 0 To NonKeysStr.Count - 1 Do
      Begin
        If i = (NonKeysStr.Count - 1) Then
        Begin
          NonKeysString := NonKeysString + 'a.'+NonKeysStr[i]+'' + ' ';
        End
        Else
        Begin
          NonKeysString := NonKeysString + 'a.'+NonKeysStr[i]+',' + ' ';
        End;
      End;
      DFromString := 'From ';
      If Pos('.DB',UpperCase(DestinationTable)) > 0 Then
      Begin
        DFromString := DFromString + '"'+DestinationTable+'" a';
      End
      Else
      Begin
        DFromString := DFromString + DestinationTable + ' a';
      End;
      WhereAnd := '';
      KeysWhere1.Clear;
      KeysWhere2.Clear;
      KeysUpdate1.Clear;
      For j := 0 To Keys.Count -1 Do
      Begin
        KeyWhere1 := '';
        KeyWhere2 := '';
        KeyUpdate1:= '';
        If WhereAnd <> '' Then KeyWhere1 := KeyWhere1 + WhereAnd;
        KeyWhere1 := KeyWhere1  + '(';
        KeyUpdate1:= KeyUpdate1 + '(';
        If KeysSpaces[j] = 'YES' Then
        Begin
          KeyWhere1  := KeyWhere1  + 'a."'+Keys[j]+'" = ';
          KeyUpdate1 := KeyUpdate1 +   '"'+Keys[j]+'" = ';
        End
        Else
        Begin
          KeyWhere1  := KeyWhere1  + 'a.'+Keys[j]+' = ';
          KeyUpdate1 := KeyUpdate1 +      Keys[j]+' = ';
        End;
        If KeysQuotes[j] = 'YES' Then
        Begin
          If KeysType[j] <> 'String' Then
          Begin
            {Do not add quotes here, wait till later}
          End
          Else
          Begin
            KeyWhere1 := KeyWhere1 +'"';
            KeyWhere2 := KeyWhere2 +'"';
            KeyUpdate1:= KeyUpdate1+'"';
          End;
        End
        Else
        Begin
          KeyWhere1 := KeyWhere1 +'';
          KeyWhere2 := KeyWhere2 +'';
          KeyUpdate1:= KeyUpdate1+'';
        End;
        KeyWhere2 := KeyWhere2 +')';
        KeysWhere1.Add(KeyWhere1);
        KeysWhere2.Add(KeyWhere2);
        KeysUpdate1.Add(KeyUpdate1);
        WhereAnd := 'And ';
      End;

      U.Sql.Clear;
      U.Sql.Add(UpdateString);
      U.Sql.Add('Temporary SetString');
      U.Sql.Add(DFromString);
      U.Sql.Add('Where');
      U.Sql.Add('Temporary Where String');

      While Not S.EOF Do
      Begin
        Try
          Inc(m);
          MsgPanel.Caption :=
            'Record '+
            StringPad(
              IntToStr(m),
              ' ',
              6,
              False);
          MsgPanel.Refresh;
          Try
            D.Active       := False;
            D.DatabaseName := DestDatabaseName;
            D.RequestLive  := False;
            D.Sql.Clear;
            D.Sql.Add('Select');
            D.Sql.Add(NonKeysString);
            D.Sql.Add(DFromString);
            D.Sql.Add('Where');

            For j := 0 To Keys.Count -1 Do
            Begin
              CurValue_S := S.FieldByName(Keys[j]).AsString;
              If (KeysQuotes[j] = 'YES') And (KeysType[j] <> 'String') Then
              Begin
                If CurValue_S = '' Then
                Begin
                  D.Sql.Add(
                    KeysWhere1[j]  +
                    ' null '       +
                    KeysWhere2[j]);
                End
                Else
                Begin
                  D.Sql.Add(
                    KeysWhere1[j]                   +
                    '"'                             +
                    CurValue_S                      +
                    '"'                             +
                    KeysWhere2[j]);
                End;
              End
              Else
              Begin
                D.Sql.Add(
                  KeysWhere1[j]                   +
                  CurValue_S                      +
                  KeysWhere2[j]);
              End;
            End;
            D.Active       := True;
            If Not (D.EOF And D.BOF) Then
            Begin
              EMessage := ESuccess;
              S.Edit;
              S.FieldByName(ErrorField).AsString := EMessage;
              S.Post;
            End
            Else
            Begin
              S.Edit;
              S.FieldByName(ErrorField).AsString := 'No Matching Record';
              S.Post;
              S.Next;
              Continue;
            End;
          Except
          End;
          U.Sql.Clear;
          U.Sql.Add(UpdateString);
          U.Sql.Add('Set');
          For i := 0 To NonKeys.Count - 1 Do
          Begin
            CurField        := NonKeys[i];
            Try
              With U Do
              Begin
                Active := False;
                SetString := CurField+' = ';
                CurValue_S := '';
                If NonKeysType[i] = 'Float' Then
                Begin
                  CurValue_S :=
                    FormatFloat(
                      '#0.0000000000',
                      S.FieldByName(CurField).AsFloat);
                End
                Else
                Begin
                  CurValue_S := S.FieldByName(CurField).AsString;
                End;
                If NonKeysQuotes[i] = 'YES' Then
                Begin
                  If NonKeysType[i] <> 'String' Then Begin
                    If CurValue_S = '' Then Begin
                      SetString := SetString + ' null ';
                    End Else Begin
                      SetString := SetString + '"'+CurValue_S+'"';
                    End;
                  End Else Begin
                    SetString := SetString + '"'+CurValue_S+'"';
                  End;
                End Else Begin
                  SetString := SetString + CurValue_S;
                End;
                SetString := SetString;
                If i <> (NonKeys.Count - 1) Then
                  SetString := SetString+',';
                Sql.Add(SetString);
              End;
            Except
              On E : Exception Do
              Begin
                If EMessage = ESuccess Then
                Begin
                  EMessage := 'Error-Field Level- Keys:';
                  For K := 0 To Keys.Count -1 Do
                  Begin
                    EMessage := EMessage + Keys[K]+'='+S.FieldByName(Keys[K]).AsString+', ';
                  End;
                  EMessage := EMessage + 'FIELDS: ';
                End;
                EMessage := {EMessage +} CurField+', ';
                EMessage := EMessage + E.Message;
                Try
                  S.Edit;
                  S.FieldByName(ErrorField).AsString := EMessage;
                  S.Post;
                Except
                End;
              End;
            End;
          End;

          CurStrings := '';
          WhereAnd := '';
          For j := 0 To Keys.Count -1 Do
          Begin
            CurStrings := CurStrings + WhereAnd;
            CurValue_S := S.FieldByName(Keys[j]).AsString;
            If (KeysQuotes[j] = 'YES') And (KeysType[j] <> 'String') Then
            Begin
              If CurValue_S = '' Then Begin
                CurString := KeysUpdate1[j]+' null '+KeysWhere2[j];
              End Else Begin
                CurString :=KeysUpdate1[j]+'"'+CurValue_S+'"'+KeysWhere2[j];
              End;
            End Else Begin
              CurString := KeysUpdate1[j]+CurValue_S+KeysWhere2[j];
            End;
            CurStrings := CurStrings + CurString + ' ';
            WhereAnd := ' And ';
          End;
          U.Sql.Add('Where');
          U.Sql.Add(CurStrings);
          U.ExecSql;
          U.Active := False;
        Except
          On E : Exception Do
          Begin
            Try
              S.Edit;
              S.FieldByName(ErrorField).AsString := E.Message;
              S.Post;
            Except
            End;
          End;
        End;
        S.Next;
      End;
      Try
        D.Active       := False;
        D.RequestLive  := True;
        D.DatabaseName := SourceDatabaseName;
        D.Sql.Clear;
        D.Sql.Add('Delete From '+SourceTable);
        D.Sql.Add('Where');
        D.Sql.Add(ErrorField+' = "'+ESuccess+'"');
        D.SQL.SaveToFile(FilePath+'Delete.Sql');
        D.ExecSql;
        D.Active := False;
      Except
        If Not IsField(SourceDatabaseName, SourceTable, ErrorField) Then
        Begin
          ShowMessage('Cannot delete records from '+
            SourceTable+' table because '+ErrorField+
            ' Field does not exist');
        End
        Else
        Begin
          ShowMessage('Error deleting source table records!');
        End;
      End;
    Except
      If EMessage = ESuccess Then
      Begin
        EMessage := 'Error-Process Level- Keys:';
        For K := 0 To Keys.Count -1 Do
        Begin
          EMessage := EMessage + Keys[K]+'='+S.FieldByName(Keys[K]).AsString+', ';
        End;
      End
      Else
      Begin
        EMessage := EMessage + 'Process Error Also';
      End;
      Try
        S.Edit;
        S.FieldByName(ErrorField).AsString := EMessage;
        S.Post;
      Except
      End;
    End;
  Finally
    S.Free;
    D.SQL.SaveToFile(FilePath+'Select.Sql');
    D.Free;
    U.SQL.SaveToFile(FilePath+'Update.Sql');
    U.Free;
    Keys.SaveToFile(FilePath+'Keys.Txt');
    Keys.Free;
    TimeLog.Free;
    CommonFields.SaveToFile(FilePath+'CommonFields.Txt');
    CommonFields.Free;
    NonKeys.SaveToFile(FilePath+'NonKeys.Txt');
    NonKeys.Free;
    NonKeysQuotes.SaveToFile(FilePath+'NonKeysQuotes.Txt');
    NonKeysQuotes.Free;
    NonKeysType.SaveToFile(FilePath+'NonKeysType.Txt');
    NonKeysType.Free;
    KeysSpaces.SaveToFile(FilePath+'KeysSpaces.Txt');
    KeysSpaces.Free;
    KeysType.SaveToFile(FilePath+'KeysType.Txt');
    KeysType.Free;
    KeysQuotes.SaveToFile(FilePath+'KeysQuotes.Txt');
    KeysQuotes.Free;
    NonKeysSpaces.SaveToFile(FilePath+'NonKeysSpaces.Txt');
    NonKeysSpaces.Free;
    NonKeysStr.SaveToFile(FilePath+'NonKeysStr.Txt');
    NonKeysStr.Free;
    KeysWhere1.SaveToFile(FilePath+'KeysWhere1.Txt');
    KeysWhere1.Free;
    KeysWhere2.SaveToFile(FilePath+'KeysWhere2.Txt');
    KeysWhere2.Free;
    KeysUpdate1.SaveToFile(FilePath+'KeysUpdate1.Txt');
    KeysUpdate1.Free;
  End;
End;

{!~
DeleteTable

Deletes A Table}
//
Unit Description UnitIndex Master Index
Function DeleteTable(const DatabaseName, TableName : string):Boolean;
Begin
  Result := DBDropTable(DatabaseName, TableName);
End;

{!~
DialogDBLookUp

Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
//
Unit Description UnitIndex Master Index
Function DialogDBLookUp(
  Const DataBaseName  : String;
  Const TableName     : String;
  Const FieldName     : String;
  Const SessionName   : String;
  Const DefaultValue  : String;
  const DialogCaption : string;
  const InputPrompt   : string;
  const DialogWidth   : Integer
  ): String;
Var
  Q      : TQuery;
  Values : TStringlist;
Begin
  Result := '';
  Q      := TQuery.Create(nil);
  Values := TStringlist.Create();
  Try
    Values.Clear;
    Values.Sorted     := True;
    Values.Duplicates := dupIgnore;
    Q.Active := False;
    Q.DatabaseName    := DatabaseName;
{$IFDEF WIN32}
    Q.SessionName     := SessionName;
{$ENDIF}
    Q.Sql.Clear;
    Q.Sql.Add('Select');
    Q.Sql.Add('Distinct');
    If Pos(' ',FieldName) > 0 Then
    Begin
      Q.Sql.Add('a."'+FieldName+'"');
    End
    Else
    Begin
      Q.Sql.Add('a.'+FieldName);
    End;
    Q.Sql.Add('From');
    If Pos('.DB',UpperCase(TableName)) > 0 Then
    Begin
      Q.Sql.Add('"'+TableName+'" a');
    End
    Else
    Begin
      Q.Sql.Add(TableName+' a');
    End;
    Q.Sql.Add('Order By');
    If Pos(' ',FieldName) > 0 Then
    Begin
      Q.Sql.Add('a."'+FieldName+'"');
    End
    Else
    Begin
      Q.Sql.Add('a.'+FieldName);
    End;
    Q.Active := True;
    If Not (Q.EOF And Q.BOF) Then
    Begin
      Q.First;
      While Not Q.EOF Do
      Begin
        Values.Add(Q.FieldByName(FieldName).AsString);
        Q.Next;
      End;
      Result :=
        DialogLookupDetail(
          DialogCaption,
          InputPrompt,
          DefaultValue,
          Values,        //TStringList
          5,             //Spacer Height
          5,             //Button Spacing
          2,             //BevelWidth
          25,            //PromptHeight
          300,           //FormHeight
          DialogWidth,   //FormWidth
          'Close dialog and return selected value.', //Hint_Cancel
          'Close dialog and make no changes.', //Hint_OK
          'Click an item to select it.',  //Hint_ListBox
          True, //ListSorted
          False //AllowDuplicates
          );
    End;
  Finally
    Q.Free;
    Values.Free;
  End;
End;

{!~
DialogLookup

Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
//
Unit Description UnitIndex Master Index
Function DialogLookup(
  const DialogCaption : string;
  const InputPrompt   : string;
  const DefaultValue  : string;
  const Values        : TStringList
  ): string;
Begin
  Result :=
  LookupDialog(
    DialogCaption,
    InputPrompt,
    DefaultValue,
    Values
    );
End;

{!~
DialogLookupDetail

Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
//
Unit Description UnitIndex Master Index
Function DialogLookupDetail(
  Const DialogCaption   : string;
  Const InputPrompt     : string;
  Const DefaultValue    : string;
  Const Values          : TStringList;
  Const ButtonSpacing   : Integer;
  Const SpacerHeight    : Integer;
  Const TopBevelWidth   : Integer;
  Const PromptHeight    : Integer;
  Const FormHeight      : Integer;
  Const FormWidth       : Integer;
  Const Hint_OK         : string;
  Const Hint_Cancel     : string;
  Const Hint_ListBox    : string;
  Const ListSorted      : Boolean;
  Const AllowDuplicates : Boolean
  ): string;
Var
  Form         : TForm;
  Base_Panel   : TPanel;
  Base_Buttons : TPanel;
  Spacer       : TPanel;
  Base_Top     : TPanel;
  ButtonSlider : TPanel;
  ButtonSpacer : TPanel;
  Prompt       : TPanel;
  ListBox      : TListBox;
  ButtonCancelB: TPanel;
  ButtonOKB    : TPanel;
  Button_Cancel: TButton;
  Button_OK    : TButton;
  DefItemIndex : Integer;
  TempValues   : TStringList;
Begin
  Result     := DefaultValue;
  Form       := TForm.Create(Application);
  TempValues := TStringList.Create();
  Try
    TempValues.Sorted := ListSorted;
    TempValues.Clear;
    If AllowDuplicates Then
    Begin
      TempValues.Duplicates := dupAccept;
    End
    Else
    Begin
      TempValues.Duplicates := dupIgnore;
    End;
    If Values <> nil Then
    Begin
      TempValues.Assign(Values);
    End;
    With Form Do
    Begin
      Try
        Canvas.Font  := Font;
        BorderStyle  := bsSizeable;
        Caption      := DialogCaption;
        Height       := FormHeight;
        Width        := FormWidth;
        ShowHint     := True;
        Position     := poScreenCenter;
        BorderIcons  := [biMaximize];
        Base_Panel   := TPanel.Create(Form);
        With Base_Panel Do
        Begin
          Parent      := Form;
          Align       := alClient;
          Caption     := ' ';
          BorderWidth := 10;
          BorderStyle := bsNone;
          BevelOuter  := bvNone;
          BevelInner  := bvNone;
        End;
        Base_Buttons  := TPanel.Create(Form);
        With Base_Buttons Do
        Begin
          Parent      := Base_Panel;
          Align       := alBottom;
          Caption     := ' ';
          BorderWidth := 0;
          BorderStyle := bsNone;
          BevelOuter  := bvNone;
          BevelInner  := bvNone;
          Height      := 27;
        End;
        ButtonSlider  := TPanel.Create(Form);
        With ButtonSlider Do
        Begin
          Parent      := Base_Buttons;
          Align       := alClient;
          Caption     := ' ';
          BorderWidth := 0;
          BorderStyle := bsNone;
          BevelOuter  := bvNone;
          BevelInner  := bvNone;
        End;
        ButtonCancelB  := TPanel.Create(Form);
        With ButtonCancelB Do
        Begin
          Parent      := ButtonSlider;
          Align       := alRight;
          Caption     := ' ';
          BorderWidth := 0;
          BorderStyle := bsNone;
          BevelOuter  := bvNone;
          BevelInner  := bvNone;
          Width       := 75+ButtonSpacing;
        End;

        ButtonSpacer  := TPanel.Create(Form);
        With ButtonSpacer Do
        Begin
          Parent      := ButtonCancelB;
          Align       := alLeft;
          Caption     := ' ';
          BorderWidth := 0;
          BorderStyle := bsNone;
          BevelOuter  := bvNone;
          BevelInner  := bvNone;
          Width       := ButtonSpacing;
        End;

        ButtonOKB  := TPanel.Create(Form);
        With ButtonOKB Do
        Begin
          Parent      := ButtonSlider;
          Align       := alRight;
          Caption     := ' ';
          BorderWidth := 0;
          BorderStyle := bsNone;
          BevelOuter  := bvNone;
          BevelInner  := bvNone;
          Width       := 75;
        End;

        Spacer        := TPanel.Create(Form);
        With Spacer Do
        Begin
          Parent      := Base_Panel;
          Align       := alBottom;
          Caption     := ' ';
          BorderWidth := 0;
          BorderStyle := bsNone;
          BevelOuter  := bvNone;
          BevelInner  := bvNone;
          Height      := SpacerHeight;
        End;
        Base_Top      := TPanel.Create(Form);
        With Base_Top Do
        Begin
          Parent      := Base_Panel;
          Align       := alClient;
          Caption     := ' ';
          BorderWidth := 10;
          BorderStyle := bsNone;
          BevelOuter  := bvRaised;
          BevelInner  := bvNone;
          BevelWidth  := TopBevelWidth;
        End;
        Prompt        := TPanel.Create(Form);
        With Prompt Do
        Begin
          Parent   := Base_Top;
          Align       := alTop;
          Caption     := ' ';
          BorderWidth := 0;
          BorderStyle := bsNone;
          BevelOuter  := bvNone;
          BevelInner  := bvNone;
          Caption     := InputPrompt;
          Height      := PromptHeight;
          Alignment   := taCenter;
        End;

        Button_Cancel := TButton.Create(Form);
        With Button_Cancel Do
        Begin
          Parent      := ButtonCancelB;
          Caption     := 'Cancel';
          ModalResult := mrCancel;
          Default     := True;
          Align       := alClient;
          Hint        := Hint_Cancel;
        End;

        Button_OK := TButton.Create(Form);
        With Button_OK Do
        Begin
          Parent      := ButtonOKB;
          Caption     := 'OK';
          ModalResult := mrOK;
          Default     := False;
          Align       := alClient;
          Hint        := Hint_OK;
        End;
        ListBox := TListBox.Create(Form);
        With ListBox Do
        Begin
          Parent      := Base_Top;
          Align       := alClient;
          Hint        := Hint_ListBox;
          Sorted      := ListSorted;

          Focused;
          If TempValues <> nil Then
          Begin
            Items.Assign(TempValues);
            DefItemIndex := Items.IndexOf(DefaultValue);
            If DefItemIndex <> -1 Then
            Begin
              ItemIndex := DefItemIndex;
              Selected[DefItemIndex];
            End
            Else
            Begin
              Result    := '';
              ItemIndex := 0;
              Selected[0];
            End;
            IntegralHeight        := True;
            Button_OK.Default     := True;
            Button_Cancel.Default := False;
          End
          Else
          Begin
            Result := '';
          End;
        End;
        SetFocusedControl(ListBox);
        If ShowModal = mrOk Then
        Begin
          If ListBox.ItemIndex<>-1 Then
            Result := ListBox.Items[ListBox.ItemIndex];
        End;
      Finally
        Form.Free;
      End;
    End;
  Finally
    TempValues.Free;
  End;
End;

{!~
DropTable

Drops A Table}
//
Unit Description UnitIndex Master Index
Function DropTable(const DatabaseName, TableName : string):Boolean;
Begin
  Result := DBDropTable(DatabaseName, TableName);
End;

{!~
EmptyTable

Empties a table of all records}
//
Unit Description UnitIndex Master Index
Function EmptyTable(
           const DatabaseName,
           TableName : string): Boolean;
Begin
  Result := DBEmptyTable(DatabaseName, TableName);
End;

{!~
ErrorMeaning

Returns the meaning of the given result code.  Error codes are for
Delphi 1.0.}
//
Unit Description UnitIndex Master Index
function ErrorMeaning (ResultCode: Integer): string;
const
  NumOfEntries = 108;
type
  ErrorEntry = record
    Code: Integer;
    Meaning: String;
  end;
  ErrorMeaningsArray = array [1..NumOfEntries] of ErrorEntry;
const
  MeaningsArray: ErrorMeaningsArray =
{DOS errors}
 ((Code:   1;  Meaning: 'Invalid DOS function number'),
  (Code:   2;  Meaning: 'File not found'),
  (Code:   3;  Meaning: 'Path not found'),
  (Code:   4;  Meaning: 'Too many open files'),
  (Code:   5;  Meaning: 'File access denied'),
  (Code:   6;  Meaning: 'Invalid file handle'),
  (Code:   7;  Meaning: 'Memory control blocks destroyed'),
  (Code:   8;  Meaning: 'Insufficient DOS memory'),
  (Code:   9;  Meaning: 'Invalid memory block address'),
  (Code:  10;  Meaning: 'Invalid DOS environment'),
  (Code:  11;  Meaning: 'Invalid format (DOS)'),
  (Code:  12;  Meaning: 'Invalid file access code'),
  (Code:  13;  Meaning: 'Invalid data (DOS)'),
  (Code:  15;  Meaning: 'Invalid drive number'),
  (Code:  16;  Meaning: 'Cannot remove current directory'),
  (Code:  17;  Meaning: 'Cannot rename across drives'),
  (Code:  18;  Meaning: 'No more files'),
  (Code:  19;  Meaning: 'Disk write-protected'),
  (Code:  20;  Meaning: 'Unknown unit (DOS)'),
  (Code:  21;  Meaning: 'Drive not ready'),
  (Code:  22;  Meaning: 'Unknown DOS command'),
  (Code:  23;  Meaning: 'CRC error'),
  (Code:  24;  Meaning: 'Bad request structure length'),
  (Code:  25;  Meaning: 'Seek error'),
  (Code:  26;  Meaning: 'Unknown media type'),
  (Code:  27;  Meaning: 'Disk sector not found'),
  (Code:  28;  Meaning: 'Out of paper'),
  (Code:  29;  Meaning: 'Write fault'),
  (Code:  30;  Meaning: 'Read fault'),
  (Code:  31;  Meaning: 'General failure'),
  (Code:  32;  Meaning: 'File sharing violation'),
  (Code:  33;  Meaning: 'File lock violation'),
  (Code:  34;  Meaning: 'Invalid disk change'),
  (Code:  35;  Meaning: 'File control block unavailable'),
  (Code:  36;  Meaning: 'Sharing buffer overflow'),
  (Code:  37;  Meaning: 'Code page mismatch'),
  (Code:  38;  Meaning: 'Error handling EOF'),
  (Code:  39;  Meaning: 'Handle disk full'),
  (Code:  50;  Meaning: 'Network request not supported'),
  (Code:  51;  Meaning: 'Remote computer not listening'),
  (Code:  52;  Meaning: 'Duplicate name on network'),
  (Code:  53;  Meaning: 'Network name not found'),
  (Code:  54;  Meaning: 'Network busy'),
  (Code:  55;  Meaning: 'Network device no longer exists'),
  (Code:  56;  Meaning: 'NetBIOS command limit exceeded'),
  (Code:  57;  Meaning: 'Network adaptor error'),
  (Code:  58;  Meaning: 'Incorrect network response'),
  (Code:  59;  Meaning: 'Unexpected network error'),
  (Code:  60;  Meaning: 'Incompatible remote adaptor'),
  (Code:  61;  Meaning: 'Print queue full'),
  (Code:  62;  Meaning: 'Not enough space for print file'),
  (Code:  63;  Meaning: 'Print file deleted'),
  (Code:  64;  Meaning: 'Network name deleted'),
  (Code:  65;  Meaning: 'Access denied'),
  (Code:  66;  Meaning: 'Network device type incorrect'),
  (Code:  67;  Meaning: 'Network name not found'),
  (Code:  68;  Meaning: 'Network name limit exceeded'),
  (Code:  69;  Meaning: 'NetBIOS session limit exceeded'),
  (Code:  70;  Meaning: 'Temporarily paused'),
  (Code:  71;  Meaning: 'Network request not accepted'),
  (Code:  72;  Meaning: 'Print/disk redirection paused'),
  (Code:  80;  Meaning: 'File already exists'),
  (Code:  82;  Meaning: 'Cannot make directory entry'),
  (Code:  83;  Meaning: 'Fail on interrupt 24'),
  (Code:  84;  Meaning: 'Too many redirections'),
  (Code:  85;  Meaning: 'Duplicate redirection'),
  (Code:  86;  Meaning: 'Invalid password'),
  (Code:  87;  Meaning: 'Invalid parameter'),
  (Code:  88;  Meaning: 'Network data fault'),
{I/O errors}
  (Code: 100;  Meaning: 'Disk read error'),
  (Code: 101;  Meaning: 'Disk write error'),
  (Code: 102;  Meaning: 'File not assigned'),
  (Code: 103;  Meaning: 'File not open'),
  (Code: 104;  Meaning: 'File not open for input'),
  (Code: 105;  Meaning: 'File not open for output'),
  (Code: 106;  Meaning: 'Invalid numeric format'),
{Critical errors (Real or protected mode only)}
  (Code: 150;  Meaning: 'Disk is write protected'),
  (Code: 151;  Meaning: 'Unknown unit'),
  (Code: 152;  Meaning: 'Drive not ready'),
  (Code: 153;  Meaning: 'Unknown DOS command'),
  (Code: 154;  Meaning: 'CRC error in data'),
  (Code: 155;  Meaning: 'Bad drive request struct length'),
  (Code: 156;  Meaning: 'Disk seek error'),
  (Code: 157;  Meaning: 'Unknown media type'),
  (Code: 158;  Meaning: 'Sector not found'),
  (Code: 159;  Meaning: 'Printer out of paper'),
  (Code: 160;  Meaning: 'Device write fault'),
  (Code: 161;  Meaning: 'Device read fault'),
  (Code: 162;  Meaning: 'Hardware failure'),
{Fatal errors}
  (Code: 200;  Meaning: 'Division by zero'),
  (Code: 201;  Meaning: 'Range check error'),
  (Code: 202;  Meaning: 'Stack overflow error'),
  (Code: 203;  Meaning: 'Heap overflow error'),
  (Code: 204;  Meaning: 'Invalid pointer operation'),
  (Code: 205;  Meaning: 'Floating point overflow'),
  (Code: 206;  Meaning: 'Floating point underflow'),
  (Code: 207;  Meaning: 'Invalid floating pt. operation'),
  (Code: 208;  Meaning: 'Overlay manager not installed'),
  (Code: 209;  Meaning: 'Overlay file read error'),
  (Code: 210;  Meaning: 'Object not initialised'),
  (Code: 211;  Meaning: 'Call to abstract method'),
  (Code: 212;  Meaning: 'Stream registration error'),
  (Code: 213;  Meaning: 'TCollection index out of range'),
  (Code: 214;  Meaning: 'TCollection overflow error'),
  (Code: 215;  Meaning: 'Arithmetic overflow error'),
  (Code: 216;  Meaning: 'General Protection Fault'),
  (Code: 217;  Meaning: 'Unhandled exception'),
  (Code: 219;  Meaning: 'Invalid typecast'));
var
  Low, High, Mid, Diff: Integer;
begin
  Low := 1;
  High := NumOfEntries;
  while Low <= High do
  begin
    Mid := (Low + High) div 2;
    Diff := MeaningsArray[Mid].Code - ResultCode;
    if Diff < 0 then Low  := Mid + 1 else
    if Diff > 0 then High := Mid - 1 else
    begin {found it}
      Result := MeaningsArray[Mid].Meaning;
      Exit;
    end;
  end; {while}
  Result := 'Error ' + IntToStr(ResultCode) +
                ' (meaning unknown)';
End;

{!~
FieldNo

Returns the field Number as an integer.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason 0 is returned.}
//
Unit Description UnitIndex Master Index
Function FieldNo(DatabaseName, TableName, FieldName: String): Integer;
Begin
  Result := DBFieldNo(DatabaseName, TableName, FieldName);
End;

{!~
FieldSize

Returns the database field Size as an integer.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason 0 is returned.}
//
Unit Description UnitIndex Master Index
Function FieldSize(DatabaseName, TableName, FieldName: String): Integer;
Begin
  Result := FieldSize(DatabaseName, TableName, FieldName);
End;

{!~
FieldType

Returns the database field type as a string.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason a null string is returned.}
//
Unit Description UnitIndex Master Index
Function FieldType(DatabaseName, TableName, FieldName: String): String;
Begin
  Result := TypeField(DatabaseName, TableName, FieldName);
End;

{!~
FieldTypeFromDataSet

Returns the database field type as a string.  If there
is an error a null string is returned.}
//
Unit Description UnitIndex Master Index
Function FieldTypeFromDataSet(DataSet: TDataSet; FieldName: String): String;
Begin
  Result := TypeFieldFromDataSet(DataSet, FieldName);
End;

{!~
IsEmptyDataSource

Tests whether a TDataSource is empty, i.e., has no records }
//
Unit Description UnitIndex Master Index
Function IsEmptyDataSource(DS: TDataSource): Boolean;
Var
  IsError   : Boolean;
  BOF       : Boolean;
  EOF       : Boolean;
  ActiveWas : Boolean;
Begin
  ActiveWas := DS.DataSet.Active;
  IsError   := False;
  BOF       := False;
  EOF       := False;

  Try
    If Not DS.DataSet.Active Then DS.DataSet.Active := True;
    BOF := DS.DataSet.BOF;
    EOF := DS.DataSet.EOF;
  Except
    IsError := True
  End;

  If IsError Then
  Begin
    Result := False;
  End
  Else
  Begin
    If BOF And EOF Then
    Begin
      Result := True;
    End
    Else
    Begin
      Result := False;
    End;
  End;
  DS.DataSet.Active := ActiveWas;
End;

{!~
IsEmptyTQuery

Tests whether a TQuery is empty, i.e., has no records }
//
Unit Description UnitIndex Master Index
Function IsEmptyTQuery(Query: TQuery): Boolean;
Var
  IsError   : Boolean;
  BOF       : Boolean;
  EOF       : Boolean;
  ActiveWas : Boolean;
Begin
  ActiveWas := Query.Active;
  IsError   := False;
  BOF       := False;
  EOF       := False;

  Try
    If Not Query.Active Then Query.Active := True;
    BOF := Query.BOF;
    EOF := Query.EOF;
  Except
    IsError := True
  End;

  If IsError Then
  Begin
    Result := False;
  End
  Else
  Begin
    If BOF And EOF Then
    Begin
      Result := True;
    End
    Else
    Begin
      Result := False;
    End;
  End;
  Query.Active := ActiveWas;
End;

{!~
IsEmptyTTable

Tests whether a TTable is empty, i.e., has no records }
//
Unit Description UnitIndex Master Index
Function IsEmptyTTable(Table: TTable): Boolean;
Var
  IsError   : Boolean;
  BOF       : Boolean;
  EOF       : Boolean;
  ActiveWas : Boolean;
Begin
  ActiveWas := Table.Active;
  IsError   := False;
  BOF       := False;
  EOF       := False;

  Try
    If Not Table.Active Then Table.Active := True;
    BOF := Table.BOF;
    EOF := Table.EOF;
  Except
    IsError := True
  End;

  If IsError Then
  Begin
    Result := False;
  End
  Else
  Begin
    If BOF And EOF Then
    Begin
      Result := True;
    End
    Else
    Begin
      Result := False;
    End;
  End;
  Table.Active := ActiveWas;
End;

{!~
IsEmptyTable

Tests whether a table is empty, i.e., has no records }
//
Unit Description UnitIndex Master Index
Function IsEmptyTable(DatabaseName, TableName: String): Boolean;
Var
  Query   : TQuery;
  IsError : Boolean;
  BOF     : Boolean;
  EOF     : Boolean;
Begin
  IsError := False;
  BOF     := False;
  EOF     := False;
  Query := TQuery.Create(nil);
  Try
    Try
      Query.DatabaseName := DatabaseName;
      Query.Sql.Clear;
      Query.Sql.Add('Select *');
      Query.Sql.Add('From');

      If (Pos('.DB', UpperCase(TableName)) > 0)  Or
         (Pos('.DBF', UpperCase(TableName)) > 0) Then
      Begin
        Query.Sql.Add('"'+TableName+'"');
      End
      Else
      Begin
        Query.Sql.Add(TableName);
      End;
      Query.Active := True;
      Query.First;
      BOF := Query.BOF;
      EOF := Query.EOF;
    Except
      IsError := True
    End;
  Finally
    Query.Free;
  End;

  If IsError Then
  Begin
    Result := False;
  End
  Else
  Begin
    If BOF And EOF Then
    Begin
      Result := True;
    End
    Else
    Begin
      Result := False;
    End;
  End;
End;

{!~
IsField

Returns True If DatabaseName:TableName:FieldName Exists,
False Otherwise}
//
Unit Description UnitIndex Master Index
Function IsField(DatabaseName, TableName, FieldName: String): Boolean;
Var
  Query   : TQuery;
  T       : TTable;
  i       : Integer;
  UpperFN : String;
  TestFN  : String;
Begin
  Result  := False;
  UpperFN := UpperCase(FieldName);
  If Not IsTable(DatabaseName, TableName) Then Exit;
  Query := TQuery.Create(nil);
  T     := TTable.Create(nil);
  Try
    Try
      Query.DatabaseName := DatabaseName;
      Query.Sql.Clear;
      Query.Sql.Add('Select ');
      Query.Sql.Add('a.'+FieldName+' XYZ');
      Query.Sql.Add('From');
      If (Pos('.DB', UpperCase(TableName)) > 0) Or
         (Pos('.DBF',UpperCase(TableName)) > 0) Then
      Begin
        Query.Sql.Add('"'+TableName+'" a');
      End
      Else
      Begin
        Query.Sql.Add(TableName+' a');
      End;
      Query.Active := True;
      Result := True;
    Except
      Try
        T.Active       := False;
        T.DatabaseName := DatabaseName;
        T.TableName    := TableName;
        T.Active       := True;
        If T.FieldDefs.IndexOf(FieldName) > -1 Then
        Begin
          Result := True;
        End
        Else
        Begin
          For i := 0 To T.FieldDefs.Count -1 Do
          Begin
            TestFN := UpperCase(T.FieldDefs[i].Name);
            If TestFN = UpperFN Then
            Begin
              Result := True;
              Break;
            End;
          End;
        End;
        T.Active := False;
      Except
      End;
    End;
  Finally
    Query.Free;
    T.Free;
  End;
End;

{!~
IsFieldKeyed

Returns True If DatabaseName:TableName:FieldName
 Exists and is Keyed, False Otherwise}
//
Unit Description UnitIndex Master Index
Function IsFieldKeyed(DatabaseName, TableName, FieldName: String): Boolean;
Var
  Table      : TTable;
  FieldIndex : Integer;
  i          : Integer;
  KeyCount   : Integer;
  LocalTable : Boolean;
  ParadoxTbl : Boolean;
  DBaseTable : Boolean;
  TempString : String;
Begin
  Result := False;
  If Not IsTable(DatabaseName, TableName) Then Exit;
  If Not IsField(DatabaseName, TableName, FieldName) Then Exit;
  TempString := UpperCase(Copy(TableName,Length(TableName)-2,3));
  ParadoxTbl := (Pos('.DB',TempString) > 0);
  TempString := UpperCase(Copy(TableName,Length(TableName)-3,4));
  DBaseTable := (Pos('.DBF',TempString) > 0);
  LocalTable := (ParadoxTbl Or DBaseTable);
  Table := TTable.Create(nil);
  Try
    Try
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active := True;
      KeyCount     := Table.IndexFieldCount;
      FieldIndex   := Table.FieldDefs.IndexOf(FieldName);

      If LocalTable Then
      Begin
        If ParadoxTbl Then
        Begin
          Result := (FieldIndex < KeyCount);
        End
        Else
        Begin
          Table.IndexDefs.UpDate;
          For i := 0 To Table.IndexDefs.Count-1 Do
          Begin
            {Need to check if FieldName is in the Expression listing}
            If Pos(UpperCase(FieldName),UpperCase(Table.IndexDefs[i].Expression))>0 Then
            Begin
              Result := True;
              Break;
            End;
            {Need to check if FieldName is in the Fields listing}
            If Pos(UpperCase(FieldName),UpperCase(Table.IndexDefs[i].Fields))>0 Then
            Begin
              Result := True;
              Break;
            End;
          End;
        End;
      End
      Else
      Begin
        If Table.
             FieldDefs[FieldIndex].
             Required
        Then
        Begin
          Result := True;
        End;
      End;
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
IsRecord

Returns True If The Record Exists, False Otherwise}
//
Unit Description UnitIndex Master Index
Function IsRecord(
  DatabaseName : String;
  TableName    : String;
  TableKeys    : TStringList;
  KeyValues    : TStringList): Boolean;
Var
  Q : TQuery;
  i : Integer;
Begin
  Q := TQuery.Create(nil);
  Try
    Q.Active := False;
    Q.DatabaseName := DatabaseName;
    Q.RequestLive  := True;
    Q.Sql.Clear;
    Q.Sql.Add('Select');
    For i := 0 To TableKeys.Count - 1 Do
    Begin
      If i = (TableKeys.Count - 1) Then
      Begin
        Q.Sql.Add(TableKeys[i]);
      End
      Else
      Begin
        Q.Sql.Add(TableKeys[i]+',');
      End;
    End;
    Q.Sql.Add('From');
    If Pos('.DB',UpperCase(TableName)) > 0 Then
    Begin
      Q.Sql.Add('"'+TableName+'" ');
    End
    Else
    Begin
      Q.Sql.Add(TableName);
    End;
    Q.Sql.Add('Where');
    For i := 0 To TableKeys.Count - 1 Do
    Begin
      If i <> 0 Then Q.Sql.Add('And');
      Q.Sql.Add(TableKeys[i]+' = '+
        DBSqlValueQuoted(DatabaseName,TableName,
          TableKeys[i],KeyValues[i]));
    End;
    Q.Active := True;
    Result   := Not IsEmptyTQuery(Q);
  Finally
    Q.Free;
  End;
End;

{!~
IsSchemaSame

Returns True If The Tables Have Identical Structures, False Otherwise.
If 1 Local Table is involved then Indices are ignored!!!!!!}
//
Unit Description UnitIndex Master Index
Function IsSchemaSame(const
           DatabaseName1,
           Table1,
           DatabaseName2,
           Table2: string): Boolean;
Begin
  Result := IsStructureSame(DatabaseName1,Table1,DatabaseName2,Table2);
End;

{!~
IsStructureSame

Returns True If The Tables Have Identical Structures, False Otherwise.
If 1 Local Table is involved then Indices are ignored!!!!!!}
//
Unit Description UnitIndex Master Index
Function IsStructureSame(const
           DatabaseName1,
           Table1,
           DatabaseName2,
           Table2: string): Boolean;
Var
  T1      : TTable;
  T2      : TTable;
  i       : Integer;
  OneLocal : Boolean;
Begin
  Result := False;
  If Not IsTable(DatabaseName1, Table1) Then Exit;
  If Not IsTable(DatabaseName2, Table2) Then Exit;
  If (Pos('.DB',UpperCase(Table1)) > 0) Or
     (Pos('.DB',UpperCase(Table2)) > 0) Then
  Begin
    OneLocal := True;
  End
  Else
  Begin
    OneLocal := False;
  End;

  T1 := TTable.Create(nil);
  T2 := TTable.Create(nil);
  Try
    Try
      T1.Active       := False;
      T1.DatabaseName := DatabaseName1;
      T1.TableName    := Table1;
      T1.Active       := True;

      T2.Active       := False;
      T2.DatabaseName := DatabaseName2;
      T2.TableName    := Table2;
      T2.Active       := True;

      If T1.FieldDefs.Count <> T2.FieldDefs.Count Then
      Begin
        Result := False;
      End
      Else
      Begin
        Result := True;
        For i := 0 To T1.FieldDefs.Count-1 Do
        Begin
          If (T1.FieldDefs[i].DataType   <> T2.FieldDefs[i].DataType)   Or
             (T1.FieldDefs[i].FieldClass <> T2.FieldDefs[i].FieldClass) Or
             (T1.FieldDefs[i].FieldNo    <> T2.FieldDefs[i].FieldNo)    Or
             (UpperCase(T1.FieldDefs[i].Name)<>UpperCase(T2.FieldDefs[i].Name)) Or
             (T1.FieldDefs[i].Size       <> T2.FieldDefs[i].Size)       Then
          Begin
            Result := False;
            Break;
          End;
          If (T1.FieldDefs[i].Required   <> T2.FieldDefs[i].Required)   And
             (Not OneLocal)                                             Then
          Begin
            Result := False;
            Break;
          End;
        End;
      End;
    Except
    End;
  Finally
    T1.Free;
    T2.Free;
  End;
End;

{!~
IsTable

Returns True If The Table Exists, False Otherwise.
This procedure needs to be improved.
Please give recommendations or new code.}
//
Unit Description UnitIndex Master Index
Function IsTable(DatabaseName, TableName: String): Boolean;
Var
  Query: TQuery;
Begin
  Result := False;
  Query := TQuery.Create(nil);
  Try
    Try
      Query.DatabaseName := DatabaseName;
      Query.Sql.Clear;
      Query.Sql.Add('Select *');
      Query.Sql.Add('From');
      If (Pos('.DB', UpperCase(TableName)) > 0) Or
         (Pos('.DBF',UpperCase(TableName)) > 0) Then
      Begin
        Query.Sql.Add('"'+TableName+'"');
      End
      Else
      Begin
        Query.Sql.Add(TableName);
      End;
      Query.Active := True;
      Result := True;
    Except
    End;
  Finally
    Query.Free;
  End;
End;

{!~
IsTableKeyed

Returns True If DatabaseName:TableName
Exists and has a primary key, False Otherwise}
//
Unit Description UnitIndex Master Index
Function IsTableKeyed(DatabaseName, TableName: String): Boolean;
Var
  Table      : TTable;
  i          : Integer;
  IsKeyed    : Boolean;
Begin
  Result  := False;
  IsKeyed := False;
  If Not IsTable(DatabaseName, TableName) Then Exit;
  Table := TTable.Create(nil);
  Try
    Try
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active       := True;
      For i := 0 To Table.FieldDefs.Count-1 Do
      Begin
         If Table.FieldDefs[i].Required Then
         Begin
           IsKeyed := True;
           Break;
         End;
      End;

      If IsKeyed Then
      Begin
        Result := True;
      End
      Else
      Begin
        Result := False;
        {Need to examine indexdefs}
        If (Pos('.DB', UpperCase(TableName)) > 0) Then
        Begin
          {Table is either Paradox or DBase}
          Table.IndexDefs.UpDate;
          If (Pos('.DBF', UpperCase(TableName)) > 0) Then
          Begin
            {Table is a DBase Table}
            If Table.IndexDefs.Count > 0 Then
            Begin
              Result := True;
            End;
          End
          Else
          Begin
            {Table is a Paradox Table}
            For i := 0 To Table.IndexDefs.Count-1 Do
            Begin
              If ixPrimary in Table.IndexDefs[i].Options Then
              Begin
                Result := True;
                Break;
              End;
            End;
          End;
        End
        Else
        Begin
          Result := False;
        End;
      End;
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
LookupDialog

Presents a lookup Dialog to the user.  The selected
value is returned if the user presses OK and the Default
value is returned if the user presses Cancel unless the
TStringList is nil in which case a blank string is returned}
//
Unit Description UnitIndex Master Index
Function LookupDialog(
  const DialogCaption : string;
  const InputPrompt   : string;
  const DefaultValue  : string;
  const Values        : TStringList
  ): string;
Begin
  Result :=
    DialogLookupDetail(
      DialogCaption,
      InputPrompt,
      DefaultValue,
      Values,        //TStringList
      5,             //Spacer Height
      5,             //Button Spacing
      2,             //BevelWidth
      25,            //PromptHeight
      300,           //FormHeight
      200,           //FormWidth
      'Close dialog and return selected value.', //Hint_Cancel
      'Close dialog and make no changes.', //Hint_OK
      'Click an item to select it.',  //Hint_ListBox
      True, //ListSorted
      False //AllowDuplicates
      );
End;

{!~
MoveTable

Moves SourceTable From SourceDatabaseName
 To DestDatabasename.  If a table exists
 with the same name at DestDatabaseName it
 is overwritten.}
//
Unit Description UnitIndex Master Index
Function MoveTable(
            SourceTable,
            SourceDatabaseName,
            DestDatabaseName: String): Boolean;
Begin
  Result := DBMoveTable(SourceTable,SourceDatabaseName,DestDatabaseName);
End;

{!~
NFields

Returns the number of fields in a table}
//
Unit Description UnitIndex Master Index
Function NFields(DatabaseName, TableName: String): Integer;
Var
  Table      : TTable;
  FieldCount : Integer;
Begin
  Result := 0;
  Table := TTable.Create(nil);
  Try
    Try
      Table.Active       := False;
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active       := True;
      FieldCount         := Table.FieldDefs.Count;
      Result             := FieldCount;
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
SubtractTable

Subtracts the records in the source
 table from the destination table}
//
Unit Description UnitIndex Master Index
Function SubtractTable(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;
Begin
  Result := False;
  If (Not IsTableKeyed(DestDatabaseName,DestinationTable)) Or
     (Not IsTableKeyed(SourceDatabaseName,SourceTable))    Then
  Begin
    Exit;
  End;

  Result := DBRecordMove(SourceDatabaseName,SourceTable,
                         DestDatabaseName,DestinationTable,batDelete);
End;

{!~
TableAdd

Add source table to destination table}
//
Unit Description UnitIndex Master Index
Function TableAdd(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;
Begin
  Result := AddTables(SourceDatabaseName,SourceTable,
                      DestDatabaseName,DestinationTable);
End;

{!~
TableCreateFromQuery

Creates a new table from a Query.
 Complex joins can be output to a new table.}
//
Unit Description UnitIndex Master Index
Function TableCreateFromQuery(
            Query: TQuery;
            NewTableName,
            TableDatabaseName: String): Boolean;
Begin
  Result := DBCreateTableFromQuery(Query,NewTableName,TableDatabaseName);
End;

{!~
TableMove

Moves SourceTable From SourceDatabaseName
 To DestDatabasename.  If a table exists
 with the same name at DestDatabaseName it
 is overwritten.}
//
Unit Description UnitIndex Master Index
Function TableMove(
            SourceTable,
            SourceDatabaseName,
            DestDatabaseName: String): Boolean;
Begin
  Result := DBMoveTable(SourceTable,SourceDatabaseName,DestDatabaseName);
End;

{!~
TableSubtract

Subtracts the records in the source
 table from the destination table}
//
Unit Description UnitIndex Master Index
Function TableSubtract(
           const
           SourceDatabaseName,
           SourceTable,
           DestDatabaseName,
           DestinationTable: string): Boolean;
Begin
  Result := SubtractTable(SourceDatabaseName,SourceTable,
                      DestDatabaseName,DestinationTable);
End;

{!~
TypeField

Returns the database field type as a string.  If there
is an error, the table doesn't exist, the field doesn't
exist or some other reason a null string is returned.}
//
Unit Description UnitIndex Master Index
Function TypeField(DatabaseName, TableName, FieldName: String): String;
Var
  Table      : TTable;
  FieldIndex : Integer;
  FieldType  : TFieldType;
Begin
  Result := '';
  If Not IsTable(DatabaseName, TableName) Then Exit;
  If Not IsField(DatabaseName, TableName, FieldName) Then Exit;
  Table := TTable.Create(nil);
  Try
    Try
      Table.Active       := False;
      Table.DatabaseName := DatabaseName;
      Table.TableName    := TableName;
      Table.Active       := True;
      FieldIndex         :=
        Table.FieldDefs.IndexOf(FieldName);
      FieldType          :=
        Table.FieldDefs[FieldIndex].DataType;

      {TFieldType
      Possible Delphi 1.0 values are
      ftUnknown, ftString, ftSmallint,
      ftInteger, ftWord, ftBoolean,
      ftFloat, ftCurrency, ftBCD, ftDate,
      ftTime, ftDateTime, ftBytes, ftVarBytes,
      ftBlob, ftMemo or ftGraphic

      Additional Delphi 2.0 values are:
      ftAutoInc
      ftFmtMemo
      ftParadoxOle
      ftDBaseOle
      ftTypedBinary
      }
      If FieldType=ftUnknown  Then Result := 'Unknown';
      If FieldType=ftString   Then Result := 'String';
      If FieldType=ftSmallInt Then Result := 'SmallInt';
      If FieldType=ftInteger  Then Result := 'Integer';
      If FieldType=ftWord     Then Result := 'Word';
      If FieldType=ftBoolean  Then Result := 'Boolean';
      If FieldType=ftFloat    Then Result := 'Float';
      If FieldType=ftCurrency Then Result := 'Currency';
      If FieldType=ftBCD      Then Result := 'BCD';
      If FieldType=ftDate     Then Result := 'Date';
      If FieldType=ftTime     Then Result := 'Time';
      If FieldType=ftDateTime Then Result := 'DateTime';
      If FieldType=ftBytes    Then Result := 'Bytes';
      If FieldType=ftVarBytes Then Result := 'VarBytes';
      If FieldType=ftBlob     Then Result := 'Blob';
      If FieldType=ftMemo     Then Result := 'Memo';
      If FieldType=ftGraphic  Then Result := 'Graphic';
{$IFDEF WIN32}
      If FieldType=ftAutoInc      Then Result := 'AutoInc';
      If FieldType=ftFmtMemo      Then Result := 'FmtMemo';
      If FieldType=ftParadoxOle   Then Result := 'ParadoxOle';
      If FieldType=ftDBaseOle      Then Result := 'DBaseOle';
      If FieldType=ftTypedBinary  Then Result := 'TypedBinary';
{$ENDIF}
    Except
    End;
  Finally
    Table.Free;
  End;
End;

{!~
TypeFieldFromDataSet

Returns the database field type as a string.  If there
is an error a null string is returned.}
//
Unit Description UnitIndex Master Index
Function TypeFieldFromDataSet(DataSet: TDataSet; FieldName: String): String;
Var
  FieldIndex : Integer;
  FieldType  : TFieldType;
Begin
  Try
    DataSet.Active     := True;
    FieldIndex         :=
      DataSet.FieldDefs.IndexOf(FieldName);
    FieldType          :=
      DataSet.FieldDefs[FieldIndex].DataType;
    {TFieldType Possible values are
    ftUnknown, ftString, ftSmallint,
    ftInteger, ftWord, ftBoolean,
    ftFloat, ftCurrency, ftBCD, ftDate,
    ftTime, ftDateTime, ftBytes, ftVarBytes,
    ftBlob, ftMemo or ftGraphic}
    If FieldType=ftUnknown  Then Result := 'Unknown';
    If FieldType=ftString   Then Result := 'String';
    If FieldType=ftSmallInt Then Result := 'SmallInt';
    If FieldType=ftInteger  Then Result := 'Integer';
    If FieldType=ftWord     Then Result := 'Word';
    If FieldType=ftBoolean  Then Result := 'Boolean';
    If FieldType=ftFloat    Then Result := 'Float';
    If FieldType=ftCurrency Then Result := 'Currency';
    If FieldType=ftBCD      Then Result := 'BCD';
    If FieldType=ftDate     Then Result := 'Date';
    If FieldType=ftTime     Then Result := 'Time';
    If FieldType=ftDateTime Then Result := 'DateTime';
    If FieldType=ftBytes    Then Result := 'Bytes';
    If FieldType=ftVarBytes Then Result := 'VarBytes';
    If FieldType=ftBlob     Then Result := 'Blob';
    If FieldType=ftMemo     Then Result := 'Memo';
    If FieldType=ftGraphic  Then Result := 'Graphic';
  Except
  End;
End;

End.

//