diff options
author | uzhas <uzhas@ydb.tech> | 2022-09-28 15:50:45 +0300 |
---|---|---|
committer | uzhas <uzhas@ydb.tech> | 2022-09-28 15:50:45 +0300 |
commit | 4e3a9425a48234e58e655869593623feeb94ca4f (patch) | |
tree | 7cabcaa3a9d567f86d489b1afbb8d1bd529b6451 | |
parent | b5cfe4dadd6e1f96663da5b2df0ec6a7d99990f0 (diff) | |
download | ydb-4e3a9425a48234e58e655869593623feeb94ca4f.tar.gz |
initial support for selecting from binding in postgres syntax
-rw-r--r-- | ydb/library/yql/sql/pg/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ydb/library/yql/sql/pg/pg_sql.cpp | 123 | ||||
-rw-r--r-- | ydb/library/yql/sql/settings/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ydb/library/yql/sql/settings/partitioning.cpp | 35 | ||||
-rw-r--r-- | ydb/library/yql/sql/settings/partitioning.h | 9 | ||||
-rw-r--r-- | ydb/library/yql/sql/v1/sql.cpp | 37 |
6 files changed, 166 insertions, 42 deletions
diff --git a/ydb/library/yql/sql/pg/CMakeLists.txt b/ydb/library/yql/sql/pg/CMakeLists.txt index ee68adcafee..0ef88046667 100644 --- a/ydb/library/yql/sql/pg/CMakeLists.txt +++ b/ydb/library/yql/sql/pg/CMakeLists.txt @@ -18,9 +18,9 @@ target_link_libraries(yql-sql-pg PUBLIC contrib-libs-cxxsupp yutil library-yql-ast + yql-parser-pg_catalog yql-parser-pg_wrapper yql-sql-settings - yql-parser-pg_catalog ) target_sources(yql-sql-pg PRIVATE ${CMAKE_SOURCE_DIR}/ydb/library/yql/sql/pg/pg_sql.cpp diff --git a/ydb/library/yql/sql/pg/pg_sql.cpp b/ydb/library/yql/sql/pg/pg_sql.cpp index 7281421913f..5bec2f4f13e 100644 --- a/ydb/library/yql/sql/pg/pg_sql.cpp +++ b/ydb/library/yql/sql/pg/pg_sql.cpp @@ -1,4 +1,5 @@ #include <ydb/library/yql/sql/pg_sql.h> +#include <ydb/library/yql/sql/settings/partitioning.h> #include <ydb/library/yql/parser/pg_wrapper/parser.h> #include <ydb/library/yql/providers/common/provider/yql_provider_names.h> #include <ydb/library/yql/core/yql_callable_names.h> @@ -1229,6 +1230,14 @@ public: return { view->Source, alias, colnames.empty() ? view->ColNames : colnames, false }; } + if (!StrCompare(value->schemaname, "bindings")) { + auto s = BuildBindingSource(value); + if (!s) { + return {}; + } + return { s, alias, colnames, true }; + } + auto p = Settings.ClusterMapping.FindPtr(value->schemaname); if (!p) { AddError(TStringBuilder() << "Unknown cluster: " << value->schemaname); @@ -1242,6 +1251,106 @@ public: QL()), alias, colnames, true }; } + TAstNode* BuildBindingSource(const RangeVar* value) { + const TString binding = value->relname; + auto pit = Settings.PrivateBindings.find(binding); + auto sit = Settings.ScopedBindings.find(binding); + + if (pit == Settings.PrivateBindings.end() && sit == Settings.ScopedBindings.end()) { + AddError(TStringBuilder() << "Table binding `" << binding << "` is not defined"); + return nullptr; + } + + const auto& bindSettings = (pit != Settings.PrivateBindings.end()) ? pit->second : sit->second; + + // ordered map ensures AST stability + std::map<TString, TString> kvs(bindSettings.Settings.begin(), bindSettings.Settings.end()); + auto pullSettingOrFail = [&](const TString& name, TString& value) -> bool { + auto it = kvs.find(name); + if (it == kvs.end()) { + AddError(TStringBuilder() << name << " is not found for " << binding); + return false; + } + value = it->second; + kvs.erase(it); + return true; + }; + + TString cluster; + TString path; + TString format; + + if (!pullSettingOrFail("cluster", cluster) || + !pullSettingOrFail("path", path) || + !pullSettingOrFail("format", format)) { + return nullptr; + } + + TVector<TAstNode*> hints; + if (auto it = kvs.find("schema"); it != kvs.end()) { + auto schema = QA(it->second); + + auto type = L(A("SqlTypeFromYson"), schema); + auto columns = L(A("SqlColumnOrderFromYson"), schema); + hints.emplace_back(QL(QA("userschema"), type, columns)); + kvs.erase(it); + } + + if (auto it = kvs.find("partitioned_by"); it != kvs.end()) { + TVector<TString> columns; + if (const TString& error = NSQLTranslation::ParsePartitionedByBinding(it->first, it->second, columns)) { + AddError(error); + } + TVector<TAstNode*> hintValues; + hintValues.push_back(QA("partitionedby")); + for (auto& column : columns) { + hintValues.push_back(QA(column)); + } + hints.emplace_back(QVL(hintValues.data(), hintValues.size())); + kvs.erase(it); + } + + // put format back to hints + kvs["format"] = format; + + for (auto& [key, value] : kvs) { + if (!key) { + AddError(TStringBuilder() << "Hint key should not be empty"); + return nullptr; + } + + hints.emplace_back(QL(QA(key), QA(value))); + } + + auto p = Settings.ClusterMapping.FindPtr(cluster); + if (!p) { + AddError(TStringBuilder() << "Unknown cluster: " << cluster); + return nullptr; + } + + auto source = L(A("DataSource"), QAX(*p), QAX(cluster)); + return L( + A("Read!"), + A("world"), + source, + L( + A("MrTableConcat"), + L( + A("Key"), + QL( + QA("table"), + L( + A("String"), + QAX(path) + ) + ) + ) + ), + L(A("Void")), + QVL(hints.data(), hints.size()) + ); + } + TFromDesc ParseRangeFunction(const RangeFunction* value) { if (value->lateral) { AddError("RangeFunction: unsupported lateral"); @@ -2703,13 +2812,13 @@ private: } TAstNode* MakeProjectionRef(const TStringBuf& scope, const A_Const* aConst) { - AT_LOCATION(aConst);
- auto num = IntVal(aConst->val);
- if (num <= 0) {
- AddError(TStringBuilder() << scope << ": position " << num << " is not in select list");
- return nullptr;
- }
-
+ AT_LOCATION(aConst); + auto num = IntVal(aConst->val); + if (num <= 0) { + AddError(TStringBuilder() << scope << ": position " << num << " is not in select list"); + return nullptr; + } + return L(A("PgProjectionRef"), QA(ToString(num - 1))); } diff --git a/ydb/library/yql/sql/settings/CMakeLists.txt b/ydb/library/yql/sql/settings/CMakeLists.txt index 2515081e1bb..079b52ad4d1 100644 --- a/ydb/library/yql/sql/settings/CMakeLists.txt +++ b/ydb/library/yql/sql/settings/CMakeLists.txt @@ -12,10 +12,12 @@ target_link_libraries(yql-sql-settings PUBLIC contrib-libs-cxxsupp yutil cpp-deprecated-split + library-cpp-json yql-core-issue core-issue-protos library-yql-utils ) target_sources(yql-sql-settings PRIVATE + ${CMAKE_SOURCE_DIR}/ydb/library/yql/sql/settings/partitioning.cpp ${CMAKE_SOURCE_DIR}/ydb/library/yql/sql/settings/translation_settings.cpp ) diff --git a/ydb/library/yql/sql/settings/partitioning.cpp b/ydb/library/yql/sql/settings/partitioning.cpp new file mode 100644 index 00000000000..49e84a855fd --- /dev/null +++ b/ydb/library/yql/sql/settings/partitioning.cpp @@ -0,0 +1,35 @@ +#include "partitioning.h" +#include <library/cpp/json/json_reader.h> +#include <util/string/builder.h> + +namespace NSQLTranslation { + +TString ParsePartitionedByBinding(const TString& name, const TString& value, TVector<TString>& columns) { + using namespace NJson; + TJsonValue json; + bool throwOnError = false; + if (!ReadJsonTree(value, &json, throwOnError)) { + return TStringBuilder() << "Binding setting " << name << " is not a valid JSON"; + } + + const TJsonValue::TArray* arr = nullptr; + if (!json.GetArrayPointer(&arr)) { + return TStringBuilder() << "Binding setting " << name << ": expecting array"; + } + + if (arr->empty()) { + return TStringBuilder() << "Binding setting " << name << ": expecting non-empty array"; + } + + for (auto& item : *arr) { + TString str; + if (!item.GetString(&str)) { + return TStringBuilder() << "Binding setting " << name << ": expecting non-empty array of strings"; + } + columns.push_back(std::move(str)); + } + + return {}; +} + +} // namespace NSQLTranslation diff --git a/ydb/library/yql/sql/settings/partitioning.h b/ydb/library/yql/sql/settings/partitioning.h new file mode 100644 index 00000000000..db825aa95ee --- /dev/null +++ b/ydb/library/yql/sql/settings/partitioning.h @@ -0,0 +1,9 @@ +#pragma once + +#include <util/generic/string.h> +#include <util/generic/vector.h> + +namespace NSQLTranslation { + // returns error message if any + TString ParsePartitionedByBinding(const TString& name, const TString& value, TVector<TString>& columns); +} // namespace NSQLTranslation diff --git a/ydb/library/yql/sql/v1/sql.cpp b/ydb/library/yql/sql/v1/sql.cpp index bffc8b1d631..fa36b157203 100644 --- a/ydb/library/yql/sql/v1/sql.cpp +++ b/ydb/library/yql/sql/v1/sql.cpp @@ -19,6 +19,7 @@ #include <ydb/library/yql/minikql/mkql_program_builder.h> #include <ydb/library/yql/providers/common/provider/yql_provider_names.h> #include <ydb/library/yql/core/yql_expr_type_annotation.h> +#include <ydb/library/yql/sql/settings/partitioning.h> #include <ydb/library/yql/sql/settings/translation_settings.h> #include <ydb/library/yql/core/yql_atom_enums.h> @@ -885,7 +886,6 @@ private: bool ClusterExpr(const TRule_cluster_expr& node, bool allowWildcard, bool allowBinding, TString& service, TDeferredAtom& cluster, bool& isBinding); bool ApplyTableBinding(const TString& binding, TTableRef& tr, TTableHints& hints); - bool ParsePartitionedByBinding(const TString& name, const TString& value, TVector<TString>& columns); bool StructLiteralItem(TVector<TNodePtr>& labels, const TRule_expr& label, TVector<TNodePtr>& values, const TRule_expr& value); protected: NSQLTranslation::ESqlMode Mode; @@ -1526,7 +1526,8 @@ bool TSqlTranslation::ApplyTableBinding(const TString& binding, TTableRef& tr, T if (auto it = kvs.find("partitioned_by"); it != kvs.end()) { TVector<TString> columns; - if (!ParsePartitionedByBinding(it->first, it->second, columns)) { + if (const auto& error = NSQLTranslation::ParsePartitionedByBinding(it->first, it->second, columns)) { + Ctx.Error() << error; return false; } TVector<TNodePtr> hintValue; @@ -1553,38 +1554,6 @@ bool TSqlTranslation::ApplyTableBinding(const TString& binding, TTableRef& tr, T return true; } -bool TSqlTranslation::ParsePartitionedByBinding(const TString& name, const TString& value, TVector<TString>& columns) { - using namespace NJson; - TJsonValue json; - bool throwOnError = false; - if (!ReadJsonTree(value, &json, throwOnError)) { - Ctx.Error() << "Binding setting " << name << " is not a valid JSON"; - return false; - } - - const TJsonValue::TArray* arr = nullptr; - if (!json.GetArrayPointer(&arr)) { - Ctx.Error() << "Binding setting " << name << ": expecting array"; - return false; - } - - if (arr->empty()) { - Ctx.Error() << "Binding setting " << name << ": expecting non-empty array"; - return false; - } - - for (auto& item : *arr) { - TString str; - if (!item.GetString(&str)) { - Ctx.Error() << "Binding setting " << name << ": expecting non-empty array of strings"; - return false; - } - columns.push_back(std::move(str)); - } - - return true; -} - bool TSqlTranslation::TableRefImpl(const TRule_table_ref& node, TTableRef& result, bool unorderedSubquery) { // table_ref: // (cluster_expr DOT)? AT? |