/// <summary>
 /// Получает метаданные указанной таблицы
 /// </summary>
 /// <param name="table">Таблица, в которой обновляются метаданные из базы данных</param>
 /// <param name="checkIndexes">Флаг сбора данных об индексах</param>
 /// <param name="checkForeignKeys">Флаг сбора данных о ссылках</param>
 /// <param name="checkConstraints">Флаг сбора данных о констрейнтах</param>
 public virtual void GetTableSchema(DBTableEx table, bool checkIndexes, bool checkForeignKeys, bool checkConstraints)
 {
     GetColumns(table);
     GetPrimaryKey(table);
     if (checkIndexes)
         GetIndexes(table);
     if (checkForeignKeys)
         GetForeignKeys(table);
     if (checkConstraints)
         GetConstraints(table);
 }
 private void GetConstraints(DBTableEx table)
 {
     string schemaName = ComposeSafeSchemaName(table.Name);
     string tableName = ComposeSafeTableName(table.Name);
     bool allOrUser = !string.IsNullOrEmpty(schemaName);
     string constraintsTable = allOrUser ? "all_constraints" : "user_constraints";
     string realSchemaName = allOrUser ? schemaName : CurrentUserName;
     Query query = new Query(
         // (Оба представления содержат поле owner)
         "select constraint_name from " + constraintsTable + " " +
         "where owner = :p0 and table_name = :p1 and constraint_type = 'C' and generated = 'USER NAME'",
         new QueryParameterCollection(new OperandValue(realSchemaName), new OperandValue(tableName)), new string[] { ":p0", ":p1" });
     SelectStatementResult data = SelectData(query);
     foreach (SelectStatementResultRow row in data.Rows)
     {
         string name = (string)row.Values[0];
         string condition = GetLong(new Query(
             "select search_condition from " + constraintsTable + " " +
             "where owner = :p0 and table_name = :p1 and constraint_name = :p2",
             new QueryParameterCollection(new OperandValue(realSchemaName),
                 new OperandValue(tableName), new OperandValue(name)), new string[] { ":p0", ":p1", ":p2" }));
         table.AddConstraint(new DBCheckConstraint(name, condition));
     }
 }
 // Получение таблицы для объекта безопасности
 private SecurityObject GetSecurityTable(string tableName, string[] privs, params DBColumn[] columns)
 {
     DBTableEx table = XPDictionaryInformer.Schema.FindTable(tableName);
     if (table == null && (privs == null ? GetUserPrivilege(tableName) : privs.All(priv => GetUserPrivilege(priv))))
     {
         table = new DBTableEx(tableName, columns);
         XPDictionaryInformer.RegisterTable(tableName, table);
     }
     if (table != null)
         return new SecurityObject(SecurityObjectTypes.Table, tableName);
     return null;
 }
 /// <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;
 }
 // Конвертация таблиц в таблицы с информацией о констрейнтах
 private DBTableEx[] ConvertTables(DBTable[] tables)
 {
     DBTableEx[] result = new DBTableEx[tables.Length];
     for (int i = 0; i < tables.Length; i++)
         result[i] = XPDictionaryInformer.TranslateAndGet(tables[i].Name);
     return result;
 }
        // Создать таблицу с дополнительными данными о констрейнтах
        private void CreateTable()
        {
            table = new DBTableEx(TableName, sourceInfo.Table);

            // Констрейнты (констрейнты базовой таблицы не наследуются)
            DBTableHelperEx.ProcessClassInfo(table, this);

            // Настраиваемая модификация данных
            if (IsCustomPersistent)
            {
                ICustomPersistent customPersistent = GetCustomPersistent(null);
                if (customPersistent == null)
                    throw new InvalidOperationException(string.Format(
                        "Custom persistent controller of class {0} is failed", FullName));
                table.CustomPersistent = customPersistent;
            }
        }
 /// <summary>
 /// Возвращает таблицу с дополнительными данными для ассоциации many-to-many
 /// </summary>
 /// <param name="property">Свойство, устанавливающее ассоциацию</param>
 /// <param name="tableName">Название таблицы</param>
 /// <returns>Таблица для ассоциации many-to-many</returns>
 public DBTableEx GetIntermediateTableEx(ReflectionPropertyInfo property, string tableName)
 {
     DBTableEx table = new DBTableEx(tableName, property.IntermediateClass.Table);
     if (IsCustomPersistent)
     {
         string associationName = ((AssociationAttribute)property.Attributes.First(a => a is AssociationAttribute)).Name;
         table.CustomPersistent = GetCustomPersistent(associationName);
     }
     return table;
 }
        /// <summary>
        /// Регистрация таблицы в схеме и в трансляции имен
        /// </summary>
        /// <param name="tableName">Исходное название таблицы</param>
        /// <param name="table">Регистрируемая таблица</param>
        internal static void RegisterTable(string tableName, DBTableEx table)
        {
            if (string.IsNullOrEmpty(tableName))
                throw new ArgumentNullException("tableName", "Register table invalid parameter");
            if (table == null)
                throw new ArgumentNullException("table", "Register table invalid parameter");

            AddTranslation(tableName, table.Name);
            Schema.Add(table.Name, new Lazy<DBTableEx>(() => table));
        }
        /// <summary>
        /// Переопределяет генерацию sql-команды
        /// </summary>
        /// <returns>Sql-команда</returns>
        protected override string InternalGenerateSql()
        {
            if (table == null) table = XPDictionaryInformer.TranslateAndGet(Root.TableName);
            string rootName = table.Name;
            schemaName = formatter.ComposeSafeSchemaName(rootName);
            tableName = formatter.ComposeSafeTableName(rootName);
            whereCondition = null;
            keyProcessed = new StringCollection();
            keyColumns = new StringBuilder();
            parametersVars = new StringBuilder();

            // Добавление
            if (Root is InsertStatement)
            {
                InsertStatement ins = (InsertStatement)Root;
                if (!ReferenceEquals(ins.IdentityParameter, null))
                {
                    identitiesByTag.ConsolidateIdentity(ins.IdentityParameter);
                    commandParams.Add(ins.IdentityParameter);
                    commandParamsNames.Add(formatterSequred.FormatProcedureParameter(ins.IdentityColumn));
                    keyProcessed.Add(ins.IdentityColumn);
                }
                PrepareParameters(false);
                return formatterSequred.FormatProcedureAdd(schemaName, tableName);
            }
            // Изменение
            else if (Root is UpdateStatement)
            {
                PrepareKey();
                PrepareParameters(true);
                return FormatBlock(formatterSequred.FormatProcedureEdit(schemaName, tableName));
            }
            // Удаление
            else if (Root is DeleteStatement)
            {
                PrepareKey();
                return FormatBlock(formatterSequred.FormatProcedureDelete(schemaName, tableName));
            }
            else
                new ArgumentException("Incorrect type of modification statement");
            return null;
        }
 /// <summary>
 /// Возвращает запрос модификации данных
 /// </summary>
 /// <param name="table">Таблица, данные которой модифицируются</param>
 /// <param name="node">Выражение модификации данных</param>
 /// <returns>Запрос модификации данных</returns>
 public Query GenerateSql(DBTableEx table, BaseStatement node)
 {
     this.table = table;
     return GenerateSql(node);
 }