meta data for this page
  •  

Copy Table Example

 execute ibeblock (
 -- Don't change names of following parameters! -------------------------------------------------
   SrcDBConnStr variant comment 'Source DB connection string',
   SrcDBUserName variant = 'SYSDBA' comment 'Source DB user name',
   SrcDBPassword variant = 'masterkey' comment 'Source DB password',
   SrcDBCharset variant = 'NONE' comment 'Source DB connection charset',
   SrcDBClientLib variant = 'gds32.dll' comment 'Source DB client library name',
   DestDBConnStr variant comment 'Destination DB connection string',
   DestDBUserName variant = 'SYSDBA' comment 'Destination DB user name',
   DestDBPassword variant = 'masterkey' comment 'Destination DB password',
   DestDBCharset variant = 'NONE' comment 'Destination DB connection charset',
   DestDBClientLib variant = 'gds32.dll' comment 'Destination DB client library name',
   SrcObjectName variant = '' comment 'Table name to be copied',
   DestObjectName variant = '' comment 'Destination table name, leave empty if no changes need',
   DebugMode boolean = TRUE,
 ------------------------------------------------------------------------------------------------
   CopyDomains boolean = TRUE comment 'Copy domains',
   CopyTriggers boolean = TRUE comment 'Copy table triggers',
   CopyPrimaryKey boolean = TRUE comment 'Copy primary key',
 --  CopyForeignKeys boolean = FALSE comment 'Copy foreign keys',
   CopyGenerators boolean = TRUE comment 'Copy generators used within table triggers',
   CopyData boolean = TRUE comment 'Copy table data',
   CopyIndices boolean = TRUE comment 'Copy table indices',
   DropTableIfExists boolean = FALSE comment 'Try to drop table if the one exists in the destination database')
 as
 begin
   Time1 = ibec_GetTickCount(); 
 
   CRLF = ibec_CRLF();
   BS = ibec_Chr(8);
   Success = BS + ' Successfull.';
   Failed = BS + ' FAILED!';

   if (DebugMode) then
   begin
     SrcDBConnStr = 'LOCALHOST/3060:D:\FB2_DATA\IBEHELP.FBA';
     SrcDBCharset = 'WIN1251';
     SrcDBClientLib = 'C:\Program Files\Firebird\bin\fbclient.dll';

     --DestDBConnStr = 'AVX-MAIN:D:\FB2_DATA\FORMTEST.FDB';
     DestDBConnStr = 'LOCALHOST/3060:D:\FB2_DATA\IBEHELP.FBA';
     DestDBCharset = 'WIN1251';
     DestDBClientLib = 'C:\Program Files\Firebird\bin\fbclient.dll';

     SrcObjectName = 'HELP_ITEMS';
     DestObjectName = 'HELP_ITEMS33';
     DropTableIfExists = TRUE;
   end; 
 
   SrcTableName = SrcObjectName;
   DestTableName = DestObjectName; 


   SrcDBParams = 'DBName=' + SrcDBConnStr + ';' +
                 'User=' + SrcDBUserName + ';' +
                 'Password=' + SrcDBPassword + ';' +
                 'Names=' + SrcDBCharset + ';' +
                 'ClientLib=' + SrcDBClientLib;

   DestDBParams = 'DBName=' + DestDBConnStr + ';' +
                  'User=' + DestDBUserName + ';' +
                  'Password=' + DestDBPassword + ';' +
                  'Names=' + DestDBCharset + ';' +
                  'ClientLib=' + DestDBClientLib;

   try
     try
       ibec_Progress('Connecting to ' + SrcDBConnStr + '...');
       SrcDB = ibec_CreateConnection(__ctFirebird, SrcDBParams);
       ibec_Progress(Success);
       SrcDBSQLDialect = ibec_GetConnectionProp(SrcDB, 'DBSQLDialect');
     except
       ibec_Progress(Failed);
       raise;
       Exit;
     end;

   try
     ibec_Progress('Connecting to ' + DestDBConnStr + '...');
     DestDB = ibec_CreateConnection(__ctFirebird, DestDBParams);
     ibec_Progress(Success);
     DestDBSQLDialect = ibec_GetConnectionProp(DestDB, 'DBSQLDialect');
   except
     ibec_Progress(Failed);
     raise;
     Exit;
   end; 

   ibec_UseConnection(SrcDB); 

   select rdb$relation_name, rdb$system_flag, rdb$external_file, rdb$description
          from rdb$relations
          where (rdb$relation_name = :SrcTableName) and (rdb$view_blr is null)
          into :SrcTableData;

   if (SrcTableData['RDB$RELATION_NAME'] is null) then
     exception cant_find_table 'There is no such table (' + :SrcTableName + ') in the source database.';
   IsSys = SrcTableData['RDB$SYSTEM_FLAG'] = 1;
   if (IsSys) then
     exception cant_copy_system_table 'Cannot copy a system table.';


   if ((DestTableName is null) or (DestTableName = ''))  then
     DestTableName = SrcTableName; 

   DestTableNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(:DestTableName, '"'), ibec_AnsiUpperCase(:DestTableName));
   SrcTableNameFmt = ibec_IIF(SrcDBSQLDialect = 3, ibec_QuotedStr(:SrcTableName, '"'), ibec_AnsiUpperCase(:SrcTableName)); 

   ibec_UseConnection(DestDB);

   if (exists(select rdb$relation_name from rdb$relations where rdb$relation_name = :DestTableName)) then
   begin
     if (DropTableIfExists) then
     begin
       DropStmt = 'DROP TABLE ' + DestTableNameFmt; 

       try
         ibec_Progress('Dropping table ' + DestTableNameFmt + '...');
         execute statement :DropStmt;
         commit;
         ibec_Progress(Success);
       except
         ibec_Progress(Failed);
         rollback;
         raise;
       end;
     end
     else
       exception table_exists_already 'Table "' + DestTableName + '" exists in the destination database already.';
   end 

   ibec_UseConnection(SrcDB);

   select rdb$field_name
          from rdb$relation_fields
          where (rdb$relation_name = 'RDB$FIELDS') and
                (rdb$field_name = 'RDB$FIELD_PRECISION')
          into :bPrecision;
   bPrecision = ibec_IIF(:bPrecision is NULL, FALSE, TRUE);

   SelStmt = 'select rf.rdb$field_name as fld_name,' +
                    'rf.rdb$field_source as fld_domain,' +
                    'rf.rdb$null_flag as fld_null_flag,' +
                    'rf.rdb$default_source as fld_default,' +
                    'rf.rdb$description as fld_description,' +
                    'f.rdb$field_type as dom_type,' +
                    'f.rdb$field_length as dom_length,' +
                    'f.rdb$field_sub_type as dom_subtype,' +
                    'f.rdb$field_scale as dom_scale,' +
                    'f.rdb$null_flag as dom_null_flag,' +
                    'f.rdb$character_length as dom_charlen,' +
                    'f.rdb$segment_length as dom_seglen,' +
                    'f.rdb$system_flag as dom_system_flag,' +
                    'f.rdb$computed_source as dom_computedby,' +
                    'f.rdb$default_source as dom_default,' +
                    'f.rdb$dimensions as dom_dims,' +
                    'f.rdb$description as dom_description,' +
                    'ch.rdb$character_set_name as dom_charset,' +
                    'ch.rdb$bytes_per_character as charset_bytes,' +
                    'dco.rdb$collation_name as dom_collation,' +
                    'fco.rdb$collation_name as fld_collation';
   if (bPrecision) then
     SelStmt = SelStmt + ', f.rdb$field_precision as dom_precision'; 

   SelStmt = SelStmt + CRLF +
             'from rdb$relation_fields rf ' + CRLF +
             'left join rdb$fields f on rf.rdb$field_source = f.rdb$field_name' + CRLF +
             'left join rdb$character_sets ch on f.rdb$character_set_id = ch.rdb$character_set_id' + CRLF +
             'left join rdb$collations dco on ((f.rdb$collation_id = dco.rdb$collation_id) and (f.rdb$character_set_id =  
dco.rdb$character_set_id))' + CRLF +
             'left join rdb$collations fco on ((rf.rdb$collation_id = fco.rdb$collation_id) and (f.rdb$character_set_id =  
fco.rdb$character_set_id))' + CRLF +
             'where rf.rdb$relation_name = ' + ibec_QuotedStr(:SrcTableName, '''') + CRLF +
             'order by rf.rdb$field_position';

   ibec_Progress('Collecting fields info...');
   i = 0;
   iUserDomainCount = 0;
   for execute statement SelStmt into :FldData
   do
   begin
     s = ibec_Trim(FldData['FLD_DOMAIN']);
     aDomains[i] = ibec_IIF(ibec_Copy(s, 1, 4) = 'RDB$', null, s);
     if (aDomains[i] is not null) then
       iUserDomainCount = iUserDomainCount + 1; 

     aFields[i] = ibec_Trim(FldData['FLD_NAME']); 

     sType = ibec_IBTypeToStr(FldData['DOM_TYPE'],
                              FldData['DOM_SUBTYPE'],
                              FldData['DOM_LENGTH'],
                              FldData['DOM_SCALE'],
                              FldData['DOM_SEGLEN'],
                              FldData['DOM_CHARLEN'],
                              FldData['DOM_PRECISION'],
                              DestDBSQLDialect);
     aTypes[i] = sType;

     aFieldsNotNull[i] = ibec_IIF(FldData['FLD_NULL_FLAG'] = 1, ' NOT NULL', '');
     aFieldsDefault[i] = ibec_IIF(FldData['FLD_DEFAULT'] is null, '', ' ' + ibec_Trim(FldData['FLD_DEFAULT']));
     aFieldsComment[i] = FldData['FLD_DESCRIPTION'];
     aFieldsCharset[i] = ibec_IIF(FldData['DOM_CHARSET'] is null, '', ibec_Trim(FldData['DOM_CHARSET']));
     aFieldsCollate[i] = ibec_IIF(FldData['FLD_COLLATION'] is null, '', ibec_Trim(FldData['FLD_COLLATION']));

     aDomainsComputedBy[i] = FldData['DOM_COMPUTEDBY'];
     i = i + 1;
   end

   ibec_UseConnection(DestDB);
   DomainsAreOK = TRUE;
   if (CopyDomains and (iUserDomainCount > 0)) then
   begin
     ibec_Progress('Creating domains...');
     foreach (aDomains as Dom key DomIdx skip nulls) do
     begin
       if (exists(select rdb$field_name from rdb$fields where rdb$field_name = :Dom)) then
         Continue;
       CreateStmt = 'CREATE DOMAIN ' +
                    ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(:Dom, '"'), ibec_AnsiUpperCase(:Dom)) +
                    ' AS ' +  sType;
       try
         execute statement :CreateStmt;
         commit;
       except
         DomainsAreOK = FALSE;
         rollback;
       end;
     end;
   end

   FieldsList = ''; 

   CreateStmt = 'CREATE TABLE ' + DestTableNameFmt;
   foreach (aFields as FldName index FldKey skip nulls) do
   begin
     sType = '';
     if (FieldsList <> '') then
       FieldsList .= ',' + CRLF;
     FldNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(:FldName, '"'), ibec_AnsiUpperCase(:FldName));
     if (DomainsAreOK and (aDomains[FldKey] is not null)) then
       FieldsList .= FldNameFmt + ' ' + aDomains[FldKey];
     else
     FieldsList .= FldNameFmt + ' ' + aTypes[FldKey];
     if ((aDomains[FldKey] is null) and (aFieldsCharset[FldKey] <> '')) then
       FieldsList .= ' CHARACTER SET ' + aFieldsCharset[FldKey];
     FieldsList .= aFieldsDefault[FldKey] + aFieldsNotNull[FldKey];
     if (aFieldsCollate[FldKey] <> '') then
       FieldsList .= ' COLLATE ' + aFieldsCollate[FldKey];
   end
   CreateStmt .= ' (' + CRLF + FieldsList + ')'; 

   ibec_UseConnection(DestDB);
   try
     ibec_Progress('Creating table ' + DestTableNameFmt + '...');
     execute statement :CreateStmt;
     commit;
     ibec_Progress(Success); 

     TblName = ibec_IIF(DestDBSQLDialect = 3, :DestTableName, ibec_AnsiUpperCase(:DestTableName));
     foreach (aFieldsComment as FldComment key FldKey skip nulls) do
     begin
       FldName = aFields[FldKey];
       update rdb$relation_fields set rdb$description = :FldComment
              where (rdb$relation_name = :TblName) and (rdb$field_name = :FldName);
     end;
     commit;
   except
     ibec_Progress(Failed);
     rollback;
   end;

   -------------------------------------------------------------
   -- TRANSFER TABLE DATA --------------------------------------
   -------------------------------------------------------------
   if (CopyData) then
   begin
     sFields = '';
     sValues = '';
     foreach (aFields as FldName key FldKey) do
     begin
       if (aDomainsComputedBy[FldKey] is null) then
       begin
         if (sFields <> '') then
         begin
           sFields .= ', ';
           sValues .= ', ';
         end;
         FldNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(:FldName, '"'), ibec_AnsiUpperCase(:FldName));
         sFields .= FldNameFmt;
         sValues .= ':' + FldNameFmt;
       end;
     end;

     SelectStmt = 'SELECT ' + sFields + ' FROM ' + SrcTableNameFmt;
     InsertStmt = 'INSERT INTO ' + DestTableNameFmt + ' (' + sFields + ') VALUES (' + sValues + ')';

     ibec_UseConnection(SrcDB);
     i = 0;
     ibec_Progress('Copying table data...');
     for execute statement :SelectStmt into :Data
     do
     begin
       ibec_UseConnection(DestDB);
       execute statement :InsertStmt values :Data;
       i = i + 1;
       if (ibec_mod(i, 500) = 0) then
       begin
         commit;
         ibec_Progress('    ' + ibec_cast(i, __typeString) + ' records copied...');
       end;
     end;
     ibec_Progress('Totally ' + ibec_cast(i, __typeString) + ' records copied.');
     ibec_UseConnection(DestDB);
     commit;
   end;

   if (CopyTriggers or CopyPrimaryKey or CopyGenerators) then
   begin
     ibec_UseConnection(SrcDB);
     TblName = ibec_IIF(SrcDBSQLDialect = 3, :SrcTableName, ibec_AnsiUpperCase(:SrcTableName));
     i = 0;
     ibec_Progress('Collecting triggers info...');
     for select T.RDB$TRIGGER_NAME, T.RDB$TRIGGER_TYPE, T.RDB$TRIGGER_SEQUENCE,
                T.RDB$TRIGGER_INACTIVE, T.RDB$TRIGGER_SOURCE
         from RDB$TRIGGERS T
         left join RDB$CHECK_CONSTRAINTS C on C.RDB$TRIGGER_NAME = T.RDB$TRIGGER_NAME
         where ((T.RDB$SYSTEM_FLAG = 0) or (T.RDB$SYSTEM_FLAG is null)) and
               (C.rdb$trigger_name is null) and (T.RDB$RELATION_NAME = :TblName)
         order by T.RDB$TRIGGER_NAME
         into :TrgData
     do
     begin
       aTriggerNames[i] = ibec_Trim(TrgData['RDB$TRIGGER_NAME']);
       aTriggerTypes[i] = ibec_IBTriggerTypeToStr(TrgData['RDB$TRIGGER_TYPE']);
       aTriggerPositions[i] = TrgData['RDB$TRIGGER_SEQUENCE'];
       aTriggerInactives[i] = ibec_IIF(TrgData['RDB$TRIGGER_INACTIVE'] = 1, 'INACTIVE', 'ACTIVE');
       aTriggerSources[i] = TrgData['RDB$TRIGGER_SOURCE'];
       i = i + 1;
     end;

     select rc.rdb$constraint_name,
            rc.rdb$index_name
     from rdb$relation_constraints rc
     where (rc.rdb$constraint_type = 'PRIMARY KEY') and (rc.rdb$relation_name = :TblName)
     into :PKData;

     if (PKData is not null) then
     begin
       i = 0;
       PKIdxName = ibec_Trim(PKData[1]);
       for select rdb$field_name
           from rdb$index_segments
           where rdb$index_name = :PKIdxName
           order by rdb$field_position
           into :PKField
       do
       begin
         PKFields[i] = ibec_Trim(:PKField);
         i = i + 1;
       end
     end;

     -----------------------------------------------------
     -- COLLECTING GENERATOR NAMES USED WITHIN TRIGGERS
     -----------------------------------------------------

     i = 0;
     ibec_Progress('Searching trigger bodies for used generators...');
     foreach (aTriggerNames as TrgName key TrgKey skip nulls) do
     begin
       TrgSrc = aTriggerSources[TrgKey];
       TrgNameFmt = ibec_IIF(SrcDBSQLDialect = 3, ibec_QuotedStr(:TrgName, '"'), ibec_AnsiUpperCase(:TrgName));
       TrgDDL = 'CREATE TRIGGER ' + TrgNameFmt + ' FOR ' + SrcTableNameFmt + CRLF +
                aTriggerTypes[TrgKey] + ' POSITION ' + ibec_Cast(aTriggerPositions[TrgKey], __typeString) + CRLF + TrgSrc;
       PSQLParser = ibec_psql_Parse(TrgDDL, SrcDBSqlDialect, __svUnknown);
       try
         if (ibec_psql_ErrorCount(PSQLParser) = 0) then
         begin
           iCount = ibec_psql_UsedObjects(PSQLParser, ObjNames, ObjTypes);
           if (iCount > 0) then
           begin
             foreach (ObjNames as ObjName key ObjKey skip nulls) do
               if (ObjTypes[ObjKey] = __dboGenerator) then
                 if (ibec_IndexOfValue(Generators, ObjName) is null) then
                 begin
                   Generators[i] = ObjName;
                   i = i + 1;
                 end;
           end;
         end;
       finally
         ibec_psql_Free(PSQLParser);
       end;
     end;

     -------------------------------------------------------
     -- CREATING GENERATORS AND SETTING THEIR VALUES
     -------------------------------------------------------

     ibec_Progress('Creating and initting generators...');
     foreach (Generators as GenName key GenKey skip nulls) do
     begin
       ibec_UseConnection(DestDB);
       if (exists(select rdb$generator_name from rdb$generators where rdb$generator_name = :GenName)) then
         Continue; 

       ibec_UseConnection(SrcDB);
       GenNameFmt = ibec_IIF(SrcDBSQLDialect = 3, ibec_QuotedStr(:GenName, '"'), ibec_AnsiUpperCase(:GenName));
       GetGenValueStmt = 'SELECT GEN_ID(' + GenNameFmt + ', 0) FROM RDB$DATABASE';
       execute statement GetGenValueStmt into :GenValue; 

       GenNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(:GenName, '"'), ibec_AnsiUpperCase(:GenName));
       CreateGenStmt = 'CREATE GENERATOR ' + GenNameFmt;
       SetGenStmt = 'SET GENERATOR ' + GenNameFmt + ' TO ' + ibec_Cast(:GenValue, __typeString); 

       ibec_UseConnection(DestDB);
       try
         ibec_Progress('    ' + GenNameFmt + '...');
         execute statement CreateGenStmt;
         commit;
         execute statement SetGenStmt;
         commit;
         ibec_Progress(Success);
       except
         ibec_Progress(Failed);
         rollback;
       end;
     end;
   end;

   if (CopyTriggers) then
   begin
     ibec_UseConnection(DestDb);
     ibec_Progress('Creating triggers...');
     foreach (aTriggerNames as TrgName key TrgKey skip nulls) do
     begin
       if (SrcTableName <> DestTableName) then
         TrgName = ibec_preg_Replace('(?i)' + SrcTableName, DestTableName, TrgName);
       TrgNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(:TrgName, '"'), ibec_AnsiUpperCase(:TrgName));
       CreateTrgStmt = 'CREATE TRIGGER ' + TrgNameFmt + ' FOR ' + DestTableNameFmt + CRLF +
                       aTriggerInactives[TrgKey] + ' ' + aTriggerTypes[TrgKey] + ' POSITION ' + ibec_Cast(aTriggerPositions[TrgKey], __typeString) + CRLF +
                      aTriggerSources[TrgKey];
 
       WasError = FALSE;
       try
         ibec_Progress('    ' + TrgNameFmt + '...');
         execute statement :CreateTrgStmt;
         commit;
         ibec_Progress(BS + ' Successfull.');
       except
         ibec_Progress(BS + ' FAILED!');
         WasError = TRUE;
         rollback;
       end;

       if (WasError) then
       begin
         ibec_Progress('    Attempt to create trigger ' + TrgNameFmt + ' with commented body...');
         PSQLParser = ibec_psql_Parse(CreateTrgStmt, DestDBSqlDialect, __svUnknown);
         try
           CreateTrgStmt = ibec_psql_CommentBody(PSQLParser);
         finally
           ibec_psql_Free(PSQLParser);
         end;
         try
           execute statement :CreateTrgStmt;
           ibec_Progress(BS + ' Successfull.');
           commit;
         except
           ibec_Progress('    Failed.');
           rollback;
         end;
       end;
     end;
   end;

   if (CopyPrimaryKey) then
   begin
     ibec_UseConnection(SrcDB);
     select rc.rdb$constraint_name, rc.rdb$index_name
            from rdb$relation_constraints rc
            where (rc.rdb$constraint_type = 'PRIMARY KEY') and (rc.rdb$relation_name = :SrcTableName)
            into :PKData;
     if (PKData is not null) then
     begin
       PKIdxName = ibec_Trim(PKData[1]);
       sFields = '';
       for select rdb$field_name
           from rdb$index_segments
           where rdb$index_name = :PKIdxName
           order by rdb$field_position
           into :PKFields
       do
       begin
         if (sFields <> '') then
           sFields .= ', ';
         FldName = ibec_Trim(PKFields[0]);
         FldNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(FldName, '"'), ibec_AnsiUpperCase(FldName));
         sFields .= FldNameFmt;
       end;
       PKName = ibec_Trim(PKData[0]);

       ibec_UseConnection(DestDB);
       PKNameBase = 'PK_' + DestTableName + '_';
       PKNameSuff = 0;
       PKExists = 1;
       while (PKExists is not null) do
       begin
         PKNameSuff = PKNameSuff + 1;
         PKName = PKNameBase + ibec_Cast(PKNameSuff, __typeString);
         PKExists = null;
         select 1 from rdb$relation_constraints rc
              where (rc.rdb$constraint_type = 'PRIMARY KEY') and (rc.rdb$constraint_name = :PKName)
              into :PKExists;
       end;

       PKNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(PKName, '"'), ibec_AnsiUpperCase(PKName));
       AlterStmt = 'ALTER TABLE ' + DestTableNameFmt + ' ADD CONSTRAINT ' + PKNameFmt + ' PRIMARY KEY (' + sFields + ')';

       ibec_UseConnection(DestDB);
       try
         ibec_Progress('Creating primary key ' + PKNameFmt + '...');
         execute statement :AlterStmt;
         commit;
         ibec_Progress(Success);
       except
         ibec_Progress(Failed);
         rollback;
       end;
     end;
   end;

   if (CopyIndices) then
   begin
     ibec_Progress('Creating indices...');
     ibec_UseConnection(SrcDB);
     for select i.rdb$index_name, i.rdb$unique_flag, i.rdb$index_inactive, i.rdb$index_type,
                i.rdb$expression_source, i.rdb$description
         from rdb$indices i
         left join rdb$relation_constraints rc on i.rdb$index_name = rc.rdb$index_name
         where ((i.rdb$system_flag = 0) or (i.rdb$system_flag is null)) and (rc.rdb$constraint_name is null)
               and i.rdb$relation_name = :SrcTableName
         into :IdxData
     do
     begin
       IdxName = ibec_Trim(IdxData[0]);
       IdxNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(IdxName, '"'), ibec_AnsiUpperCase(IdxName));
       IdxUnique = ibec_IIF((IdxData[1] is null) or (IdxData[1] = 0), '', 'UNIQUE ');
       IdxActive = ibec_IIF((IdxData[2] is null) or (IdxData[1] = 0), '', 'INACTIVE ');
       IdxType = ibec_IIF((IdxData[3] is null) or (IdxData[1] = 0), '', 'DESCENDING ');
       IdxExpression = IdxData[4];
       IdxDescription = IdxData[5];

       sFields = '';
       for select rdb$field_name
           from rdb$index_segments
           where rdb$index_name = :IdxName
           order by rdb$field_position
           into :IdxFields
       do
       begin
         if (sFields <> '') then
           sFields .= ', ';
         FldName = ibec_Trim(IdxFields[0]);
         FldNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(FldName, '"'), ibec_AnsiUpperCase(FldName));
         sFields .= FldNameFmt;
       end;

       ibec_UseConnection(DestDB);
       IDXExists = null;
       select 1 from rdb$indices where rdb$index_name = :IdxName into :IDXExists;
       if (IDXExists is not null) then
       begin
         IDXNameBase = 'IDX_' + DestTableName + '_';
         IDXNameSuff = 0;
         IDXExists = 1;
         while (IDXExists is not null) do
         begin
           IDXNameSuff = IDXNameSuff + 1;
           IdxName = IDXNameBase + ibec_Cast(IDXNameSuff, __typeString);
           IDXExists = null;
           select 1 from rdb$indices where rdb$index_name = :IdxName into :IDXExists;
         end;
         IdxNameFmt = ibec_IIF(DestDBSQLDialect = 3, ibec_QuotedStr(IdxName, '"'), ibec_AnsiUpperCase(IdxName));
       end; 

       CreateIndexStmt = 'CREATE ' + IdxUnique + IdxType + 'INDEX ' + IdxNameFmt + ' ON ' +
                         DestTableNameFmt;
       if (IdxExpression is not null) then
         CreateIndexStmt .= ' COMPUTED BY (' + IdxExpression + ')';
       else
         CreateIndexStmt .= ' (' + sFields + ')';

       ibec_UseConnection(DestDB);
       try
         ibec_Progress('    ' + IdxNameFmt + '...');
         execute statement :CreateIndexStmt;
         commit;
         if (IdxActive <> '') then
         begin
           ibec_Progress(BS + ' Making inactive...');
           execute statement 'ALTER INDEX ' || IdxNameFmt || ' INACTIVE';
           commit;
         end;
         ibec_Progress(Success);
       except
         ibec_Progress(Failed);
         rollback;
       end;
       ibec_UseConnection(SrcDB);
     end;
   end;

 finally
   if (SrcDB is not null) then
   begin
     ibec_Progress('Closing connection to ' + SrcDBConnStr + '...');
     ibec_CloseConnection(SrcDB);
   end;
   if (DestDB is not null) then
   begin
     ibec_Progress('Closing connection to ' + DestDBConnStr + '...');
     ibec_CloseConnection(DestDB);
   end;
   Time2 = ibec_GetTickCount();
   sTime = ibec_div((Time2 - Time1), 1000) || '.' ||ibec_mod((Time2 - Time1), 1000);
   ibec_Progress('Finished.');
   ibec_Progress('Total time spent: ' || sTime || ' seconds');
   ibec_Progress('That''s all, folks!');
 end;
end