Browse Source

Merge pull request #7509 from ghalliday/issue10243

HPCC-10243 Support for WHEN(scalar, action, BEFORE|SUCCESS|FAILURE)

Reviewed-By: Jamie Noss <james.noss@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 10 years ago
parent
commit
6b718792fd

+ 2 - 2
ecl/hql/hqlexpr.cpp

@@ -1953,7 +1953,6 @@ childDatasetType getChildDatasetType(IHqlExpression * expr)
     case no_split:
     case no_spill:
     case no_activerow:
-    case no_executewhen:  //second argument is independent of the other arguments
     case no_selectnth:
     case no_readspill:
     case no_commonspill:
@@ -1964,6 +1963,7 @@ childDatasetType getChildDatasetType(IHqlExpression * expr)
     case no_setgraphloopresult:
     case no_spillgraphresult:
         return childdataset_dataset_noscope;
+    case no_executewhen:  //second argument is independent of the other arguments
     case no_setresult:
     case no_sizeof:
     case no_offsetof:
@@ -2232,12 +2232,12 @@ inline unsigned doGetNumChildTables(IHqlExpression * dataset)
     case no_extractresult:
     case no_filtergroup:
     case no_forcegraph:
-    case no_executewhen:
     case no_normalizegroup:
     case no_owned_ds:
     case no_dataset_alias:
     case no_ensureresult:
         return 1;
+    case no_executewhen:
     case no_deserialize:
     case no_serialize:
         if (dataset->queryChild(0)->isDataset())

+ 13 - 5
ecl/hql/hqlgram.y

@@ -6440,11 +6440,15 @@ primexpr1
                             $$.setExpr(createCompound($3.getExpr(), $5.getExpr()));
                             $$.setPosition($1);
                         }
-    | WHEN '(' expression ',' action ')'
+    | WHEN '(' expression ',' action sideEffectOptions ')'
                         {
                             parser->normalizeExpression($3);
-                            $$.setExpr(createCompound($5.getExpr(), $3.getExpr()));
-                            $$.setPosition($1);
+                            OwnedHqlExpr options = $6.getExpr();
+                            OwnedHqlExpr expr = $3.getExpr();
+                            if (options)
+                                $$.setExpr(createValueF(no_executewhen, expr->getType(), LINK(expr), $5.getExpr(), options.getClear(), NULL), $1);
+                            else
+                                $$.setExpr(createCompound($5.getExpr(), expr), $1);
                         }
     | __COMMON__ '(' expression ')'
                         {
@@ -7335,9 +7339,13 @@ simpleDataRow
                             parser->normalizeExpression($5, type_stringorunicode, false);
                             $$.setExpr(createRow(no_fromjson, $3.getExpr(), createComma($5.getExpr(), $6.getExpr())), $1);
                         }
-    | WHEN '(' dataRow ',' action ')'
+    | WHEN '(' dataRow ',' action sideEffectOptions ')'
                         {
-                            $$.setExpr(createCompound($5.getExpr(), $3.getExpr()), $1);
+                            OwnedHqlExpr options = $6.getExpr();
+                            if (options)
+                                $$.setExpr(createRow(no_executewhen, $3.getExpr(), createComma($5.getExpr(), options.getClear())), $1);
+                            else
+                                $$.setExpr(createCompound($5.getExpr(), $3.getExpr()), $1);
                         }
     ;
 

+ 32 - 0
ecl/hqlcpp/hqlcpp.cpp

@@ -2362,6 +2362,9 @@ void HqlCppTranslator::buildExprAssign(BuildCtx & ctx, const CHqlBoundTarget & t
         buildStmt(ctx, expr->queryChild(0));
         buildExprAssign(ctx, target, expr->queryChild(1));
         break;
+    case no_executewhen:
+        doBuildAssignExecuteWhen(ctx, target, expr);
+        break;
     case no_concat:
         doBuildAssignConcat(ctx, target, expr);
         break;
@@ -3178,6 +3181,7 @@ void HqlCppTranslator::buildExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoun
     case no_loopcounter:
     case no_toxml:
     case no_tojson:
+    case no_executewhen:
         buildTempExpr(ctx, expr, tgt);
         return;
     case no_asstring:
@@ -7212,6 +7216,34 @@ void HqlCppTranslator::doBuildAssignConcat(BuildCtx & ctx, const CHqlBoundTarget
     }
 }
 
+void HqlCppTranslator::doBuildAssignExecuteWhen(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
+{
+    IHqlExpression * value = expr->queryChild(0);
+    IHqlExpression * action = expr->queryChild(1);
+
+    if (expr->hasAttribute(beforeAtom))
+    {
+        buildStmt(ctx, action);
+        buildExprAssign(ctx, target, value);
+    }
+    else if (expr->hasAttribute(failureAtom))
+    {
+        BuildCtx tryctx(ctx);
+        tryctx.addTry();
+        buildExprAssign(tryctx, target, value);
+
+        BuildCtx catchctx(ctx);
+        catchctx.addCatch(NULL);
+        buildStmt(catchctx, action);
+        catchctx.addThrow(NULL);
+    }
+    else
+    {
+        buildExprAssign(ctx, target, value);
+        buildStmt(ctx, action);
+    }
+}
+
 //---------------------------------------------------------------------------
 //-- no_div --
 // also used for no_modulus

+ 1 - 0
ecl/hqlcpp/hqlcpp.ipp

@@ -1188,6 +1188,7 @@ public:
     void doBuildAssignConcat(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr);
     void doBuildAssignCount(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr);
     void doBuildAssignDivide(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr);
+    void doBuildAssignExecuteWhen(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr);
     void doBuildAssignEventExtra(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr);
     void doBuildAssignEventName(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr);
     void doBuildAssignFailMessage(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr);

+ 1 - 1
ecl/hqlcpp/hqliproj.cpp

@@ -1393,7 +1393,7 @@ void ImplicitProjectTransformer::analyseExpr(IHqlExpression * expr)
             Parent::analyseExpr(expr);
             break;
         case no_executewhen:
-            if (expr->isDataset())
+            if (expr->isDataset() || expr->isDatarow())
             {
                 assertex(extra->activityKind() == SimpleActivity);
                 Parent::analyseExpr(expr);

+ 33 - 0
ecl/hqlcpp/hqlstmt.cpp

@@ -220,6 +220,17 @@ IHqlStmt * BuildCtx::addCase(IHqlStmt * _owner, IHqlExpression * source)
 }
 
 
+IHqlStmt * BuildCtx::addCatch(IHqlExpression * caught)
+{
+    if (ignoreInput)
+        return NULL;
+    HqlCompoundStmt * next = new HqlCompoundStmt(catch_stmt, curStmts);
+    if (caught)
+        next->addExpr(LINK(caught));
+    return appendCompound(next);
+}
+
+
 IHqlStmt * BuildCtx::addConditionalGroup(IHqlStmt * stmt)
 {
     if (ignoreInput)
@@ -476,6 +487,26 @@ IHqlStmt * BuildCtx::addSwitch(IHqlExpression * source)
 }
 
 
+IHqlStmt * BuildCtx::addThrow(IHqlExpression * thrown)
+{
+    if (ignoreInput)
+        return NULL;
+    HqlStmt * next = new HqlStmt(throw_stmt, curStmts);
+    if (thrown)
+        next->addExpr(LINK(thrown));
+    return appendSimple(next);
+}
+
+
+IHqlStmt * BuildCtx::addTry()
+{
+    if (ignoreInput)
+        return NULL;
+    HqlCompoundStmt * next = new HqlCompoundStmt(try_stmt, curStmts);
+    return appendCompound(next);
+}
+
+
 HqlStmt * BuildCtx::appendCompound(HqlCompoundStmt * next)
 {
     assertThrow(!ignoreInput);
@@ -941,6 +972,8 @@ IHqlStmt * BuildCtx::recursiveGetBestContext(HqlStmts * searchStmts, HqlExprCopy
     case quote_compound_stmt:
     case quote_compoundopt_stmt:
     case indirect_stmt:
+    case catch_stmt:
+    case try_stmt:
         return NULL;
     case filter_stmt:
     case switch_stmt:

+ 6 - 0
ecl/hqlcpp/hqlstmt.hpp

@@ -99,6 +99,7 @@ public:
     IHqlStmt *                  addBlock();
     IHqlStmt *                  addBreak();
     IHqlStmt *                  addCase(IHqlStmt * owner, IHqlExpression * condition);
+    IHqlStmt *                  addCatch(IHqlExpression * caught);
     IHqlStmt *                  addConditionalGroup(IHqlStmt * stmt); // generated if stmt->isIncluded() is true
     IHqlStmt *                  addContinue();
     IHqlStmt *                  addDeclare(IHqlExpression * name, IHqlExpression * value=NULL);
@@ -125,6 +126,8 @@ public:
     IHqlStmt *                  addQuoted(StringBuffer & text)              { return addQuoted(text.str()); }
     IHqlStmt *                  addQuotedCompound(StringBuffer & text, const char * extra = NULL){ return addQuotedCompound(text.str(), extra); }
     IHqlStmt *                  addSwitch(IHqlExpression * condition);
+    IHqlStmt *                  addThrow(IHqlExpression * thrown);
+    IHqlStmt *                  addTry();
     void                        associate(HqlExprAssociation & next);
     void                        associateOwn(HqlExprAssociation & next);
     HqlExprAssociation *        associateExpr(IHqlExpression * represents, IHqlExpression * expr);
@@ -199,6 +202,9 @@ enum StmtKind {
              continue_stmt,
              function_stmt,
              assign_link_stmt,
+             try_stmt,
+             catch_stmt,
+             throw_stmt,
 };
 
 

+ 35 - 0
ecl/hqlcpp/hqlwcpp.cpp

@@ -1741,6 +1741,26 @@ void HqlCppWriter::generateStmt(IHqlStmt * stmt)
         case switch_stmt:
             generateStmtSwitch(stmt);
             break;
+        case try_stmt:
+            indent().append("try");
+            generateChildren(stmt, true);
+            break;
+        case catch_stmt:
+            generateStmtCatch(stmt);
+            break;
+        case throw_stmt:
+            {
+                IHqlExpression * value = stmt->queryExpr(0);
+                if (value)
+                {
+                    indent().append("throw ");
+                    generateExprCpp(stmt->queryExpr(0)).append(';');
+                }
+                else
+                    indent().append("throw;");
+                newline();
+                break;
+            }
         case assigninc_stmt:
         case assigndec_stmt:
             generateStmtAssignModify(stmt);
@@ -1918,6 +1938,21 @@ void HqlCppWriter::generateStmtCase(IHqlStmt * stmt)
     }
 }
 
+void HqlCppWriter::generateStmtCatch(IHqlStmt * stmt)
+{
+    IHqlExpression * caught = stmt->queryExpr(0);
+    indent().append("catch (");
+    if (caught)
+    {
+        generateParamCpp(caught, NULL);
+    }
+    else
+        out.append("...");
+
+    out.append(")");
+    generateChildren(stmt, true);
+}
+
 void HqlCppWriter::generateStmtDeclare(IHqlStmt * declare)
 {
     IHqlExpression * name = declare->queryExpr(0);

+ 1 - 0
ecl/hqlcpp/hqlwcpp.ipp

@@ -91,6 +91,7 @@ protected:
     void generateStmtAssign(IHqlStmt * assign, bool link);
     void generateStmtAssignModify(IHqlStmt * assign);
     void generateStmtCase(IHqlStmt * stmt);
+    void generateStmtCatch(IHqlStmt * stmt);
     void generateStmtDeclare(IHqlStmt * declare);
     void generateStmtFilter(IHqlStmt * stmt);
     void generateStmtFunction(IHqlStmt * stmt);

+ 12 - 0
testing/regress/ecl/key/when10.xml

@@ -0,0 +1,12 @@
+<Dataset name='Result 1'>
+ <Row><Result_1>Ready</Result_1></Row>
+</Dataset>
+<Dataset name='Result 2'>
+ <Row><Result_2>Done</Result_2></Row>
+</Dataset>
+<Dataset name='Result 3'>
+ <Row><Result_3>Doing</Result_3></Row>
+</Dataset>
+<Dataset name='Result 5'>
+ <Row><Result_5>7</Result_5></Row>
+</Dataset>

+ 12 - 0
testing/regress/ecl/key/when11.xml

@@ -0,0 +1,12 @@
+<Dataset name='Result 1'>
+ <Row><Result_1>Ready</Result_1></Row>
+</Dataset>
+<Dataset name='Result 2'>
+ <Row><Result_2>Done</Result_2></Row>
+</Dataset>
+<Dataset name='Result 3'>
+ <Row><Result_3>Doing</Result_3></Row>
+</Dataset>
+<Dataset name='Result 5'>
+ <Row><f1>9</f1><f2>3</f2><f3>4</f3><f4>5</f4></Row>
+</Dataset>

+ 38 - 0
testing/regress/ecl/when10.ecl

@@ -0,0 +1,38 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2015 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+r := {unsigned f1, unsigned f2, unsigned f3, unsigned f4 };
+
+r t(unsigned a, unsigned b, unsigned c, unsigned d) := TRANSFORM
+    SELF.f1 := a;
+    SELF.f2 := b;
+    SELF.f3 := c;
+    SELF.f4 := d;
+END;
+
+ds := dataset([
+        t(1,2,3,4),
+        t(1,4,2,5),
+        t(9,3,4,5),
+        t(3,4,2,9)]);
+
+
+p := WHEN(COUNT(NOFOLD(ds)), OUTPUT('Ready'), BEFORE);
+p2 := WHEN(p, OUTPUT('Done'), SUCCESS);
+p3 := WHEN(p2, OUTPUT('Doing'), PARALLEL);
+p4 := WHEN(p3, OUTPUT('Failed'), FAILURE);
+output(p4+3);

+ 38 - 0
testing/regress/ecl/when11.ecl

@@ -0,0 +1,38 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2015 HPCC Systems.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+r := {unsigned f1, unsigned f2, unsigned f3, unsigned f4 };
+
+r t(unsigned a, unsigned b, unsigned c, unsigned d) := TRANSFORM
+    SELF.f1 := a;
+    SELF.f2 := b;
+    SELF.f3 := c;
+    SELF.f4 := d;
+END;
+
+ds := dataset([
+        t(1,2,3,4),
+        t(1,4,2,5),
+        t(9,3,4,5),
+        t(3,4,2,9)]);
+
+
+p := WHEN(ds[3], OUTPUT('Ready'), BEFORE);
+p2 := WHEN(p, OUTPUT('Done'), SUCCESS);
+p3 := WHEN(p2, OUTPUT('Doing'), PARALLEL);
+p4 := WHEN(p3, OUTPUT('Failed'), FAILURE);
+output(DATASET(p4));