Browse Source

fail parse on errors in MATCH_RECOGNIZE

zverevgeny 1 year ago
parent
commit
0f10245df9

+ 2 - 0
ydb/library/yql/sql/v1/match_recognize.cpp

@@ -202,6 +202,7 @@ bool TMatchRecognizeNavigate::DoInit(TContext& ctx, ISource* src) {
     if (DefaultNavigatingFunction == Name) {
         if (not varColumn->IsTheSameVar()) {
             ctx.Error(Pos) << "Row pattern navigation function is required";
+            return false;
         }
         navigatedRowIndex =  varLastRowIndex;
     }
@@ -229,6 +230,7 @@ bool TMatchRecognizeNavigate::DoInit(TContext& ctx, ISource* src) {
         );
     } else {
         ctx.Error(Pos) << "Internal logic error";
+        return false;
     }
     Add("Member");
     Add(

+ 9 - 5
ydb/library/yql/sql/v1/select.cpp

@@ -1680,11 +1680,15 @@ public:
 
         auto block(Y(Y("let", "core", input)));
 
-        if (auto matchRecognize = Source->BuildMatchRecognize(ctx, "core")) {
-            //use unique name match_recognize to find this block easily in unit tests
-            block = L(block, Y("let", "match_recognize", matchRecognize));
-            //then bind to the conventional name
-            block = L(block, Y("let", "core", "match_recognize"));
+        if (Source->HasMatchRecognize()) {
+            if (auto matchRecognize = Source->BuildMatchRecognize(ctx, "core")) {
+                //use unique name match_recognize to find this block easily in unit tests
+                block = L(block, Y("let", "match_recognize", matchRecognize));
+                //then bind to the conventional name
+                block = L(block, Y("let", "core", "match_recognize"));
+            } else {
+                return nullptr;
+            }
         }
 
         bool ordered = ctx.UseUnordered(*this);

+ 6 - 4
ydb/library/yql/sql/v1/source.cpp

@@ -937,11 +937,13 @@ TNodePtr ISource::BuildSortSpec(const TVector<TSortSpecificationPtr>& orderBy, c
     }
 }
 
+bool ISource::HasMatchRecognize() const {
+    return static_cast<bool>(MatchRecognizeBuilder);
+}
+
 TNodePtr ISource::BuildMatchRecognize(TContext& ctx, TString&& inputTable){
-    if (MatchRecognizeBuilder){
-        return MatchRecognizeBuilder->Build(ctx, std::move(inputTable), this);
-    }
-    return TNodePtr{};
+    YQL_ENSURE(HasMatchRecognize());
+    return MatchRecognizeBuilder->Build(ctx, std::move(inputTable), this);
 };
 
 IJoin::IJoin(TPosition pos)

+ 1 - 0
ydb/library/yql/sql/v1/source.h

@@ -94,6 +94,7 @@ namespace NSQLTranslationV1 {
         virtual bool ShouldUseSourceAsColumn(const TString& source) const;
         virtual bool IsJoinKeysInitializing() const;
         virtual const TString* GetWindowName() const;
+        virtual bool HasMatchRecognize() const;
         virtual TNodePtr BuildMatchRecognize(TContext& ctx, TString&& inputTable);
         virtual bool DoInit(TContext& ctx, ISource* src);
         virtual TNodePtr Build(TContext& ctx) = 0;

+ 15 - 0
ydb/library/yql/sql/v1/sql_match_recognize_ut.cpp

@@ -648,4 +648,19 @@ FROM Input MATCH_RECOGNIZE(
         UNIT_ASSERT(IsLambda(defines->GetChild(5), 3));
         UNIT_ASSERT(IsLambda(defines->GetChild(6), 3));
     }
+
+    Y_UNIT_TEST(CheckRequiredNavigationFunction) {
+        TString stmtPrefix = R"(
+USE plato;
+SELECT *
+FROM Input MATCH_RECOGNIZE(
+    PATTERN ( Y Q L )
+    DEFINE
+        L as L.V =
+)";
+        //Be aware that right parenthesis is added at the end of the query as required
+        UNIT_ASSERT(MatchRecognizeSqlToYql(stmtPrefix + "LAST(Q.dt) )").IsOk());
+        UNIT_ASSERT(!MatchRecognizeSqlToYql(stmtPrefix + "Q.dt )").IsOk());
+    }
+
 }