/// <summary>
 /// Выполняет изменение структуры данных
 /// </summary>
 protected UpdateSchemaResult ProcessUpdateSchema(UpdateSchemaMode mode, bool skipIfFirstTableNotExists, params DBTableEx[] tables)
 {
     // Конвертация исходных таблиц в таблицы с информацией о констрейнтах
     ICollection collectedTables = CollectTablesToCreate(tables);
     Hashtable createdTables = new Hashtable();
     Hashtable recreateSafe = new Hashtable();
     // Проверка существования первой таблицы
     if (skipIfFirstTableNotExists && collectedTables.Count > 0)
     {
         IEnumerator te = tables.GetEnumerator();
         IEnumerator ce = collectedTables.GetEnumerator();
         te.MoveNext();
         ce.MoveNext();
         if (object.ReferenceEquals(te.Current, ce.Current))
             return UpdateSchemaResult.FirstTableNotExists;
     }
     // Изменение структуры данных
     if (CanCreateSchema)
         BeginTransaction();
     try
     {
         // Создание таблиц
         if (!CanCreateSchema && collectedTables.Count > 0)
         {
             IEnumerator ce = collectedTables.GetEnumerator();
             ce.MoveNext();
             throw new SchemaCorrectionNeededException("Table '" + ComposeSafeTableName(((DBTable)ce.Current).Name) + "' not found");
         }
         else
         {
             foreach (DBTableEx table in collectedTables)
             {
                 if (table.IsView || table.IsCustom) continue;
                 CreateTable(table);
                 CreateSequence(table);
                 CreatePrimaryKey(table);
                 createdTables[table] = table;
                 recreateSafe[table] = table;
             }
         }
         // Модификация таблиц
         Hashtable realTables = new Hashtable();
         foreach (DBTableEx table in tables)
         {
             // Пропуск представлений, уже созданных таблиц
             // и таблиц с настраиваемой модификацией данных
             if (table.IsView || createdTables[table] != null || table.IsCustom) continue;
             DBTableEx realTable = new DBTableEx(table.Name);
             bool collectIndexes = false;
             bool collectFKs = false;
             bool collectConstraints = false;
             if (CanCreateSchema)
             {
                 collectIndexes = table.Indexes.Count > 0;
                 collectFKs = table.ForeignKeys.Count > 0;
                 collectConstraints = table.Constraints.Exists(c => c is DBCriteriaConstraint);
                 if (NeedsIndexForForeignKey)
                     collectIndexes = collectIndexes || collectFKs;
             }
             GetTableSchema(realTable, collectIndexes, collectFKs, collectConstraints);
             realTables[table] = realTable;
             // Новые колонки
             foreach (DBColumn column in table.Columns)
             {
                 // Создание колонки
                 DBColumn realColumn = FindColumnByName(realTable, column);
                 if (realColumn == null)
                 {
                     if (!CanCreateSchema) throw new SchemaCorrectionNeededException(string.Format(
                         "Column '{0}' not found in table '{1}'", ComposeSafeColumnName(column.Name), ComposeSafeTableName(table.Name)));
                     CreateColumn(table, column);
                     recreateSafe[table] = table;
                 }
                 // Изменение типа колонки
                 if (realColumn != null && GetDBTableColumnType(table, column) != realColumn.DBTypeName)
                 {
                     if (!CanCreateSchema) throw new SchemaCorrectionNeededException(string.Format(
                         "Type of column '{0}' in table '{1}' is changed to {2}", ComposeSafeColumnName(column.Name), ComposeSafeTableName(table.Name), GetSqlCreateColumnType(table, column)));
                     ChangeColumn(table, realColumn, column);
                     recreateSafe[table] = table;
                 }
                 // Изменение констрейнта обязательности
                 bool notNull = table.ColumnIsNotNull(column);
                 if (realColumn != null && notNull != realTable.ColumnIsNotNull(realColumn))
                 {
                     ChangeColumnNullable(table, column, notNull);
                     recreateSafe[table] = table;
                 }
             }
             // Старые колонки
             if (CanCreateSchema && (updateOptions & UpdateSchemaOptions.UnsafeChanges) != 0)
             {
                 List<DBColumn> realColumns = new List<DBColumn>(realTable.Columns);
                 foreach (DBColumn column in table.Columns)
                 {
                     // Поиск по колонкам заданной таблицы table, чтобы учесть преобразование имен колонок
                     DBColumn realColumn = FindColumnByName(realTable, column);
                     if (realColumn != null) realColumns.Remove(realColumn);
                 }
                 foreach (DBColumn realColumn in realColumns)
                     DeleteColumn(realTable, realColumn);
             }
             // Последовательность для первичного ключа
             if (CanCreateSchema && GetTableSequenceColumn(table) != null && !GetSequence(table))
             {
                 CreateSequence(table);
                 recreateSafe[table] = table;
             }
             // Первичный ключ
             if (CanCreateSchema && table.PrimaryKey != null && realTable.PrimaryKey == null)
             {
                 CreatePrimaryKey(table);
                 recreateSafe[table] = table;
             }
             // Невалидные или отсутствующие представления и пакеты
             if (recreateSafe[table] == null && !GetValidSafeObjects(table))
                 recreateSafe[table] = table;
         }
         // Индексы, ссылки, констрейнты
         if (CanCreateSchema)
         {
             foreach (DBTableEx table in tables)
             {
                 // Новая или измененная таблица
                 DBTableEx realTable = (DBTableEx)realTables[table];
                 if (realTable == null && createdTables[table] != null)
                 {
                     realTable = new DBTableEx(table.Name);
                     realTable.Columns.AddRange(table.Columns);
                 }
                 if (realTable == null) continue;
                 // Индексы
                 foreach (DBIndex index in table.Indexes)
                 {
                     if (!IsIndexExists(realTable, index))
                     {
                         CreateIndex(table, index);
                         realTable.AddIndex(index);
                     }
                 }
                 // Индексы ссылок
                 if (NeedsIndexForForeignKey)
                 {
                     foreach (DBForeignKey fk in table.ForeignKeys)
                     {
                         DBIndex index = new DBIndex(fk.Columns, false);
                         if (!IsIndexExists(realTable, index) &&
                             (table.PrimaryKey == null || (table.PrimaryKey != null && !IsColumnsEqual(table.PrimaryKey.Columns, index.Columns))))
                         {
                             CreateIndex(table, index);
                             realTable.AddIndex(index);
                         }
                     }
                 }
                 // Ссылки
                 foreach (DBForeignKey fk in table.ForeignKeys)
                 {
                     if (!IsForeignKeyExists(realTable, fk))
                         CreateForeignKey(table, fk);
                 }
                 // Констрейнты
                 foreach (DBCriteriaConstraint cons in table.Constraints.Where(c => c is DBCriteriaConstraint))
                 {
                     string expression = OracleCheckConstraintGenerator.GenerateExpression(this, cons.Criteria);
                     if (expression != null && !realTable.Constraints.Exists(
                         c => c is DBCheckConstraint && ((DBCheckConstraint)c).Condition == expression))
                         CreateConstraint(table, expression);
                     if (expression == null) //&& !IsConstraintExists - сложные констрейнты реализованы в пакетах
                         recreateSafe[table] = table;
                 }
                 if (table.Constraints.Exists(c => !(c is DBCriteriaConstraint || c is DBNotNullConstraint)))
                     recreateSafe[table] = table;
             }
         }
         // Представления и пакеты
         if (CanCreateSchema)
         {
             bool allSafeObjects = (updateOptions & UpdateSchemaOptions.AllSafeObjects) == UpdateSchemaOptions.AllSafeObjects;
             foreach (DBTableEx table in tables)
             {
                 if (table.IsView || table.IsCustom || (!allSafeObjects && recreateSafe[table] == null)) continue;
                 CreateOrReplaceView(table);
                 CreateOrReplacePackage(table);
             }
         }
         // Завершение транзакции
         if (CanCreateSchema)
             CommitTransaction();
     }
     catch
     {
         if (CanCreateSchema)
             RollbackTransaction();
         throw;
     }
     return UpdateSchemaResult.SchemaExists;
 }
 /// <contentfrom cref="ISqlDataStoreSafe.UpdateSchema" />
 public UpdateSchemaResult UpdateSchema(UpdateSchemaMode mode, bool dontCreateIfFirstTableNotExist, params DBTable[] tables)
 {
     using (IDisposable c1 = new PerformanceCounters.QueueLengthCounter(PerformanceCounters.SqlDataStoreTotalRequests, PerformanceCounters.SqlDataStoreTotalQueue, PerformanceCounters.SqlDataStoreSchemaUpdateRequests, PerformanceCounters.SqlDataStoreSchemaUpdateQueue))
     {
         lock (SyncRoot)
         {
             return ProcessUpdateSchema(mode, dontCreateIfFirstTableNotExist, tables);
         }
     }
 }
        /// <summary>
        /// Выполняет изменение структуры данных с возможностью записи скрипта
        /// </summary>
        protected UpdateSchemaResult ProcessUpdateSchema(UpdateSchemaMode mode, bool skipIfFirstTableNotExists, params DBTable[] tables)
        {
            // Изменение структуры реальной базы данных
            SetCommandAdapterParameters();
            UpdateSchemaResult result;
            try
            {
                result = ProcessUpdateSchema(mode, skipIfFirstTableNotExists, ConvertTables(tables));

                // Небезопасные команды изменения структуры, записываемые в комментариях в отдельном блоке
                if (scriptMode && scriptWriter != null && scriptUnsafe != null && scriptUnsafe.Length > 0)
                {
                    scriptWriter.WriteLine("/* Unsafe changes");
                    scriptWriter.WriteLine(scriptUnsafe.ToString());
                    scriptWriter.WriteLine("*/");
                }
            }
            finally
            {
                FreeCommandAdapterParameters();
            }
            if (scriptMode && scriptPath != null && scriptCommands > 0)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Please execute the script and press <Enter>.");
                Console.ResetColor();
                Console.ReadLine();
            }
            return result;
        }