aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergey Uzhakov <uzhastik@gmail.com>2022-05-13 23:01:39 +0300
committerSergey Uzhakov <uzhastik@gmail.com>2022-05-13 23:01:39 +0300
commit9a8029ee9bed1e997d94112794c31b19c9c238e5 (patch)
tree65549f1da1ded9b72284b9446a4a8d55a0d35e12
parent9d89d7ad0cabebdc77fc8a74fe7d744f884cc5fb (diff)
downloadydb-9a8029ee9bed1e997d94112794c31b19c9c238e5.tar.gz
YQL-14787, YQL-14785: pg syntax: support BETWEEN, AND + OR for >2 args
ref:62a6a5ca50c10063c160ce68882b8c6d64584da0
-rw-r--r--ydb/library/yql/sql/pg/pg_sql.cpp210
1 files changed, 147 insertions, 63 deletions
diff --git a/ydb/library/yql/sql/pg/pg_sql.cpp b/ydb/library/yql/sql/pg/pg_sql.cpp
index 2d0dffc1ab..e04beea527 100644
--- a/ydb/library/yql/sql/pg/pg_sql.cpp
+++ b/ydb/library/yql/sql/pg/pg_sql.cpp
@@ -506,7 +506,7 @@ public:
}
auto lambda = L(A("lambda"), QL(), x);
- auto columnName = QA(name);
+ auto columnName = QAX(name);
res.push_back(L(A("PgResultItem"), columnName, L(A("Void")), lambda));
}
@@ -745,10 +745,10 @@ public:
}
void AddFrom(const TFromDesc& p, TVector<TAstNode*>& fromList) {
- auto aliasNode = QA(p.Alias);
+ auto aliasNode = QAX(p.Alias);
TVector<TAstNode*> colNamesNodes;
for (const auto& c : p.ColNames) {
- colNamesNodes.push_back(QA(c));
+ colNamesNodes.push_back(QAX(c));
}
auto colNamesTuple = QVL(colNamesNodes.data(), colNamesNodes.size());
@@ -805,8 +805,8 @@ public:
return {};
}
- auto sink = L(A("DataSink"), QA(*p), QA(value->schemaname));
- auto key = L(A("Key"), QL(QA("table"), L(A("String"), QA(value->relname))));
+ auto sink = L(A("DataSink"), QAX(*p), QAX(value->schemaname));
+ auto key = L(A("Key"), QL(QA("table"), L(A("String"), QAX(value->relname))));
return { sink, key };
}
@@ -840,9 +840,9 @@ public:
return {};
}
- auto source = L(A("DataSource"), QA(*p), QA(value->schemaname));
+ auto source = L(A("DataSource"), QAX(*p), QAX(value->schemaname));
return { L(A("Read!"), A("world"), source, L(A("Key"),
- QL(QA("table"), L(A("String"), QA(value->relname)))),
+ QL(QA("table"), L(A("String"), QAX(value->relname)))),
L(A("Void")),
QL()), alias, colnames, true };
}
@@ -979,7 +979,7 @@ public:
return L(A("PgConst"), QA(ToString(StrFloatVal(val))), L(A("PgType"), QA("float8")));
}
case T_String: {
- return L(A("PgConst"), QA(ToString(StrVal(val))), L(A("PgType"), QA("text")));
+ return L(A("PgConst"), QAX(ToString(StrVal(val))), L(A("PgType"), QA("text")));
}
case T_Null: {
return L(A("Null"));
@@ -1024,7 +1024,7 @@ public:
}
if (StrLength(value->over->name)) {
- window = QA(value->over->name);
+ window = QAX(value->over->name);
} else {
auto index = settings.WindowItems->size();
auto def = ParseWindowDef(value->over);
@@ -1094,7 +1094,7 @@ public:
}
args.push_back(A(callable));
- args.push_back(QA(name));
+ args.push_back(QAX(name));
if (window) {
args.push_back(window);
}
@@ -1161,7 +1161,7 @@ public:
TStringBuf targetType = StrVal(ListNodeNth(typeName->names, ListLength(typeName->names) - 1));
if (NodeTag(CAST_NODE(A_Const, arg)->val) == T_String && targetType == "bool") {
auto str = StrVal(CAST_NODE(A_Const, arg)->val);
- return L(A("PgConst"), QA(str), L(A("PgType"), QA("bool")));
+ return L(A("PgConst"), QAX(str), L(A("PgType"), QA("bool")));
}
}
@@ -1177,42 +1177,43 @@ public:
finalType = "_" + finalType;
}
- return L(A("PgCast"), input, L(A("PgType"), QA(finalType)));
+ return L(A("PgCast"), input, L(A("PgType"), QAX(finalType)));
}
AddError("Unsupported form of type cast");
return nullptr;
}
- TAstNode* ParseBoolExpr(const BoolExpr* value, const TExprSettings& settings) {
- switch (value->boolop) {
- case AND_EXPR: {
- if (ListLength(value->args) != 2) {
- AddError("Expected 2 args for AND");
- return nullptr;
- }
-
- auto lhs = ParseExpr(ListNodeNth(value->args, 0), settings);
- auto rhs = ParseExpr(ListNodeNth(value->args, 1), settings);
- if (!lhs || !rhs) {
- return nullptr;
- }
+ TAstNode* ParseAndOrExpr(const BoolExpr* value, const TExprSettings& settings, const TString& pgOpName) {
+ auto length = ListLength(value->args);
+ if (length < 2) {
+ AddError(TStringBuilder() << "Expected >1 args for " << pgOpName << " but have " << length << " args");
+ return nullptr;
+ }
- return L(A("PgAnd"), lhs, rhs);
+ auto lhs = ParseExpr(ListNodeNth(value->args, 0), settings);
+ if (!lhs) {
+ return nullptr;
}
- case OR_EXPR: {
- if (ListLength(value->args) != 2) {
- AddError("Expected 2 args for OR");
- return nullptr;
- }
- auto lhs = ParseExpr(ListNodeNth(value->args, 0), settings);
- auto rhs = ParseExpr(ListNodeNth(value->args, 1), settings);
- if (!lhs || !rhs) {
+ for (auto i = 1; i < length; ++i) {
+ auto rhs = ParseExpr(ListNodeNth(value->args, i), settings);
+ if (!rhs) {
return nullptr;
}
+ lhs = L(A(pgOpName), lhs, rhs);
+ }
+
+ return lhs;
+ }
- return L(A("PgOr"), lhs, rhs);
+ TAstNode* ParseBoolExpr(const BoolExpr* value, const TExprSettings& settings) {
+ switch (value->boolop) {
+ case AND_EXPR: {
+ return ParseAndOrExpr(value, settings, "PgAnd");
+ }
+ case OR_EXPR: {
+ return ParseAndOrExpr(value, settings, "PgOr");
}
case NOT_EXPR: {
if (ListLength(value->args) != 1) {
@@ -1234,8 +1235,8 @@ public:
}
TAstNode* ParseWindowDef(const WindowDef* value) {
- auto name = QA(value->name);
- auto refName = QA(value->refname);
+ auto name = QAX(value->name);
+ auto refName = QAX(value->refname);
TVector<TAstNode*> sortItems;
for (int i = 0; i < ListLength(value->orderClause); ++i) {
auto node = ListNodeNth(value->orderClause, i);
@@ -1456,9 +1457,9 @@ public:
return nullptr;
}
- optionItems.push_back(QL(QA("type"), QA(type)));
- optionItems.push_back(QL(QA("from"), QA(from)));
- optionItems.push_back(QL(QA("to"), QA(to)));
+ optionItems.push_back(QL(QA("type"), QAX(type)));
+ optionItems.push_back(QL(QA("from"), QAX(from)));
+ optionItems.push_back(QL(QA("to"), QAX(to)));
}
auto options = QVL(optionItems.data(), optionItems.size());
@@ -1553,21 +1554,16 @@ public:
if (fields.size() == 0) {
return L(A("PgStar"));
} else {
- return L(A("PgQualifiedStar"), QA(fields[0]));
+ return L(A("PgQualifiedStar"), QAX(fields[0]));
}
} else if (fields.size() == 1) {
- return L(A("PgColumnRef"), QA(fields[0]));
+ return L(A("PgColumnRef"), QAX(fields[0]));
} else {
- return L(A("PgColumnRef"), QA(fields[0]), QA(fields[1]));
+ return L(A("PgColumnRef"), QAX(fields[0]), QAX(fields[1]));
}
}
- TAstNode* ParseAExpr(const A_Expr* value, const TExprSettings& settings) {
- if (value->kind != AEXPR_OP) {
- AddError(TStringBuilder() << "A_Expr_Kind unsupported value: " << (int)value->kind);
- return nullptr;
- }
-
+ TAstNode* ParseAExprOp(const A_Expr* value, const TExprSettings& settings) {
if (ListLength(value->name) != 1) {
AddError(TStringBuilder() << "Unsupported count of names: " << ListLength(value->name));
return nullptr;
@@ -1591,16 +1587,96 @@ public:
return nullptr;
}
- return L(A("PgOp"), QA(op), rhs);
- } else {
- auto lhs = ParseExpr(value->lexpr, settings);
- auto rhs = ParseExpr(value->rexpr, settings);
- if (!lhs || !rhs) {
- return nullptr;
- }
+ return L(A("PgOp"), QAX(op), rhs);
+ }
- return L(A("PgOp"), QA(op), lhs, rhs);
+ auto lhs = ParseExpr(value->lexpr, settings);
+ auto rhs = ParseExpr(value->rexpr, settings);
+ if (!lhs || !rhs) {
+ return nullptr;
}
+
+ return L(A("PgOp"), QAX(op), lhs, rhs);
+ }
+
+ TAstNode* ParseAExprBetween(const A_Expr* value, const TExprSettings& settings) {
+ if (!value->lexpr || !value->rexpr) {
+ AddError("Missing operands");
+ return nullptr;
+ }
+
+ if (NodeTag(value->rexpr) != T_List) {
+ AddError(TStringBuilder() << "Expected T_List tag, but have " << NodeTag(value->rexpr));
+ return nullptr;
+ }
+
+ const List* rexprList = CAST_NODE(List, value->rexpr);
+ if (ListLength(rexprList) != 2) {
+ AddError(TStringBuilder() << "Expected 2 args in BETWEEN range, but have " << ListLength(rexprList));
+ return nullptr;
+ }
+
+ auto b = ListNodeNth(rexprList, 0);
+ auto e = ListNodeNth(rexprList, 1);
+
+ auto lhs = ParseExpr(value->lexpr, settings);
+ auto rbhs = ParseExpr(b, settings);
+ auto rehs = ParseExpr(e, settings);
+ if (!lhs || !rbhs || !rehs) {
+ return nullptr;
+ }
+
+ if (IsIn({ AEXPR_BETWEEN_SYM, AEXPR_NOT_BETWEEN_SYM }, value->kind)) {
+ auto minmax = L(A("If"),
+ L(A("Coalesce"),
+ L(A("FromPg"),
+ L(A("PgOp"), QA("<"), rbhs, rehs)
+ ),
+ L(A("Bool"), QA("false"))
+ ), QL(rbhs, rehs), QL(rehs, rbhs)
+ );
+
+ rbhs = L(A("Nth"), minmax, QA("0"));
+ rehs = L(A("Nth"), minmax, QA("1"));
+ }
+
+ switch (value->kind) {
+ case AEXPR_BETWEEN:
+ [[fallthrough]];
+ case AEXPR_BETWEEN_SYM:
+ {
+ auto gte = L(A("PgOp"), QA(">="), lhs, rbhs);
+ auto lte = L(A("PgOp"), QA("<="), lhs, rehs);
+ return L(A("PgAnd"), gte, lte);
+ }
+ case AEXPR_NOT_BETWEEN:
+ [[fallthrough]];
+ case AEXPR_NOT_BETWEEN_SYM:
+ {
+ auto lt = L(A("PgOp"), QA("<"), lhs, rbhs);
+ auto gt = L(A("PgOp"), QA(">"), lhs, rehs);
+ return L(A("PgOr"), lt, gt);
+ }
+ default:
+ AddError(TStringBuilder() << "BETWEEN kind unsupported value: " << (int)value->kind);
+ return nullptr;
+ }
+ }
+
+ TAstNode* ParseAExpr(const A_Expr* value, const TExprSettings& settings) {
+ switch (value->kind) {
+ case AEXPR_OP:
+ return ParseAExprOp(value, settings);
+ case AEXPR_BETWEEN:
+ case AEXPR_NOT_BETWEEN:
+ case AEXPR_BETWEEN_SYM:
+ case AEXPR_NOT_BETWEEN_SYM:
+ return ParseAExprBetween(value, settings);
+ default:
+ AddError(TStringBuilder() << "A_Expr_Kind unsupported value: " << (int)value->kind);
+ return nullptr;
+ }
+
}
template <typename T>
@@ -1642,19 +1718,27 @@ public:
}
TAstNode* QVL(TAstNode** nodes, ui32 size, TPosition pos = {}) {
- return Q(VL(nodes, size, pos));
+ return Q(VL(nodes, size, pos), pos);
}
- TAstNode* A(const TString& str, TPosition pos = {}) {
- return TAstNode::NewAtom(pos, str, *AstParseResult.Pool);
+ TAstNode* A(const TString& str, TPosition pos = {}, ui32 flags = 0) {
+ return TAstNode::NewAtom(pos, str, *AstParseResult.Pool, flags);
+ }
+
+ TAstNode* AX(const TString& str, TPosition pos = {}) {
+ return A(str, pos, TNodeFlags::ArbitraryContent);
}
TAstNode* Q(TAstNode* node, TPosition pos = {}) {
- return L(A("quote"), node, pos);
+ return L(A("quote", pos), node, pos);
+ }
+
+ TAstNode* QA(const TString& str, TPosition pos = {}, ui32 flags = 0) {
+ return Q(A(str, pos, flags), pos);
}
- TAstNode* QA(const TString& str, TPosition pos = {}) {
- return Q(A(str, pos));
+ TAstNode* QAX(const TString& str, TPosition pos = {}) {
+ return QA(str, pos, TNodeFlags::ArbitraryContent);
}
template <typename... TNodes>