mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 09:32:06 +00:00
Rename some restore settings.
This commit is contained in:
parent
88b0cf3ca0
commit
d20b3d78c5
@ -1,8 +1,10 @@
|
||||
#include <Backups/RestoreSettings.h>
|
||||
#include <Backups/BackupInfo.h>
|
||||
#include <Common/FieldVisitorConvertToNumber.h>
|
||||
#include <Core/SettingsFields.h>
|
||||
#include <Parsers/ASTBackupQuery.h>
|
||||
#include <Parsers/ASTSetQuery.h>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -10,6 +12,30 @@ namespace DB
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int UNKNOWN_SETTING;
|
||||
extern const int CANNOT_PARSE_RESTORE_TABLE_CREATION_MODE;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
RestoreTableCreationMode parseRestoreTableCreationMode(const Field & field)
|
||||
{
|
||||
if (field.getType() == Field::Types::String)
|
||||
{
|
||||
String str = field.get<String>();
|
||||
if (str == "1" || boost::iequals(str, "true"))
|
||||
return RestoreTableCreationMode::kCreate;
|
||||
if (str == "0" || boost::iequals(str, "false"))
|
||||
return RestoreTableCreationMode::kMustExist;
|
||||
if (boost::iequals(str, "if not exists"))
|
||||
return RestoreTableCreationMode::kCreateIfNotExists;
|
||||
throw Exception("Cannot parse creation mode from string '" + str + "'",
|
||||
ErrorCodes::CANNOT_PARSE_RESTORE_TABLE_CREATION_MODE);
|
||||
}
|
||||
if (applyVisitor(FieldVisitorConvertToNumber<bool>(), field))
|
||||
return RestoreTableCreationMode::kCreate;
|
||||
else
|
||||
return RestoreTableCreationMode::kMustExist;
|
||||
}
|
||||
}
|
||||
|
||||
RestoreSettings RestoreSettings::fromRestoreQuery(const ASTBackupQuery & query)
|
||||
@ -28,14 +54,14 @@ RestoreSettings RestoreSettings::fromRestoreQuery(const ASTBackupQuery & query)
|
||||
res.password = SettingFieldString{setting.value};
|
||||
else if (setting.name == "structure_only")
|
||||
res.structure_only = SettingFieldBool{setting.value};
|
||||
else if (setting.name == "throw_if_database_exists")
|
||||
res.throw_if_database_exists = SettingFieldBool{setting.value};
|
||||
else if (setting.name == "throw_if_table_exists")
|
||||
res.throw_if_table_exists = SettingFieldBool{setting.value};
|
||||
else if (setting.name == "throw_if_database_def_differs")
|
||||
res.throw_if_database_def_differs = SettingFieldBool{setting.value};
|
||||
else if (setting.name == "throw_if_table_def_differs")
|
||||
res.throw_if_table_def_differs = SettingFieldBool{setting.value};
|
||||
else if (setting.name == "create_table")
|
||||
res.create_table = parseRestoreTableCreationMode(setting.value);
|
||||
else if (setting.name == "create_database")
|
||||
res.create_database = parseRestoreTableCreationMode(setting.value);
|
||||
else if (setting.name == "allow_different_table_def")
|
||||
res.allow_different_table_def = SettingFieldBool{setting.value};
|
||||
else if (setting.name == "allow_different_database_def")
|
||||
res.allow_different_database_def = SettingFieldBool{setting.value};
|
||||
else
|
||||
throw Exception(ErrorCodes::UNKNOWN_SETTING, "Unknown setting {}", setting.name);
|
||||
}
|
||||
|
@ -12,6 +12,21 @@ struct StorageRestoreSettings
|
||||
{
|
||||
};
|
||||
|
||||
/// How the RESTORE command will handle table/database existence.
|
||||
enum class RestoreTableCreationMode
|
||||
{
|
||||
/// RESTORE TABLE always tries to create a table and it throws an exception if the table already exists.
|
||||
kCreate,
|
||||
|
||||
/// RESTORE TABLE never tries to create a table and it throws an exception if the table doesn't exist.
|
||||
kMustExist,
|
||||
|
||||
/// RESTORE TABLE tries to create a table if it doesn't exist.
|
||||
kCreateIfNotExists,
|
||||
};
|
||||
|
||||
using RestoreDatabaseCreationMode = RestoreTableCreationMode;
|
||||
|
||||
/// Settings specified in the "SETTINGS" clause of a RESTORE query.
|
||||
struct RestoreSettings : public StorageRestoreSettings
|
||||
{
|
||||
@ -27,19 +42,21 @@ struct RestoreSettings : public StorageRestoreSettings
|
||||
/// without the data of tables.
|
||||
bool structure_only = false;
|
||||
|
||||
/// Whether RESTORE DATABASE must throw an exception if a destination database already exists.
|
||||
bool throw_if_database_exists = true;
|
||||
/// How RESTORE command should work if a table to restore already exists.
|
||||
RestoreTableCreationMode create_table = RestoreTableCreationMode::kCreateIfNotExists;
|
||||
|
||||
/// Whether RESTORE TABLE must throw an exception if a destination table already exists.
|
||||
bool throw_if_table_exists = true;
|
||||
/// How RESTORE command should work if a database to restore already exists.
|
||||
RestoreDatabaseCreationMode create_database = RestoreDatabaseCreationMode::kCreateIfNotExists;
|
||||
|
||||
/// Whether RESTORE DATABASE must throw an exception if a destination database has
|
||||
/// a different definition comparing with the definition read from backup.
|
||||
bool throw_if_database_def_differs = true;
|
||||
/// Normally RESTORE command throws an exception if a destination table exists but has a different definition
|
||||
/// (i.e. create query) comparing with its definition extracted from backup.
|
||||
/// Set `allow_different_table_def` to true to skip this check.
|
||||
bool allow_different_table_def = false;
|
||||
|
||||
/// Whether RESTORE TABLE must throw an exception if a destination table has
|
||||
/// a different definition comparing with the definition read from backup.
|
||||
bool throw_if_table_def_differs = true;
|
||||
/// Normally RESTORE command throws an exception if a destination database exists but has a different definition
|
||||
/// (i.e. create query) comparing with its definition extracted from backup.
|
||||
/// Set `allow_different_database_def` to true to skip this check.
|
||||
bool allow_different_database_def = false;
|
||||
|
||||
static RestoreSettings fromRestoreQuery(const ASTBackupQuery & query);
|
||||
};
|
||||
|
@ -70,9 +70,12 @@ namespace
|
||||
private:
|
||||
void createDatabase()
|
||||
{
|
||||
/// We need to call clone() for `create_query` because the interpreter can decide
|
||||
/// to change a passed AST a little bit.
|
||||
InterpreterCreateQuery create_interpreter{create_query->clone(), context};
|
||||
if (restore_settings->create_database == RestoreDatabaseCreationMode::kMustExist)
|
||||
return;
|
||||
|
||||
auto cloned_create_query = typeid_cast<std::shared_ptr<ASTCreateQuery>>(create_query->clone());
|
||||
cloned_create_query->if_not_exists = (restore_settings->create_database == RestoreDatabaseCreationMode::kCreateIfNotExists);
|
||||
InterpreterCreateQuery create_interpreter{cloned_create_query, context};
|
||||
create_interpreter.execute();
|
||||
}
|
||||
|
||||
@ -92,7 +95,7 @@ namespace
|
||||
|
||||
void checkDatabaseCreateQuery()
|
||||
{
|
||||
if (ignore_if_database_def_differs || !restore_settings->throw_if_database_def_differs)
|
||||
if (ignore_if_database_def_differs || restore_settings->allow_different_database_def)
|
||||
return;
|
||||
|
||||
getDatabaseCreateQuery();
|
||||
@ -153,9 +156,12 @@ namespace
|
||||
private:
|
||||
void createStorage()
|
||||
{
|
||||
/// We need to call clone() for `create_query` because the interpreter can decide
|
||||
/// to change a passed AST a little bit.
|
||||
InterpreterCreateQuery create_interpreter{create_query->clone(), context};
|
||||
if (restore_settings->create_table == RestoreTableCreationMode::kMustExist)
|
||||
return;
|
||||
|
||||
auto cloned_create_query = typeid_cast<std::shared_ptr<ASTCreateQuery>>(create_query->clone());
|
||||
cloned_create_query->if_not_exists = (restore_settings->create_table == RestoreTableCreationMode::kCreateIfNotExists);
|
||||
InterpreterCreateQuery create_interpreter{cloned_create_query, context};
|
||||
create_interpreter.execute();
|
||||
}
|
||||
|
||||
@ -178,7 +184,7 @@ namespace
|
||||
|
||||
void checkStorageCreateQuery()
|
||||
{
|
||||
if (!restore_settings->throw_if_table_def_differs)
|
||||
if (restore_settings->allow_different_table_def)
|
||||
return;
|
||||
|
||||
getStorageCreateQuery();
|
||||
@ -330,7 +336,6 @@ namespace
|
||||
|
||||
/// Make a create query for this table.
|
||||
auto create_query = renameInCreateQuery(readCreateQueryFromBackup(table_name_));
|
||||
create_query->if_not_exists = !restore_settings.throw_if_table_exists;
|
||||
|
||||
CreateTableInfo info;
|
||||
info.create_query = create_query;
|
||||
@ -416,8 +421,6 @@ namespace
|
||||
db_name_in_backup.clear();
|
||||
}
|
||||
|
||||
create_db_query->if_not_exists = !restore_settings.throw_if_database_exists;
|
||||
|
||||
CreateDatabaseInfo info_db;
|
||||
info_db.create_query = create_db_query;
|
||||
info_db.name_in_backup = std::move(db_name_in_backup);
|
||||
|
@ -621,6 +621,7 @@
|
||||
M(650, SERIALIZATION_ERROR) \
|
||||
M(651, CAPN_PROTO_BAD_TYPE) \
|
||||
M(652, ONLY_NULLS_WHILE_READING_SCHEMA) \
|
||||
M(653, CANNOT_PARSE_RESTORE_TABLE_CREATION_MODE) \
|
||||
\
|
||||
M(999, KEEPER_EXCEPTION) \
|
||||
M(1000, POCO_EXCEPTION) \
|
||||
|
@ -78,12 +78,12 @@ def test_restore_table_into_existing_table(engine):
|
||||
instance.query(f"BACKUP TABLE test.table TO {backup_name}")
|
||||
|
||||
instance.query(
|
||||
f"RESTORE TABLE test.table INTO test.table FROM {backup_name} SETTINGS throw_if_table_exists=0"
|
||||
f"RESTORE TABLE test.table INTO test.table FROM {backup_name}"
|
||||
)
|
||||
assert instance.query("SELECT count(), sum(x) FROM test.table") == "200\t9900\n"
|
||||
|
||||
instance.query(
|
||||
f"RESTORE TABLE test.table INTO test.table FROM {backup_name} SETTINGS throw_if_table_exists=0"
|
||||
f"RESTORE TABLE test.table INTO test.table FROM {backup_name}"
|
||||
)
|
||||
assert instance.query("SELECT count(), sum(x) FROM test.table") == "300\t14850\n"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user