/// <summary>
        /// Выполняет указанную команду администрирования безопасности
        /// </summary>
        /// <param name="statement">Команда администрирования безопасности</param>
        /// <returns>Объекты безопасности в результате выполнения указанной команды в зависимости от типа команды <see cref="AdminSecurityOperations"/></returns>
        protected virtual IEnumerable<SecurityObject> AdminSecurity(SecurityStatement statement)
        {
            // Команда запроса объектов администрирования
            if (statement.Operation == AdminSecurityOperations.GetRolePrivileges ||
                statement.Operation == AdminSecurityOperations.GetCurrentPrivileges ||
                statement.Operation == AdminSecurityOperations.GetTable)
            {
                List<SecurityObject> result = new List<SecurityObject>();
                SecurityObjectTypes objectType = statement.LeftOperand != null ? statement.LeftOperand.ObjectType : SecurityObjectTypes.UserInfo;
                string objectName = statement.LeftOperand != null ? statement.LeftOperand.ObjectName : null;
                SecurityObject tableSecurity = null;
                switch (statement.Operation)
                {
                    // Запрос привилегий роли
                    case AdminSecurityOperations.GetRolePrivileges:
                        foreach (SelectStatementResultRow row in SelectSimple(
                            GetUserPrivilege("dba_role_privs") ?
                            "select owner||'.'||table_name table_name from dba_tab_privs where grantee = :pRole" :
                            "select owner||'.'||table_name table_name from role_tab_privs where role = :pRole",
                            ":pRole", objectName, "table_name").Rows)
                            if (GetTablePrivilege((string)row.Values[0], out tableSecurity)) result.Add(tableSecurity);
                        break;
                    // Запрос текущих привилегий пользователя
                    case AdminSecurityOperations.GetCurrentPrivileges:
                        foreach (SelectStatementResultRow row in SelectData(new Query(
                            "select owner||'.'||view_name from all_views where owner <> 'SYS' and owner <> 'SYSTEM' and view_name like 'VW:_%' escape ':' union all " +
                            "select owner||'.'||object_name from all_procedures where owner <> 'SYS' and owner <> 'SYSTEM' and object_name like 'P:_%' escape ':'")).Rows)
                            if (GetTablePrivilege((string)row.Values[0], out tableSecurity)) result.Add(tableSecurity);
                        break;
                    // Запрос таблицы для объектов
                    case AdminSecurityOperations.GetTable:
                        // Таблица пользователей (Id, IsActive, IsExpired, Locked, Created)
                        if (objectType == SecurityObjectTypes.User && statement.RightOperand == null)
                        {
                            DBColumn username = new DBColumn("username", true, null, 30, DBColumnType.String);
                            DBColumn isActive = new DBColumn("is_active", false, null, 0, DBColumnType.Boolean);
                            DBColumn isExpired = new DBColumn("is_expired", false, null, 0, DBColumnType.Boolean);
                            DBColumn locked = new DBColumn("lock_date", false, null, 0, DBColumnType.DateTime);
                            DBColumn created = new DBColumn("created", false, null, 0, DBColumnType.DateTime);
                            DBColumn nullValue = new DBCriteriaColumn("null", false, null, 0, DBColumnType.String, new OperandValue(null));
                            tableSecurity =
                                GetSecurityTable("(select username, " +
                                    "cast(decode(instr(account_status,'LOCKED'),0,1,0) as number(1)) is_active, " +
                                    "cast(decode(instr(account_status,'EXPIRED'),0,0,1) as number(1)) is_expired, " +
                                    "lock_date, created from dba_users)",
                                    new string[] { "dba_users" }, username, isActive, isExpired, locked, created) ??
                                // isActive, isExpired не имеет смысла брать из user_users
                                GetSecurityTable("all_users", null, username, nullValue, nullValue, nullValue, created) ??
                                GetSecurityTable("user_users", null, username, nullValue, nullValue, locked, created);
                        }
                        // Таблица ролей (Id)
                        else if (objectType == SecurityObjectTypes.Role && statement.RightOperand == null)
                        {
                            tableSecurity =
                                GetSecurityTable("dba_roles", "role") ??
                                // Выделена в запрос, чтобы не путать с использованием в таблице ролей пользователей с тремя полями
                                GetSecurityTable("(select granted_role from user_role_privs)", "granted_role", new string[] { "user_role_privs" });
                        }
                        // Таблица иерархии ролей (Parent, Child)
                        else if (objectType == SecurityObjectTypes.Role && statement.RightOperand != null &&
                            statement.RightOperand.ObjectType == SecurityObjectTypes.Role)
                        {
                            tableSecurity =
                                GetSecurityTable("(select grantee, granted_role from dba_role_privs, dba_roles where grantee = role)",
                                    "grantee", "granted_role", new string[] { "dba_role_privs", "dba_roles" }) ??
                                GetSecurityTable("role_role_privs", "role", "granted_role");
                        }
                        // Таблица ролей пользователей (Parent, Child)
                        else if (statement.Operation == AdminSecurityOperations.GetTable && statement.RightOperand != null && (
                            (statement.LeftOperand.ObjectType == SecurityObjectTypes.Role && statement.RightOperand.ObjectType == SecurityObjectTypes.User) ||
                            (statement.LeftOperand.ObjectType == SecurityObjectTypes.User && statement.RightOperand.ObjectType == SecurityObjectTypes.Role)))
                        {
                            tableSecurity =
                                GetSecurityTable("(select grantee, granted_role from dba_role_privs, dba_users where grantee = username)",
                                    "grantee", "granted_role", new string[] { "dba_role_privs", "dba_users" }) ??
                                GetSecurityTable("user_role_privs", "username", "granted_role");
                        }
                        if (tableSecurity != null) result.Add(tableSecurity);
                        break;
                }
                return result;
            }

            // Команда модификации объектов администрирования
            foreach (string sql in new AdminSecurityGenerator(statement, this).GenerateSqlCommands())
            {
                IDbCommand command = CreateCommand();
                command.CommandText = sql;
                try
                {
                    command.ExecuteNonQuery();
                    Trace.WriteLineIf(xpoSwitch.TraceInfo, sql, "AdminSecurity");
                }
                catch (Exception e)
                {
                    throw WrapException(e, command);
                }
            }
            return null;
        }
 /// <summary>
 /// Конструктор
 /// </summary>
 /// <param name="statement">Команда администрирования безопасности</param>
 /// <param name="formatter">Представитель форматирования sql-запросов с безопасным доступом к данным</param>
 public AdminSecurityGenerator(SecurityStatement statement, ISecuredSqlGeneratorFormatter formatter)
 {
     this.root = statement;
     this.formatter = formatter;
 }