diff --git a/dbms/include/DB/IO/WriteBufferFromHTTPServerResponse.h b/dbms/include/DB/IO/WriteBufferFromHTTPServerResponse.h index 35eb1f3df81f78fc1927742b049f7d05ea1b27da..75ec990e8e3e331d6016084787d2973d2d760da2 100644 --- a/dbms/include/DB/IO/WriteBufferFromHTTPServerResponse.h +++ b/dbms/include/DB/IO/WriteBufferFromHTTPServerResponse.h @@ -42,7 +42,6 @@ private: Poco::Net::HTTPServerResponse & response; bool add_cors_header; - bool add_authenticate_header = false; bool compress; ZlibCompressionMethod compression_method; int compression_level = Z_DEFAULT_COMPRESSION; @@ -77,11 +76,6 @@ private: if (add_cors_header) response.set("Access-Control-Allow-Origin", "*"); - if (add_authenticate_header) - { - response.set("WWW-Authenticate", "Basic realm=\"User Visible Realm\""); - } - setResponseDefaultHeaders(response); std::tie(response_header_ostr, response_body_ostr) = response.beginSend(); @@ -221,11 +215,6 @@ public: send_progress_interval_ms = send_progress_interval_ms_; } - void addAuthenticateRequest() - { - add_authenticate_header = true; - } - ~WriteBufferFromHTTPServerResponse() { try diff --git a/dbms/include/DB/Interpreters/Context.h b/dbms/include/DB/Interpreters/Context.h index 99d95f2e8aabc94eb78bf4e6c871773e2b4ce344..ff53d362ec3ca613e04d16647eb427b29ed3f1c3 100644 --- a/dbms/include/DB/Interpreters/Context.h +++ b/dbms/include/DB/Interpreters/Context.h @@ -284,6 +284,7 @@ public: QueryLog & getQueryLog(); const MergeTreeSettings & getMergeTreeSettings(); + /// Prevents DROP TABLE if its size is greater than max_size (50GB by default, max_size=0 turn off this check) void setMaxTableSizeToDrop(size_t max_size); void checkTableCanBeDropped(const String & database, const String & table, size_t table_size); diff --git a/dbms/include/DB/Storages/IStorage.h b/dbms/include/DB/Storages/IStorage.h index e75589f6424003512f7a71f99929e94114dd27dd..3466fc3bbddb5856152ebe79f205e20dece1c48f 100644 --- a/dbms/include/DB/Storages/IStorage.h +++ b/dbms/include/DB/Storages/IStorage.h @@ -271,12 +271,17 @@ public: bool is_dropped{false}; - /// Поддерживается ли индекс в секции IN + /// Does table support index for IN sections virtual bool supportsIndexForIn() const { return false; } - /// проверяет валидность данных + /// Checks validity of the data virtual bool checkData() const { throw DB::Exception("Check query is not supported for " + getName() + " storage"); } + /// Checks that table could be dropped right now + /// If it can - returns true + /// Otherwise - throws an exception with detailed information or returns false + virtual bool checkTableCanBeDropped() const { return true; } + protected: using ITableDeclaration::ITableDeclaration; using std::enable_shared_from_this::shared_from_this; diff --git a/dbms/include/DB/Storages/StorageMergeTree.h b/dbms/include/DB/Storages/StorageMergeTree.h index f403a1e11574fe0524c786e1c9c5fe481a08297e..8e9a2df9fdcd300388ed731de84940c7eb272948 100644 --- a/dbms/include/DB/Storages/StorageMergeTree.h +++ b/dbms/include/DB/Storages/StorageMergeTree.h @@ -103,7 +103,10 @@ public: bool supportsIndexForIn() const override { return true; } + bool checkTableCanBeDropped() const override; + MergeTreeData & getData() { return data; } + const MergeTreeData & getData() const { return data; } private: String path; diff --git a/dbms/include/DB/Storages/StorageReplicatedMergeTree.h b/dbms/include/DB/Storages/StorageReplicatedMergeTree.h index dfa43f9d8e7afe108dd3e0d8b199313feeb68a86..a5242aa45af8ca24dadbac2733870e68535eb723 100644 --- a/dbms/include/DB/Storages/StorageReplicatedMergeTree.h +++ b/dbms/include/DB/Storages/StorageReplicatedMergeTree.h @@ -156,7 +156,10 @@ public: bool supportsIndexForIn() const override { return true; } + bool checkTableCanBeDropped() const override; + MergeTreeData & getData() { return data; } + const MergeTreeData & getData() const { return data; } MergeTreeData * getUnreplicatedData() { return unreplicated_data.get(); } diff --git a/dbms/src/Core/ErrorCodes.cpp b/dbms/src/Core/ErrorCodes.cpp index bd55edfa8ea3869f194b15e32556139de8a38ca8..8f2bc47b84848cf0f4c97d90c8dc771d4686ab27 100644 --- a/dbms/src/Core/ErrorCodes.cpp +++ b/dbms/src/Core/ErrorCodes.cpp @@ -361,6 +361,7 @@ namespace ErrorCodes extern const int BAD_LAMBDA = 356; extern const int RESERVED_IDENTIFIER_NAME = 357; extern const int INTO_OUTFILE_NOT_ALLOWED = 358; + extern const int TABLE_SIZE_EXCEED_MAX_DROP_SIZE_LIMIT = 359; extern const int KEEPER_EXCEPTION = 999; extern const int POCO_EXCEPTION = 1000; diff --git a/dbms/src/Interpreters/Context.cpp b/dbms/src/Interpreters/Context.cpp index 170b0a74a5d9690e8c280e8d6d13af04ec54ed93..28ca63c4baa024991ea1a53042ccbead77a24871 100644 --- a/dbms/src/Interpreters/Context.cpp +++ b/dbms/src/Interpreters/Context.cpp @@ -72,6 +72,7 @@ namespace ErrorCodes extern const int THERE_IS_NO_SESSION; extern const int NO_ELEMENTS_IN_CONFIG; extern const int DDL_GUARD_IS_ACTIVE; + extern const int TABLE_SIZE_EXCEED_MAX_DROP_SIZE_LIMIT; } class TableFunctionFactory; @@ -1114,28 +1115,32 @@ void Context::checkTableCanBeDropped(const String & database, const String & tab { try { - force_file.remove(true); + force_file.remove(); return; } catch (...) { + /// User should recreate force file on each drop, it shouldn't be protected + tryLogCurrentException("Drop table check", "Can't remove force file to enable table drop"); } } String table_size_str = formatReadableSizeWithDecimalSuffix(table_size); String max_table_size_to_drop_str = formatReadableSizeWithDecimalSuffix(max_table_size_to_drop); + std::stringstream ostr; - throw Exception( - "Table " + database + "." + table + " was not dropped.\n" - "Reason:\n" - "1) Table size (" + table_size_str + ") is greater than max_table_size_to_drop (" + max_table_size_to_drop_str + ")\n" - "2) File " + force_file.path() + " intedned to force DROP " + - (force_file_exists ? String("exists but not writeable (could not be removed)") : String("doesn't exists")) + "\n" - "How to fix this:\n" - "1) Either increase (or set to zero) max_table_size_to_drop in server config and restart clickhouse\n" - "2) Either create forcing file " + force_file.path() + " and make sure that clickhouse has written permission for it.\n" - "2) bash example: touch '" + force_file.path() + "' && chmod 0777 '" + force_file.path() + "'" - , ErrorCodes::TABLE_WAS_NOT_DROPPED); + ostr << "Table " << database << "." << table << " was not dropped.\n" + << "Reason:\n" + << "1. Table size (" << table_size_str << ") is greater than max_table_size_to_drop (" << max_table_size_to_drop_str << ")\n" + << "2. File " << force_file.path() << " intedned to force DROP " + << (force_file_exists ? "exists but not writeable (could not be removed)" : "doesn't exist") << "\n"; + + ostr << "How to fix this:\n" + << "1. Either increase (or set to zero) max_table_size_to_drop in server config and restart clickhouse\n" + << "2. Either create forcing file " << force_file.path() << " and make sure that clickhouse has written permission for it.\n" + << "2. bash example: touch '" << force_file.path() << "' && chmod 0777 '" << force_file.path() << "'"; + + throw Exception(ostr.str(), ErrorCodes::TABLE_SIZE_EXCEED_MAX_DROP_SIZE_LIMIT); } diff --git a/dbms/src/Interpreters/InterpreterDropQuery.cpp b/dbms/src/Interpreters/InterpreterDropQuery.cpp index e8c4e9b03ba62b89bd891d894014ab162f9b6783..97bacd2cb09ca4dbb2cfe9bee66f20c6a5b60776 100644 --- a/dbms/src/Interpreters/InterpreterDropQuery.cpp +++ b/dbms/src/Interpreters/InterpreterDropQuery.cpp @@ -86,22 +86,26 @@ BlockIO InterpreterDropQuery::execute() { table.first->shutdown(); - /// Если кто-то успел удалить эту таблицу, выбросит исключение. + /// If table was already dropped by anyone, an exception will be thrown auto table_lock = table.first->lockForAlter(); String current_table_name = table.first->getTableName(); if (drop.detach) { - /// Удаляем таблицу из оперативки, метаданные и данные не трогаем. + /// Drop table from memory, don't touch data and metadata database->detachTable(current_table_name); } else { - /// Delete table data - table.first->drop(); + if (!table.first->checkTableCanBeDropped()) + throw Exception("Table " + database_name + "." + current_table_name + " couldn't be dropped due to failed pre-drop check", + ErrorCodes::TABLE_WAS_NOT_DROPPED); + /// Delete table metdata and table itself from memory database->removeTable(current_table_name); + /// Delete table data + table.first->drop(); table.first->is_dropped = true; diff --git a/dbms/src/Server/HTTPHandler.cpp b/dbms/src/Server/HTTPHandler.cpp index 6fde5f998012bac30761e49da11d61466d782090..4c21a04ffde0254c8c43f3a08e7ccf6c532c64ea 100644 --- a/dbms/src/Server/HTTPHandler.cpp +++ b/dbms/src/Server/HTTPHandler.cpp @@ -294,8 +294,7 @@ void HTTPHandler::trySendExceptionToClient(const std::string & s, int exception_ if (auth_fail) { - response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_UNAUTHORIZED); - used_output.out->addAuthenticateRequest(); + response.requireAuthentication("ClickHouse server HTTP API"); } else { diff --git a/dbms/src/Storages/StorageMergeTree.cpp b/dbms/src/Storages/StorageMergeTree.cpp index 1ae1f8dcdb56b4e6f055eeefb953e130dc67bed8..ea5d36e906710da819fd636612e141dc063a4135 100644 --- a/dbms/src/Storages/StorageMergeTree.cpp +++ b/dbms/src/Storages/StorageMergeTree.cpp @@ -124,10 +124,14 @@ BlockOutputStreamPtr StorageMergeTree::write(ASTPtr query, const Settings & sett return std::make_shared(*this); } -void StorageMergeTree::drop() +bool StorageMergeTree::checkTableCanBeDropped() const { context.checkTableCanBeDropped(database_name, table_name, getData().getColumnsTotalSize()); + return true; +} +void StorageMergeTree::drop() +{ shutdown(); data.dropAllData(); } diff --git a/dbms/src/Storages/StorageReplicatedMergeTree.cpp b/dbms/src/Storages/StorageReplicatedMergeTree.cpp index 357652c1baad92a46568ec9c19e3ebaad8af387c..0effd785a2032530f6f96afac7b3fce8b56f7ae5 100644 --- a/dbms/src/Storages/StorageReplicatedMergeTree.cpp +++ b/dbms/src/Storages/StorageReplicatedMergeTree.cpp @@ -2803,6 +2803,12 @@ void StorageReplicatedMergeTree::attachPartition(ASTPtr query, const Field & fie } } +bool StorageReplicatedMergeTree::checkTableCanBeDropped() const +{ + /// Consider only synchronized data + context.checkTableCanBeDropped(database_name, table_name, getData().getColumnsTotalSize()); + return true; +} void StorageReplicatedMergeTree::drop() { @@ -2812,8 +2818,7 @@ void StorageReplicatedMergeTree::drop() if (is_readonly || !zookeeper) throw Exception("Can't drop readonly replicated table (need to drop data in ZooKeeper as well)", ErrorCodes::TABLE_IS_READ_ONLY); - /// Consider only synchronized data - context.checkTableCanBeDropped(database_name, table_name, getData().getColumnsTotalSize()); + // checkTableCanBeDropped(); // uncomment to feel yourself safe shutdown();