Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom settings support in DDL-queries for CREATE DICTIONARY #10465

Merged
merged 11 commits into from
Apr 26, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,7 @@ SOURCE(SOURCE_TYPE(param1 val1 ... paramN valN)) -- Source configuration

The source is configured in the `source` section.

For source types
[Local file](#dicts-external_dicts_dict_sources-local_file),
[Executable file](#dicts-external_dicts_dict_sources-executable),
[HTTP(s)](#dicts-external_dicts_dict_sources-http),
[ClickHouse](#dicts-external_dicts_dict_sources-clickhouse)
For source types [Local file](#dicts-external_dicts_dict_sources-local_file), [Executable file](#dicts-external_dicts_dict_sources-executable), [HTTP(s)](#dicts-external_dicts_dict_sources-http), [ClickHouse](#dicts-external_dicts_dict_sources-clickhouse)
optional settings are available:

``` xml
Expand All @@ -53,6 +49,12 @@ optional settings are available:
</settings>
</source>
```
or
``` sql
SOURCE(FILE(path '/opt/dictionaries/os.tsv' format 'TabSeparated'))
SETTINGS(format_csv_allow_single_quotes = 0)
```


Types of sources (`source_type`):

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ SOURCE(SOURCE_TYPE(param1 val1 ... paramN valN)) -- Source configuration

La source est configurée dans le `source` section.

Pour les sources de types [Fichier Local](#dicts-external_dicts_dict_sources-local_file), [Fichier exécutable](#dicts-external_dicts_dict_sources-executable), [HTTP(s)](#dicts-external_dicts_dict_sources-http), [ClickHouse](#dicts-external_dicts_dict_sources-clickhouse)
les paramètres optionnels sont possibles:

``` xml
@@ -53,6 +49,12 @@ optional settings are available:
</settings>
</source>
```
ou
``` sql
SOURCE(FILE(path '/opt/dictionaries/os.tsv' format 'TabSeparated'))
SETTINGS(format_csv_allow_single_quotes = 1)
```

Les Types de sources (`source_type`):

- [Fichier Local](#dicts-external_dicts_dict_sources-local_file)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,7 @@ SOURCE(SOURCE_TYPE(param1 val1 ... paramN valN)) -- Source configuration

Источник настраивается в разделе `source`.

Для типов источников
[Локальный файл](#dicts-external_dicts_dict_sources-local_file),
[Исполняемый файл](#dicts-external_dicts_dict_sources-executable),
[HTTP(s)](#dicts-external_dicts_dict_sources-http),
[ClickHouse](#dicts-external_dicts_dict_sources-clickhouse)
Для типов источников [Локальный файл](#dicts-external_dicts_dict_sources-local_file), [Исполняемый файл](#dicts-external_dicts_dict_sources-executable), [HTTP(s)](#dicts-external_dicts_dict_sources-http), [ClickHouse](#dicts-external_dicts_dict_sources-clickhouse)
доступны дополнительные настройки:

``` xml
Expand All @@ -48,6 +44,11 @@ SOURCE(SOURCE_TYPE(param1 val1 ... paramN valN)) -- Source configuration
</settings>
</source>
```
или
``` sql
SOURCE(FILE(path '/opt/dictionaries/os.tsv' format 'TabSeparated'))
SETTINGS(format_csv_allow_single_quotes = 0)
```

Типы источников (`source_type`):

Expand Down
17 changes: 15 additions & 2 deletions src/Dictionaries/getDictionaryConfigurationFromAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,13 +375,26 @@ void buildConfigurationFromFunctionWithKeyValueArguments(
* </mysql>
* </source>
*/
void buildSourceConfiguration(AutoPtr<Document> doc, AutoPtr<Element> root, const ASTFunctionWithKeyValueArguments * source)
void buildSourceConfiguration(AutoPtr<Document> doc, AutoPtr<Element> root, const ASTFunctionWithKeyValueArguments * source, const ASTDictionarySettings * settings)
{
AutoPtr<Element> outer_element(doc->createElement("source"));
root->appendChild(outer_element);
AutoPtr<Element> source_element(doc->createElement(source->name));
outer_element->appendChild(source_element);
buildConfigurationFromFunctionWithKeyValueArguments(doc, source_element, source->elements->as<const ASTExpressionList>());

if (settings != nullptr)
{
AutoPtr<Element> settings_element(doc->createElement("settings"));
outer_element->appendChild(settings_element);
for (const auto & [name, value] : settings->changes)
{
AutoPtr<Element> setting_change_element(doc->createElement(name));
settings_element->appendChild(setting_change_element);
AutoPtr<Text> setting_value(doc->createTextNode(getFieldAsString(value)));
setting_change_element->appendChild(setting_value);
}
}
}

/** Check all AST fields are filled, throws exception
Expand Down Expand Up @@ -454,7 +467,7 @@ DictionaryConfigurationPtr getDictionaryConfigurationFromAST(const ASTCreateQuer
buildPrimaryKeyConfiguration(xml_document, structure_element, complex, pk_attrs, query.dictionary_attributes_list);

buildLayoutConfiguration(xml_document, current_dictionary, dictionary_layout);
buildSourceConfiguration(xml_document, current_dictionary, query.dictionary->source);
buildSourceConfiguration(xml_document, current_dictionary, query.dictionary->source, query.dictionary->dict_settings);
buildLifetimeConfiguration(xml_document, current_dictionary, query.dictionary->lifetime);

if (query.dictionary->range)
Expand Down
37 changes: 37 additions & 0 deletions src/Parsers/ASTDictionary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,34 @@ void ASTDictionaryLayout::formatImpl(const FormatSettings & settings,
settings.ostr << ")";
}

ASTPtr ASTDictionarySettings::clone() const
{
auto res = std::make_shared<ASTDictionarySettings>(*this);
res->children.clear();
res->changes = changes;

return res;
}

void ASTDictionarySettings::formatImpl(const FormatSettings & settings,
FormatState &,
FormatStateStacked) const
{

settings.ostr << (settings.hilite ? hilite_keyword : "")
<< "SETTINGS"
<< (settings.hilite ? hilite_none : "")
<< "(";
for (auto it = changes.begin(); it != changes.end(); ++it)
{
if (it != changes.begin())
settings.ostr << ", ";

settings.ostr << it->name << " = " << applyVisitor(FieldVisitorToString(), it->value);
}
settings.ostr << (settings.hilite ? hilite_none : "") << ")";
}


ASTPtr ASTDictionary::clone() const
{
Expand All @@ -128,6 +156,9 @@ ASTPtr ASTDictionary::clone() const
if (range)
res->set(res->range, range->clone());

if (dict_settings)
res->set(res->dict_settings, dict_settings->clone());

return res;
}

Expand Down Expand Up @@ -166,6 +197,12 @@ void ASTDictionary::formatImpl(const FormatSettings & settings, FormatState & st
settings.ostr << settings.nl_or_ws;
range->formatImpl(settings, state, frame);
}

if (dict_settings)
{
settings.ostr << settings.nl_or_ws;
dict_settings->formatImpl(settings, state, frame);
}
}

}
18 changes: 18 additions & 0 deletions src/Parsers/ASTDictionary.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTExpressionList.h>

#include <Parsers/ASTSetQuery.h>

#include <Parsers/ParserSetQuery.h>

namespace DB
{

Expand Down Expand Up @@ -60,6 +64,18 @@ class ASTDictionaryRange : public IAST
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
};

class ASTDictionarySettings : public IAST
{
public:
SettingsChanges changes;

String getID(char) const override { return "Dictionary settings"; }

ASTPtr clone() const override;

void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
};


/// AST contains all parts of external dictionary definition except attributes
class ASTDictionary : public IAST
Expand All @@ -77,6 +93,8 @@ class ASTDictionary : public IAST
ASTDictionaryLayout * layout;
/// Range for dictionary (only for range-hashed dictionaries)
ASTDictionaryRange * range;
/// Settings for dictionary (optionally)
ASTDictionarySettings * dict_settings;

String getID(char) const override { return "Dictionary definition"; }

Expand Down
47 changes: 47 additions & 0 deletions src/Parsers/ParserDictionary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

#include <Poco/String.h>

#include <Parsers/ParserSetQuery.h>

namespace DB
{

Expand Down Expand Up @@ -149,6 +151,31 @@ bool ParserDictionaryLayout::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
return true;
}

bool ParserDictionarySettings::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
ParserToken s_comma(TokenType::Comma);

SettingsChanges changes;

while (true)
{
if (!changes.empty() && !s_comma.ignore(pos))
break;

changes.push_back(SettingChange{});

if (!ParserSetQuery::parseNameValuePair(changes.back(), pos, expected))
return false;
}

auto query = std::make_shared<ASTDictionarySettings>();
query->changes = std::move(changes);

node = query;

return true;
}


bool ParserDictionary::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
Expand All @@ -157,19 +184,22 @@ bool ParserDictionary::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
ParserKeyword lifetime_keyword("LIFETIME");
ParserKeyword range_keyword("RANGE");
ParserKeyword layout_keyword("LAYOUT");
ParserKeyword settings_keyword("SETTINGS");
ParserToken open(TokenType::OpeningRoundBracket);
ParserToken close(TokenType::ClosingRoundBracket);
ParserFunctionWithKeyValueArguments key_value_pairs_p;
ParserList expression_list_p(std::make_unique<ParserIdentifier>(), std::make_unique<ParserToken>(TokenType::Comma), false);
ParserDictionaryLifetime lifetime_p;
ParserDictionaryRange range_p;
ParserDictionaryLayout layout_p;
ParserDictionarySettings settings_p;

ASTPtr primary_key;
ASTPtr ast_source;
ASTPtr ast_lifetime;
ASTPtr ast_layout;
ASTPtr ast_range;
ASTPtr ast_settings;

/// Primary is required to be the first in dictionary definition
if (primary_key_keyword.ignore(pos) && !expression_list_p.parse(pos, primary_key, expected))
Expand Down Expand Up @@ -235,6 +265,20 @@ bool ParserDictionary::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
continue;
}

if (!ast_settings && settings_keyword.ignore(pos, expected))
{
if (!open.ignore(pos))
return false;

if (!settings_p.parse(pos, ast_settings, expected))
return false;

if (!close.ignore(pos))
return false;

continue;
}

break;
}

Expand All @@ -255,6 +299,9 @@ bool ParserDictionary::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
if (ast_range)
query->set(query->range, ast_range);

if (ast_settings)
query->set(query->dict_settings, ast_settings);

return true;
}

Expand Down
9 changes: 9 additions & 0 deletions src/Parsers/ParserDictionary.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <Parsers/IParser.h>
#include <Parsers/IParserBase.h>

#include <Parsers/ParserSetQuery.h>

namespace DB
{

Expand Down Expand Up @@ -37,6 +39,13 @@ class ParserDictionaryLayout : public IParserBase
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};

class ParserDictionarySettings: public IParserBase
{
protected:
const char * getName() const override { return "settings definition"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
};


/// Combines together all parsers from above and also parses primary key and
/// dictionary source, which consists of custom key-value pairs:
Expand Down
2 changes: 1 addition & 1 deletion src/Parsers/ParserSetQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace DB


/// Parse `name = value`.
static bool parseNameValuePair(SettingChange & change, IParser::Pos & pos, Expected & expected)
bool ParserSetQuery::parseNameValuePair(SettingChange & change, IParser::Pos & pos, Expected & expected)
{
ParserIdentifier name_p;
ParserLiteral value_p;
Expand Down
3 changes: 1 addition & 2 deletions src/Parsers/ParserSetQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ class ParserSetQuery : public IParserBase
{
public:
explicit ParserSetQuery(bool parse_only_internals_ = false) : parse_only_internals(parse_only_internals_) {}

static bool parseNameValuePair(SettingChange & change, IParser::Pos & pos, Expected & expected);
protected:
const char * getName() const override { return "SET query"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;

/// Parse the list `name = value` pairs, without SET.
bool parse_only_internals;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INITIALIZING DICTIONARY
END
47 changes: 47 additions & 0 deletions tests/queries/0_stateless/01259_dictionary_custom_settings_ddl.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
DROP DATABASE IF EXISTS database_for_dict;

CREATE DATABASE database_for_dict Engine = Ordinary;

DROP TABLE IF EXISTS database_for_dict.table_for_dict;

CREATE TABLE database_for_dict.table_for_dict
(
key_column UInt64,
second_column UInt64,
third_column String
)
ENGINE = MergeTree()
ORDER BY key_column;

INSERT INTO database_for_dict.table_for_dict VALUES (100500, 10000000, 'Hello world');

DROP DATABASE IF EXISTS ordinary_db;

CREATE DATABASE ordinary_db ENGINE = Ordinary;

DROP DICTIONARY IF EXISTS ordinary_db.dict1;

CREATE DICTIONARY ordinary_db.dict1
(
key_column UInt64 DEFAULT 0,
second_column UInt64 DEFAULT 1,
third_column String DEFAULT 'qqq'
)
PRIMARY KEY key_column
SOURCE(CLICKHOUSE(HOST 'localhost' PORT 9000 USER 'default' TABLE 'table_for_dict' PASSWORD '' DB 'database_for_dict'))
LIFETIME(MIN 1 MAX 10)
LAYOUT(FLAT()) SETTINGS(max_result_bytes=1);

SELECT 'INITIALIZING DICTIONARY';

SELECT dictGetUInt64('ordinary_db.dict1', 'second_column', toUInt64(100500)); -- { serverError 396 }

SELECT 'END';

DROP DICTIONARY IF EXISTS ordinary_db.dict1;

DROP DATABASE IF EXISTS ordinary_db;

DROP TABLE IF EXISTS database_for_dict.table_for_dict;

DROP DATABASE IF EXISTS database_for_dict;