2016-03-19 01:18:49 +00:00
|
|
|
|
#include <memory>
|
|
|
|
|
|
2011-11-05 23:31:19 +00:00
|
|
|
|
#include <Poco/File.h>
|
2011-10-24 12:10:59 +00:00
|
|
|
|
#include <Poco/FileStream.h>
|
|
|
|
|
|
2011-11-05 23:31:19 +00:00
|
|
|
|
#include <DB/Common/escapeForFileName.h>
|
|
|
|
|
|
2011-11-01 17:57:37 +00:00
|
|
|
|
#include <DB/IO/WriteBufferFromString.h>
|
2016-03-19 01:18:49 +00:00
|
|
|
|
#include <DB/IO/WriteBufferFromFile.h>
|
2011-11-01 17:57:37 +00:00
|
|
|
|
#include <DB/IO/WriteHelpers.h>
|
|
|
|
|
|
2015-07-25 09:56:56 +00:00
|
|
|
|
#include <DB/DataStreams/NullAndDoCopyBlockInputStream.h>
|
2015-09-18 00:46:36 +00:00
|
|
|
|
#include <DB/DataStreams/ProhibitColumnsBlockOutputStream.h>
|
|
|
|
|
#include <DB/DataStreams/MaterializingBlockOutputStream.h>
|
|
|
|
|
#include <DB/DataStreams/AddingDefaultBlockOutputStream.h>
|
|
|
|
|
#include <DB/DataStreams/PushingToViewsBlockOutputStream.h>
|
2011-11-01 15:16:04 +00:00
|
|
|
|
|
2011-08-18 20:33:20 +00:00
|
|
|
|
#include <DB/Parsers/ASTCreateQuery.h>
|
|
|
|
|
#include <DB/Parsers/ASTNameTypePair.h>
|
2014-09-25 13:40:26 +00:00
|
|
|
|
#include <DB/Parsers/ASTColumnDeclaration.h>
|
2012-05-22 20:18:45 +00:00
|
|
|
|
#include <DB/Parsers/formatAST.h>
|
2015-04-14 02:45:30 +00:00
|
|
|
|
#include <DB/Parsers/ASTIdentifier.h>
|
|
|
|
|
#include <DB/Parsers/ParserCreateQuery.h>
|
|
|
|
|
#include <DB/Parsers/parseQuery.h>
|
2012-05-22 20:18:45 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
#include <DB/Storages/StorageFactory.h>
|
|
|
|
|
#include <DB/Storages/StorageLog.h>
|
|
|
|
|
#include <DB/Storages/System/StorageSystemNumbers.h>
|
|
|
|
|
|
2011-11-01 15:16:04 +00:00
|
|
|
|
#include <DB/Interpreters/InterpreterSelectQuery.h>
|
2011-08-18 20:33:20 +00:00
|
|
|
|
#include <DB/Interpreters/InterpreterCreateQuery.h>
|
2014-09-25 15:01:09 +00:00
|
|
|
|
#include <DB/Interpreters/ExpressionAnalyzer.h>
|
2015-05-28 03:49:28 +00:00
|
|
|
|
|
2014-11-11 14:11:49 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypesNumberFixed.h>
|
2014-07-10 11:13:45 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypeNested.h>
|
2015-05-28 03:49:28 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypeFactory.h>
|
2011-08-18 20:33:20 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
#include <DB/Databases/DatabaseFactory.h>
|
|
|
|
|
#include <DB/Databases/IDatabase.h>
|
|
|
|
|
|
2011-08-18 20:33:20 +00:00
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int DIRECTORY_DOESNT_EXIST;
|
|
|
|
|
extern const int DIRECTORY_ALREADY_EXISTS;
|
|
|
|
|
extern const int TABLE_ALREADY_EXISTS;
|
|
|
|
|
extern const int EMPTY_LIST_OF_COLUMNS_PASSED;
|
|
|
|
|
extern const int INCORRECT_QUERY;
|
|
|
|
|
extern const int ENGINE_REQUIRED;
|
|
|
|
|
extern const int TABLE_METADATA_ALREADY_EXISTS;
|
2016-03-19 01:18:49 +00:00
|
|
|
|
extern const int UNKNOWN_DATABASE_ENGINE;
|
2016-01-11 21:46:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-08-18 20:33:20 +00:00
|
|
|
|
|
2012-03-05 00:09:41 +00:00
|
|
|
|
InterpreterCreateQuery::InterpreterCreateQuery(ASTPtr query_ptr_, Context & context_)
|
|
|
|
|
: query_ptr(query_ptr_), context(context_)
|
2011-11-01 15:16:04 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2011-11-01 15:16:04 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
void InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
|
2011-08-18 20:33:20 +00:00
|
|
|
|
{
|
2016-03-19 01:18:49 +00:00
|
|
|
|
String database_name = create.database;
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
if (create.if_not_exists && context.isDatabaseExist(database_name))
|
|
|
|
|
return;
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
String database_engine_name;
|
|
|
|
|
if (!create.storage)
|
2011-08-19 18:31:14 +00:00
|
|
|
|
{
|
2016-03-19 01:18:49 +00:00
|
|
|
|
database_engine_name = "Ordinary"; /// Движок баз данных по-умолчанию.
|
|
|
|
|
ASTFunction * func = new ASTFunction();
|
|
|
|
|
func->name = database_engine_name;
|
|
|
|
|
create.storage = func;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const ASTFunction & engine_id = typeid_cast<const ASTFunction &>(*create.storage);
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
/// На данный момент, движков таблиц с аргументами не бывает.
|
|
|
|
|
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);
|
2011-08-19 18:31:14 +00:00
|
|
|
|
}
|
2011-11-05 23:31:19 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
database_engine_name = engine_id.name;
|
2011-11-05 23:31:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
String database_name_escaped = escapeForFileName(database_name);
|
2014-03-20 10:59:45 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
/// Создаём директории с данными и метаданными таблиц.
|
|
|
|
|
String path = context.getPath();
|
|
|
|
|
String data_path = path + "data/" + database_name_escaped + "/";
|
|
|
|
|
String metadata_path = path + "metadata/" + database_name_escaped + "/";
|
2012-08-02 17:33:31 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
Poco::File(metadata_path).createDirectory();
|
|
|
|
|
Poco::File(data_path).createDirectory();
|
2014-03-20 10:59:45 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
DatabasePtr database = DatabaseFactory::get(database_engine_name, database_name, metadata_path, context, thread_pool);
|
2016-03-03 04:12:47 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
/// Записываем файл с метаданными, если нужно.
|
|
|
|
|
String metadata_file_tmp_path = path + "metadata/" + database_name_escaped + ".sql.tmp";
|
|
|
|
|
String metadata_file_path = path + "metadata/" + database_name_escaped + ".sql";
|
2016-03-03 04:12:47 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
bool need_write_metadata = !create.attach;
|
2016-03-03 04:12:47 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
if (need_write_metadata)
|
2016-03-03 04:12:47 +00:00
|
|
|
|
{
|
2016-03-19 01:18:49 +00:00
|
|
|
|
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();
|
2016-03-03 04:12:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
try
|
2011-11-05 23:31:19 +00:00
|
|
|
|
{
|
2016-03-19 01:18:49 +00:00
|
|
|
|
context.addDatabase(database_name, database);
|
2012-08-02 17:33:31 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
if (need_write_metadata)
|
|
|
|
|
Poco::File(metadata_file_tmp_path).renameTo(metadata_file_path);
|
2012-08-02 17:33:31 +00:00
|
|
|
|
}
|
2016-03-19 01:18:49 +00:00
|
|
|
|
catch (...)
|
2011-11-06 06:22:52 +00:00
|
|
|
|
{
|
2016-03-19 01:18:49 +00:00
|
|
|
|
if (need_write_metadata)
|
|
|
|
|
Poco::File(metadata_file_tmp_path).remove();
|
2015-09-18 00:46:36 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
throw;
|
2011-11-06 06:22:52 +00:00
|
|
|
|
}
|
2011-08-18 20:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
|
|
|
|
|
using ColumnsAndDefaults = std::pair<NamesAndTypesList, ColumnDefaults>;
|
|
|
|
|
|
|
|
|
|
/// AST в список столбцов с типами. Столбцы типа Nested развернуты в список настоящих столбцов.
|
|
|
|
|
static ColumnsAndDefaults parseColumns(
|
|
|
|
|
ASTPtr expression_list, const Context & context)
|
2014-07-10 11:13:45 +00:00
|
|
|
|
{
|
2014-09-30 03:08:47 +00:00
|
|
|
|
auto & column_list_ast = typeid_cast<ASTExpressionList &>(*expression_list);
|
|
|
|
|
|
2014-09-25 15:01:09 +00:00
|
|
|
|
/// list of table columns in correct order
|
2014-11-11 14:11:49 +00:00
|
|
|
|
NamesAndTypesList columns{};
|
2014-09-29 14:58:48 +00:00
|
|
|
|
ColumnDefaults defaults{};
|
2014-09-25 15:01:09 +00:00
|
|
|
|
|
2014-09-29 13:32:16 +00:00
|
|
|
|
/// Columns requiring type-deduction or default_expression type-check
|
2014-09-30 03:08:47 +00:00
|
|
|
|
std::vector<std::pair<NameAndTypePair *, ASTColumnDeclaration *>> defaulted_columns{};
|
2014-09-29 13:32:16 +00:00
|
|
|
|
|
|
|
|
|
/** all default_expressions as a single expression list,
|
|
|
|
|
* mixed with conversion-columns for each explicitly specified type */
|
|
|
|
|
ASTPtr default_expr_list{new ASTExpressionList};
|
2014-09-30 03:08:47 +00:00
|
|
|
|
default_expr_list->children.reserve(column_list_ast.children.size());
|
2014-09-29 13:32:16 +00:00
|
|
|
|
|
2015-05-28 03:49:28 +00:00
|
|
|
|
const DataTypeFactory & data_type_factory = DataTypeFactory::instance();
|
|
|
|
|
|
2014-09-30 03:08:47 +00:00
|
|
|
|
for (auto & ast : column_list_ast.children)
|
2014-07-10 11:13:45 +00:00
|
|
|
|
{
|
2014-09-25 15:01:09 +00:00
|
|
|
|
auto & col_decl = typeid_cast<ASTColumnDeclaration &>(*ast);
|
2014-09-29 13:32:16 +00:00
|
|
|
|
|
2014-09-25 13:40:26 +00:00
|
|
|
|
if (col_decl.type)
|
|
|
|
|
{
|
|
|
|
|
const auto & type_range = col_decl.type->range;
|
2014-09-29 13:32:16 +00:00
|
|
|
|
columns.emplace_back(col_decl.name,
|
2015-05-28 03:49:28 +00:00
|
|
|
|
data_type_factory.get({ type_range.first, type_range.second }));
|
2014-09-25 13:40:26 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2014-11-11 14:11:49 +00:00
|
|
|
|
/// we're creating dummy DataTypeUInt8 in order to prevent the NullPointerException in ExpressionActions
|
|
|
|
|
columns.emplace_back(col_decl.name, new DataTypeUInt8);
|
2014-09-25 13:40:26 +00:00
|
|
|
|
|
2014-09-29 13:32:16 +00:00
|
|
|
|
/// add column to postprocessing if there is a default_expression specified
|
|
|
|
|
if (col_decl.default_expression)
|
2014-09-25 13:40:26 +00:00
|
|
|
|
{
|
2014-09-29 13:32:16 +00:00
|
|
|
|
defaulted_columns.emplace_back(&columns.back(), &col_decl);
|
|
|
|
|
|
|
|
|
|
/** for columns with explicitly-specified type create two expressions:
|
|
|
|
|
* 1. default_expression aliased as column name with _tmp suffix
|
|
|
|
|
* 2. conversion of expression (1) to explicitly-specified type alias as column name */
|
|
|
|
|
if (col_decl.type)
|
|
|
|
|
{
|
|
|
|
|
const auto & final_column_name = col_decl.name;
|
2015-03-31 12:55:32 +00:00
|
|
|
|
const auto tmp_column_name = final_column_name + "_tmp";
|
|
|
|
|
const auto data_type_ptr = columns.back().type.get();
|
|
|
|
|
|
2015-12-23 11:16:28 +00:00
|
|
|
|
default_expr_list->children.emplace_back(setAlias(
|
|
|
|
|
makeASTFunction("CAST", ASTPtr{new ASTIdentifier{{}, tmp_column_name}},
|
|
|
|
|
ASTPtr{new ASTLiteral{{}, data_type_ptr->getName()}}), final_column_name));
|
2014-09-30 03:08:47 +00:00
|
|
|
|
default_expr_list->children.emplace_back(setAlias(col_decl.default_expression->clone(), tmp_column_name));
|
2014-09-29 13:32:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2014-09-30 03:08:47 +00:00
|
|
|
|
default_expr_list->children.emplace_back(setAlias(col_decl.default_expression->clone(), col_decl.name));
|
2014-09-25 13:40:26 +00:00
|
|
|
|
}
|
2014-07-10 11:13:45 +00:00
|
|
|
|
}
|
2014-09-25 13:40:26 +00:00
|
|
|
|
|
2014-09-29 13:32:16 +00:00
|
|
|
|
/// set missing types and wrap default_expression's in a conversion-function if necessary
|
|
|
|
|
if (!defaulted_columns.empty())
|
2014-09-25 13:40:26 +00:00
|
|
|
|
{
|
2015-07-15 01:26:35 +00:00
|
|
|
|
const auto actions = ExpressionAnalyzer{default_expr_list, context, {}, columns}.getActions(true);
|
2014-09-29 13:32:16 +00:00
|
|
|
|
const auto block = actions->getSampleBlock();
|
2014-09-25 13:40:26 +00:00
|
|
|
|
|
2014-09-29 13:32:16 +00:00
|
|
|
|
for (auto & column : defaulted_columns)
|
2014-09-25 15:01:09 +00:00
|
|
|
|
{
|
2014-09-29 13:32:16 +00:00
|
|
|
|
const auto name_and_type_ptr = column.first;
|
|
|
|
|
const auto col_decl_ptr = column.second;
|
2014-09-25 13:40:26 +00:00
|
|
|
|
|
2015-10-20 16:22:08 +00:00
|
|
|
|
const auto & column_name = col_decl_ptr->name;
|
|
|
|
|
const auto has_explicit_type = nullptr != col_decl_ptr->type;
|
|
|
|
|
auto & explicit_type = name_and_type_ptr->type;
|
|
|
|
|
|
|
|
|
|
/// if column declaration contains explicit type, name_and_type_ptr->type is not null
|
|
|
|
|
if (has_explicit_type)
|
2014-09-29 13:32:16 +00:00
|
|
|
|
{
|
2015-10-20 16:22:08 +00:00
|
|
|
|
const auto & tmp_column = block.getByName(column_name + "_tmp");
|
|
|
|
|
const auto & deduced_type = tmp_column.type;
|
2014-09-29 13:32:16 +00:00
|
|
|
|
|
2015-10-20 16:22:08 +00:00
|
|
|
|
/// type mismatch between explicitly specified and deduced type, add conversion for non-array types
|
|
|
|
|
if (explicit_type->getName() != deduced_type->getName())
|
2014-09-29 13:32:16 +00:00
|
|
|
|
{
|
2015-12-23 11:16:28 +00:00
|
|
|
|
col_decl_ptr->default_expression = makeASTFunction("CAST", col_decl_ptr->default_expression,
|
|
|
|
|
new ASTLiteral{{}, explicit_type->getName()});
|
2014-09-29 13:32:16 +00:00
|
|
|
|
|
|
|
|
|
col_decl_ptr->children.clear();
|
|
|
|
|
col_decl_ptr->children.push_back(col_decl_ptr->type);
|
|
|
|
|
col_decl_ptr->children.push_back(col_decl_ptr->default_expression);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2015-10-20 16:22:08 +00:00
|
|
|
|
/// no explicit type, name_and_type_ptr->type is null, set to deduced type
|
|
|
|
|
explicit_type = block.getByName(column_name).type;
|
2014-09-29 14:58:48 +00:00
|
|
|
|
|
2015-10-20 16:22:08 +00:00
|
|
|
|
defaults.emplace(column_name, ColumnDefault{
|
2014-09-29 14:58:48 +00:00
|
|
|
|
columnDefaultTypeFromString(col_decl_ptr->default_specifier),
|
2014-10-21 12:11:20 +00:00
|
|
|
|
col_decl_ptr->default_expression
|
2014-09-29 14:58:48 +00:00
|
|
|
|
});
|
2014-09-29 13:32:16 +00:00
|
|
|
|
}
|
2014-09-25 13:40:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-29 14:58:48 +00:00
|
|
|
|
return { *DataTypeNested::expandNestedColumns(columns), defaults };
|
2014-07-10 11:13:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
|
|
|
|
|
static NamesAndTypesList removeAndReturnColumns(
|
|
|
|
|
ColumnsAndDefaults & columns_and_defaults, const ColumnDefaultType type)
|
2014-07-10 11:13:45 +00:00
|
|
|
|
{
|
2014-09-30 03:08:47 +00:00
|
|
|
|
auto & columns = columns_and_defaults.first;
|
|
|
|
|
auto & defaults = columns_and_defaults.second;
|
|
|
|
|
|
2014-10-03 15:30:10 +00:00
|
|
|
|
NamesAndTypesList removed{};
|
2014-09-30 03:08:47 +00:00
|
|
|
|
|
|
|
|
|
for (auto it = std::begin(columns); it != std::end(columns);)
|
2014-07-10 11:13:45 +00:00
|
|
|
|
{
|
2014-09-30 03:08:47 +00:00
|
|
|
|
const auto jt = defaults.find(it->name);
|
2014-10-03 15:30:10 +00:00
|
|
|
|
if (jt != std::end(defaults) && jt->second.type == type)
|
2014-09-30 03:08:47 +00:00
|
|
|
|
{
|
2014-10-03 15:30:10 +00:00
|
|
|
|
removed.push_back(*it);
|
2014-09-30 03:08:47 +00:00
|
|
|
|
it = columns.erase(it);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
++it;
|
2014-07-10 11:13:45 +00:00
|
|
|
|
}
|
2014-09-30 03:08:47 +00:00
|
|
|
|
|
2014-10-03 15:30:10 +00:00
|
|
|
|
return removed;
|
2014-07-10 11:13:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
|
2014-07-10 11:13:45 +00:00
|
|
|
|
ASTPtr InterpreterCreateQuery::formatColumns(const NamesAndTypesList & columns)
|
|
|
|
|
{
|
2014-09-25 13:40:26 +00:00
|
|
|
|
ASTPtr columns_list_ptr{new ASTExpressionList};
|
2014-07-10 11:13:45 +00:00
|
|
|
|
ASTExpressionList & columns_list = typeid_cast<ASTExpressionList &>(*columns_list_ptr);
|
|
|
|
|
|
2014-09-25 13:40:26 +00:00
|
|
|
|
for (const auto & column : columns)
|
2014-07-10 11:13:45 +00:00
|
|
|
|
{
|
2014-09-25 13:40:26 +00:00
|
|
|
|
const auto column_declaration = new ASTColumnDeclaration;
|
|
|
|
|
ASTPtr column_declaration_ptr{column_declaration};
|
2014-07-10 11:13:45 +00:00
|
|
|
|
|
2014-09-25 13:40:26 +00:00
|
|
|
|
column_declaration->name = column.name;
|
2014-07-10 11:13:45 +00:00
|
|
|
|
|
2014-09-25 13:40:26 +00:00
|
|
|
|
StringPtr type_name{new String(column.type->getName())};
|
|
|
|
|
auto pos = type_name->data();
|
|
|
|
|
const auto end = pos + type_name->size();
|
2014-07-10 11:13:45 +00:00
|
|
|
|
|
|
|
|
|
ParserIdentifierWithOptionalParameters storage_p;
|
2015-04-14 02:45:30 +00:00
|
|
|
|
column_declaration->type = parseQuery(storage_p, pos, end, "data type");
|
2014-09-25 13:40:26 +00:00
|
|
|
|
column_declaration->type->query_string = type_name;
|
|
|
|
|
columns_list.children.push_back(column_declaration_ptr);
|
2014-07-10 11:13:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return columns_list_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-30 03:08:47 +00:00
|
|
|
|
ASTPtr InterpreterCreateQuery::formatColumns(NamesAndTypesList columns,
|
2014-10-03 15:30:10 +00:00
|
|
|
|
const NamesAndTypesList & materialized_columns,
|
2014-09-30 03:08:47 +00:00
|
|
|
|
const NamesAndTypesList & alias_columns,
|
|
|
|
|
const ColumnDefaults & column_defaults)
|
2014-09-25 15:01:09 +00:00
|
|
|
|
{
|
2014-10-03 15:30:10 +00:00
|
|
|
|
columns.insert(std::end(columns), std::begin(materialized_columns), std::end(materialized_columns));
|
2014-09-30 03:08:47 +00:00
|
|
|
|
columns.insert(std::end(columns), std::begin(alias_columns), std::end(alias_columns));
|
|
|
|
|
|
|
|
|
|
ASTPtr columns_list_ptr{new ASTExpressionList};
|
|
|
|
|
ASTExpressionList & columns_list = typeid_cast<ASTExpressionList &>(*columns_list_ptr);
|
|
|
|
|
|
|
|
|
|
for (const auto & column : columns)
|
|
|
|
|
{
|
|
|
|
|
const auto column_declaration = new ASTColumnDeclaration;
|
|
|
|
|
ASTPtr column_declaration_ptr{column_declaration};
|
|
|
|
|
|
|
|
|
|
column_declaration->name = column.name;
|
|
|
|
|
|
|
|
|
|
StringPtr type_name{new String(column.type->getName())};
|
|
|
|
|
auto pos = type_name->data();
|
|
|
|
|
const auto end = pos + type_name->size();
|
|
|
|
|
|
|
|
|
|
ParserIdentifierWithOptionalParameters storage_p;
|
2015-04-14 02:45:30 +00:00
|
|
|
|
column_declaration->type = parseQuery(storage_p, pos, end, "data type");
|
2014-09-30 03:08:47 +00:00
|
|
|
|
column_declaration->type->query_string = type_name;
|
|
|
|
|
|
|
|
|
|
const auto it = column_defaults.find(column.name);
|
|
|
|
|
if (it != std::end(column_defaults))
|
|
|
|
|
{
|
|
|
|
|
column_declaration->default_specifier = toString(it->second.type);
|
2014-10-21 12:11:20 +00:00
|
|
|
|
column_declaration->default_expression = it->second.expression->clone();
|
2014-09-30 03:08:47 +00:00
|
|
|
|
}
|
2014-09-25 15:01:09 +00:00
|
|
|
|
|
2014-09-30 03:08:47 +00:00
|
|
|
|
columns_list.children.push_back(column_declaration_ptr);
|
2014-07-10 11:13:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return columns_list_ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-30 03:08:47 +00:00
|
|
|
|
|
2016-03-19 01:18:49 +00:00
|
|
|
|
InterpreterCreateQuery::ColumnsInfo InterpreterCreateQuery::getColumnsInfo(
|
|
|
|
|
const ASTPtr & columns, const Context & context)
|
|
|
|
|
{
|
|
|
|
|
ColumnsInfo res;
|
|
|
|
|
|
|
|
|
|
auto && columns_and_defaults = parseColumns(columns, context);
|
|
|
|
|
res.materialized_columns = removeAndReturnColumns(columns_and_defaults, ColumnDefaultType::Materialized);
|
|
|
|
|
res.alias_columns = removeAndReturnColumns(columns_and_defaults, ColumnDefaultType::Alias);
|
|
|
|
|
res.columns = new NamesAndTypesList{std::move(columns_and_defaults.first)};
|
|
|
|
|
res.column_defaults = std::move(columns_and_defaults.second);
|
|
|
|
|
|
|
|
|
|
if (res.columns->size() + res.materialized_columns.size() == 0)
|
|
|
|
|
throw Exception{"Cannot CREATE table without physical columns", ErrorCodes::EMPTY_LIST_OF_COLUMNS_PASSED};
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
InterpreterCreateQuery::ColumnsInfo InterpreterCreateQuery::setColumns(
|
|
|
|
|
ASTCreateQuery & create, const Block & as_select_sample, const StoragePtr & as_storage) const
|
|
|
|
|
{
|
|
|
|
|
ColumnsInfo res;
|
|
|
|
|
|
|
|
|
|
if (create.columns)
|
|
|
|
|
{
|
|
|
|
|
res = getColumnsInfo(create.columns, context);
|
|
|
|
|
}
|
|
|
|
|
else if (!create.as_table.empty())
|
|
|
|
|
{
|
|
|
|
|
res.columns = new NamesAndTypesList(as_storage->getColumnsListNonMaterialized());
|
|
|
|
|
res.materialized_columns = as_storage->materialized_columns;
|
|
|
|
|
res.alias_columns = as_storage->alias_columns;
|
|
|
|
|
res.column_defaults = as_storage->column_defaults;
|
|
|
|
|
}
|
|
|
|
|
else if (create.select)
|
|
|
|
|
{
|
|
|
|
|
res.columns = new NamesAndTypesList;
|
|
|
|
|
for (size_t i = 0; i < as_select_sample.columns(); ++i)
|
|
|
|
|
res.columns->push_back(NameAndTypePair(as_select_sample.getByPosition(i).name, as_select_sample.getByPosition(i).type));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw Exception("Incorrect CREATE query: required list of column descriptions or AS section or SELECT.", ErrorCodes::INCORRECT_QUERY);
|
|
|
|
|
|
|
|
|
|
/// Даже если в запросе был список столбцов, на всякий случай приведем его к стандартному виду (развернём Nested).
|
|
|
|
|
ASTPtr new_columns = formatColumns(*res.columns, res.materialized_columns, res.alias_columns, res.column_defaults);
|
|
|
|
|
if (create.columns)
|
|
|
|
|
{
|
|
|
|
|
auto it = std::find(create.children.begin(), create.children.end(), create.columns);
|
|
|
|
|
if (it != create.children.end())
|
|
|
|
|
*it = new_columns;
|
|
|
|
|
else
|
|
|
|
|
create.children.push_back(new_columns);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
create.children.push_back(new_columns);
|
|
|
|
|
create.columns = new_columns;
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String InterpreterCreateQuery::setEngine(
|
|
|
|
|
ASTCreateQuery & create, const StoragePtr & as_storage) const
|
|
|
|
|
{
|
|
|
|
|
String storage_name;
|
|
|
|
|
|
|
|
|
|
auto set_engine = [&](const char * engine)
|
|
|
|
|
{
|
|
|
|
|
storage_name = engine;
|
|
|
|
|
ASTFunction * func = new ASTFunction();
|
|
|
|
|
func->name = engine;
|
|
|
|
|
create.storage = func;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (create.storage)
|
|
|
|
|
{
|
|
|
|
|
storage_name = typeid_cast<ASTFunction &>(*create.storage).name;
|
|
|
|
|
}
|
|
|
|
|
else if (!create.as_table.empty())
|
|
|
|
|
{
|
|
|
|
|
/// NOTE Получение структуры у таблицы, указанной в AS делается не атомарно с созданием таблицы.
|
|
|
|
|
|
|
|
|
|
String as_database_name = create.as_database.empty() ? context.getCurrentDatabase() : create.as_database;
|
|
|
|
|
String as_table_name = create.as_table;
|
|
|
|
|
|
|
|
|
|
storage_name = as_storage->getName();
|
|
|
|
|
create.storage = typeid_cast<const ASTCreateQuery &>(*context.getCreateQuery(as_database_name, as_table_name)).storage;
|
|
|
|
|
}
|
|
|
|
|
else if (create.is_temporary)
|
|
|
|
|
set_engine("Memory");
|
|
|
|
|
else if (create.is_view)
|
|
|
|
|
set_engine("View");
|
|
|
|
|
else if (create.is_materialized_view)
|
|
|
|
|
set_engine("MaterializedView");
|
|
|
|
|
else
|
|
|
|
|
throw Exception("Incorrect CREATE query: required ENGINE.", ErrorCodes::ENGINE_REQUIRED);
|
|
|
|
|
|
|
|
|
|
return storage_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create)
|
|
|
|
|
{
|
|
|
|
|
String path = context.getPath();
|
|
|
|
|
String current_database = context.getCurrentDatabase();
|
|
|
|
|
|
|
|
|
|
String database_name = create.database.empty() ? current_database : create.database;
|
|
|
|
|
String database_name_escaped = escapeForFileName(database_name);
|
|
|
|
|
String table_name = create.table;
|
|
|
|
|
String table_name_escaped = escapeForFileName(table_name);
|
|
|
|
|
|
|
|
|
|
String data_path = path + "data/" + database_name_escaped + "/";
|
|
|
|
|
String metadata_path = path + "metadata/" + database_name_escaped + "/" + table_name_escaped + ".sql";
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<InterpreterSelectQuery> interpreter_select;
|
|
|
|
|
Block as_select_sample;
|
|
|
|
|
/// Для таблиц типа view, чтобы получить столбцы, может понадобиться sample_block.
|
|
|
|
|
if (create.select && (!create.attach || (!create.columns && (create.is_view || create.is_materialized_view))))
|
|
|
|
|
{
|
|
|
|
|
interpreter_select = std::make_unique<InterpreterSelectQuery>(create.select, context);
|
|
|
|
|
as_select_sample = interpreter_select->getSampleBlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String as_database_name = create.as_database.empty() ? current_database : create.as_database;
|
|
|
|
|
String as_table_name = create.as_table;
|
|
|
|
|
|
|
|
|
|
StoragePtr as_storage;
|
|
|
|
|
IStorage::TableStructureReadLockPtr as_storage_lock;
|
|
|
|
|
if (!as_table_name.empty())
|
|
|
|
|
{
|
|
|
|
|
as_storage = context.getTable(as_database_name, as_table_name);
|
|
|
|
|
as_storage_lock = as_storage->lockStructure(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Устанавливаем и получаем список столбцов.
|
|
|
|
|
ColumnsInfo columns = setColumns(create, as_select_sample, as_storage);
|
|
|
|
|
|
|
|
|
|
/// Выбор нужного движка таблицы
|
|
|
|
|
String storage_name = setEngine(create, as_storage);
|
|
|
|
|
|
|
|
|
|
StoragePtr res;
|
|
|
|
|
|
|
|
|
|
{
|
2016-03-21 12:57:12 +00:00
|
|
|
|
std::unique_ptr<DDLGuard> guard;
|
2016-03-19 01:18:49 +00:00
|
|
|
|
|
|
|
|
|
if (!create.is_temporary)
|
|
|
|
|
{
|
|
|
|
|
context.assertDatabaseExists(database_name);
|
|
|
|
|
|
2016-04-01 17:41:13 +00:00
|
|
|
|
/** Если таблица уже существует, и в запросе указано IF NOT EXISTS,
|
|
|
|
|
* то мы разрешаем конкуррентные запросы CREATE (которые ничего не делают).
|
|
|
|
|
* Иначе конкуррентные запросы на создание таблицы, если таблицы не существует,
|
|
|
|
|
* могут кидать исключение, даже если указано IF NOT EXISTS.
|
|
|
|
|
*/
|
|
|
|
|
guard = context.getDDLGuardIfTableDoesntExist(database_name, table_name,
|
|
|
|
|
"Table " + database_name + "." + table_name + " is creating or attaching right now");
|
|
|
|
|
|
|
|
|
|
if (!guard)
|
2016-03-19 01:18:49 +00:00
|
|
|
|
{
|
|
|
|
|
if (create.if_not_exists)
|
|
|
|
|
return {};
|
|
|
|
|
else
|
|
|
|
|
throw Exception("Table " + database_name + "." + table_name + " already exists.", ErrorCodes::TABLE_ALREADY_EXISTS);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = StorageFactory::instance().get(
|
|
|
|
|
storage_name, data_path, table_name, database_name, context,
|
|
|
|
|
context.getGlobalContext(), query_ptr, columns.columns,
|
|
|
|
|
columns.materialized_columns, columns.alias_columns, columns.column_defaults, create.attach);
|
|
|
|
|
|
|
|
|
|
if (create.is_temporary)
|
|
|
|
|
context.getSessionContext().addExternalTable(table_name, res);
|
|
|
|
|
else
|
|
|
|
|
context.getDatabase(database_name)->createTable(table_name, res, query_ptr, storage_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Если запрос CREATE SELECT, то вставим в таблицу данные
|
|
|
|
|
if (create.select && storage_name != "View" && (storage_name != "MaterializedView" || create.is_populate))
|
|
|
|
|
{
|
|
|
|
|
auto table_lock = res->lockStructure(true);
|
|
|
|
|
|
|
|
|
|
/// Также см. InterpreterInsertQuery.
|
|
|
|
|
BlockOutputStreamPtr out{
|
|
|
|
|
new ProhibitColumnsBlockOutputStream{
|
|
|
|
|
new AddingDefaultBlockOutputStream{
|
|
|
|
|
new MaterializingBlockOutputStream{
|
|
|
|
|
new PushingToViewsBlockOutputStream{
|
|
|
|
|
create.database, create.table,
|
|
|
|
|
create.is_temporary ? context.getSessionContext() : context,
|
|
|
|
|
query_ptr
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
/// @note shouldn't these two contexts be session contexts in case of temporary table?
|
|
|
|
|
columns.columns, columns.column_defaults, context, static_cast<bool>(context.getSettingsRef().strict_insert_defaults)
|
|
|
|
|
},
|
|
|
|
|
columns.materialized_columns
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BlockIO io;
|
|
|
|
|
io.in_sample = as_select_sample;
|
|
|
|
|
io.in = new NullAndDoCopyBlockInputStream(interpreter_select->execute().in, out);
|
|
|
|
|
|
|
|
|
|
return io;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BlockIO InterpreterCreateQuery::execute()
|
|
|
|
|
{
|
|
|
|
|
ASTCreateQuery & create = typeid_cast<ASTCreateQuery &>(*query_ptr);
|
|
|
|
|
|
|
|
|
|
/// CREATE|ATTACH DATABASE
|
|
|
|
|
if (!create.database.empty() && create.table.empty())
|
|
|
|
|
{
|
|
|
|
|
createDatabase(create);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return createTable(create);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-08-18 20:33:20 +00:00
|
|
|
|
}
|