String getTableDefinitionFromCreateQuery(const ASTPtr & query) { ASTPtr query_clone = query->clone(); ASTCreateQuery & create = typeid_cast<ASTCreateQuery &>(*query_clone.get()); /// We remove everything that is not needed for ATTACH from the query. create.attach = true; create.database.clear(); create.as_database.clear(); create.as_table.clear(); create.if_not_exists = false; create.is_populate = false; /// For views it is necessary to save the SELECT query itself, for the rest - on the contrary if (!create.is_view && !create.is_materialized_view) create.select = nullptr; create.format = nullptr; create.out_file = nullptr; std::ostringstream statement_stream; formatAST(create, statement_stream, false); statement_stream << '\n'; return statement_stream.str(); }
void CollectAliases::dump(WriteBuffer & out) const { /// For need of tests, we need to dump result in some fixed order. std::vector<Aliases::const_iterator> vec; vec.reserve(aliases.size()); for (auto it = aliases.begin(); it != aliases.end(); ++it) vec.emplace_back(it); std::sort(vec.begin(), vec.end(), [](const auto & a, const auto & b) { return a->first < b->first; }); for (const auto & it : vec) { writeProbablyBackQuotedString(it->first, out); writeCString(" -> ", out); switch (it->second.kind) { case Kind::Expression: writeCString("(expression) ", out); break; case Kind::Table: writeCString("(table) ", out); break; case Kind::ArrayJoin: writeCString("(array join) ", out); break; } std::stringstream formatted_ast; formatAST(*it->second.node, formatted_ast, 0, false, true); writeString(formatted_ast.str(), out); writeChar('\n', out); } }
void AnalyzeColumns::dump(WriteBuffer & out) const { /// For need of tests, we need to dump result in some fixed order. std::vector<Columns::const_iterator> vec; vec.reserve(columns.size()); for (auto it = columns.begin(); it != columns.end(); ++it) vec.emplace_back(it); std::sort(vec.begin(), vec.end(), [](const auto & a, const auto & b) { return a->first < b->first; }); for (const auto & it : vec) { writeString(it->first, out); writeCString(" -> ", out); writeProbablyBackQuotedString(it->second.name_in_table, out); writeCString(" ", out); writeProbablyBackQuotedString(it->second.data_type->getName(), out); const auto & table = it->second.table; writeCString(". Database name: ", out); if (table.database_name.empty()) writeCString("(none)", out); else writeProbablyBackQuotedString(table.database_name, out); writeCString(". Table name: ", out); if (table.table_name.empty()) writeCString("(none)", out); else writeProbablyBackQuotedString(table.table_name, out); writeCString(". Alias: ", out); if (table.alias.empty()) writeCString("(none)", out); else writeProbablyBackQuotedString(table.alias, out); writeCString(". Storage: ", out); if (!table.storage) writeCString("(none)", out); else writeProbablyBackQuotedString(table.storage->getName(), out); writeCString(". AST: ", out); if (it->second.node) { std::stringstream formatted_ast; formatAST(*it->second.node, formatted_ast, false, true); writeString(formatted_ast.str(), out); } else writeCString("(none)", out); writeChar('\n', out); } }
static void processImpl(const ASTPtr & ast, CollectAliases::Aliases & aliases, CollectAliases::Kind kind, size_t keep_kind_for_depth) { String alias = ast->tryGetAlias(); if (!alias.empty()) { auto it_inserted = aliases.emplace(alias, CollectAliases::AliasInfo(ast, kind)); if (!it_inserted.second && ast->getTreeHash() != it_inserted.first->second.node->getTreeHash()) { std::stringstream message; message << "Different expressions with the same alias " << backQuoteIfNeed(alias) << ":\n"; formatAST(*it_inserted.first->second.node, message, 0, false, true); message << "\nand\n"; formatAST(*ast, message, 0, false, true); message << "\n"; throw Exception(message.str(), ErrorCodes::MULTIPLE_EXPRESSIONS_FOR_ALIAS); } } for (auto & child : ast->children) { if (typeid_cast<const ASTSelectQuery *>(child.get())) { /// Don't go into subqueries. } else if (typeid_cast<const ASTTableExpression *>(child.get())) { processImpl(child, aliases, CollectAliases::Kind::Table, 1); } else if (typeid_cast<const ASTArrayJoin *>(child.get())) { /// ASTArrayJoin -> ASTExpressionList -> element of expression AS alias processImpl(child, aliases, CollectAliases::Kind::ArrayJoin, 3); } else if (keep_kind_for_depth > 0) { processImpl(child, aliases, kind, keep_kind_for_depth - 1); } else { processImpl(child, aliases, CollectAliases::Kind::Expression, 0); } } }
String getTableDefinitionFromCreateQuery(const ASTPtr & query) { ASTPtr query_clone = query->clone(); ASTCreateQuery & create = typeid_cast<ASTCreateQuery &>(*query_clone.get()); /// Удаляем из запроса всё, что не нужно для ATTACH. create.attach = true; create.database.clear(); create.as_database.clear(); create.as_table.clear(); create.if_not_exists = false; create.is_populate = false; String engine = typeid_cast<ASTFunction &>(*create.storage).name; /// Для engine VIEW необходимо сохранить сам селект запрос, для остальных - наоборот if (engine != "View" && engine != "MaterializedView") create.select = nullptr; std::ostringstream statement_stream; formatAST(create, statement_stream, 0, false); statement_stream << '\n'; return statement_stream.str(); }
void TypeAndConstantInference::dump(WriteBuffer & out) const { /// For need of tests, we need to dump result in some fixed order. std::vector<Info::const_iterator> vec; vec.reserve(info.size()); for (auto it = info.begin(); it != info.end(); ++it) vec.emplace_back(it); std::sort(vec.begin(), vec.end(), [](const auto & a, const auto & b) { return a->first < b->first; }); for (const auto & it : vec) { writeString(it->first, out); writeCString(" -> ", out); writeString(it->second.data_type->getName(), out); if (it->second.is_constant_expression) { writeCString(" = ", out); String value = applyVisitor(FieldVisitorToString(), it->second.value); writeString(value, out); } writeCString(". AST: ", out); if (!it->second.node) writeCString("(none)", out); else { std::stringstream formatted_ast; formatAST(*it->second.node, formatted_ast, false, true); writeString(formatted_ast.str(), out); } writeChar('\n', out); } }
BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create) { if (!create.cluster.empty()) return executeDDLQueryOnCluster(query_ptr, context, {create.database}); String database_name = create.database; if (create.if_not_exists && context.isDatabaseExist(database_name)) return {}; String database_engine_name; if (!create.storage) { database_engine_name = "Ordinary"; /// Default database engine. auto engine = std::make_shared<ASTFunction>(); engine->name = database_engine_name; auto storage = std::make_shared<ASTStorage>(); storage->set(storage->engine, engine); create.set(create.storage, storage); } else { const ASTStorage & storage = *create.storage; const ASTFunction & engine = *storage.engine; /// Currently, there are no database engines, that support any arguments. if (engine.arguments || engine.parameters || storage.partition_by || storage.order_by || storage.sample_by || storage.settings) { std::stringstream ostr; formatAST(storage, ostr, false, false); throw Exception("Unknown database engine: " + ostr.str(), ErrorCodes::UNKNOWN_DATABASE_ENGINE); } database_engine_name = engine.name; } String database_name_escaped = escapeForFileName(database_name); /// Create directories for tables metadata. String path = context.getPath(); String metadata_path = path + "metadata/" + database_name_escaped + "/"; Poco::File(metadata_path).createDirectory(); DatabasePtr database = DatabaseFactory::get(database_engine_name, database_name, metadata_path, context); /// Will write file with database metadata, if needed. String metadata_file_tmp_path = path + "metadata/" + database_name_escaped + ".sql.tmp"; String metadata_file_path = path + "metadata/" + database_name_escaped + ".sql"; bool need_write_metadata = !create.attach; if (need_write_metadata) { create.attach = true; create.if_not_exists = false; std::ostringstream statement_stream; formatAST(create, statement_stream, false); statement_stream << '\n'; String statement = statement_stream.str(); /// Exclusive flag guarantees, that database is not created right now in another thread. WriteBufferFromFile out(metadata_file_tmp_path, statement.size(), O_WRONLY | O_CREAT | O_EXCL); writeString(statement, out); out.next(); if (context.getSettingsRef().fsync_metadata) out.sync(); out.close(); } try { context.addDatabase(database_name, database); if (need_write_metadata) Poco::File(metadata_file_tmp_path).renameTo(metadata_file_path); database->loadTables(context, thread_pool, has_force_restore_data_flag); } catch (...) { if (need_write_metadata) Poco::File(metadata_file_tmp_path).remove(); throw; } return {}; }
String queryToString(const IAST & query) { std::ostringstream out; formatAST(query, out, false, true); return out.str(); }
void InterpreterCreateQuery::createDatabase(ASTCreateQuery & create) { String database_name = create.database; if (create.if_not_exists && context.isDatabaseExist(database_name)) return; String database_engine_name; if (!create.storage) { database_engine_name = "Ordinary"; /// Движок баз данных по-умолчанию. auto func = std::make_shared<ASTFunction>(); func->name = database_engine_name; create.storage = func; } else { const ASTFunction & engine_id = typeid_cast<const ASTFunction &>(*create.storage); /// На данный момент, движков таблиц с аргументами не бывает. if (engine_id.arguments || engine_id.parameters) { std::stringstream ostr; formatAST(*create.storage, ostr, 0, false, false); throw Exception("Unknown database engine: " + ostr.str(), ErrorCodes::UNKNOWN_DATABASE_ENGINE); } database_engine_name = engine_id.name; } String database_name_escaped = escapeForFileName(database_name); /// Создаём директории с данными и метаданными таблиц. String path = context.getPath(); String data_path = path + "data/" + database_name_escaped + "/"; String metadata_path = path + "metadata/" + database_name_escaped + "/"; Poco::File(metadata_path).createDirectory(); Poco::File(data_path).createDirectory(); DatabasePtr database = DatabaseFactory::get(database_engine_name, database_name, metadata_path, context); /// Записываем файл с метаданными, если нужно. String metadata_file_tmp_path = path + "metadata/" + database_name_escaped + ".sql.tmp"; String metadata_file_path = path + "metadata/" + database_name_escaped + ".sql"; bool need_write_metadata = !create.attach; if (need_write_metadata) { create.attach = true; create.if_not_exists = false; std::ostringstream statement_stream; formatAST(create, statement_stream, 0, false); statement_stream << '\n'; String statement = statement_stream.str(); /// Гарантирует, что база данных не создаётся прямо сейчас. WriteBufferFromFile out(metadata_file_tmp_path, statement.size(), O_WRONLY | O_CREAT | O_EXCL); writeString(statement, out); out.next(); out.sync(); out.close(); } try { context.addDatabase(database_name, database); if (need_write_metadata) Poco::File(metadata_file_tmp_path).renameTo(metadata_file_path); database->loadTables(context, thread_pool); } catch (...) { if (need_write_metadata) Poco::File(metadata_file_tmp_path).remove(); throw; } }