public function loadActualSchema()
 {
     $databases = $this->getDatabaseNames();
     $conn = $this->getConn();
     $tables = queryfx_all($conn, 'SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_COLLATION
     FROM INFORMATION_SCHEMA.TABLES
     WHERE TABLE_SCHEMA IN (%Ls)', $databases);
     $database_info = queryfx_all($conn, 'SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
     FROM INFORMATION_SCHEMA.SCHEMATA
     WHERE SCHEMA_NAME IN (%Ls)', $databases);
     $database_info = ipull($database_info, null, 'SCHEMA_NAME');
     // Find databases which exist, but which the user does not have permission
     // to see.
     $invisible_databases = array();
     foreach ($databases as $database_name) {
         if (isset($database_info[$database_name])) {
             continue;
         }
         try {
             queryfx($conn, 'SHOW TABLES IN %T', $database_name);
         } catch (AphrontAccessDeniedQueryException $ex) {
             // This database exists, the user just doesn't have permission to
             // see it.
             $invisible_databases[] = $database_name;
         } catch (AphrontSchemaQueryException $ex) {
             // This database is legitimately missing.
         }
     }
     $sql = array();
     foreach ($tables as $table) {
         $sql[] = qsprintf($conn, '(TABLE_SCHEMA = %s AND TABLE_NAME = %s)', $table['TABLE_SCHEMA'], $table['TABLE_NAME']);
     }
     if ($sql) {
         $column_info = queryfx_all($conn, 'SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME,
         COLLATION_NAME, COLUMN_TYPE, IS_NULLABLE, EXTRA
       FROM INFORMATION_SCHEMA.COLUMNS
       WHERE (%Q)', '(' . implode(') OR (', $sql) . ')');
         $column_info = igroup($column_info, 'TABLE_SCHEMA');
     } else {
         $column_info = array();
     }
     // NOTE: Tables like KEY_COLUMN_USAGE and TABLE_CONSTRAINTS only contain
     // primary, unique, and foreign keys, so we can't use them here. We pull
     // indexes later on using SHOW INDEXES.
     $server_schema = new PhabricatorConfigServerSchema();
     $tables = igroup($tables, 'TABLE_SCHEMA');
     foreach ($tables as $database_name => $database_tables) {
         $info = $database_info[$database_name];
         $database_schema = id(new PhabricatorConfigDatabaseSchema())->setName($database_name)->setCharacterSet($info['DEFAULT_CHARACTER_SET_NAME'])->setCollation($info['DEFAULT_COLLATION_NAME']);
         $database_column_info = idx($column_info, $database_name, array());
         $database_column_info = igroup($database_column_info, 'TABLE_NAME');
         foreach ($database_tables as $table) {
             $table_name = $table['TABLE_NAME'];
             $table_schema = id(new PhabricatorConfigTableSchema())->setName($table_name)->setCollation($table['TABLE_COLLATION']);
             $columns = idx($database_column_info, $table_name, array());
             foreach ($columns as $column) {
                 if (strpos($column['EXTRA'], 'auto_increment') === false) {
                     $auto_increment = false;
                 } else {
                     $auto_increment = true;
                 }
                 $column_schema = id(new PhabricatorConfigColumnSchema())->setName($column['COLUMN_NAME'])->setCharacterSet($column['CHARACTER_SET_NAME'])->setCollation($column['COLLATION_NAME'])->setColumnType($column['COLUMN_TYPE'])->setNullable($column['IS_NULLABLE'] == 'YES')->setAutoIncrement($auto_increment);
                 $table_schema->addColumn($column_schema);
             }
             $key_parts = queryfx_all($conn, 'SHOW INDEXES FROM %T.%T', $database_name, $table_name);
             $keys = igroup($key_parts, 'Key_name');
             foreach ($keys as $key_name => $key_pieces) {
                 $key_pieces = isort($key_pieces, 'Seq_in_index');
                 $head = head($key_pieces);
                 // This handles string indexes which index only a prefix of a field.
                 $column_names = array();
                 foreach ($key_pieces as $piece) {
                     $name = $piece['Column_name'];
                     if ($piece['Sub_part']) {
                         $name = $name . '(' . $piece['Sub_part'] . ')';
                     }
                     $column_names[] = $name;
                 }
                 $key_schema = id(new PhabricatorConfigKeySchema())->setName($key_name)->setColumnNames($column_names)->setUnique(!$head['Non_unique'])->setIndexType($head['Index_type']);
                 $table_schema->addKey($key_schema);
             }
             $database_schema->addTable($table_schema);
         }
         $server_schema->addDatabase($database_schema);
     }
     foreach ($invisible_databases as $database_name) {
         $server_schema->addDatabase(id(new PhabricatorConfigDatabaseSchema())->setName($database_name)->setAccessDenied(true));
     }
     return $server_schema;
 }