ActiveSyncSource::Databases ActiveSyncSource::getDatabases() { Databases result; // empty string always selects the default database result.push_back(Database("", "", true)); return result; }
/** Выполнить сложную работу по уничтожению объектов заранее. */ void shutdown() { if (shutdown_called) return; shutdown_called = true; query_log.reset(); /** В этот момент, некоторые таблицы могут иметь потоки, которые блокируют наш mutex. * Чтобы корректно их завершить, скопируем текущий список таблиц, * и попросим их всех закончить свою работу. * Потом удалим все объекты с таблицами. */ Databases current_databases; { Poco::ScopedLock<Poco::Mutex> lock(mutex); current_databases = databases; } for (auto & database : current_databases) database.second->shutdown(); { Poco::ScopedLock<Poco::Mutex> lock(mutex); databases.clear(); } }
BlockInputStreams StorageSystemColumns::read( const Names & column_names, ASTPtr query, const Context & context, const Settings & settings, QueryProcessingStage::Enum & processed_stage, const size_t max_block_size, const unsigned threads) { check(column_names); processed_stage = QueryProcessingStage::FetchColumns; Block block; std::map<std::pair<std::string, std::string>, StoragePtr> storages; { Databases databases = context.getDatabases(); /// Добавляем столбец database. ColumnPtr database_column = std::make_shared<ColumnString>(); for (const auto & database : databases) database_column->insert(database.first); block.insert(ColumnWithTypeAndName(database_column, std::make_shared<DataTypeString>(), "database")); /// Отфильтруем блок со столбцом database. VirtualColumnUtils::filterBlockWithQuery(query, block, context); if (!block.rows()) return BlockInputStreams(); database_column = block.getByName("database").column; size_t rows = database_column->size(); /// Добавляем столбец table. ColumnPtr table_column = std::make_shared<ColumnString>(); IColumn::Offsets_t offsets(rows); for (size_t i = 0; i < rows; ++i) { const std::string database_name = (*database_column)[i].get<std::string>(); const DatabasePtr database = databases.at(database_name); offsets[i] = i ? offsets[i - 1] : 0; for (auto iterator = database->getIterator(); iterator->isValid(); iterator->next()) { const String & table_name = iterator->name(); storages.emplace(std::piecewise_construct, std::forward_as_tuple(database_name, table_name), std::forward_as_tuple(iterator->table())); table_column->insert(table_name); offsets[i] += 1; } } for (size_t i = 0; i < block.columns(); ++i) { ColumnPtr & column = block.getByPosition(i).column; column = column->replicate(offsets); } block.insert(ColumnWithTypeAndName(table_column, std::make_shared<DataTypeString>(), "table")); } /// Отфильтруем блок со столбцами database и table. VirtualColumnUtils::filterBlockWithQuery(query, block, context); if (!block.rows()) return BlockInputStreams(); ColumnPtr filtered_database_column = block.getByName("database").column; ColumnPtr filtered_table_column = block.getByName("table").column; /// Составляем результат. ColumnPtr database_column = std::make_shared<ColumnString>(); ColumnPtr table_column = std::make_shared<ColumnString>(); ColumnPtr name_column = std::make_shared<ColumnString>(); ColumnPtr type_column = std::make_shared<ColumnString>(); ColumnPtr default_type_column = std::make_shared<ColumnString>(); ColumnPtr default_expression_column = std::make_shared<ColumnString>(); ColumnPtr bytes_column = std::make_shared<ColumnUInt64>(); size_t rows = filtered_database_column->size(); for (size_t i = 0; i < rows; ++i) { const std::string database_name = (*filtered_database_column)[i].get<std::string>(); const std::string table_name = (*filtered_table_column)[i].get<std::string>(); NamesAndTypesList columns; ColumnDefaults column_defaults; std::unordered_map<String, size_t> column_sizes; { StoragePtr storage = storages.at(std::make_pair(database_name, table_name)); IStorage::TableStructureReadLockPtr table_lock; try { table_lock = storage->lockStructure(false); } catch (const Exception & e) { /** There are case when IStorage::drop was called, * but we still own the object. * Then table will throw exception at attempt to lock it. * Just skip the table. */ if (e.code() == ErrorCodes::TABLE_IS_DROPPED) continue; else throw; } columns = storage->getColumnsList(); columns.insert(std::end(columns), std::begin(storage->alias_columns), std::end(storage->alias_columns)); column_defaults = storage->column_defaults; /** Данные о размерах столбцов для таблиц семейства MergeTree. * NOTE: В дальнейшем можно сделать интерфейс, позволяющий получить размеры столбцов у IStorage. */ if (auto storage_concrete = dynamic_cast<StorageMergeTree *>(storage.get())) { column_sizes = storage_concrete->getData().getColumnSizes(); } else if (auto storage_concrete = dynamic_cast<StorageReplicatedMergeTree *>(storage.get())) { column_sizes = storage_concrete->getData().getColumnSizes(); auto unreplicated_data = storage_concrete->getUnreplicatedData(); if (unreplicated_data) { auto unreplicated_column_sizes = unreplicated_data->getColumnSizes(); for (const auto & name_size : unreplicated_column_sizes) column_sizes[name_size.first] += name_size.second; } } } for (const auto & column : columns) { database_column->insert(database_name); table_column->insert(table_name); name_column->insert(column.name); type_column->insert(column.type->getName()); { const auto it = column_defaults.find(column.name); if (it == std::end(column_defaults)) { default_type_column->insertDefault(); default_expression_column->insertDefault(); } else { default_type_column->insert(toString(it->second.type)); default_expression_column->insert(queryToString(it->second.expression)); } } { const auto it = column_sizes.find(column.name); if (it == std::end(column_sizes)) bytes_column->insertDefault(); else bytes_column->insert(it->second); } } } block.clear(); block.insert(ColumnWithTypeAndName(database_column, std::make_shared<DataTypeString>(), "database")); block.insert(ColumnWithTypeAndName(table_column, std::make_shared<DataTypeString>(), "table")); block.insert(ColumnWithTypeAndName(name_column, std::make_shared<DataTypeString>(), "name")); block.insert(ColumnWithTypeAndName(type_column, std::make_shared<DataTypeString>(), "type")); block.insert(ColumnWithTypeAndName(default_type_column, std::make_shared<DataTypeString>(), "default_type")); block.insert(ColumnWithTypeAndName(default_expression_column, std::make_shared<DataTypeString>(), "default_expression")); block.insert(ColumnWithTypeAndName(bytes_column, std::make_shared<DataTypeUInt64>(), "bytes")); return BlockInputStreams{ 1, std::make_shared<OneBlockInputStream>(block) }; }
EvolutionSyncSource::Databases EvolutionContactSource::getDatabases() { ESourceList *sources = NULL; #ifdef USE_EBOOK_CLIENT if (!e_book_client_get_sources(&sources, NULL)) { #else if (!e_book_get_addressbooks(&sources, NULL)) { #endif SyncContext::throwError("unable to access address books"); } Databases secondary; Databases result; for (GSList *g = e_source_list_peek_groups (sources); g; g = g->next) { ESourceGroup *group = E_SOURCE_GROUP (g->data); for (GSList *s = e_source_group_peek_sources (group); s; s = s->next) { ESource *source = E_SOURCE (s->data); eptr<char> uri(e_source_get_uri(source)); string uristr; if (uri) { uristr = uri.get(); } Database entry(e_source_peek_name(source), uristr, false); if (boost::starts_with(uristr, "couchdb://")) { // Append CouchDB address books at the end of the list, // otherwise preserving the order of address books. // // The reason is Moblin Bugzilla #7877 (aka CouchDB // feature request #479110): the initial release of // evolution-couchdb in Ubuntu 9.10 is unusable because // it does not support the REV property. // // Reordering the entries ensures that the CouchDB // address book is not used as the default database by // SyncEvolution, as it happened in Ubuntu 9.10. // Users can still pick it intentionally via // "evolutionsource". secondary.push_back(entry); } else { result.push_back(entry); } } } result.insert(result.end(), secondary.begin(), secondary.end()); // No results? Try system address book (workaround for embedded Evolution Dataserver). if (!result.size()) { #ifdef USE_EBOOK_CLIENT EBookClientCXX book; const char *name; name = "<<system>>"; book = EBookClientCXX::steal(e_book_client_new_system (NULL)); if (!book) { name = "<<default>>"; book = EBookClientCXX::steal(e_book_client_new_default (NULL)); } if (book) { const char *uri = e_client_get_uri (E_CLIENT ((EBookClient*)book)); result.push_back(Database(name, uri, true)); } #else eptr<EBook, GObject> book; GErrorCXX gerror; const char *name; name = "<<system>>"; book = e_book_new_system_addressbook (gerror); gerror.clear(); if (!book) { name = "<<default>>"; book = e_book_new_default_addressbook (gerror); } if (book) { const char *uri = e_book_get_uri (book); result.push_back(Database(name, uri, true)); } #endif } else { // the first DB found is the default result[0].m_isDefault = true; } return result; } #ifdef USE_EBOOK_CLIENT static void handle_error_cb (EClient */*client*/, const gchar *error_msg, gpointer user_data) { EvolutionContactSource *that = static_cast<EvolutionContactSource *>(user_data); SE_LOG_ERROR(that, NULL, "%s", error_msg); }