mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 17:12:03 +00:00
getCreateTableQuery and getCreateDatabaseQuery [#CLICKHOUSE-3590]
This commit is contained in:
parent
cda51eb920
commit
d6e9d08d5e
@ -3,6 +3,11 @@
|
||||
#include <Interpreters/ExternalDictionaries.h>
|
||||
#include <Storages/StorageDictionary.h>
|
||||
#include <common/logger_useful.h>
|
||||
#include <Parsers/IAST.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <IO/Operators.h>
|
||||
#include <Parsers/ParserCreateQuery.h>
|
||||
#include <Parsers/parseQuery.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -158,11 +163,34 @@ time_t DatabaseDictionary::getTableMetadataModificationTime(
|
||||
return static_cast<time_t>(0);
|
||||
}
|
||||
|
||||
ASTPtr DatabaseDictionary::getCreateQuery(
|
||||
const Context &,
|
||||
const String &) const
|
||||
ASTPtr DatabaseDictionary::getCreateTableQuery(
|
||||
const Context & context,
|
||||
const String & table_name) const
|
||||
{
|
||||
throw Exception("There is no CREATE TABLE query for DatabaseDictionary tables", ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY);
|
||||
String query;
|
||||
{
|
||||
WriteBufferFromString buffer(query);
|
||||
|
||||
auto dictionary = context.getExternalDictionaries().getDictionary(table_name);
|
||||
auto names_and_types = StorageDictionary::getNamesAndTypes(dictionary->getStructure());
|
||||
buffer << "CREATE TABLE " << backQuoteIfNeed(name) << '.' << backQuoteIfNeed(table_name) << " (";
|
||||
buffer << StorageDictionary::generateNamesAndTypesDescription(names_and_types.begin(), names_and_types.end());
|
||||
buffer << ") Engine = Dictionary(" << backQuoteIfNeed(table_name) << ")";
|
||||
}
|
||||
|
||||
ParserCreateQuery parser;
|
||||
return parseQuery(parser, query.data(), query.data() + query.size(), "");
|
||||
}
|
||||
|
||||
ASTPtr DatabaseDictionary::getCreateDatabaseQuery(const Context & /*context*/) const
|
||||
{
|
||||
String query;
|
||||
{
|
||||
WriteBufferFromString buffer(query);
|
||||
buffer << "CREATE DATABASE " << backQuoteIfNeed(name) << " ENGINE = Dictionary";
|
||||
}
|
||||
ParserCreateQuery parser;
|
||||
return parseQuery(parser, query.data(), query.data() + query.size(), "");
|
||||
}
|
||||
|
||||
void DatabaseDictionary::shutdown()
|
||||
|
@ -89,10 +89,12 @@ public:
|
||||
const Context & context,
|
||||
const String & table_name) override;
|
||||
|
||||
ASTPtr getCreateQuery(
|
||||
ASTPtr getCreateTableQuery(
|
||||
const Context & context,
|
||||
const String & table_name) const override;
|
||||
|
||||
ASTPtr getCreateDatabaseQuery(const Context & context) const override;
|
||||
|
||||
void shutdown() override;
|
||||
void drop() override;
|
||||
};
|
||||
|
@ -121,13 +121,18 @@ time_t DatabaseMemory::getTableMetadataModificationTime(
|
||||
return static_cast<time_t>(0);
|
||||
}
|
||||
|
||||
ASTPtr DatabaseMemory::getCreateQuery(
|
||||
ASTPtr DatabaseMemory::getCreateTableQuery(
|
||||
const Context &,
|
||||
const String &) const
|
||||
{
|
||||
throw Exception("There is no CREATE TABLE query for DatabaseMemory tables", ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY);
|
||||
}
|
||||
|
||||
ASTPtr DatabaseMemory::getCreateDatabaseQuery(const Context &) const
|
||||
{
|
||||
throw Exception("There is no CREATE DATABASE query for DatabaseMemory", ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY);
|
||||
}
|
||||
|
||||
void DatabaseMemory::shutdown()
|
||||
{
|
||||
/// You can not hold a lock during shutdown.
|
||||
|
@ -80,10 +80,12 @@ public:
|
||||
const Context & context,
|
||||
const String & table_name) override;
|
||||
|
||||
ASTPtr getCreateQuery(
|
||||
ASTPtr getCreateTableQuery(
|
||||
const Context & context,
|
||||
const String & table_name) const override;
|
||||
|
||||
ASTPtr getCreateDatabaseQuery(const Context & context) const override;
|
||||
|
||||
void shutdown() override;
|
||||
void drop() override;
|
||||
};
|
||||
|
@ -335,22 +335,13 @@ void DatabaseOrdinary::removeTable(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ASTPtr DatabaseOrdinary::getCreateQueryImpl(const String & path, const String & table_name) const
|
||||
static ASTPtr getQueryFromMetadata(const String & metadata_path)
|
||||
{
|
||||
String metadata_path;
|
||||
if (!Poco::File(metadata_path).exists())
|
||||
return nullptr;
|
||||
|
||||
String query;
|
||||
|
||||
if (table_name.empty())
|
||||
{
|
||||
metadata_path = detail::getDatabaseMetadataPath(path);
|
||||
if (!Poco::File(metadata_path).exists())
|
||||
query = "CREATE DATABASE " + backQuoteIfNeed(name) + " ENGINE = Ordinary";
|
||||
}
|
||||
else
|
||||
metadata_path = detail::getTableMetadataPath(path, table_name);
|
||||
|
||||
if (query.empty())
|
||||
{
|
||||
ReadBufferFromFile in(metadata_path, 4096);
|
||||
readStringUntilEOF(query, in);
|
||||
@ -360,6 +351,20 @@ ASTPtr DatabaseOrdinary::getCreateQueryImpl(const String & path, const String &
|
||||
return parseQuery(parser, query.data(), query.data() + query.size(), "in file " + metadata_path);
|
||||
}
|
||||
|
||||
static ASTPtr getCreateQueryFromMetadata(const String & metadata_path, const String & database)
|
||||
{
|
||||
ASTPtr ast = getQueryFromMetadata(metadata_path);
|
||||
|
||||
if (ast)
|
||||
{
|
||||
ASTCreateQuery & ast_create_query = typeid_cast<ASTCreateQuery &>(*ast);
|
||||
ast_create_query.attach = false;
|
||||
ast_create_query.database = database;
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
|
||||
void DatabaseOrdinary::renameTable(
|
||||
const Context & context,
|
||||
@ -394,7 +399,9 @@ void DatabaseOrdinary::renameTable(
|
||||
throw Exception{e};
|
||||
}
|
||||
|
||||
ASTPtr ast = getCreateQueryImpl(metadata_path, table_name);
|
||||
ASTPtr ast = getQueryFromMetadata(detail::getTableMetadataPath(metadata_path, table_name));
|
||||
if (!ast)
|
||||
throw Exception("There is no metadata file for table " + table_name, ErrorCodes::FILE_DOESNT_EXIST);
|
||||
ASTCreateQuery & ast_create_query = typeid_cast<ASTCreateQuery &>(*ast);
|
||||
ast_create_query.table = to_table_name;
|
||||
|
||||
@ -422,27 +429,40 @@ time_t DatabaseOrdinary::getTableMetadataModificationTime(
|
||||
}
|
||||
|
||||
|
||||
ASTPtr DatabaseOrdinary::getCreateQuery(
|
||||
ASTPtr DatabaseOrdinary::getCreateTableQuery(
|
||||
const Context & context,
|
||||
const String & table_name) const
|
||||
{
|
||||
ASTPtr ast;
|
||||
try
|
||||
{
|
||||
ast = getCreateQueryImpl(metadata_path, table_name);
|
||||
}
|
||||
catch (const Exception & e)
|
||||
{
|
||||
/// Handle system.* tables for which there are no table.sql files
|
||||
if (e.code() == ErrorCodes::FILE_DOESNT_EXIST && tryGetTable(context, table_name) != nullptr)
|
||||
throw Exception("There is no CREATE TABLE query for table " + table_name, ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY);
|
||||
|
||||
throw;
|
||||
auto table_metadata_path = detail::getTableMetadataPath(metadata_path, table_name);
|
||||
ast = getCreateQueryFromMetadata(table_metadata_path, name);
|
||||
if (!ast)
|
||||
{
|
||||
/// Handle system.* tables for which there are no table.sql files.
|
||||
auto msg = tryGetTable(context, table_name)
|
||||
? "There is no CREATE TABLE query for table "
|
||||
: "There is no metadata file for table ";
|
||||
|
||||
throw Exception(msg + table_name, ErrorCodes::CANNOT_GET_CREATE_TABLE_QUERY);
|
||||
}
|
||||
|
||||
ASTCreateQuery & ast_create_query = typeid_cast<ASTCreateQuery &>(*ast);
|
||||
ast_create_query.attach = false;
|
||||
ast_create_query.database = name;
|
||||
return ast;
|
||||
}
|
||||
|
||||
ASTPtr DatabaseOrdinary::getCreateDatabaseQuery(const Context & /*context*/) const
|
||||
{
|
||||
ASTPtr ast;
|
||||
|
||||
auto database_metadata_path = detail::getDatabaseMetadataPath(metadata_path);
|
||||
ast = getCreateQueryFromMetadata(database_metadata_path, name);
|
||||
if (!ast)
|
||||
{
|
||||
/// Handle databases (such as default) for which there are no database.sql files.
|
||||
String query = "CREATE DATABASE " + backQuoteIfNeed(name) + " ENGINE = Ordinary";
|
||||
ParserCreateQuery parser;
|
||||
ast = parseQuery(parser, query.data(), query.data() + query.size(), "");
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
@ -55,10 +55,12 @@ public:
|
||||
const Context & context,
|
||||
const String & table_name) override;
|
||||
|
||||
ASTPtr getCreateQuery(
|
||||
ASTPtr getCreateTableQuery(
|
||||
const Context & context,
|
||||
const String & table_name) const override;
|
||||
|
||||
ASTPtr getCreateDatabaseQuery(const Context & context) const override;
|
||||
|
||||
String getDataPath() const override;
|
||||
String getMetadataPath() const override;
|
||||
String getTableMetadataPath(const String & table_name) const override;
|
||||
@ -68,7 +70,6 @@ public:
|
||||
|
||||
private:
|
||||
void startupTables(ThreadPool * thread_pool);
|
||||
ASTPtr getCreateQueryImpl(const String & path, const String & table_name) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -124,12 +124,14 @@ public:
|
||||
const Context & context,
|
||||
const String & name) = 0;
|
||||
|
||||
/// Get the CREATE TABLE query for the table or CREATE DATABASE query for database if name is empty.
|
||||
/// It can also provide information for detached tables for which there is metadata.
|
||||
virtual ASTPtr getCreateQuery(
|
||||
/// Get the CREATE TABLE query for the table. It can also provide information for detached tables for which there is metadata.
|
||||
virtual ASTPtr getCreateTableQuery(
|
||||
const Context & context,
|
||||
const String & name) const = 0;
|
||||
|
||||
/// Get the CREATE DATABASE query for current database.
|
||||
virtual ASTPtr getCreateDatabaseQuery(const Context & context) const = 0;
|
||||
|
||||
/// Returns path for persistent data storage if the database supports it, empty string otherwise
|
||||
virtual String getDataPath() const { return {}; }
|
||||
/// Returns metadata path if the database supports it, empty string otherwise
|
||||
|
@ -910,17 +910,17 @@ DatabasePtr Context::detachDatabase(const String & database_name)
|
||||
}
|
||||
|
||||
|
||||
ASTPtr Context::getCreateQuery(const String & database_name, const String & table_name) const
|
||||
ASTPtr Context::getCreateTableQuery(const String & database_name, const String & table_name) const
|
||||
{
|
||||
auto lock = getLock();
|
||||
|
||||
String db = resolveDatabase(database_name, current_database);
|
||||
assertDatabaseExists(db);
|
||||
|
||||
return shared->databases[db]->getCreateQuery(*this, table_name);
|
||||
return shared->databases[db]->getCreateTableQuery(*this, table_name);
|
||||
}
|
||||
|
||||
ASTPtr Context::getCreateExternalQuery(const String & table_name) const
|
||||
ASTPtr Context::getCreateExternalTableQuery(const String & table_name) const
|
||||
{
|
||||
TableAndCreateASTs::const_iterator jt = external_tables.find(table_name);
|
||||
if (external_tables.end() == jt)
|
||||
@ -929,6 +929,15 @@ ASTPtr Context::getCreateExternalQuery(const String & table_name) const
|
||||
return jt->second.second;
|
||||
}
|
||||
|
||||
ASTPtr Context::getCreateDatabaseQuery(const String & database_name) const
|
||||
{
|
||||
auto lock = getLock();
|
||||
|
||||
String db = resolveDatabase(database_name, current_database);
|
||||
assertDatabaseExists(db);
|
||||
|
||||
return shared->databases[db]->getCreateDatabaseQuery(*this);
|
||||
}
|
||||
|
||||
Settings Context::getSettings() const
|
||||
{
|
||||
|
@ -241,8 +241,9 @@ public:
|
||||
UInt16 getTCPPort() const;
|
||||
|
||||
/// Get query for the CREATE table.
|
||||
ASTPtr getCreateQuery(const String & database_name, const String & table_name) const;
|
||||
ASTPtr getCreateExternalQuery(const String & table_name) const;
|
||||
ASTPtr getCreateTableQuery(const String & database_name, const String & table_name) const;
|
||||
ASTPtr getCreateExternalTableQuery(const String & table_name) const;
|
||||
ASTPtr getCreateDatabaseQuery(const String & database_name) const;
|
||||
|
||||
const DatabasePtr getDatabase(const String & database_name) const;
|
||||
DatabasePtr getDatabase(const String & database_name);
|
||||
|
@ -432,7 +432,7 @@ void InterpreterCreateQuery::setEngine(ASTCreateQuery & create) const
|
||||
String as_database_name = create.as_database.empty() ? context.getCurrentDatabase() : create.as_database;
|
||||
String as_table_name = create.as_table;
|
||||
|
||||
ASTPtr as_create_ptr = context.getCreateQuery(as_database_name, as_table_name);
|
||||
ASTPtr as_create_ptr = context.getCreateTableQuery(as_database_name, as_table_name);
|
||||
const auto & as_create = typeid_cast<const ASTCreateQuery &>(*as_create_ptr);
|
||||
|
||||
if (as_create.is_view)
|
||||
@ -461,7 +461,7 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create)
|
||||
if (create.attach && !create.storage && !create.columns)
|
||||
{
|
||||
// Table SQL definition is available even if the table is detached
|
||||
auto query = context.getCreateQuery(database_name, table_name);
|
||||
auto query = context.getCreateTableQuery(database_name, table_name);
|
||||
auto & as_create = typeid_cast<const ASTCreateQuery &>(*query);
|
||||
create = as_create; // Copy the saved create query, but use ATTACH instead of CREATE
|
||||
create.attach = true;
|
||||
|
@ -44,8 +44,13 @@ BlockInputStreamPtr InterpreterShowCreateQuery::executeImpl()
|
||||
if (ast.temporary && !ast.database.empty())
|
||||
throw Exception("Temporary databases are not possible.", ErrorCodes::SYNTAX_ERROR);
|
||||
|
||||
ASTPtr create_query = (ast.temporary ? context.getCreateExternalQuery(ast.table) :
|
||||
context.getCreateQuery(ast.database, ast.table));
|
||||
ASTPtr create_query;
|
||||
if (ast.temporary)
|
||||
create_query = context.getCreateExternalTableQuery(ast.table);
|
||||
else if (ast.table.empty())
|
||||
create_query = context.getCreateDatabaseQuery(ast.database);
|
||||
else
|
||||
create_query = context.getCreateTableQuery(ast.database, ast.table);
|
||||
|
||||
if (!create_query && ast.temporary)
|
||||
throw Exception("Unable to show the create query of " + ast.table + ". Maybe it was created by the system.", ErrorCodes::THERE_IS_NO_QUERY);
|
||||
|
@ -89,7 +89,6 @@ void StorageDictionary::checkNamesAndTypesCompatibleWithDictionary(const Diction
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void registerStorageDictionary(StorageFactory & factory)
|
||||
{
|
||||
factory.registerStorage("Dictionary", [](const StorageFactory::Arguments & args)
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <Core/Defines.h>
|
||||
#include <common/MultiVersion.h>
|
||||
#include <ext/shared_ptr_helper.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <IO/Operators.h>
|
||||
|
||||
|
||||
namespace Poco
|
||||
@ -33,6 +35,26 @@ public:
|
||||
void drop() override {}
|
||||
static NamesAndTypesList getNamesAndTypes(const DictionaryStructure & dictionary_structure);
|
||||
|
||||
template <typename ForwardIterator>
|
||||
static std::string generateNamesAndTypesDescription(ForwardIterator begin, ForwardIterator end)
|
||||
{
|
||||
std::string description;
|
||||
{
|
||||
WriteBufferFromString buffer(description);
|
||||
bool first = true;
|
||||
for (; begin != end; ++begin)
|
||||
{
|
||||
if (!first)
|
||||
buffer << ", ";
|
||||
first = false;
|
||||
|
||||
buffer << begin->name << ' ' << begin->type->getName();
|
||||
}
|
||||
}
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
private:
|
||||
using Ptr = MultiVersion<IDictionaryBase>::Version;
|
||||
|
||||
@ -42,24 +64,6 @@ private:
|
||||
|
||||
void checkNamesAndTypesCompatibleWithDictionary(const DictionaryStructure & dictionary_structure) const;
|
||||
|
||||
template <typename ForwardIterator>
|
||||
std::string generateNamesAndTypesDescription(ForwardIterator begin, ForwardIterator end) const
|
||||
{
|
||||
if (begin == end)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
std::string description;
|
||||
for (; begin != end; ++begin)
|
||||
{
|
||||
description += ", ";
|
||||
description += begin->name;
|
||||
description += ' ';
|
||||
description += begin->type->getName();
|
||||
}
|
||||
return description.substr(2, description.size());
|
||||
}
|
||||
|
||||
protected:
|
||||
StorageDictionary(const String & table_name_,
|
||||
const NamesAndTypesList & columns_,
|
||||
|
@ -204,7 +204,7 @@ BlockInputStreams StorageSystemTables::read(
|
||||
|
||||
try
|
||||
{
|
||||
ast = database->getCreateQuery(context, table_name);
|
||||
ast = database->getCreateTableQuery(context, table_name);
|
||||
}
|
||||
catch (const Exception & e)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user