Merge branch 'master' into fix-comment

This commit is contained in:
Alexey Milovidov 2023-08-05 13:36:59 +03:00 committed by GitHub
commit 5722557391
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 763 additions and 317 deletions

View File

@ -96,5 +96,4 @@ rg -Fa "Fatal" /var/log/clickhouse-server/clickhouse-server.log ||:
zstd < /var/log/clickhouse-server/clickhouse-server.log > /test_output/clickhouse-server.log.zst &
# Compressed (FIXME: remove once only github actions will be left)
rm /var/log/clickhouse-server/clickhouse-server.log
mv /var/log/clickhouse-server/stderr.log /test_output/ ||:

View File

@ -16,14 +16,14 @@ All available clusters are listed in the [system.clusters](../../operations/syst
**Syntax**
``` sql
cluster('cluster_name', db.table[, sharding_key])
cluster('cluster_name', db, table[, sharding_key])
clusterAllReplicas('cluster_name', db.table[, sharding_key])
clusterAllReplicas('cluster_name', db, table[, sharding_key])
cluster(['cluster_name', db.table, sharding_key])
cluster(['cluster_name', db, table, sharding_key])
clusterAllReplicas(['cluster_name', db.table, sharding_key])
clusterAllReplicas(['cluster_name', db, table, sharding_key])
```
**Arguments**
- `cluster_name` Name of a cluster that is used to build a set of addresses and connection parameters to remote and local servers.
- `cluster_name` Name of a cluster that is used to build a set of addresses and connection parameters to remote and local servers, set `default` if not specified.
- `db.table` or `db`, `table` - Name of a database and a table.
- `sharding_key` - A sharding key. Optional. Needs to be specified if the cluster has more than one shard.

View File

@ -13,10 +13,10 @@ Both functions can be used in `SELECT` and `INSERT` queries.
## Syntax
``` sql
remote('addresses_expr', db, table[, 'user'[, 'password'], sharding_key])
remote('addresses_expr', db.table[, 'user'[, 'password'], sharding_key])
remoteSecure('addresses_expr', db, table[, 'user'[, 'password'], sharding_key])
remoteSecure('addresses_expr', db.table[, 'user'[, 'password'], sharding_key])
remote('addresses_expr', [db, table, 'user'[, 'password'], sharding_key])
remote('addresses_expr', [db.table, 'user'[, 'password'], sharding_key])
remoteSecure('addresses_expr', [db, table, 'user'[, 'password'], sharding_key])
remoteSecure('addresses_expr', [db.table, 'user'[, 'password'], sharding_key])
```
## Parameters
@ -29,6 +29,8 @@ remoteSecure('addresses_expr', db.table[, 'user'[, 'password'], sharding_key])
The port is required for an IPv6 address.
If only specify this parameter, `db` and `table` will use `system.one` by default.
Type: [String](../../sql-reference/data-types/string.md).
- `db` — Database name. Type: [String](../../sql-reference/data-types/string.md).

View File

@ -266,8 +266,16 @@ void KeeperClient::runInteractive()
LineReader::Patterns query_extenders = {"\\"};
LineReader::Patterns query_delimiters = {};
char word_break_characters[] = " \t\v\f\a\b\r\n/";
ReplxxLineReader lr(suggest, history_file, false, query_extenders, query_delimiters, {});
ReplxxLineReader lr(
suggest,
history_file,
/* multiline= */ false,
query_extenders,
query_delimiters,
word_break_characters,
/* highlighter_= */ {});
lr.enableBracketedPaste();
while (true)

View File

@ -466,6 +466,11 @@ int main(int argc_, char ** argv_)
checkHarmfulEnvironmentVariables(argv_);
#endif
/// This is used for testing. For example,
/// clickhouse-local should be able to run a simple query without throw/catch.
if (getenv("CLICKHOUSE_TERMINATE_ON_ANY_EXCEPTION")) // NOLINT(concurrency-mt-unsafe)
DB::terminate_on_any_exception = true;
/// Reset new handler to default (that throws std::bad_alloc)
/// It is needed because LLVM library clobbers it.
std::set_new_handler(nullptr);

231
rust/Cargo.lock generated
View File

@ -78,6 +78,55 @@ dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "anyhow"
version = "1.0.72"
@ -89,9 +138,9 @@ dependencies = [
[[package]]
name = "ariadne"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "367fd0ad87307588d087544707bc5fbf4805ded96c7db922b70d368fa1cb5702"
checksum = "72fe02fc62033df9ba41cba57ee19acf5e742511a140c7dbc3a873e19a19a1bd"
dependencies = [
"unicode-width",
"yansi",
@ -142,6 +191,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
[[package]]
name = "blake3"
version = "1.4.1"
@ -204,7 +259,7 @@ version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23170228b96236b5a7299057ac284a321457700bc8c41a4476052f0f4ba5349d"
dependencies = [
"hashbrown 0.12.3",
"hashbrown",
"stacker",
]
@ -218,6 +273,12 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "constant_time_eq"
version = "0.3.0"
@ -488,21 +549,36 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "enum-as-inner"
version = "0.5.1"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116"
checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 1.0.109",
"syn 2.0.27",
]
[[package]]
name = "equivalent"
version = "1.0.1"
name = "errno"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "fnv"
@ -555,12 +631,6 @@ dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
[[package]]
name = "heck"
version = "0.4.1"
@ -603,13 +673,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "2.0.0"
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"equivalent",
"hashbrown 0.14.0",
"hermit-abi",
"rustix",
"windows-sys",
]
[[package]]
@ -621,6 +692,15 @@ dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.9"
@ -657,6 +737,12 @@ dependencies = [
"cc",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]]
name = "log"
version = "0.4.19"
@ -708,7 +794,7 @@ version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cfg-if",
"libc",
]
@ -720,7 +806,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
dependencies = [
"autocfg",
"bitflags",
"bitflags 1.3.2",
"cfg-if",
"libc",
"memoffset 0.6.5",
@ -787,31 +873,55 @@ dependencies = [
]
[[package]]
name = "prql-compiler"
version = "0.8.1"
name = "prql-ast"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c99b52154002ac7f286dd2293c2f8d4e30526c1d396b14deef5ada1deef3c9ff"
checksum = "71194e75f14dbe7debdf2b5eca0812c978021a1bd23d6fe1da98b58e407e035a"
dependencies = [
"enum-as-inner",
"semver",
"serde",
"strum",
]
[[package]]
name = "prql-compiler"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ff28e838b1be4227cc567a75c11caa3be25c5015f0e5fd21279c06e944ba44f"
dependencies = [
"anstream",
"anyhow",
"ariadne",
"chumsky",
"csv",
"enum-as-inner",
"itertools",
"lazy_static",
"itertools 0.11.0",
"log",
"once_cell",
"prql-ast",
"prql-parser",
"regex",
"semver",
"serde",
"serde_json",
"serde_yaml",
"sqlformat",
"sqlparser",
"strum",
"strum_macros",
]
[[package]]
name = "prql-parser"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3182e2ef0465a960eb02519b18768e39123d3c3a0037a2d2934055a3ef901870"
dependencies = [
"chumsky",
"itertools 0.11.0",
"prql-ast",
"semver",
]
[[package]]
name = "psm"
version = "0.1.21"
@ -858,7 +968,7 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -907,6 +1017,19 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ee020b1716f0a80e2ace9b03441a749e402e86712f15f16fe8a8f75afac732f"
dependencies = [
"bitflags 2.3.3",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "rustversion"
version = "1.0.14"
@ -971,19 +1094,6 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.9.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "skim"
version = "0.10.4"
@ -991,7 +1101,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d28de0a6cb2cdd83a076f1de9d965b973ae08b244df1aa70b432946dda0f32"
dependencies = [
"beef",
"bitflags",
"bitflags 1.3.2",
"chrono",
"crossbeam",
"defer-drop",
@ -1015,16 +1125,16 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c12bc9199d1db8234678b7051747c07f517cdcf019262d1847b94ec8b1aee3e"
dependencies = [
"itertools",
"itertools 0.10.5",
"nom",
"unicode_categories",
]
[[package]]
name = "sqlparser"
version = "0.33.0"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "355dc4d4b6207ca8a3434fc587db0a8016130a574dbcdbfb93d7f7b5bc5b211a"
checksum = "2eaa1e88e78d2c2460d78b7dc3f0c08dbb606ab4222f9aff36f420d36e307d87"
dependencies = [
"log",
"serde",
@ -1051,24 +1161,24 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strum"
version = "0.24.1"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.24.3"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
checksum = "6069ca09d878a33f883cc06aaa9718ede171841d3832450354410b718b097232"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 1.0.109",
"syn 2.0.27",
]
[[package]]
@ -1191,7 +1301,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e19c6ab038babee3d50c8c12ff8b910bdb2196f62278776422f50390d8e53d8"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"lazy_static",
"log",
"nix 0.24.3",
@ -1223,12 +1333,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "unsafe-libyaml"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
[[package]]
name = "utf8parse"
version = "0.2.1"
@ -1368,6 +1472,15 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.1"

View File

@ -1,12 +1,12 @@
[package]
edition = "2021"
name = "_ch_rust_prql"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
prql-compiler = "0.8.1"
prql-compiler = "0.9.3"
serde_json = "1.0"
[lib]

View File

@ -2313,15 +2313,28 @@ void ClientBase::runInteractive()
LineReader::Patterns query_extenders = {"\\"};
LineReader::Patterns query_delimiters = {";", "\\G", "\\G;"};
char word_break_characters[] = " \t\v\f\a\b\r\n`~!@#$%^&*()-=+[{]}\\|;:'\",<.>/?";
#if USE_REPLXX
replxx::Replxx::highlighter_callback_t highlight_callback{};
if (config().getBool("highlight", true))
highlight_callback = highlight;
ReplxxLineReader lr(*suggest, history_file, config().has("multiline"), query_extenders, query_delimiters, highlight_callback);
ReplxxLineReader lr(
*suggest,
history_file,
config().has("multiline"),
query_extenders,
query_delimiters,
word_break_characters,
highlight_callback);
#else
LineReader lr(history_file, config().has("multiline"), query_extenders, query_delimiters);
LineReader lr(
history_file,
config().has("multiline"),
query_extenders,
query_delimiters,
word_break_characters);
#endif
static const std::initializer_list<std::pair<String, String>> backslash_aliases =

View File

@ -66,7 +66,7 @@ void addNewWords(Words & to, const Words & from, Compare comp)
namespace DB
{
replxx::Replxx::completions_t LineReader::Suggest::getCompletions(const String & prefix, size_t prefix_length)
replxx::Replxx::completions_t LineReader::Suggest::getCompletions(const String & prefix, size_t prefix_length, const char * word_break_characters)
{
std::string_view last_word;
@ -135,7 +135,10 @@ void LineReader::Suggest::addWords(Words && new_words)
}
LineReader::LineReader(const String & history_file_path_, bool multiline_, Patterns extenders_, Patterns delimiters_)
: history_file_path(history_file_path_), multiline(multiline_), extenders(std::move(extenders_)), delimiters(std::move(delimiters_))
: history_file_path(history_file_path_)
, multiline(multiline_)
, extenders(std::move(extenders_))
, delimiters(std::move(delimiters_))
{
/// FIXME: check extender != delimiter
}

View File

@ -21,7 +21,7 @@ public:
using Callback = std::function<Words(const String & prefix, size_t prefix_length)>;
/// Get vector for the matched range of words if any.
replxx::Replxx::completions_t getCompletions(const String & prefix, size_t prefix_length);
replxx::Replxx::completions_t getCompletions(const String & prefix, size_t prefix_length, const char * word_break_characters);
void addWords(Words && new_words);
void setCompletionsCallback(Callback && callback) { custom_completions_callback = callback; }
@ -65,7 +65,6 @@ protected:
};
const String history_file_path;
static constexpr char word_break_characters[] = " \t\v\f\a\b\r\n`~!@#$%^&*()-=+[{]}\\|;:'\",<.>/?";
String input;

View File

@ -287,8 +287,10 @@ ReplxxLineReader::ReplxxLineReader(
bool multiline_,
Patterns extenders_,
Patterns delimiters_,
const char word_break_characters_[],
replxx::Replxx::highlighter_callback_t highlighter_)
: LineReader(history_file_path_, multiline_, std::move(extenders_), std::move(delimiters_)), highlighter(std::move(highlighter_))
, word_break_characters(word_break_characters_)
, editor(getEditor())
{
using namespace std::placeholders;
@ -326,9 +328,9 @@ ReplxxLineReader::ReplxxLineReader(
rx.install_window_change_handler();
auto callback = [&suggest] (const String & context, size_t context_size)
auto callback = [&suggest, this] (const String & context, size_t context_size)
{
return suggest.getCompletions(context, context_size);
return suggest.getCompletions(context, context_size, word_break_characters);
};
rx.set_completion_callback(callback);

View File

@ -15,6 +15,7 @@ public:
bool multiline,
Patterns extenders_,
Patterns delimiters_,
const char word_break_characters_[],
replxx::Replxx::highlighter_callback_t highlighter_);
~ReplxxLineReader() override;
@ -33,6 +34,8 @@ private:
replxx::Replxx rx;
replxx::Replxx::highlighter_callback_t highlighter;
const char * word_break_characters;
// used to call flock() to synchronize multiple clients using same history file
int history_file_fd = -1;
bool bracketed_paste_enabled = false;

View File

@ -50,6 +50,8 @@ void abortOnFailedAssertion(const String & description)
abort();
}
bool terminate_on_any_exception = false;
/// - Aborts the process if error code is LOGICAL_ERROR.
/// - Increments error codes statistics.
void handle_error_code([[maybe_unused]] const std::string & msg, int code, bool remote, const Exception::FramePointers & trace)
@ -84,6 +86,8 @@ Exception::Exception(const MessageMasked & msg_masked, int code, bool remote_)
: Poco::Exception(msg_masked.msg, code)
, remote(remote_)
{
if (terminate_on_any_exception)
std::terminate();
capture_thread_frame_pointers = thread_frame_pointers;
handle_error_code(msg_masked.msg, code, remote, getStackFramePointers());
}
@ -92,6 +96,8 @@ Exception::Exception(MessageMasked && msg_masked, int code, bool remote_)
: Poco::Exception(msg_masked.msg, code)
, remote(remote_)
{
if (terminate_on_any_exception)
std::terminate();
capture_thread_frame_pointers = thread_frame_pointers;
handle_error_code(message(), code, remote, getStackFramePointers());
}
@ -99,6 +105,8 @@ Exception::Exception(MessageMasked && msg_masked, int code, bool remote_)
Exception::Exception(CreateFromPocoTag, const Poco::Exception & exc)
: Poco::Exception(exc.displayText(), ErrorCodes::POCO_EXCEPTION)
{
if (terminate_on_any_exception)
std::terminate();
capture_thread_frame_pointers = thread_frame_pointers;
#ifdef STD_EXCEPTION_HAS_STACK_TRACE
auto * stack_trace_frames = exc.get_stack_trace_frames();
@ -111,6 +119,8 @@ Exception::Exception(CreateFromPocoTag, const Poco::Exception & exc)
Exception::Exception(CreateFromSTDTag, const std::exception & exc)
: Poco::Exception(demangle(typeid(exc).name()) + ": " + String(exc.what()), ErrorCodes::STD_EXCEPTION)
{
if (terminate_on_any_exception)
std::terminate();
capture_thread_frame_pointers = thread_frame_pointers;
#ifdef STD_EXCEPTION_HAS_STACK_TRACE
auto * stack_trace_frames = exc.get_stack_trace_frames();

View File

@ -20,6 +20,10 @@ namespace DB
void abortOnFailedAssertion(const String & description);
/// This flag can be set for testing purposes - to check that no exceptions are thrown.
extern bool terminate_on_any_exception;
class Exception : public Poco::Exception
{
public:
@ -27,17 +31,23 @@ public:
Exception()
{
if (terminate_on_any_exception)
std::terminate();
capture_thread_frame_pointers = thread_frame_pointers;
}
Exception(const PreformattedMessage & msg, int code): Exception(msg.text, code)
{
if (terminate_on_any_exception)
std::terminate();
capture_thread_frame_pointers = thread_frame_pointers;
message_format_string = msg.format_string;
}
Exception(PreformattedMessage && msg, int code): Exception(std::move(msg.text), code)
{
if (terminate_on_any_exception)
std::terminate();
capture_thread_frame_pointers = thread_frame_pointers;
message_format_string = msg.format_string;
}

View File

@ -783,6 +783,7 @@ class IColumn;
M(UInt64, extract_kvp_max_pairs_per_row, 1000, "Max number pairs that can be produced by extractKeyValuePairs function. Used to safeguard against consuming too much memory.", 0) \
M(Timezone, session_timezone, "", "This setting can be removed in the future due to potential caveats. It is experimental and is not suitable for production usage. The default timezone for current session or query. The server default timezone if empty.", 0) \
M(Bool, allow_create_index_without_type, false, "Allow CREATE INDEX query without TYPE. Query will be ignored. Made for SQL compatibility tests.", 0)\
M(Bool, create_index_ignore_unique, false, "Ignore UNIQUE keyword in CREATE UNIQUE INDEX. Made for SQL compatibility tests.", 0)\
// End of COMMON_SETTINGS
// Please add settings related to formats into the FORMAT_FACTORY_SETTINGS and move obsolete settings to OBSOLETE_SETTINGS.

View File

@ -77,7 +77,6 @@ public:
void deserializeTextJSON(IColumn & column, ReadBuffer & istr, const FormatSettings &) const override;
void serializeTextJSONPretty(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings, size_t indent) const override;
void serializeTextXML(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const override;
};

View File

@ -11,9 +11,11 @@
#include <Storages/IStorage.h>
#include <TableFunctions/TableFunctionFactory.h>
#include <Common/filesystemHelpers.h>
#include <Formats/FormatFactory.h>
#include <filesystem>
namespace fs = std::filesystem;
namespace DB
@ -75,10 +77,8 @@ bool DatabaseFilesystem::checkTableFilePath(const std::string & table_path, Cont
/// Check access for file before checking its existence.
if (check_path && !fileOrSymlinkPathStartsWith(table_path, user_files_path))
{
if (throw_on_error)
throw Exception(ErrorCodes::PATH_ACCESS_DENIED, "File is not inside {}", user_files_path);
else
return false;
/// Access denied is thrown regardless of 'throw_on_error'
throw Exception(ErrorCodes::PATH_ACCESS_DENIED, "File is not inside {}", user_files_path);
}
/// Check if the corresponding file exists.
@ -128,20 +128,25 @@ bool DatabaseFilesystem::isTableExist(const String & name, ContextPtr context_)
if (tryGetTableFromCache(name))
return true;
return checkTableFilePath(getTablePath(name), context_, /* throw_on_error */false);
return checkTableFilePath(getTablePath(name), context_, /* throw_on_error */ false);
}
StoragePtr DatabaseFilesystem::getTableImpl(const String & name, ContextPtr context_) const
StoragePtr DatabaseFilesystem::getTableImpl(const String & name, ContextPtr context_, bool throw_on_error) const
{
/// Check if table exists in loaded tables map.
if (auto table = tryGetTableFromCache(name))
return table;
auto table_path = getTablePath(name);
checkTableFilePath(table_path, context_, /* throw_on_error */true);
if (!checkTableFilePath(table_path, context_, throw_on_error))
return {};
String format = FormatFactory::instance().getFormatFromFileName(table_path, throw_on_error);
if (format.empty())
return {};
/// If the file exists, create a new table using TableFunctionFile and return it.
auto args = makeASTFunction("file", std::make_shared<ASTLiteral>(table_path));
auto args = makeASTFunction("file", std::make_shared<ASTLiteral>(table_path), std::make_shared<ASTLiteral>(format));
auto table_function = TableFunctionFactory::instance().get(args, context_);
if (!table_function)
@ -158,7 +163,7 @@ StoragePtr DatabaseFilesystem::getTableImpl(const String & name, ContextPtr cont
StoragePtr DatabaseFilesystem::getTable(const String & name, ContextPtr context_) const
{
/// getTableImpl can throw exceptions, do not catch them to show correct error to user.
if (auto storage = getTableImpl(name, context_))
if (auto storage = getTableImpl(name, context_, true))
return storage;
throw Exception(ErrorCodes::UNKNOWN_TABLE, "Table {}.{} doesn't exist",
@ -167,20 +172,7 @@ StoragePtr DatabaseFilesystem::getTable(const String & name, ContextPtr context_
StoragePtr DatabaseFilesystem::tryGetTable(const String & name, ContextPtr context_) const
{
try
{
return getTableImpl(name, context_);
}
catch (const Exception & e)
{
/// Ignore exceptions thrown by TableFunctionFile, which indicate that there is no table
/// see tests/02722_database_filesystem.sh for more details.
if (e.code() == ErrorCodes::FILE_DOESNT_EXIST)
{
return nullptr;
}
throw;
}
return getTableImpl(name, context_, false);
}
bool DatabaseFilesystem::empty() const

View File

@ -48,7 +48,7 @@ public:
DatabaseTablesIteratorPtr getTablesIterator(ContextPtr, const FilterByNameFunction &) const override;
protected:
StoragePtr getTableImpl(const String & name, ContextPtr context) const;
StoragePtr getTableImpl(const String & name, ContextPtr context, bool throw_on_error) const;
StoragePtr tryGetTableFromCache(const std::string & name) const;

View File

@ -42,50 +42,13 @@ void ZstdDeflatingAppendableWriteBuffer::nextImpl()
if (!offset())
return;
input.src = reinterpret_cast<unsigned char *>(working_buffer.begin());
input.size = offset();
input.pos = 0;
if (first_write && append_to_existing_file && isNeedToAddEmptyBlock())
{
addEmptyBlock();
first_write = false;
}
try
{
bool ended = false;
do
{
out->nextIfAtEnd();
output.dst = reinterpret_cast<unsigned char *>(out->buffer().begin());
output.size = out->buffer().size();
output.pos = out->offset();
size_t compression_result = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_flush);
if (ZSTD_isError(compression_result))
throw Exception(
ErrorCodes::ZSTD_ENCODER_FAILED,
"ZSTD stream decoding failed: error code: {}; ZSTD version: {}",
ZSTD_getErrorName(compression_result), ZSTD_VERSION_STRING);
first_write = false;
out->position() = out->buffer().begin() + output.pos;
bool everything_was_compressed = (input.pos == input.size);
bool everything_was_flushed = compression_result == 0;
ended = everything_was_compressed && everything_was_flushed;
} while (!ended);
}
catch (...)
{
/// Do not try to write next time after exception.
out->position() = out->buffer().begin();
throw;
}
flush(ZSTD_e_flush);
}
ZstdDeflatingAppendableWriteBuffer::~ZstdDeflatingAppendableWriteBuffer()
@ -103,58 +66,58 @@ void ZstdDeflatingAppendableWriteBuffer::finalizeImpl()
}
else
{
try
{
finalizeBefore();
out->finalize();
finalizeAfter();
}
catch (...)
{
/// Do not try to flush next time after exception.
out->position() = out->buffer().begin();
throw;
}
finalizeBefore();
out->finalize();
finalizeAfter();
}
}
void ZstdDeflatingAppendableWriteBuffer::finalizeBefore()
{
next();
out->nextIfAtEnd();
input.src = reinterpret_cast<unsigned char *>(working_buffer.begin());
input.size = offset();
input.pos = 0;
output.dst = reinterpret_cast<unsigned char *>(out->buffer().begin());
output.size = out->buffer().size();
output.pos = out->offset();
/// Actually we can use ZSTD_e_flush here and add empty termination
/// block on each new buffer creation for non-empty file unconditionally (without isNeedToAddEmptyBlock).
/// However ZSTD_decompressStream is able to read non-terminated frame (we use it in reader buffer),
/// but console zstd utility cannot.
size_t remaining = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_end);
while (remaining != 0)
flush(ZSTD_e_end);
}
void ZstdDeflatingAppendableWriteBuffer::flush(ZSTD_EndDirective mode)
{
input.src = reinterpret_cast<unsigned char *>(working_buffer.begin());
input.size = offset();
input.pos = 0;
try
{
if (ZSTD_isError(remaining))
throw Exception(ErrorCodes::ZSTD_ENCODER_FAILED,
"ZSTD stream encoder end failed: error: '{}' ZSTD version: {}",
ZSTD_getErrorName(remaining), ZSTD_VERSION_STRING);
remaining = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_end);
out->position() = out->buffer().begin() + output.pos;
if (!out->hasPendingData())
bool ended = false;
do
{
out->next();
out->nextIfAtEnd();
output.dst = reinterpret_cast<unsigned char *>(out->buffer().begin());
output.size = out->buffer().size();
output.pos = out->offset();
}
size_t compression_result = ZSTD_compressStream2(cctx, &output, &input, mode);
if (ZSTD_isError(compression_result))
throw Exception(
ErrorCodes::ZSTD_ENCODER_FAILED,
"ZSTD stream decoding failed: error code: {}; ZSTD version: {}",
ZSTD_getErrorName(compression_result), ZSTD_VERSION_STRING);
out->position() = out->buffer().begin() + output.pos;
bool everything_was_compressed = (input.pos == input.size);
bool everything_was_flushed = compression_result == 0;
ended = everything_was_compressed && everything_was_flushed;
} while (!ended);
}
catch (...)
{
/// Do not try to write next time after exception.
out->position() = out->buffer().begin();
throw;
}
}

View File

@ -52,6 +52,8 @@ private:
/// NOTE: will fill compressed data to the out.working_buffer, but will not call out.next method until the buffer is full
void nextImpl() override;
void flush(ZSTD_EndDirective mode);
/// Write terminating ZSTD_e_end: empty block + frame epilogue. BTW it
/// should be almost noop, because frame epilogue contains only checksums,
/// and they are disabled for this buffer.

View File

@ -32,13 +32,8 @@ ZstdDeflatingWriteBuffer::ZstdDeflatingWriteBuffer(
ZstdDeflatingWriteBuffer::~ZstdDeflatingWriteBuffer() = default;
void ZstdDeflatingWriteBuffer::nextImpl()
void ZstdDeflatingWriteBuffer::flush(ZSTD_EndDirective mode)
{
if (!offset())
return;
ZSTD_EndDirective mode = ZSTD_e_flush;
input.src = reinterpret_cast<unsigned char *>(working_buffer.begin());
input.size = offset();
input.pos = 0;
@ -54,7 +49,6 @@ void ZstdDeflatingWriteBuffer::nextImpl()
output.size = out->buffer().size();
output.pos = out->offset();
size_t compression_result = ZSTD_compressStream2(cctx, &output, &input, mode);
if (ZSTD_isError(compression_result))
throw Exception(
@ -78,24 +72,15 @@ void ZstdDeflatingWriteBuffer::nextImpl()
}
}
void ZstdDeflatingWriteBuffer::nextImpl()
{
if (offset())
flush(ZSTD_e_flush);
}
void ZstdDeflatingWriteBuffer::finalizeBefore()
{
next();
out->nextIfAtEnd();
input.src = reinterpret_cast<unsigned char *>(working_buffer.begin());
input.size = offset();
input.pos = 0;
output.dst = reinterpret_cast<unsigned char *>(out->buffer().begin());
output.size = out->buffer().size();
output.pos = out->offset();
size_t remaining = ZSTD_compressStream2(cctx, &output, &input, ZSTD_e_end);
if (ZSTD_isError(remaining))
throw Exception(ErrorCodes::ZSTD_ENCODER_FAILED, "zstd stream encoder end failed: zstd version: {}", ZSTD_VERSION_STRING);
out->position() = out->buffer().begin() + output.pos;
flush(ZSTD_e_end);
}
void ZstdDeflatingWriteBuffer::finalizeAfter()

View File

@ -37,6 +37,8 @@ private:
void finalizeBefore() override;
void finalizeAfter() override;
void flush(ZSTD_EndDirective mode);
ZSTD_CCtx * cctx;
ZSTD_inBuffer input;
ZSTD_outBuffer output;

View File

@ -587,7 +587,7 @@ KeyMetadata::iterator FileCache::addFileSegment(
}
}
bool FileCache::tryReserve(FileSegment & file_segment, const size_t size)
bool FileCache::tryReserve(FileSegment & file_segment, const size_t size, FileCacheReserveStat & reserve_stat)
{
ProfileEventTimeIncrement<Microseconds> watch(ProfileEvents::FilesystemCacheReserveMicroseconds);
@ -653,6 +653,7 @@ bool FileCache::tryReserve(FileSegment & file_segment, const size_t size)
{
chassert(segment_metadata->file_segment->assertCorrectness());
auto & stat_by_kind = reserve_stat.stat_by_kind[segment_metadata->file_segment->getKind()];
if (segment_metadata->releasable())
{
const auto & key = segment_metadata->file_segment->key();
@ -661,9 +662,18 @@ bool FileCache::tryReserve(FileSegment & file_segment, const size_t size)
it = to_delete.emplace(key, locked_key.getKeyMetadata()).first;
it->second.add(segment_metadata);
stat_by_kind.releasable_size += segment_metadata->size();
++stat_by_kind.releasable_count;
freeable_space += segment_metadata->size();
++freeable_count;
}
else
{
stat_by_kind.non_releasable_size += segment_metadata->size();
++stat_by_kind.non_releasable_count;
}
return PriorityIterationResult::CONTINUE;
};
@ -718,6 +728,10 @@ bool FileCache::tryReserve(FileSegment & file_segment, const size_t size)
return is_overflow;
};
/// If we have enough space in query_priority, we are not interested about stat there anymore.
/// Clean the stat before iterating main_priority to avoid calculating any segment stat twice.
reserve_stat.stat_by_kind.clear();
if (is_main_priority_overflow())
{
main_priority->iterate(

View File

@ -30,6 +30,22 @@ namespace ErrorCodes
extern const int BAD_ARGUMENTS;
}
/// Track acquired space in cache during reservation
/// to make error messages when no space left more informative.
struct FileCacheReserveStat
{
struct Stat
{
size_t releasable_size;
size_t releasable_count;
size_t non_releasable_size;
size_t non_releasable_count;
};
std::unordered_map<FileSegmentKind, Stat> stat_by_kind;
};
/// Local cache for remote filesystem files, represented as a set of non-overlapping non-empty file segments.
/// Different caching algorithms are implemented using IFileCachePriority.
class FileCache : private boost::noncopyable
@ -106,7 +122,7 @@ public:
size_t getMaxFileSegmentSize() const { return max_file_segment_size; }
bool tryReserve(FileSegment & file_segment, size_t size);
bool tryReserve(FileSegment & file_segment, size_t size, FileCacheReserveStat & stat);
FileSegmentsHolderPtr getSnapshot();

View File

@ -186,9 +186,7 @@ bool FileSegment::isDownloaded() const
String FileSegment::getCallerId()
{
if (!CurrentThread::isInitialized()
|| !CurrentThread::get().getQueryContext()
|| CurrentThread::getQueryId().empty())
if (!CurrentThread::isInitialized() || CurrentThread::getQueryId().empty())
return "None:" + toString(getThreadId());
return std::string(CurrentThread::getQueryId()) + ":" + toString(getThreadId());
@ -478,7 +476,7 @@ LockedKeyPtr FileSegment::lockKeyMetadata(bool assert_exists) const
return metadata->tryLock();
}
bool FileSegment::reserve(size_t size_to_reserve)
bool FileSegment::reserve(size_t size_to_reserve, FileCacheReserveStat * reserve_stat)
{
if (!size_to_reserve)
throw Exception(ErrorCodes::LOGICAL_ERROR, "Zero space reservation is not allowed");
@ -514,9 +512,8 @@ bool FileSegment::reserve(size_t size_to_reserve)
size_t already_reserved_size = reserved_size - expected_downloaded_size;
bool reserved = already_reserved_size >= size_to_reserve;
if (reserved)
return reserved;
if (already_reserved_size >= size_to_reserve)
return true;
size_to_reserve = size_to_reserve - already_reserved_size;
@ -525,7 +522,12 @@ bool FileSegment::reserve(size_t size_to_reserve)
if (is_unbound && is_file_segment_size_exceeded)
segment_range.right = range().left + expected_downloaded_size + size_to_reserve;
reserved = cache->tryReserve(*this, size_to_reserve);
/// if reserve_stat is not passed then use dummy stat and discard the result.
FileCacheReserveStat dummy_stat;
if (!reserve_stat)
reserve_stat = &dummy_stat;
bool reserved = cache->tryReserve(*this, size_to_reserve, *reserve_stat);
if (!reserved)
setDownloadFailedUnlocked(lockFileSegment());

View File

@ -26,6 +26,7 @@ namespace DB
{
class ReadBufferFromFileBase;
struct FileCacheReserveStat;
/*
* FileSegmentKind is used to specify the eviction policy for file segments.
@ -243,12 +244,7 @@ public:
/// Try to reserve exactly `size` bytes (in addition to the getDownloadedSize() bytes already downloaded).
/// Returns true if reservation was successful, false otherwise.
bool reserve(size_t size_to_reserve);
/// Try to reserve at max `size_to_reserve` bytes.
/// Returns actual size reserved. It can be less than size_to_reserve in non strict mode.
/// In strict mode throws an error on attempt to reserve space too much space.
size_t tryReserve(size_t size_to_reserve, bool strict = false);
bool reserve(size_t size_to_reserve, FileCacheReserveStat * reserve_stat = nullptr);
/// Write data into reserved space.
void write(const char * from, size_t size, size_t offset);

View File

@ -1,5 +1,6 @@
#include <Interpreters/Cache/WriteBufferToFileSegment.h>
#include <Interpreters/Cache/FileSegment.h>
#include <Interpreters/Cache/FileCache.h>
#include <IO/SwapHelper.h>
#include <IO/ReadBufferFromFile.h>
@ -44,11 +45,25 @@ void WriteBufferToFileSegment::nextImpl()
size_t bytes_to_write = offset();
FileCacheReserveStat reserve_stat;
/// In case of an error, we don't need to finalize the file segment
/// because it will be deleted soon and completed in the holder's destructor.
bool ok = file_segment->reserve(bytes_to_write);
bool ok = file_segment->reserve(bytes_to_write, &reserve_stat);
if (!ok)
throw Exception(ErrorCodes::NOT_ENOUGH_SPACE, "Failed to reserve space for the file cache ({})", file_segment->getInfoForLog());
{
String reserve_stat_msg;
for (const auto & [kind, stat] : reserve_stat.stat_by_kind)
reserve_stat_msg += fmt::format("{} hold {}, can release {}; ",
toString(kind), ReadableSize(stat.non_releasable_size), ReadableSize(stat.releasable_size));
throw Exception(ErrorCodes::NOT_ENOUGH_SPACE, "Failed to reserve {} bytes for {}: {}(segment info: {})",
bytes_to_write,
file_segment->getKind() == FileSegmentKind::Temporary ? "temporary file" : "the file in cache",
reserve_stat_msg,
file_segment->getInfoForLog()
);
}
try
{

View File

@ -336,7 +336,6 @@ DatabaseAndTable DatabaseCatalog::getTableImpl(
return db_and_table;
}
if (table_id.database_name == TEMPORARY_DATABASE)
{
/// For temporary tables UUIDs are set in Context::resolveStorageID(...).
@ -369,8 +368,24 @@ DatabaseAndTable DatabaseCatalog::getTableImpl(
database = it->second;
}
auto table = database->tryGetTable(table_id.table_name, context_);
if (!table && exception)
StoragePtr table;
if (exception)
{
try
{
table = database->getTable(table_id.table_name, context_);
}
catch (const Exception & e)
{
exception->emplace(e);
}
}
else
{
table = database->tryGetTable(table_id.table_name, context_);
}
if (!table && exception && !exception->has_value())
exception->emplace(Exception(ErrorCodes::UNKNOWN_TABLE, "Table {} doesn't exist", table_id.getNameForLogs()));
if (!table)

View File

@ -16,6 +16,7 @@ namespace ErrorCodes
{
extern const int TABLE_IS_READ_ONLY;
extern const int INCORRECT_QUERY;
extern const int NOT_IMPLEMENTED;
}
@ -24,6 +25,15 @@ BlockIO InterpreterCreateIndexQuery::execute()
auto current_context = getContext();
const auto & create_index = query_ptr->as<ASTCreateIndexQuery &>();
if (create_index.unique)
{
if (!current_context->getSettingsRef().create_index_ignore_unique)
{
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "CREATE UNIQUE INDEX is not supported."
" SET create_index_ignore_unique=1 to ignore this UNIQUE keyword.");
}
}
// Noop if allow_create_index_without_type = true. throw otherwise
if (!create_index.index_decl->as<ASTIndexDeclaration>()->type)
{

View File

@ -38,7 +38,7 @@ void ASTCreateIndexQuery::formatQueryImpl(const FormatSettings & settings, Forma
settings.ostr << (settings.hilite ? hilite_keyword : "") << indent_str;
settings.ostr << "CREATE INDEX " << (if_not_exists ? "IF NOT EXISTS " : "");
settings.ostr << "CREATE " << (unique ? "UNIQUE " : "") << "INDEX " << (if_not_exists ? "IF NOT EXISTS " : "");
index_name->formatImpl(settings, state, frame);
settings.ostr << " ON ";

View File

@ -20,6 +20,7 @@ public:
ASTPtr index_decl;
bool if_not_exists{false};
bool unique{false};
String getID(char delim) const override;

View File

@ -80,6 +80,7 @@ bool ParserCreateIndexQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expect
node = query;
ParserKeyword s_create("CREATE");
ParserKeyword s_unique("UNIQUE");
ParserKeyword s_index("INDEX");
ParserKeyword s_if_not_exists("IF NOT EXISTS");
ParserKeyword s_on("ON");
@ -91,10 +92,14 @@ bool ParserCreateIndexQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expect
String cluster_str;
bool if_not_exists = false;
bool unique = false;
if (!s_create.ignore(pos, expected))
return false;
if (s_unique.ignore(pos, expected))
unique = true;
if (!s_index.ignore(pos, expected))
return false;
@ -131,6 +136,7 @@ bool ParserCreateIndexQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expect
query->children.push_back(index_decl);
query->if_not_exists = if_not_exists;
query->unique = unique;
query->cluster = cluster_str;
if (query->database)

View File

@ -6,7 +6,7 @@ namespace DB
{
/** Query like this:
* CREATE INDEX [IF NOT EXISTS] name ON [db].name (expression) TYPE type GRANULARITY value
* CREATE [UNIQUE] INDEX [IF NOT EXISTS] name ON [db].name (expression) TYPE type GRANULARITY value
*/
class ParserCreateIndexQuery : public IParserBase

View File

@ -37,8 +37,10 @@ namespace
template <typename T, typename SourceType>
struct StatisticsNumeric
{
T min = std::numeric_limits<T>::max();
T max = std::numeric_limits<T>::min();
T min = std::numeric_limits<T>::has_infinity
? std::numeric_limits<T>::infinity() : std::numeric_limits<T>::max();
T max = std::numeric_limits<T>::has_infinity
? -std::numeric_limits<T>::infinity() : std::numeric_limits<T>::lowest();
void add(SourceType x)
{

View File

@ -37,7 +37,10 @@ void TableFunctionRemote::parseArguments(const ASTPtr & ast_function, ContextPtr
String cluster_name;
String cluster_description;
String database, table, username = "default", password;
String database = "system";
String table = "one"; /// The table containing one row is used by default for queries without explicit table specification.
String username = "default";
String password;
if (args_func.size() != 1)
throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
@ -86,7 +89,7 @@ void TableFunctionRemote::parseArguments(const ASTPtr & ast_function, ContextPtr
else
{
/// Supported signatures:
///
/// remote('addresses_expr')
/// remote('addresses_expr', db.table)
/// remote('addresses_expr', 'db', 'table')
/// remote('addresses_expr', db.table, 'user')
@ -102,6 +105,8 @@ void TableFunctionRemote::parseArguments(const ASTPtr & ast_function, ContextPtr
///
/// remoteSecure() - same as remote()
///
/// cluster()
/// cluster('cluster_name')
/// cluster('cluster_name', db.table)
/// cluster('cluster_name', 'db', 'table')
/// cluster('cluster_name', db.table, sharding_key)
@ -109,7 +114,7 @@ void TableFunctionRemote::parseArguments(const ASTPtr & ast_function, ContextPtr
///
/// clusterAllReplicas() - same as cluster()
if (args.size() < 2 || args.size() > max_args)
if ((!is_cluster_function && args.empty()) || args.size() > max_args)
throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
size_t arg_num = 0;
@ -128,8 +133,15 @@ void TableFunctionRemote::parseArguments(const ASTPtr & ast_function, ContextPtr
if (is_cluster_function)
{
args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context);
cluster_name = checkAndGetLiteralArgument<String>(args[arg_num], "cluster_name");
if (!args.empty())
{
args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context);
cluster_name = checkAndGetLiteralArgument<String>(args[arg_num], "cluster_name");
}
else
{
cluster_name = "default";
}
}
else
{
@ -141,44 +153,49 @@ void TableFunctionRemote::parseArguments(const ASTPtr & ast_function, ContextPtr
}
++arg_num;
const auto * function = args[arg_num]->as<ASTFunction>();
if (function && TableFunctionFactory::instance().isTableFunctionName(function->name))
{
remote_table_function_ptr = args[arg_num];
++arg_num;
}
else
{
args[arg_num] = evaluateConstantExpressionForDatabaseName(args[arg_num], context);
database = checkAndGetLiteralArgument<String>(args[arg_num], "database");
++arg_num;
auto qualified_name = QualifiedTableName::parseFromString(database);
if (qualified_name.database.empty())
/// Names of database and table is not necessary.
if (arg_num < args.size())
{
const auto * function = args[arg_num]->as<ASTFunction>();
if (function && TableFunctionFactory::instance().isTableFunctionName(function->name))
{
if (arg_num >= args.size())
remote_table_function_ptr = args[arg_num];
++arg_num;
}
else
{
args[arg_num] = evaluateConstantExpressionForDatabaseName(args[arg_num], context);
database = checkAndGetLiteralArgument<String>(args[arg_num], "database");
++arg_num;
auto qualified_name = QualifiedTableName::parseFromString(database);
if (qualified_name.database.empty())
{
throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
if (arg_num >= args.size())
{
throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
}
else
{
std::swap(qualified_name.database, qualified_name.table);
args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context);
qualified_name.table = checkAndGetLiteralArgument<String>(args[arg_num], "table");
++arg_num;
}
}
else
database = std::move(qualified_name.database);
table = std::move(qualified_name.table);
/// Cluster function may have sharding key for insert
if (is_cluster_function && arg_num < args.size())
{
std::swap(qualified_name.database, qualified_name.table);
args[arg_num] = evaluateConstantExpressionOrIdentifierAsLiteral(args[arg_num], context);
qualified_name.table = checkAndGetLiteralArgument<String>(args[arg_num], "table");
sharding_key = args[arg_num];
++arg_num;
}
}
database = std::move(qualified_name.database);
table = std::move(qualified_name.table);
/// Cluster function may have sharding key for insert
if (is_cluster_function && arg_num < args.size())
{
sharding_key = args[arg_num];
++arg_num;
}
}
/// Username and password parameters are prohibited in cluster version of the function
@ -329,11 +346,13 @@ TableFunctionRemote::TableFunctionRemote(const std::string & name_, bool secure_
{
is_cluster_function = (name == "cluster" || name == "clusterAllReplicas");
help_message = PreformattedMessage::create(
"Table function '{}' requires from 2 to {} parameters: "
"<addresses pattern or cluster name>, <name of remote database>, <name of remote table>{}",
"Table function '{}' requires from {} to {} parameters: "
"{}",
name,
is_cluster_function ? 0 : 1,
is_cluster_function ? 4 : 6,
is_cluster_function ? " [, sharding_key]" : " [, username[, password], sharding_key]");
is_cluster_function ? "[<cluster name or default if not specify>, <name of remote database>, <name of remote table>] [, sharding_key]"
: "<addresses pattern> [, <name of remote database>, <name of remote table>] [, username[, password], sharding_key]");
}
void registerTableFunctionRemote(TableFunctionFactory & factory)

View File

@ -2,6 +2,7 @@
# pylint: disable=redefined-outer-name
import pytest
import fnmatch
from helpers.cluster import ClickHouseCluster
from helpers.client import QueryRuntimeException
@ -68,7 +69,9 @@ def test_cache_evicted_by_temporary_data(start_cluster):
"max_bytes_before_external_sort": "4M",
},
)
assert "Failed to reserve space for the file cache" in str(exc.value)
assert fnmatch.fnmatch(
str(exc.value), "*Failed to reserve * for temporary file*"
), exc.value
# Some data evicted from cache by temporary data
cache_size_after_eviction = get_cache_size()
@ -104,6 +107,8 @@ def test_cache_evicted_by_temporary_data(start_cluster):
"SELECT randomPrintableASCII(1024) FROM numbers(32 * 1024) FORMAT TSV",
params={"buffer_size": 0, "wait_end_of_query": 1},
)
assert "Failed to reserve space for the file cache" in str(exc.value)
assert fnmatch.fnmatch(
str(exc.value), "*Failed to reserve * for temporary file*"
), exc.value
q("DROP TABLE IF EXISTS t1")

View File

@ -1,2 +1,4 @@
[(1,4),(2,5),(3,6)]
[(1,4),(2,5),(3,6)]
[(1,4),(2,5),(3,6)]
[(1,4),(2,5),(3,6)]

View File

@ -1,3 +1,4 @@
-- Tags: shard
SELECT arrayMap((x, y) -> (x, y), [1, 2, 3], [4, 5, 6]) FROM remote('127.0.0.{2,3}', system.one) ORDER BY rand();
SELECT arrayMap((x, y) -> (x, y), [1, 2, 3], [4, 5, 6]) FROM remote('127.0.0.{2,3}') ORDER BY rand();

View File

@ -1,3 +1,4 @@
-- Tags: shard
SELECT x FROM (SELECT count() AS x FROM remote('127.0.0.2', system.one) WITH TOTALS) LIMIT 1;
SELECT x FROM (SELECT count() AS x FROM remote('127.0.0.2') WITH TOTALS) LIMIT 1;

View File

@ -1 +1,2 @@
SELECT (SELECT 1) FROM remote('127.0.0.{1,2}', system.one);
SELECT (SELECT 1) FROM remote('127.0.0.{1,2}');

View File

@ -1,7 +1,7 @@
[[[(1,2.9),(1,1),(2.9,1),(3,0),(0,0),(0,3),(1,2.9)]],[[(1,2.9),(1,4),(4,4),(4,1),(2.9,1),(2.6,2),(2,2.6),(1,2.9)]]]
-------- MultiPolygon with Polygon
MULTIPOLYGON(((-20 -10.3067,-20 -20,-10 -20.8791,-10 -40,-40 -40,-40 -10,-20 -10.3067)),((20 10.3067,20 -20,-10 -20.8791,-10 -10,-20 -10.3067,-20 20,10 20.8791,10 10,20 10.3067)),((20 10.3067,20 20,10 20.8791,10 40,40 40,40 10,20 10.3067)))
[(-40,-40),(-40,-10),(-20,-20),(-20,-10.307),(-20,20),(-10,-40),(-10,-20.879),(-10,-10),(10,10),(10,20.879),(10,40),(20,-20),(20,10.307),(20,20),(40,10),(40,40)]
-------- MultiPolygon with Polygon with Holes
MULTIPOLYGON(((-10 -20.8791,-20 -20,-20 -10.3067,-10 -10,-10 -20.8791)),((10 20.8791,20 20,20 10.3067,10 10,10 20.8791)),((50 50,50 -50,-50 -50,-50 50,50 50),(20 10.3067,40 10,40 40,10 40,10 20.8791,-20 20,-20 -10.3067,-40 -10,-40 -40,-10 -40,-10 -20.8791,20 -20,20 10.3067)))
[(-50,-50),(-50,50),(-40,-40),(-40,-10),(-20,-20),(-20,-10.307),(-20,20),(-10,-40),(-10,-20.879),(-10,-10),(10,10),(10,20.879),(10,40),(20,-20),(20,10.307),(20,20),(40,10),(40,40),(50,-50),(50,50)]
-------- Polygon with Polygon with Holes
MULTIPOLYGON(((-20 -10.3067,-10 -10,-10 -20.8791,-20 -20,-20 -10.3067)),((10 20.8791,20 20,20 10.3067,10 10,10 20.8791)),((50 50,50 -50,-50 -50,-50 50,50 50),(20 10.3067,40 10,40 40,10 40,10 20.8791,-20 20,-20 -10.3067,-40 -10,-40 -40,-10 -40,-10 -20.8791,20 -20,20 10.3067)))
[(-50,-50),(-50,50),(-40,-40),(-40,-10),(-20,-20),(-20,-10.307),(-20,20),(-10,-40),(-10,-20.879),(-10,-10),(10,10),(10,20.879),(10,40),(20,-20),(20,10.307),(20,20),(40,10),(40,40),(50,-50),(50,50)]

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,18 @@
1
1
1
1
1
2
1
2
1
2
1
2
1
1
1
2
1
2

View File

@ -1,10 +1,16 @@
-- Tags: replica, shard
SELECT _shard_num FROM cluster('test_shard_localhost', system.one);
SELECT _shard_num FROM cluster('test_shard_localhost');
SELECT _shard_num FROM clusterAllReplicas('test_shard_localhost', system.one);
SELECT _shard_num FROM clusterAllReplicas('test_shard_localhost');
SELECT _shard_num FROM cluster('test_cluster_two_shards', system.one) ORDER BY _shard_num;
SELECT _shard_num FROM cluster('test_cluster_two_shards') ORDER BY _shard_num;
SELECT _shard_num FROM clusterAllReplicas('test_cluster_two_shards', system.one) ORDER BY _shard_num;
SELECT _shard_num FROM clusterAllReplicas('test_cluster_two_shards') ORDER BY _shard_num;
SELECT _shard_num FROM cluster('test_cluster_one_shard_two_replicas', system.one) ORDER BY _shard_num;
SELECT _shard_num FROM cluster('test_cluster_one_shard_two_replicas') ORDER BY _shard_num;
SELECT _shard_num FROM clusterAllReplicas('test_cluster_one_shard_two_replicas', system.one) ORDER BY _shard_num;
SELECT _shard_num FROM clusterAllReplicas('test_cluster_one_shard_two_replicas') ORDER BY _shard_num;

View File

@ -1,2 +1,4 @@
{'a':1,'b':2}
{'a':1,'b':2}
{'a':1,'b':2}
{'a':1,'b':2}

View File

@ -1 +1,2 @@
SELECT map('a', 1, 'b', 2) FROM remote('127.0.0.{1,2}', system, one);
SELECT map('a', 1, 'b', 2) FROM remote('127.0.0.{1,2}');

View File

@ -10,3 +10,14 @@ SELECT * FROM remote('::1', system.one) FORMAT Null; -- { serverError 36 }
SELECT * FROM remote('[::1][::1]', system.one) FORMAT Null; -- { serverError 36 }
SELECT * FROM remote('[::1][::1', system.one) FORMAT Null; -- { serverError 36 }
SELECT * FROM remote('[::1]::1]', system.one) FORMAT Null; -- { serverError 36 }
SELECT * FROM remote('[::1]') FORMAT Null;
SELECT * FROM remote('[::1]:9000') FORMAT Null;
SELECT * FROM remote('[::1') FORMAT Null; -- { serverError 36 }
SELECT * FROM remote('::1]') FORMAT Null; -- { serverError 36 }
SELECT * FROM remote('::1') FORMAT Null; -- { serverError 36 }
SELECT * FROM remote('[::1][::1]') FORMAT Null; -- { serverError 36 }
SELECT * FROM remote('[::1][::1') FORMAT Null; -- { serverError 36 }
SELECT * FROM remote('[::1]::1]') FORMAT Null; -- { serverError 36 }

View File

@ -1,2 +1,4 @@
SELECT _shard_num FROM cluster("{default_cluster_macro}", system.one);
SELECT _shard_num FROM cluster("{default_cluster_macro}");
SELECT _shard_num FROM clusterAllReplicas("{default_cluster_macro}", system.one);
SELECT _shard_num FROM clusterAllReplicas("{default_cluster_macro}");

View File

@ -4,3 +4,7 @@ SET optimize_monotonous_functions_in_order_by = 1;
SELECT *
FROM cluster(test_cluster_two_shards_localhost, system, one)
ORDER BY toDateTime(dummy);
SELECT *
FROM cluster(test_cluster_two_shards_localhost)
ORDER BY toDateTime(dummy)

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Tags: no-random-settings
# Tags: no-random-settings, no-asan, no-msan, no-tsan, no-debug
# shellcheck disable=SC2009
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)

View File

@ -4,16 +4,32 @@ SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM system.one;
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}', system.one);
1
1
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}');
1
1
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}', system.one) GROUP BY NULL;
1
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}') GROUP BY NULL;
1
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}', system.one) GROUP BY 1;
1
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}') GROUP BY 1;
1
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}', system.one) GROUP BY 'A';
1
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}') GROUP BY 'A';
1
SELECT 1 IN ( SELECT 1 ) FROM remote('127.0.0.{1,2}', system.one) GROUP BY dummy;
1
SELECT 1 IN ( SELECT 1 ) FROM remote('127.0.0.{1,2}') GROUP BY dummy;
1
SELECT 1000.0001, toUInt64(arrayJoin([NULL, 257, 65536, NULL])), arrayExists(x -> (x IN (SELECT '2.55')), [-9223372036854775808]) FROM remote('127.0.0.{1,2}', system.one) GROUP BY NULL, NULL, NULL, NULL;
1000.0001 \N 0
1000.0001 257 0
1000.0001 65536 0
1000.0001 \N 0
SELECT 1000.0001, toUInt64(arrayJoin([NULL, 257, 65536, NULL])), arrayExists(x -> (x IN (SELECT '2.55')), [-9223372036854775808]) FROM remote('127.0.0.{1,2}') GROUP BY NULL, NULL, NULL, NULL;
1000.0001 \N 0
1000.0001 257 0
1000.0001 65536 0
1000.0001 \N 0

View File

@ -2,13 +2,19 @@
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM system.one;
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}', system.one);
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}');
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}', system.one) GROUP BY NULL;
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}') GROUP BY NULL;
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}', system.one) GROUP BY 1;
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}') GROUP BY 1;
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}', system.one) GROUP BY 'A';
SELECT arrayExists(x -> (x IN (SELECT '2')), [2]) FROM remote('127.0.0.{2,3}') GROUP BY 'A';
SELECT 1 IN ( SELECT 1 ) FROM remote('127.0.0.{1,2}', system.one) GROUP BY dummy;
SELECT 1 IN ( SELECT 1 ) FROM remote('127.0.0.{1,2}') GROUP BY dummy;
SELECT 1000.0001, toUInt64(arrayJoin([NULL, 257, 65536, NULL])), arrayExists(x -> (x IN (SELECT '2.55')), [-9223372036854775808]) FROM remote('127.0.0.{1,2}', system.one) GROUP BY NULL, NULL, NULL, NULL;
SELECT 1000.0001, toUInt64(arrayJoin([NULL, 257, 65536, NULL])), arrayExists(x -> (x IN (SELECT '2.55')), [-9223372036854775808]) FROM remote('127.0.0.{1,2}') GROUP BY NULL, NULL, NULL, NULL;

View File

@ -40,32 +40,31 @@ ${CLICKHOUSE_LOCAL} -q "SELECT COUNT(*) FROM \"${tmp_dir}/tmp.csv\""
#################
echo "Test 2: check DatabaseFilesystem access rights and errors handling on server"
# DATABASE_ACCESS_DENIED: Allows list files only inside user_files
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`../tmp.csv\`;" 2>&1| grep -F "Code: 481" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`/tmp/tmp.csv\`;" 2>&1| grep -F "Code: 481" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`../tmp.csv\`;" 2>&1 | tr '\n' ' ' | grep -oF "PATH_ACCESS_DENIED" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`/tmp/tmp.csv\`;" 2>&1 | tr '\n' ' ' | grep -oF "PATH_ACCESS_DENIED" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --multiline --multiquery --query """
USE test1;
SELECT COUNT(*) FROM \"../${tmp_dir}/tmp.csv\";
""" 2>&1| grep -F "Code: 481" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`../../../../../../tmp.csv\`;" 2>&1| grep -F "Code: 481" > /dev/null && echo "OK" || echo 'FAIL' ||:
""" 2>&1 | tr '\n' ' ' | grep -oF "PATH_ACCESS_DENIED" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`../../../../../../tmp.csv\`;" 2>&1 | tr '\n' ' ' | grep -oF "PATH_ACCESS_DENIED" > /dev/null && echo "OK" || echo 'FAIL' ||:
# BAD_ARGUMENTS: path should be inside user_files
${CLICKHOUSE_CLIENT} --multiline --multiquery -q """
DROP DATABASE IF EXISTS test2;
CREATE DATABASE test2 ENGINE = Filesystem('/tmp');
""" 2>&1| grep -F "Code: 36" > /dev/null && echo "OK" || echo 'FAIL' ||:
""" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "BAD_ARGUMENTS" > /dev/null && echo "OK" || echo 'FAIL' ||:
# BAD_ARGUMENTS: .../user_files/relative_unknown_dir does not exists
${CLICKHOUSE_CLIENT} --multiline --multiquery -q """
DROP DATABASE IF EXISTS test2;
CREATE DATABASE test2 ENGINE = Filesystem('relative_unknown_dir');
""" 2>&1| grep -F "Code: 36" > /dev/null && echo "OK" || echo 'FAIL' ||:
""" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "BAD_ARGUMENTS" > /dev/null && echo "OK" || echo 'FAIL' ||:
# FILE_DOESNT_EXIST: unknown file
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`tmp2.csv\`;" 2>&1| grep -F "Code: 60" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`tmp2.csv\`;" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "FILE_DOESNT_EXIST" > /dev/null && echo "OK" || echo 'FAIL' ||:
# BAD_ARGUMENTS: Cannot determine the file format by it's extension
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`${unique_name}/tmp.myext\`;" 2>&1| grep -F "Code: 36" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT COUNT(*) FROM test1.\`${unique_name}/tmp.myext\`;" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "BAD_ARGUMENTS" > /dev/null && echo "OK" || echo 'FAIL' ||:
# Clean
${CLICKHOUSE_CLIENT} --query "DROP DATABASE test1;"
rm -rd $tmp_dir

View File

@ -46,12 +46,12 @@ DROP DATABASE IF EXISTS test3;
CREATE DATABASE test3 ENGINE = S3;
USE test3;
SELECT * FROM \"http://localhost:11111/test/a.myext\"
""" 2>&1| grep -F "UNKNOWN_TABLE" > /dev/null && echo "OK"
""" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "BAD_ARGUMENTS" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --multiline --multiquery -q """
USE test3;
SELECT * FROM \"abacaba\"
""" 2>&1| grep -F "UNKNOWN_TABLE" > /dev/null && echo "OK"
""" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "BAD_ARGUMENTS" > /dev/null && echo "OK" || echo 'FAIL' ||:
# Cleanup
${CLICKHOUSE_CLIENT} --multiline --multiquery -q """

View File

@ -4,9 +4,8 @@ test1
1 2 3
test2
Test 2: check exceptions
OK0
OK1
OK2
OK3
OK4
OK5
BAD_ARGUMENTS
OK
OK
OK
OK

View File

@ -1,6 +1,8 @@
#!/usr/bin/env bash
# Tags: no-fasttest, use-hdfs, no-parallel
CLICKHOUSE_CLIENT_SERVER_LOGS_LEVEL=none
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CURDIR"/../shell_config.sh
@ -36,19 +38,20 @@ echo "Test 2: check exceptions"
${CLICKHOUSE_CLIENT} --multiline --multiquery -q """
DROP DATABASE IF EXISTS test3;
CREATE DATABASE test3 ENGINE = HDFS('abacaba');
""" 2>&1| grep -F "BAD_ARGUMENTS" > /dev/null && echo "OK0"
""" 2>&1 | tr '\n' ' ' | grep -oF "BAD_ARGUMENTS"
${CLICKHOUSE_CLIENT} --multiline --multiquery -q """
DROP DATABASE IF EXISTS test4;
CREATE DATABASE test4 ENGINE = HDFS;
USE test4;
SELECT * FROM \"abacaba/file.tsv\"
""" 2>&1| grep -F "UNKNOWN_TABLE" > /dev/null && echo "OK1"
""" 2>&1 | tr '\n' ' ' | grep -oF "CANNOT_EXTRACT_TABLE_STRUCTURE"
${CLICKHOUSE_CLIENT} -q "SELECT * FROM test4.\`http://localhost:11111/test/a.tsv\`" 2>&1| grep -F "UNKNOWN_TABLE" > /dev/null && echo "OK2"
${CLICKHOUSE_CLIENT} --query "SELECT * FROM test4.\`hdfs://localhost:12222/file.myext\`" 2>&1| grep -F "UNKNOWN_TABLE" > /dev/null && echo "OK3"
${CLICKHOUSE_CLIENT} --query "SELECT * FROM test4.\`hdfs://localhost:12222/test_02725_3.tsv\`" 2>&1| grep -F "UNKNOWN_TABLE" > /dev/null && echo "OK4"
${CLICKHOUSE_CLIENT} --query "SELECT * FROM test4.\`hdfs://localhost:12222\`" 2>&1| grep -F "UNKNOWN_TABLE" > /dev/null && echo "OK5"
${CLICKHOUSE_CLIENT} -q "SELECT * FROM test4.\`http://localhost:11111/test/a.tsv\`" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "BAD_ARGUMENTS" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT * FROM test4.\`hdfs://localhost:12222/file.myext\`" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "BAD_ARGUMENTS" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT * FROM test4.\`hdfs://localhost:12222/test_02725_3.tsv\`" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "CANNOT_EXTRACT_TABLE_STRUCTURE" > /dev/null && echo "OK" || echo 'FAIL' ||:
${CLICKHOUSE_CLIENT} --query "SELECT * FROM test4.\`hdfs://localhost:12222\`" 2>&1 | tr '\n' ' ' | grep -oF -e "UNKNOWN_TABLE" -e "BAD_ARGUMENTS" > /dev/null && echo "OK" || echo 'FAIL' ||:
# Cleanup

View File

@ -43,6 +43,7 @@ ipv6 Nullable(FixedString(16))
[(2,0,NULL,'','[]')]
1 1
0 1
5090915589685802007
16159458007063698496
16159458007063698496
BYTE_ARRAY String

View File

@ -147,6 +147,8 @@ insert into function file(compressed_02735.parquet) select concat('aaaaaaaaaaaaa
select total_compressed_size < 10000, total_uncompressed_size > 15000 from file(compressed_02735.parquet, ParquetMetadata);
insert into function file(compressed_02735.parquet) select concat('aaaaaaaaaaaaaaaa', toString(number)) as s from numbers(1000) settings output_format_parquet_row_group_size = 10000, output_format_parquet_compression_method='none';
select total_compressed_size < 10000, total_uncompressed_size > 15000 from file(compressed_02735.parquet, ParquetMetadata);
insert into function file(compressed_02735.parquet) select if(number%3==1, NULL, 42) as x from numbers(70) settings output_format_parquet_compression_method='zstd';
select sum(cityHash64(*)) from file(compressed_02735.parquet);
-- Single-threaded encoding and Arrow encoder.
drop table if exists other_encoders_02735;

View File

@ -21,18 +21,18 @@ INSERT INTO aboba (user_id, message, creation_date, metric) VALUES (101, 'Hello,
SET dialect = 'prql';
from aboba
derive [
derive {
a = 2,
b = s\"LEFT(message, 2)\"
]
select [ user_id, message, a, b ];
}
select { user_id, message, a, b };
from aboba
filter user_id > 101
group user_id (
aggregate [
aggregate {
metrics = sum metric
]
}
);
SET dialect = 'clickhouse';
@ -49,10 +49,10 @@ SELECT '---';
SET dialect = 'prql';
from aboba
select [ user_id, message, metric ]
select { user_id, message, metric }
derive creation_date = s\"toTimeZone(creation_date, 'Europe/Amsterdam')\"
select [ user_id, message, creation_date, metric];
select { user_id, message, creation_date, metric};
from s\"SELECT * FROM system.users\" | select non_existent_column; # {serverError UNKNOWN_IDENTIFIER}
from non_existent_table; # {serverError UNKNOWN_TABLE}
"
"

View File

@ -0,0 +1,3 @@
SET allow_create_index_without_type=1;
SET create_index_ignore_unique=1;
CREATE UNIQUE INDEX idx_tab2_0 ON tab2 (col1);

View File

@ -0,0 +1,5 @@
Aborted
1
1
1
2

View File

@ -0,0 +1,56 @@
#!/usr/bin/env bash
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CURDIR"/../shell_config.sh
export CLICKHOUSE_TERMINATE_ON_ANY_EXCEPTION=1
# The environment variable works as expected:
bash -c "
abort_handler()
{
exit 0
}
trap 'abort_handler' ABRT
$CLICKHOUSE_LOCAL --query 'this is wrong'
" 2>&1 | grep -o 'Aborted'
# No exceptions are thrown in simple cases:
$CLICKHOUSE_LOCAL --query "SELECT 1"
$CLICKHOUSE_LOCAL --query "SHOW TABLES"
$CLICKHOUSE_LOCAL --query "SELECT * FROM system.tables WHERE database = currentDatabase() FORMAT Null"
# The same for the client app:
$CLICKHOUSE_CLIENT --query "SELECT 1"
$CLICKHOUSE_CLIENT --query "SHOW TABLES"
$CLICKHOUSE_CLIENT --query "SELECT * FROM system.tables WHERE database = currentDatabase() FORMAT Null"
# Multi queries are ok:
$CLICKHOUSE_LOCAL --multiquery "SELECT 1; SELECT 2;"
# It can run in interactive mode:
function run()
{
command=$1
expect << EOF
log_user 0
set timeout 60
match_max 100000
spawn bash -c "$command"
expect ":) "
send -- "SELECT 1\r"
expect "1"
expect ":) "
send -- "exit\r"
expect eof
EOF
}
run "$CLICKHOUSE_LOCAL"

View File

@ -0,0 +1,3 @@
\N
\N

View File

@ -0,0 +1,5 @@
DROP TABLE IF EXISTS numbers500k;
CREATE TABLE numbers500k (`number` UInt32) ENGINE = MergeTree() ORDER BY tuple();
INSERT INTO numbers500k SELECT number FROM system.numbers LIMIT 500000;
SELECT intDiv(number, NULL) AS k FROM (SELECT * FROM remote('127.0.0.{2,3}', currentDatabase(), numbers500k) PREWHERE 31 WHERE 65537 > 0 ORDER BY number DESC NULLS FIRST) GROUP BY GROUPING SETS ((k)) WITH TOTALS ORDER BY k ASC NULLS LAST LIMIT 2147483648;
DROP TABLE IF EXISTS numbers500k;

View File

@ -62,7 +62,8 @@ def default_clickhouse_odbc_conn_str():
return str(
OdbcConnectingArgs.create_from_kw(
dsn="ClickHouse DSN (ANSI)",
Url="http://localhost:8123/query?default_format=ODBCDriver2&default_table_engine=MergeTree&union_default_mode=DISTINCT&group_by_use_nulls=1&join_use_nulls=1&allow_create_index_without_type=1",
Timeout="300",
Url="http://localhost:8123/query?default_format=ODBCDriver2&default_table_engine=MergeTree&union_default_mode=DISTINCT&group_by_use_nulls=1&join_use_nulls=1&allow_create_index_without_type=1&create_index_ignore_unique=1",
)
)

View File

@ -186,10 +186,10 @@ def mode_check_statements(parser):
out_stages_dir = os.path.join(out_dir, f"{args.mode}-stages")
complete_sqlite_dir = os.path.join(out_stages_dir, "complete-sqlite")
complete_sqlite_dir = os.path.join(out_stages_dir, "statements-sqlite")
os.makedirs(complete_sqlite_dir, exist_ok=True)
reports["complete-sqlite"] = run_all_tests_in_parallel(
reports["statements-sqlite"] = run_all_tests_in_parallel(
setup_kwargs=as_kwargs(
engine=Engines.SQLITE,
),
@ -224,6 +224,64 @@ def mode_check_statements(parser):
parser.set_defaults(func=calle)
def mode_check_complete(parser):
parser.add_argument("--input-dir", metavar="DIR", required=True)
parser.add_argument("--out-dir", metavar="DIR", required=True)
def calle(args):
input_dir = os.path.realpath(args.input_dir)
out_dir = os.path.realpath(args.out_dir)
if not os.path.exists(input_dir):
raise FileNotFoundError(
input_dir, f"check statements: no such file or directory {input_dir}"
)
if not os.path.isdir(input_dir):
raise NotADirectoryError(
input_dir, f"check statements:: not a dir {input_dir}"
)
reports = dict()
out_stages_dir = os.path.join(out_dir, f"{args.mode}-stages")
complete_sqlite_dir = os.path.join(out_stages_dir, "complete-sqlite")
os.makedirs(complete_sqlite_dir, exist_ok=True)
reports["complete-sqlite"] = run_all_tests_in_parallel(
setup_kwargs=as_kwargs(
engine=Engines.SQLITE,
),
runner_kwargs=as_kwargs(
verify_mode=False,
stop_at_statement_error=True,
),
input_dir=input_dir,
output_dir=complete_sqlite_dir,
)
verify_clickhouse_dir = os.path.join(out_stages_dir, "complete-clickhouse")
os.makedirs(verify_clickhouse_dir, exist_ok=True)
reports["complete-clickhouse"] = run_all_tests_in_parallel(
setup_kwargs=as_kwargs(
engine=Engines.ODBC,
conn_str=default_clickhouse_odbc_conn_str(),
),
runner_kwargs=as_kwargs(
verify_mode=True,
stop_at_statement_error=True,
),
input_dir=complete_sqlite_dir,
output_dir=verify_clickhouse_dir,
)
statements_report(reports, out_dir, args.mode)
parser.set_defaults(func=calle)
def make_actual_report(reports):
return {stage: report.get_map() for stage, report in reports.items()}
@ -399,16 +457,22 @@ def parse_args():
)
subparsers = parser.add_subparsers(dest="mode")
mode_check_complete(
subparsers.add_parser(
"complete-test",
help="Run all tests. Check that all statements and queries are passed",
)
)
mode_check_statements(
subparsers.add_parser(
"statements-test",
help="Run all test. Check that all statements are passed",
help="Run all tests. Check that all statements are passed",
)
)
mode_self_test(
subparsers.add_parser(
"self-test",
help="Run all test. Check that all statements are passed",
help="Run all tests. Check that all statements are passed",
)
)
args = parser.parse_args()

File diff suppressed because one or more lines are too long

View File

@ -142,4 +142,13 @@ SELECT number+1 from system.numbers LIMIT 20
----
20 values hashing to 52c46dff81346ead02fcf6245c762b1a
# Debug how incorrect result type parses
statement ok
CREATE TABLE tab0(pk INTEGER PRIMARY KEY, col0 INTEGER, col1 FLOAT, col2 TEXT, col3 INTEGER, col4 FLOAT, col5 TEXT)
statement ok
INSERT INTO tab0 VALUES(0,535,860.48,'uxbns',253,640.58,'jvqkl')
skipif ClickHouse
query I rowsort label-20
SELECT + col2 AS col5 FROM tab0 WHERE NOT ( col0 ) * - - col4 IS NULL

View File

@ -9,7 +9,13 @@ from enum import Enum
from hashlib import md5
from functools import reduce
from exceptions import Error, ProgramError, ErrorWithParent, DataResultDiffer
from exceptions import (
Error,
ProgramError,
ErrorWithParent,
DataResultDiffer,
QueryExecutionError,
)
logger = logging.getLogger("parser")
@ -480,6 +486,7 @@ class QueryResult:
for row in rows:
res_row = []
for c, t in zip(row, types):
logger.debug(f"Builging row. c:{c} t:{t}")
if c is None:
res_row.append("NULL")
continue
@ -490,7 +497,12 @@ class QueryResult:
else:
res_row.append(str(c))
elif t == "I":
res_row.append(str(int(c)))
try:
res_row.append(str(int(c)))
except ValueError as ex:
raise QueryExecutionError(
f"Got non-integer result '{c}' for I type."
)
elif t == "R":
res_row.append(f"{c:.3f}")

View File

@ -361,7 +361,7 @@ class TestRunner:
continue
if block.get_block_type() == test_parser.BlockType.control:
clogger.debug("Skip control block", name_pos)
clogger.debug("Skip control block %s", name_pos)
block.dump_to(out_stream)
continue
@ -374,13 +374,14 @@ class TestRunner:
continue
request = block.get_request()
exec_res = execute_request(request, self.connection)
if block.get_block_type() in self.skip_request_types:
clogger.debug("Runtime skip block for %s", self.dbms_name)
block.dump_to(out_stream)
continue
exec_res = execute_request(request, self.connection)
if block.get_block_type() == test_parser.BlockType.statement:
try:
clogger.debug("this is statement")