aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruzhas <uzhas@ydb.tech>2022-09-28 15:50:45 +0300
committeruzhas <uzhas@ydb.tech>2022-09-28 15:50:45 +0300
commit4e3a9425a48234e58e655869593623feeb94ca4f (patch)
tree7cabcaa3a9d567f86d489b1afbb8d1bd529b6451
parentb5cfe4dadd6e1f96663da5b2df0ec6a7d99990f0 (diff)
downloadydb-4e3a9425a48234e58e655869593623feeb94ca4f.tar.gz
initial support for selecting from binding in postgres syntax
-rw-r--r--ydb/library/yql/sql/pg/CMakeLists.txt2
-rw-r--r--ydb/library/yql/sql/pg/pg_sql.cpp123
-rw-r--r--ydb/library/yql/sql/settings/CMakeLists.txt2
-rw-r--r--ydb/library/yql/sql/settings/partitioning.cpp35
-rw-r--r--ydb/library/yql/sql/settings/partitioning.h9
-rw-r--r--ydb/library/yql/sql/v1/sql.cpp37
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?