diff --git a/CMakeLists.txt b/CMakeLists.txt index 226d255fd37..5cc6c342961 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "None") set (CMAKE_BUILD_TYPE "RELWITHDEBINFO") endif () string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UC) -message (STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE} ) +message (STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") set (CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Debug;Release;MinSizeRel" CACHE STRING "" FORCE) diff --git a/contrib/jemalloc-cmake/CMakeLists.txt b/contrib/jemalloc-cmake/CMakeLists.txt index d60d34604a9..696ea5fee10 100644 --- a/contrib/jemalloc-cmake/CMakeLists.txt +++ b/contrib/jemalloc-cmake/CMakeLists.txt @@ -50,3 +50,7 @@ target_include_directories(jemalloc PRIVATE ${JEMALLOC_SOURCE_DIR}/include) target_compile_definitions(jemalloc PRIVATE -DJEMALLOC_NO_PRIVATE_NAMESPACE) + +if (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG") + target_compile_definitions(jemalloc PRIVATE -DJEMALLOC_DEBUG=1) +endif () diff --git a/dbms/src/Common/ErrorCodes.cpp b/dbms/src/Common/ErrorCodes.cpp index c21e87af1f3..513a26987e0 100644 --- a/dbms/src/Common/ErrorCodes.cpp +++ b/dbms/src/Common/ErrorCodes.cpp @@ -391,6 +391,8 @@ namespace ErrorCodes extern const int CANNOT_READLINE = 414; extern const int ALL_REPLICAS_LOST = 415; extern const int REPLICA_STATUS_CHANGED = 416; + extern const int EXPECTED_ALL_OR_ANY = 417; + extern const int UNKNOWN_JOIN_STRICTNESS = 418; extern const int KEEPER_EXCEPTION = 999; extern const int POCO_EXCEPTION = 1000; diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index b88c7e16da2..b00ce36f73a 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -96,6 +96,7 @@ namespace ErrorCodes extern const int CONDITIONAL_TREE_PARENT_NOT_FOUND; extern const int TYPE_MISMATCH; extern const int INVALID_JOIN_ON_EXPRESSION; + extern const int EXPECTED_ALL_OR_ANY; } @@ -2054,8 +2055,13 @@ void ExpressionAnalyzer::getActionsImpl(const ASTPtr & ast, bool no_subqueries, if (AggregateFunctionFactory::instance().isAggregateFunctionName(node->name)) return; - const FunctionBuilderPtr & function_builder = FunctionFactory::instance().get(node->name, context); - auto projection_action = getProjectionAction(node->name, actions_stack, projection_manipulator, getColumnName(), context); + /// Context object that we pass to function should live during query. + const Context & function_context = context.hasQueryContext() + ? context.getQueryContext() + : context; + + const FunctionBuilderPtr & function_builder = FunctionFactory::instance().get(node->name, function_context); + auto projection_action = getProjectionAction(node->name, actions_stack, projection_manipulator, getColumnName(), function_context); Names argument_names; DataTypes argument_types; @@ -2483,7 +2489,18 @@ bool ExpressionAnalyzer::appendJoin(ExpressionActionsChain & chain, bool only_ty ExpressionActionsChain::Step & step = chain.steps.back(); const auto & join_element = static_cast(*select_query->join()); - const auto & join_params = static_cast(*join_element.table_join); + auto & join_params = static_cast(*join_element.table_join); + + if (join_params.strictness == ASTTableJoin::Strictness::Unspecified && join_params.kind != ASTTableJoin::Kind::Cross) + { + if (settings.join_default_strictness.toString() == "ANY") + join_params.strictness = ASTTableJoin::Strictness::Any; + else if (settings.join_default_strictness.toString() == "ALL") + join_params.strictness = ASTTableJoin::Strictness::All; + else + throw Exception("Expected ANY or ALL in JOIN section, because setting (join_default_strictness) is empty", DB::ErrorCodes::EXPECTED_ALL_OR_ANY); + } + const auto & table_to_join = static_cast(*join_element.table_expression); getActionsFromJoinKeys(join_params, only_types, false, step.actions); diff --git a/dbms/src/Interpreters/Settings.h b/dbms/src/Interpreters/Settings.h index a669ef4d3d4..57d5d71799a 100644 --- a/dbms/src/Interpreters/Settings.h +++ b/dbms/src/Interpreters/Settings.h @@ -173,6 +173,8 @@ struct Settings \ M(SettingBool, join_use_nulls, 0, "Use NULLs for non-joined rows of outer JOINs. If false, use default value of corresponding columns data type.") \ \ + M(SettingJoinStrictness, join_default_strictness, JoinStrictness::Unspecified, "Set default strictness in JOIN query. Possible values: empty string, 'ANY', 'ALL'. If empty, query without strictness will throw exception.") \ + \ M(SettingUInt64, preferred_block_size_bytes, 1000000, "") \ \ M(SettingUInt64, max_replica_delay_for_distributed_queries, 300, "If set, distributed queries of Replicated tables will choose servers with replication delay in seconds less than the specified value (not inclusive). Zero means do not take delay into account.") \ diff --git a/dbms/src/Interpreters/SettingsCommon.cpp b/dbms/src/Interpreters/SettingsCommon.cpp index dfc79fd86c5..ccf4cade6a1 100644 --- a/dbms/src/Interpreters/SettingsCommon.cpp +++ b/dbms/src/Interpreters/SettingsCommon.cpp @@ -22,6 +22,7 @@ namespace ErrorCodes extern const int UNKNOWN_COMPRESSION_METHOD; extern const int UNKNOWN_DISTRIBUTED_PRODUCT_MODE; extern const int UNKNOWN_GLOBAL_SUBQUERIES_METHOD; + extern const int UNKNOWN_JOIN_STRICTNESS; extern const int SIZE_OF_FIXED_STRING_DOESNT_MATCH; extern const int BAD_ARGUMENTS; } @@ -288,6 +289,53 @@ void SettingLoadBalancing::write(WriteBuffer & buf) const } +JoinStrictness SettingJoinStrictness::getJoinStrictness(const String & s) +{ + if (s == "") return JoinStrictness::Unspecified; + if (s == "ALL") return JoinStrictness::ALL; + if (s == "ANY") return JoinStrictness::ANY; + + throw Exception("Unknown join strictness mode: '" + s + "', must be one of '', 'ALL', 'ANY'", + ErrorCodes::UNKNOWN_JOIN_STRICTNESS); +} + +String SettingJoinStrictness::toString() const +{ + const char * strings[] = {"", "ALL", "ANY"}; + if (value < JoinStrictness::Unspecified || value > JoinStrictness::ANY) + throw Exception("Unknown join strictness mode", ErrorCodes::UNKNOWN_JOIN_STRICTNESS); + return strings[static_cast(value)]; +} + +void SettingJoinStrictness::set(JoinStrictness x) +{ + value = x; + changed = true; +} + +void SettingJoinStrictness::set(const Field & x) +{ + set(safeGet(x)); +} + +void SettingJoinStrictness::set(const String & x) +{ + set(getJoinStrictness(x)); +} + +void SettingJoinStrictness::set(ReadBuffer & buf) +{ + String x; + readBinary(x, buf); + set(x); +} + +void SettingJoinStrictness::write(WriteBuffer & buf) const +{ + writeBinary(toString(), buf); +} + + TotalsMode SettingTotalsMode::getTotalsMode(const String & s) { if (s == "before_having") return TotalsMode::BEFORE_HAVING; diff --git a/dbms/src/Interpreters/SettingsCommon.h b/dbms/src/Interpreters/SettingsCommon.h index fc441ea30c1..667912d01be 100644 --- a/dbms/src/Interpreters/SettingsCommon.h +++ b/dbms/src/Interpreters/SettingsCommon.h @@ -191,6 +191,37 @@ struct SettingLoadBalancing }; +enum class JoinStrictness +{ + Unspecified = 0, /// Query JOIN without strictness will throw Exception. + ALL, /// Query JOIN without strictness -> ALL JOIN ... + ANY, /// Query JOIN without strictness -> ANY JOIN ... +}; + + +struct SettingJoinStrictness +{ + JoinStrictness value; + bool changed = false; + + SettingJoinStrictness(JoinStrictness x) : value(x) {} + + operator JoinStrictness() const { return value; } + SettingJoinStrictness & operator= (JoinStrictness x) { set(x); return *this; } + + static JoinStrictness getJoinStrictness(const String & s); + + String toString() const; + + void set(JoinStrictness x); + void set(const Field & x); + void set(const String & x); + void set(ReadBuffer & buf); + + void write(WriteBuffer & buf) const; +}; + + /// Which rows should be included in TOTALS. enum class TotalsMode { diff --git a/dbms/src/Parsers/ParserTablesInSelectQuery.cpp b/dbms/src/Parsers/ParserTablesInSelectQuery.cpp index 6b28deeb227..5eb00858e7c 100644 --- a/dbms/src/Parsers/ParserTablesInSelectQuery.cpp +++ b/dbms/src/Parsers/ParserTablesInSelectQuery.cpp @@ -136,6 +136,8 @@ bool ParserTablesInSelectQueryElement::parseImpl(Pos & pos, ASTPtr & node, Expec table_join->strictness = ASTTableJoin::Strictness::Any; else if (ParserKeyword("ALL").ignore(pos)) table_join->strictness = ASTTableJoin::Strictness::All; + else + table_join->strictness = ASTTableJoin::Strictness::Unspecified; if (ParserKeyword("INNER").ignore(pos)) table_join->kind = ASTTableJoin::Kind::Inner; diff --git a/dbms/tests/queries/0_stateless/00701_context_use_after_free.reference b/dbms/tests/queries/0_stateless/00701_context_use_after_free.reference new file mode 100644 index 00000000000..573541ac970 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00701_context_use_after_free.reference @@ -0,0 +1 @@ +0 diff --git a/dbms/tests/queries/0_stateless/00701_context_use_after_free.sql b/dbms/tests/queries/0_stateless/00701_context_use_after_free.sql new file mode 100644 index 00000000000..c7e68fcdf5c --- /dev/null +++ b/dbms/tests/queries/0_stateless/00701_context_use_after_free.sql @@ -0,0 +1 @@ +SELECT (toDecimal128(materialize('1'), 0), toDecimal128('2', 0)) < (toDecimal128('1', 0), toDecimal128('2', 0)); diff --git a/dbms/tests/queries/0_stateless/00701_join_default_strictness.reference b/dbms/tests/queries/0_stateless/00701_join_default_strictness.reference new file mode 100644 index 00000000000..ae51f642911 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00701_join_default_strictness.reference @@ -0,0 +1,12 @@ +1 1 +1 2 +1 3 +1 1 +1 1 +1 1 +1 2 +1 2 +1 2 +1 3 +1 3 +1 3 diff --git a/dbms/tests/queries/0_stateless/00701_join_default_strictness.sql b/dbms/tests/queries/0_stateless/00701_join_default_strictness.sql new file mode 100644 index 00000000000..a246ca68d45 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00701_join_default_strictness.sql @@ -0,0 +1,24 @@ +CREATE DATABASE IF NOT EXISTS test; +DROP TABLE IF EXISTS test.a1; +DROP TABLE IF EXISTS test.a2; + +SET send_logs_level = 'none'; + +CREATE TABLE test.a1(a UInt8, b UInt8) ENGINE=Memory; +CREATE TABLE test.a2(a UInt8, b UInt8) ENGINE=Memory; + +INSERT INTO test.a1 VALUES (1, 1); +INSERT INTO test.a1 VALUES (1, 2); +INSERT INTO test.a1 VALUES (1, 3); +INSERT INTO test.a2 VALUES (1, 2); +INSERT INTO test.a2 VALUES (1, 3); +INSERT INTO test.a2 VALUES (1, 4); + +SELECT a, b FROM test.a1 LEFT JOIN (SELECT a, b FROM test.a2) USING a ORDER BY b; -- { serverError 417 } + +SELECT a, b FROM test.a1 LEFT JOIN (SELECT a, b FROM test.a2) USING a ORDER BY b SETTINGS join_default_strictness='ANY'; + +SELECT a, b FROM test.a1 LEFT JOIN (SELECT a, b FROM test.a2) USING a ORDER BY b SETTINGS join_default_strictness='ALL'; + +DROP TABLE IF EXISTS test.a1; +DROP TABLE IF EXISTS test.a2;