Bläddra i källkod

Merge pull request #9857 from afishbeck/eclMatched

HPCC-15523 Support JOIN transform MATCHED(LEFT) and MATCHED(RIGHT)

Reviewed-by: Gavin Halliday <ghalliday@hpccsystems.com>
Gavin Halliday 8 år sedan
förälder
incheckning
cd8682832a

+ 1 - 0
ecl/hql/hqlattr.cpp

@@ -85,6 +85,7 @@ unsigned getOperatorMetaFlags(node_operator op)
     case no_quoted:                 // codegen only
     case no_getresult:
     case no_matched:
+    case no_matched_injoin:
     case no_matchtext:
     case no_matchlength:
     case no_matchposition:

+ 2 - 0
ecl/hql/hqlexpr.cpp

@@ -1511,6 +1511,7 @@ const char *getOpString(node_operator op)
     case no_parse: return "PARSE";
     case no_newparse: return "PARSE";
     case no_skip: return "SKIP";
+    case no_matched_injoin: return "MATCHED";
     case no_matched: return "MATCHED";
     case no_matchtext: return "MATCHTEXT";
     case no_matchlength: return "MATCHLENGTH";
@@ -1850,6 +1851,7 @@ bool checkConstant(node_operator op)
     case no_xmlunicode:
     case no_xmlproject:
     case no_matched:
+    case no_matched_injoin:
     case no_matchtext:
     case no_matchunicode:
     case no_matchlength:

+ 1 - 0
ecl/hql/hqlexpr.hpp

@@ -726,6 +726,7 @@ enum node_operator : unsigned short {
         no_getenv,
         no_fromjson,
         no_tojson,
+        no_matched_injoin,
         no_last_op,
 
 //These never get created as IHqlExpressions....

+ 8 - 0
ecl/hql/hqlgram.y

@@ -6495,6 +6495,14 @@ primexpr1
                         {
                             $$.setExpr(createValue(no_matched, makeBoolType(), $3.getExpr())); //, parser->createUniqueId()));
                         }
+    | MATCHED '(' dataRow ')'
+                        {
+                            $$.setExpr(createValue(no_matched_injoin, makeBoolType(), $3.getExpr()), $1);
+                        }
+    | MATCHED '(' dataSet ')'
+                        {
+                            $$.setExpr(createValue(no_matched_injoin, makeBoolType(), $3.getExpr()), $1);
+                        }
     | MATCHTEXT '(' patternReference ')'
                         {
                             $$.setExpr(createValue(no_matchtext, makeStringType(UNKNOWN_LENGTH, NULL, NULL), $3.getExpr())); //, parser->createUniqueId()));

+ 2 - 0
ecl/hqlcpp/hqlcerrors.hpp

@@ -328,6 +328,7 @@
 #define HQLERR_ReadSpillBeforeWriteFix          4838
 #define HQLERR_AccessUnavailableGraph           4839
 #define HQLERR_NoMappingForField                4840
+#define HQLERR_InvalidMatchedPatternInJoin      4841
 //#define HQLERR_Max                            4999
 
 //---- Text for all errors (make it easy to internationalise) ---------------------------
@@ -359,6 +360,7 @@
 #define HQLERR_IndexTypeNotSupported_Text       "Index is not supported for type %s yet"
 #define HQLERR_RankOnNull_Text                  "RANK has no meaning on an empty list"
 #define HQLERR_MatchedUsedOutsideParse_Text     "%s can only be used in a record supplied to a PARSE() command"
+#define HQLERR_InvalidMatchedPatternInJoin_Text "MATCHED parameter in JOIN/DENORMALIZE must refer to current LEFT or RIGHT"
 #define HQLERR_BadMatchedPath_Text              "The parameter to MATCHED(%s) is not found in the pattern"
 #define HQLERR_RoxieExpectedConstantFilename_Text "Roxie requires constant filenames - expression %s cannot be computed at deployment time"
 #define HQLERR_MatchTextNotUnicode_Text         "MATCHTEXT found where MATCHUNICODE was expected"

+ 26 - 0
ecl/hqlcpp/hqlcpp.cpp

@@ -3032,6 +3032,9 @@ void HqlCppTranslator::buildExpr(BuildCtx & ctx, IHqlExpression * expr, CHqlBoun
             buildExpr(ctx, null, tgt); 
             return;
         }
+    case no_matched_injoin:
+        doBuildExprMatchedInJoin(ctx, expr, tgt);
+        return;
     case no_matched:
     case no_matchtext:
     case no_matchlength:
@@ -9608,6 +9611,29 @@ void HqlCppTranslator::doBuildExprFailCode(BuildCtx & ctx, IHqlExpression * expr
     }
 }
 
+void HqlCppTranslator::doBuildExprMatchedInJoin(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
+{
+    IHqlExpression *selExpr = expr->queryChild(0);
+    assertex(selExpr);
+
+    node_operator op = selExpr->getOperator();
+    if (op==no_rows) //denormalize group
+    {
+        selExpr = selExpr->queryChild(0);
+        assertex(selExpr);
+        op = selExpr->getOperator();
+        if (op!=no_right)
+            throwError(HQLERR_InvalidMatchedPatternInJoin);
+    }
+
+    OwnedHqlExpr markerExpr = createValue(no_matched_injoin, makeBoolType(), LINK(selExpr));
+    if (!ctx.getMatchExpr(markerExpr, tgt))
+    {
+        if (!buildExprInCorrectContext(ctx, expr, tgt, false))
+            throwError(HQLERR_InvalidMatchedPatternInJoin); //to get this far they must be matching on a dataset that is not the current left or right
+        return;
+    }
+}
 
 void HqlCppTranslator::doBuildAssignFailMessage(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
 {

+ 4 - 0
ecl/hqlcpp/hqlcpp.ipp

@@ -1379,6 +1379,7 @@ public:
     void doBuildExprList(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt);
     void doBuildExprConstList(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt);
     void doBuildExprDynList(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt);
+    void doBuildExprMatchedInJoin(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt);
     void doBuildExprNegate(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt);
     void doBuildExprNot(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt);
     void doBuildExprOffsetOf(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt);
@@ -1646,6 +1647,7 @@ public:
 
     void doBuildParseTransform(BuildCtx & classctx, IHqlExpression * expr);
     void doBuildParseValidators(BuildCtx & classctx, IHqlExpression * expr);
+
     void doBuildMatched(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, CHqlBoundExpr * bound);
     void doBuildMatchAttr(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * expr, CHqlBoundExpr * bound);
     void doBuildParseSearchText(BuildCtx & classctx, IHqlExpression * dataset, IHqlExpression * search, type_t searchType, ITypeInfo * transferType);
@@ -1721,6 +1723,8 @@ public:
     void buildSlidingMatchFunction(BuildCtx & ctx, const HqlExprArray & leftEq, const HqlExprArray & rightEq, const HqlExprArray & slidingMatches, const char * funcname, unsigned childIndex, const DatasetReference & datasetL, const DatasetReference & datasetR);
     void doBuildIndexOutputTransform(BuildCtx & ctx, IHqlExpression * record, SharedHqlExpr & rawRecord, bool hasFileposition, IHqlExpression * maxlength);
 
+    void associateLocalJoinTransformFlags(BuildCtx & ctx, const char * name, IHqlExpression *ds, node_operator side, IHqlExpression *selSeq);
+
     void buildKeyedJoinExtra(ActivityInstance & instance, IHqlExpression * expr, KeyedJoinInfo * joinKey);
     void buildKeyJoinIndexReadHelper(ActivityInstance & instance, IHqlExpression * expr, KeyedJoinInfo * joinKey);
     void buildKeyJoinFetchHelper(ActivityInstance & instance, IHqlExpression * expr, KeyedJoinInfo * joinKey);

+ 28 - 3
ecl/hqlcpp/hqlhtcpp.cpp

@@ -12392,18 +12392,24 @@ ABoundActivity * HqlCppTranslator::doBuildActivityJoinOrDenormalize(BuildCtx & c
     case no_selfjoin:
     case no_denormalize:
         {
-            MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned counter)");
+            MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned counter, unsigned flags)");
             ensureRowAllocated(func.ctx, "crSelf");
 
             IHqlExpression * counter = queryAttributeChild(expr, _countProject_Atom, 0);
             associateCounter(func.ctx, counter, "counter");
+            associateLocalJoinTransformFlags(func.ctx, "flags", dataset1, no_left, selSeq);
+            associateLocalJoinTransformFlags(func.ctx, "flags", dataset2, no_right, selSeq);
+
             buildTransformBody(func.ctx, transform, dataset1, dataset2, instance->dataset, selSeq);
             break;
         }
     case no_denormalizegroup:
         {
-            MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned numRows, const void * * _rows)");
+            MemberFunction func(*this, instance->startctx, "virtual size32_t transform(ARowBuilder & crSelf, const void * _left, const void * _right, unsigned numRows, const void * * _rows, unsigned flags)");
             ensureRowAllocated(func.ctx, "crSelf");
+            associateLocalJoinTransformFlags(func.ctx, "flags", dataset1, no_left, selSeq);
+            associateLocalJoinTransformFlags(func.ctx, "flags", dataset2, no_right, selSeq);
+
             func.ctx.addQuotedLiteral("unsigned char * * rows = (unsigned char * *) _rows;");
 
 
@@ -12417,9 +12423,12 @@ ABoundActivity * HqlCppTranslator::doBuildActivityJoinOrDenormalize(BuildCtx & c
     IHqlExpression * onFail = expr->queryAttribute(onFailAtom);
     if (onFail)
     {
-        MemberFunction func(*this, instance->startctx, "virtual size32_t onFailTransform(ARowBuilder & crSelf, const void * _left, const void * _right, IException * except)");
+        MemberFunction func(*this, instance->startctx, "virtual size32_t onFailTransform(ARowBuilder & crSelf, const void * _left, const void * _right, IException * except, unsigned flags)");
         ensureRowAllocated(func.ctx, "crSelf");
         associateLocalFailure(func.ctx, "except");
+        associateLocalJoinTransformFlags(func.ctx, "flags", dataset1, no_left, selSeq);
+        associateLocalJoinTransformFlags(func.ctx, "flags", dataset2, no_right, selSeq);
+
         buildTransformBody(func.ctx, onFail->queryChild(0), dataset1, dataset2, instance->dataset, selSeq);
     }
 
@@ -17460,6 +17469,22 @@ void HqlCppTranslator::buildSOAPtoXml(BuildCtx & ctx, IHqlExpression * dataset,
     buildXmlSerialize(func.ctx, transform->queryRecord(), self, &assigns);
 }
 
+void HqlCppTranslator::associateLocalJoinTransformFlags(BuildCtx & ctx, const char * name, IHqlExpression *ds, node_operator side, IHqlExpression *selSeq)
+{
+    __int64 mask = 0;
+    if (side==no_right)
+        mask = JTFmatchedright;
+    else if (side==no_left)
+        mask = JTFmatchedleft;
+
+    OwnedIValue maskValue = createIntValue(mask, 4, false);
+    OwnedHqlExpr flagsVariable = createVariable(name, makeIntType(4, false));
+    OwnedHqlExpr matchedRowExpr  = createValue(no_band, makeIntType(4, false), flagsVariable.getClear(), createConstant(maskValue.getClear()));
+
+    OwnedHqlExpr markerExpr = createValue(no_matched_injoin, makeBoolType(), createSelector(side, ds, selSeq));
+    OwnedHqlExpr testExpr = createValue(no_ne, makeBoolType(), matchedRowExpr.getClear(), createConstant(createIntValue(0, 4, false)));
+    ctx.associateExpr(markerExpr,  testExpr);
+}
 
 IHqlExpression * HqlCppTranslator::associateLocalFailure(BuildCtx & ctx, const char * exceptionName)
 {

+ 1 - 0
ecl/hqlcpp/hqlinline.cpp

@@ -1515,6 +1515,7 @@ bool EvalContext::evaluateInParent(BuildCtx & ctx, IHqlExpression * expr, bool h
     case no_filepos:
     case no_file_logicalname:
     case no_counter:
+    case no_matched_injoin:
     case no_variable:       // this really should happen
         return true;        // would have been bound if found
     case no_id2blob:

+ 46 - 40
ecl/hthor/hthor.cpp

@@ -4655,12 +4655,12 @@ void CHThorJoinActivity::fillRight()
         matchedRight.append(false);
 }
 
-const void * CHThorJoinActivity::joinRecords(const void * curLeft, const void * curRight, unsigned counter)
+const void * CHThorJoinActivity::joinRecords(const void * curLeft, const void * curRight, unsigned counter, unsigned flags)
 {
     try
     {
         outBuilder.ensureRow();
-        size32_t thisSize = helper.transform(outBuilder, curLeft, curRight, counter);
+        size32_t thisSize = helper.transform(outBuilder, curLeft, curRight, counter, flags);
         if(thisSize)
             return outBuilder.finalizeRowClear(thisSize);
         else
@@ -4672,14 +4672,16 @@ const void * CHThorJoinActivity::joinRecords(const void * curLeft, const void *
     }
 }
 
-const void * CHThorJoinActivity::groupDenormalizeRecords(const void * curLeft, ConstPointerArray & rows)
+const void * CHThorJoinActivity::groupDenormalizeRecords(const void * curLeft, ConstPointerArray & rows, unsigned flags)
 {
     try
     {
         outBuilder.ensureRow();
         unsigned numRows = rows.ordinality();
         const void * rhs = numRows ? rows.item(0) : defaultRight.get();
-        memsize_t thisSize = helper.transform(outBuilder, curLeft, rhs, numRows, (const void * *)rows.getArray());
+        if (numRows>0)
+            flags |= JTFmatchedright;
+        memsize_t thisSize = helper.transform(outBuilder, curLeft, rhs, numRows, (const void * *)rows.getArray(), flags);
         if(thisSize)
             return outBuilder.finalizeRowClear(thisSize);
         else
@@ -4696,7 +4698,7 @@ const void * CHThorJoinActivity::joinException(const void * curLeft, IException
     try
     {
         outBuilder.ensureRow();
-        size32_t thisSize = helper.onFailTransform(outBuilder, curLeft, defaultRight, except);
+        size32_t thisSize = helper.onFailTransform(outBuilder, curLeft, defaultRight, except, JTFmatchedleft);
         if(thisSize)
             return outBuilder.finalizeRowClear(thisSize);
         else
@@ -4811,7 +4813,7 @@ const void *CHThorJoinActivity::nextRow()
                             if (!matchedRight.item(rightIndex))
                             {
                                 const void * rhs = right.item(rightIndex++);
-                                const void * ret = joinRecords(defaultLeft, rhs, 0);
+                                const void * ret = joinRecords(defaultLeft, rhs, 0, JTFmatchedright);
                                 if (ret)
                                 {
                                     processed++;
@@ -4837,7 +4839,7 @@ const void *CHThorJoinActivity::nextRow()
                                 try
                                 {
                                     RtlDynamicRowBuilder rowBuilder(rowAllocator);
-                                    size32_t thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
+                                    size32_t thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount, JTFmatchedright);
                                     if (thisSize)
                                     {
                                         rowSize = thisSize;
@@ -4871,7 +4873,7 @@ const void *CHThorJoinActivity::nextRow()
                         state = JSfillright;
                         if (filteredRight.ordinality())
                         {
-                            const void * ret = groupDenormalizeRecords(defaultLeft, filteredRight);
+                            const void * ret = groupDenormalizeRecords(defaultLeft, filteredRight, 0);
                             filteredRight.kill();
 
                             if (ret)
@@ -4897,14 +4899,14 @@ const void *CHThorJoinActivity::nextRow()
                 switch (kind)
                 {
                 case TAKjoin:
-                    ret = joinRecords(left, defaultRight, 0);
+                    ret = joinRecords(left, defaultRight, 0, JTFmatchedleft);
                     break;
                 case TAKdenormalize:
                     ret = left.getClear();
                     break;
                 case TAKdenormalizegroup:
                     filteredRight.kill();
-                    ret = groupDenormalizeRecords(left, filteredRight);
+                    ret = groupDenormalizeRecords(left, filteredRight, JTFmatchedleft);
                     break;
                 default:
                     throwUnexpected();
@@ -4936,7 +4938,7 @@ const void *CHThorJoinActivity::nextRow()
                                 matchedLeft = true;
                                 if (!exclude)
                                 {
-                                    const void *ret = joinRecords(left, rhs, ++joinCounter);
+                                    const void *ret = joinRecords(left, rhs, ++joinCounter, JTFmatchedleft|JTFmatchedright);
                                     if (ret)
                                     {
                                         processed++;
@@ -4966,7 +4968,7 @@ const void *CHThorJoinActivity::nextRow()
                                     try
                                     {
                                         RtlDynamicRowBuilder rowBuilder(rowAllocator);
-                                        unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
+                                        unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount, JTFmatchedleft|JTFmatchedright);
                                         if (thisSize)
                                         {
                                             rowSize = thisSize;
@@ -5010,7 +5012,7 @@ const void *CHThorJoinActivity::nextRow()
 
                         if (!exclude && filteredRight.ordinality())
                         {
-                            const void * ret = groupDenormalizeRecords(left, filteredRight);
+                            const void * ret = groupDenormalizeRecords(left, filteredRight, JTFmatchedleft);
                             filteredRight.kill();
 
                             if (ret)
@@ -5230,7 +5232,7 @@ const void * CHThorSelfJoinActivity::nextRow()
                 const void * rhs = group.item(rightIndex++);
                 if(helper.match(lhs, rhs))
                 {
-                    const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL);
+                    const void * ret = joinRecords(lhs, rhs, ++joinCounter, JTFmatchedleft|JTFmatchedright, NULL);
                     if(ret)
                     {
                         processed++;
@@ -5252,7 +5254,7 @@ const void * CHThorSelfJoinActivity::nextRow()
         if(failingOuterAtmost)
             while(group.isItem(leftIndex))
             {
-                const void * ret = joinRecords(group.item(leftIndex++), defaultRight, 0, NULL);
+                const void * ret = joinRecords(group.item(leftIndex++), defaultRight, 0, JTFmatchedleft, NULL);
                 if(ret)
                 {
                     processed++;
@@ -5263,7 +5265,7 @@ const void * CHThorSelfJoinActivity::nextRow()
         {
             if(leftOuterJoin && !matchedLeft && !failingLimit)
             {
-                const void * ret = joinRecords(group.item(leftIndex), defaultRight, 0, NULL);
+                const void * ret = joinRecords(group.item(leftIndex), defaultRight, 0, JTFmatchedleft, NULL);
                 if(ret)
                 {
                     matchedLeft = true;
@@ -5284,7 +5286,7 @@ const void * CHThorSelfJoinActivity::nextRow()
                 OwnedConstRoxieRow lhs(groupedInput->nextRow());  // dualCache never active here
                 while(lhs)
                 {
-                    const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit);
+                    const void * ret = joinRecords(lhs, defaultRight, 0, JTFmatchedleft, failingLimit);
                     if(ret)
                     {
                         processed++;
@@ -5298,7 +5300,7 @@ const void * CHThorSelfJoinActivity::nextRow()
                 while(group.isItem(rightOuterIndex))
                     if(!matchedRight.item(rightOuterIndex++))
                     {
-                        const void * ret = joinRecords(defaultLeft, group.item(rightOuterIndex-1), 0, NULL);
+                        const void * ret = joinRecords(defaultLeft, group.item(rightOuterIndex-1), 0, JTFmatchedright, NULL);
                         if(ret)
                         {
                             processed++;
@@ -5313,7 +5315,7 @@ const void * CHThorSelfJoinActivity::nextRow()
         if(failingLimit)
         {
             leftIndex++;
-            const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit);
+            const void * ret = joinRecords(lhs, defaultRight, 0, JTFmatchedleft, failingLimit);
             if(ret)
             {
                 processed++;
@@ -5329,7 +5331,7 @@ const void * CHThorSelfJoinActivity::nextRow()
                 matchedRight.replace(true, rightIndex-1);
                 if(!exclude)
                 {
-                    const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL);
+                    const void * ret = joinRecords(lhs, rhs, ++joinCounter, JTFmatchedleft|JTFmatchedright, NULL);
                     if(ret)
                     {
                         processed++;
@@ -5343,12 +5345,12 @@ const void * CHThorSelfJoinActivity::nextRow()
     return NULL;
 }
 
-const void * CHThorSelfJoinActivity::joinRecords(const void * curLeft, const void * curRight, unsigned counter, IException * except)
+const void * CHThorSelfJoinActivity::joinRecords(const void * curLeft, const void * curRight, unsigned counter, unsigned flags, IException * except)
 {
     outBuilder.ensureRow();
     try
     {
-            size32_t thisSize = (except ? helper.onFailTransform(outBuilder, curLeft, curRight, except) : helper.transform(outBuilder, curLeft, curRight, counter));
+            size32_t thisSize = (except ? helper.onFailTransform(outBuilder, curLeft, curRight, except, flags) : helper.transform(outBuilder, curLeft, curRight, counter, flags));
             if(thisSize){
                 return outBuilder.finalizeRowClear(thisSize);   
             }
@@ -5543,12 +5545,12 @@ void CHThorLookupJoinActivity::setInput(unsigned index, IHThorInput * _input)
 }
 
 //following are all copied from CHThorJoinActivity - should common up.
-const void * CHThorLookupJoinActivity::joinRecords(const void * left, const void * right, unsigned counter)
+const void * CHThorLookupJoinActivity::joinRecords(const void * left, const void * right, unsigned counter, unsigned flags)
 {
     try
     {
         outBuilder.ensureRow();
-        size32_t thisSize = helper.transform(outBuilder, left, right, counter);
+        size32_t thisSize = helper.transform(outBuilder, left, right, counter, flags);
         if(thisSize)
             return outBuilder.finalizeRowClear(thisSize);
         else
@@ -5565,7 +5567,7 @@ const void * CHThorLookupJoinActivity::joinException(const void * left, IExcepti
     try
     {
         outBuilder.ensureRow();
-        memsize_t thisSize = helper.onFailTransform(outBuilder, left, defaultRight, except);
+        memsize_t thisSize = helper.onFailTransform(outBuilder, left, defaultRight, except, JTFmatchedleft);
         if(thisSize)
             return outBuilder.finalizeRowClear(thisSize);
         else
@@ -5577,14 +5579,16 @@ const void * CHThorLookupJoinActivity::joinException(const void * left, IExcepti
     }
 }
 
-const void * CHThorLookupJoinActivity::groupDenormalizeRecords(const void * left, ConstPointerArray & rows)
+const void * CHThorLookupJoinActivity::groupDenormalizeRecords(const void * left, ConstPointerArray & rows, unsigned flags)
 {
     try
     {
         outBuilder.ensureRow();
         unsigned numRows = rows.ordinality();
         const void * right = numRows ? rows.item(0) : defaultRight.get();
-        memsize_t thisSize = helper.transform(outBuilder, left, right, numRows, (const void * *)rows.getArray());
+        if (numRows>0)
+            flags |= JTFmatchedright;
+        memsize_t thisSize = helper.transform(outBuilder, left, right, numRows, (const void * *)rows.getArray(), flags);
         if(thisSize)
             return outBuilder.finalizeRowClear(thisSize);
         else
@@ -5660,7 +5664,7 @@ const void * CHThorLookupJoinActivity::nextRowJoin()
                     gotMatch = true;
                     if(exclude)
                         break;
-                    ret = joinRecords(left, right, ++joinCounter);
+                    ret = joinRecords(left, right, ++joinCounter, JTFmatchedleft|JTFmatchedright);
                     if(ret)
                     {
                         processed++;
@@ -5672,7 +5676,7 @@ const void * CHThorLookupJoinActivity::nextRowJoin()
             }
             if(leftOuterJoin && !gotMatch)
             {
-                ret = joinRecords(left, defaultRight, 0);
+                ret = joinRecords(left, defaultRight, 0, JTFmatchedleft);
                 gotMatch = true;
             }
         }
@@ -5732,7 +5736,7 @@ const void * CHThorLookupJoinActivity::nextRowDenormalize()
                     try
                     {
                         RtlDynamicRowBuilder rowBuilder(rowAllocator);
-                        unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
+                        unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount, JTFmatchedleft|JTFmatchedright);
                         if (thisSize)
                         {
                             rowSize = thisSize;
@@ -5773,7 +5777,7 @@ const void * CHThorLookupJoinActivity::nextRowDenormalize()
             }
 
             if((filteredRight.ordinality() > 0) || (leftOuterJoin && !gotMatch))
-                ret = groupDenormalizeRecords(left, filteredRight);
+                ret = groupDenormalizeRecords(left, filteredRight, JTFmatchedleft);
             filteredRight.kill();
         }
         left.clear();
@@ -5920,12 +5924,12 @@ void CHThorAllJoinActivity::loadRight()
     rightOrdinality = rightset.ordinality();
 }
 
-const void * CHThorAllJoinActivity::joinRecords(const void * left, const void * right, unsigned counter)
+const void * CHThorAllJoinActivity::joinRecords(const void * left, const void * right, unsigned counter, unsigned flags)
 {
     try
     {
         outBuilder.ensureRow();
-        memsize_t thisSize = helper.transform(outBuilder, left, right, counter);
+        memsize_t thisSize = helper.transform(outBuilder, left, right, counter, flags);
         if(thisSize)
             return outBuilder.finalizeRowClear(thisSize);
         else
@@ -5937,14 +5941,16 @@ const void * CHThorAllJoinActivity::joinRecords(const void * left, const void *
     }
 }
 
-const void * CHThorAllJoinActivity::groupDenormalizeRecords(const void * curLeft, ConstPointerArray & rows)
+const void * CHThorAllJoinActivity::groupDenormalizeRecords(const void * curLeft, ConstPointerArray & rows, unsigned flags)
 {
     try
     {
         outBuilder.ensureRow();
         unsigned numRows = rows.ordinality();
         const void * right = numRows ? rows.item(0) : defaultRight.get();
-        memsize_t thisSize = helper.transform(outBuilder, curLeft, right, numRows, (const void * *)rows.getArray());
+        if (numRows>0)
+            flags |= JTFmatchedright;
+        memsize_t thisSize = helper.transform(outBuilder, curLeft, right, numRows, (const void * *)rows.getArray(), flags);
         if(thisSize)
             return outBuilder.finalizeRowClear(thisSize);
         else
@@ -5999,14 +6005,14 @@ const void * CHThorAllJoinActivity::nextRow()
                 switch(kind)
                 {
                 case TAKalljoin:
-                    ret = joinRecords(left, defaultRight, 0);
+                    ret = joinRecords(left, defaultRight, 0, JTFmatchedleft);
                     break;
                 case TAKalldenormalize:
                     ret = left.getClear();
                     break;
                 case TAKalldenormalizegroup:
                     filteredRight.kill();
-                    ret = groupDenormalizeRecords(left, filteredRight);
+                    ret = groupDenormalizeRecords(left, filteredRight, JTFmatchedleft);
                     break;
                 default:
                     throwUnexpected();
@@ -6059,7 +6065,7 @@ const void * CHThorAllJoinActivity::nextRow()
                     matchedLeft = true;
                     matchedRight.replace(true, rightIndex);
                     if(!exclude)
-                        ret = joinRecords(left, right, ++joinCounter);
+                        ret = joinRecords(left, right, ++joinCounter, JTFmatchedleft|JTFmatchedright);
                 }
                 rightIndex++;
                 if(ret)
@@ -6088,7 +6094,7 @@ const void * CHThorAllJoinActivity::nextRow()
                             try
                             {
                                 RtlDynamicRowBuilder rowBuilder(rowAllocator);
-                                unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
+                                unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount, JTFmatchedleft|JTFmatchedright);
                                 if(thisSize)
                                 {
                                     rowSize = thisSize;
@@ -6127,7 +6133,7 @@ const void * CHThorAllJoinActivity::nextRow()
             }
             if(!exclude && filteredRight.ordinality())
             {
-                const void * ret = groupDenormalizeRecords(left, filteredRight);
+                const void * ret = groupDenormalizeRecords(left, filteredRight, JTFmatchedleft);
                 filteredRight.kill();
                 if(ret)
                 {

+ 7 - 7
ecl/hthor/hthor.ipp

@@ -1330,8 +1330,8 @@ private:
     const void *nextRightInGroup();
     //bool getMatchingRecords();
     //bool queryAdvanceCursors();
-    const void * joinRecords(const void * curLeft, const void * curRight, unsigned counter);
-    const void * groupDenormalizeRecords(const void * curLeft, ConstPointerArray & rows);
+    const void * joinRecords(const void * curLeft, const void * curRight, unsigned counter, unsigned flags);
+    const void * groupDenormalizeRecords(const void * curLeft, ConstPointerArray & rows, unsigned flags);
     const void * joinException(const void * curLeft, IException * except);
     void failLimit();
     void createDefaultLeft();   
@@ -1397,7 +1397,7 @@ class CHThorSelfJoinActivity : public CHThorActivityBase
     IRowStream *dualCacheInput;
 private:
     bool fillGroup();
-    const void * joinRecords(const void * curLeft, const void * curRight, unsigned counter, IException * except);
+    const void * joinRecords(const void * curLeft, const void * curRight, unsigned counter, unsigned flags, IException * except);
     void failLimit(const void * next);
 
 public:
@@ -1476,8 +1476,8 @@ private:
 
 private:
     void loadRight();
-    const void * groupDenormalizeRecords(const void * curLeft, ConstPointerArray & rows);
-    const void * joinRecords(const void * left, const void * right, unsigned counter);
+    const void * groupDenormalizeRecords(const void * curLeft, ConstPointerArray & rows, unsigned flags);
+    const void * joinRecords(const void * left, const void * right, unsigned counter, unsigned flags);
     const void * joinException(const void * left, IException * except);
     const void * getRightFirst() { if(hasGroupLimit) return fillRightGroup(); else return table->find(left); }
     const void * getRightNext() { if(hasGroupLimit) return readRightGroup(); else return table->findNext(left); }
@@ -1540,8 +1540,8 @@ private:
 
 private:
     void loadRight();
-    const void * joinRecords(const void * left, const void * right, unsigned counter);
-    const void * groupDenormalizeRecords(const void * left, ConstPointerArray & rows);
+    const void * joinRecords(const void * left, const void * right, unsigned counter, unsigned flags);
+    const void * groupDenormalizeRecords(const void * left, ConstPointerArray & rows, unsigned flags);
     void createDefaultRight();  
 public:
     CHThorAllJoinActivity(IAgentContext & _agent, unsigned _activityId, unsigned _subgraphId, IHThorAllJoinArg &_arg, ThorActivityKind _kind);

+ 46 - 40
roxie/ccd/ccdserver.cpp

@@ -12610,7 +12610,7 @@ public:
             matchedRight.append(false);
     }
 
-    const void * joinRecords(const void * curLeft, const void * curRight, unsigned counter)
+    const void * joinRecords(const void * curLeft, const void * curRight, unsigned counter, unsigned flags)
     {
         if (cloneLeft)
         {
@@ -12620,7 +12620,7 @@ public:
         try
         {
             RtlDynamicRowBuilder rowBuilder(rowAllocator);
-            size32_t thisSize = helper.transform(rowBuilder, curLeft, curRight, counter);
+            size32_t thisSize = helper.transform(rowBuilder, curLeft, curRight, counter, flags);
             if (thisSize)
                 return rowBuilder.finalizeRowClear(thisSize);
             else
@@ -12632,14 +12632,16 @@ public:
         }
     }
 
-    const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows)
+    const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows, unsigned flags)
     {
         try
         {
             RtlDynamicRowBuilder rowBuilder(rowAllocator);
             unsigned numRows = rows.ordinality();
             const void * right = numRows ? rows.item(0) : defaultRight.get();
-            size32_t thisSize = helper.transform(rowBuilder, curLeft, right, numRows, (const void * *)rows.getArray());
+            if (numRows>0)
+                flags |= JTFmatchedright;
+            size32_t thisSize = helper.transform(rowBuilder, curLeft, right, numRows, (const void * *)rows.getArray(), flags);
             if (thisSize)
                 return rowBuilder.finalizeRowClear(thisSize);
             else
@@ -12654,7 +12656,7 @@ public:
     const void * joinException(const void * curLeft, IException * except)
     {
         RtlDynamicRowBuilder rowBuilder(rowAllocator);
-        size32_t thisSize = helper.onFailTransform(rowBuilder, curLeft, defaultRight, except);
+        size32_t thisSize = helper.onFailTransform(rowBuilder, curLeft, defaultRight, except, JTFmatchedleft);
         return rowBuilder.finalizeRowClear(thisSize);
     }
 
@@ -12759,7 +12761,7 @@ public:
                                 if (!matchedRight.item(rightIndex))
                                 {
                                     const void * rhs = right.item(rightIndex++);
-                                    const void *ret = joinRecords(defaultLeft, rhs, 0);
+                                    const void *ret = joinRecords(defaultLeft, rhs, 0, JTFmatchedright);
                                     if (ret)
                                     {
                                         processed++;
@@ -12786,7 +12788,7 @@ public:
                                     try
                                     {
                                         RtlDynamicRowBuilder rowBuilder(rowAllocator);
-                                        unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
+                                        unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount, JTFmatchedright);
                                         if (thisSize)
                                         {
                                             rowSize = thisSize;
@@ -12820,7 +12822,7 @@ public:
                             state = JSfillright;
                             if (filteredRight.ordinality())
                             {
-                                const void * ret = denormalizeRecords(defaultLeft, filteredRight);
+                                const void * ret = denormalizeRecords(defaultLeft, filteredRight, 0);
                                 filteredRight.kill();
 
                                 if (ret)
@@ -12844,7 +12846,7 @@ public:
                     switch (activityKind)
                     {
                     case TAKjoin:
-                        ret = joinRecords(left, defaultRight, 0);
+                        ret = joinRecords(left, defaultRight, 0, JTFmatchedleft);
                         break;
                     case TAKdenormalize:
                         ret = left;
@@ -12852,7 +12854,7 @@ public:
                         break;
                     case TAKdenormalizegroup:
                         filteredRight.kill();
-                        ret = denormalizeRecords(left, filteredRight);
+                        ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
                         break;
                     }
                 }
@@ -12883,7 +12885,7 @@ public:
                                     matchedLeft = true;
                                     if (!exclude)
                                     {
-                                        const void *ret = joinRecords(left, rhs, ++joinCounter);
+                                        const void *ret = joinRecords(left, rhs, ++joinCounter, JTFmatchedleft|JTFmatchedright);
                                         if (ret)
                                         {
                                             processed++;
@@ -12913,7 +12915,7 @@ public:
                                         if (!exclude)
                                         {
                                             RtlDynamicRowBuilder rowBuilder(rowAllocator);
-                                            unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount);
+                                            unsigned thisSize = helper.transform(rowBuilder, newLeft, rhs, ++leftCount, JTFmatchedleft|JTFmatchedright);
                                             if (thisSize)
                                             {
                                                 rowSize = thisSize;
@@ -12957,7 +12959,7 @@ public:
 
                             if (!exclude && filteredRight.ordinality())
                             {
-                                const void * ret = denormalizeRecords(left, filteredRight);
+                                const void * ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
                                 filteredRight.kill();
 
                                 if (ret)
@@ -17866,7 +17868,7 @@ class CRoxieServerSelfJoinActivity : public CRoxieServerActivity
 
     virtual bool needsAllocator() const { return true; }
 
-    const void *joinRecords(const void * curLeft, const void * curRight, unsigned counter, IException * except)
+    const void *joinRecords(const void * curLeft, const void * curRight, unsigned counter, IException * except, unsigned flags)
     {
         try
         {
@@ -17876,7 +17878,7 @@ class CRoxieServerSelfJoinActivity : public CRoxieServerActivity
                 return curLeft;
             }
             RtlDynamicRowBuilder rowBuilder(rowAllocator);
-            size32_t outsize = except ? helper.onFailTransform(rowBuilder, curLeft, curRight, except) : helper.transform(rowBuilder, curLeft, curRight, counter);
+            size32_t outsize = except ? helper.onFailTransform(rowBuilder, curLeft, curRight, except, flags) : helper.transform(rowBuilder, curLeft, curRight, counter, flags);
             if (outsize)
                 return rowBuilder.finalizeRowClear(outsize);
             else
@@ -18034,7 +18036,7 @@ public:
                     const void * rhs = group.item(rightIndex++);
                     if(helper.match(lhs, rhs))
                     {
-                        const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL);
+                        const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL, JTFmatchedleft|JTFmatchedright);
                         if(ret)
                         {
                             processed++;
@@ -18057,7 +18059,7 @@ public:
                 if(failingOuterAtmost)
                     while(group.isItem(leftIndex))
                     {
-                        const void * ret = joinRecords(group.item(leftIndex++), defaultRight, 0, NULL);
+                        const void * ret = joinRecords(group.item(leftIndex++), defaultRight, 0, NULL, JTFmatchedleft);
                         if(ret)
                         {
                             processed++;
@@ -18068,7 +18070,7 @@ public:
                 {
                     if(leftOuterJoin && !matchedLeft && !failingLimit)
                     {
-                        const void * ret = joinRecords(group.item(leftIndex), defaultRight, 0, NULL);
+                        const void * ret = joinRecords(group.item(leftIndex), defaultRight, 0, NULL, JTFmatchedleft);
                         if(ret)
                         {
                             matchedLeft = true;
@@ -18089,7 +18091,7 @@ public:
                         const void * lhs;
                         while((lhs = groupedInput->nextRow()) != NULL)  // dualCache never active here
                         {
-                            const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit);
+                            const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit, JTFmatchedleft);
                             ReleaseRoxieRow(lhs);
                             if(ret)
                             {
@@ -18103,7 +18105,7 @@ public:
                         while(group.isItem(rightOuterIndex))
                             if(!matchedRight.item(rightOuterIndex++))
                             {
-                                const void * ret = joinRecords(defaultLeft, group.item(rightOuterIndex-1), 0, NULL);
+                                const void * ret = joinRecords(defaultLeft, group.item(rightOuterIndex-1), 0, NULL, JTFmatchedright);
                                 if(ret)
                                 {
                                     processed++;
@@ -18118,7 +18120,7 @@ public:
                 if(failingLimit)
                 {
                     leftIndex++;
-                    const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit);
+                    const void * ret = joinRecords(lhs, defaultRight, 0, failingLimit, JTFmatchedleft);
                     if(ret)
                     {
                         processed++;
@@ -18134,7 +18136,7 @@ public:
                         matchedRight.replace(true, rightIndex-1);
                         if(!exclude)
                         {
-                            const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL);
+                            const void * ret = joinRecords(lhs, rhs, ++joinCounter, NULL, JTFmatchedleft|JTFmatchedright);
                             if(ret)
                             {
                                 processed++;
@@ -18679,7 +18681,7 @@ private:
                         gotMatch = true;
                         if(exclude)
                             break;
-                        ret = joinRecords(left, right, ++joinCounter);
+                        ret = joinRecords(left, right, ++joinCounter, JTFmatchedleft|JTFmatchedright);
                         if(ret)
                         {
                             processed++;
@@ -18691,7 +18693,7 @@ private:
                 }
                 if(leftOuterJoin && !gotMatch)
                 {
-                    ret = joinRecords(left, defaultRight, 0);
+                    ret = joinRecords(left, defaultRight, 0, JTFmatchedleft);
                     gotMatch = true;
                 }
             }
@@ -18750,7 +18752,7 @@ private:
                                 break;
 
                             RtlDynamicRowBuilder rowBuilder(rowAllocator);
-                            unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
+                            unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount, JTFmatchedleft|JTFmatchedright);
                             if (thisSize)
                             {
                                 rowSize = thisSize;
@@ -18793,7 +18795,7 @@ private:
                 }
 
                 if((filteredRight.ordinality() > 0) || (leftOuterJoin && !gotMatch))
-                    ret = denormalizeRecords(left, filteredRight);
+                    ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
                 filteredRight.kill();
             }
             ReleaseRoxieRow(left);
@@ -18808,7 +18810,7 @@ private:
         }
     }
 
-    const void * joinRecords(const void * left, const void * right, unsigned counter)
+    const void * joinRecords(const void * left, const void * right, unsigned counter, unsigned flags)
     {
         if (cloneLeft)
         {
@@ -18818,7 +18820,7 @@ private:
         try
         {
             RtlDynamicRowBuilder rowBuilder(rowAllocator);
-            unsigned outSize = helper.transform(rowBuilder, left, right, counter);
+            unsigned outSize = helper.transform(rowBuilder, left, right, counter, flags);
             if (outSize)
                 return rowBuilder.finalizeRowClear(outSize);
             else
@@ -18835,7 +18837,7 @@ private:
         try
         {
             RtlDynamicRowBuilder rowBuilder(rowAllocator);
-            unsigned outSize = helper.onFailTransform(rowBuilder, left, defaultRight, except);
+            unsigned outSize = helper.onFailTransform(rowBuilder, left, defaultRight, except, JTFmatchedleft);
             if (outSize)
                 return rowBuilder.finalizeRowClear(outSize);
             else
@@ -18847,14 +18849,16 @@ private:
         }
     }
 
-    const void * denormalizeRecords(const void * left, ConstPointerArray & rows)
+    const void * denormalizeRecords(const void * left, ConstPointerArray & rows, unsigned flags)
     {
         try
         {
             RtlDynamicRowBuilder rowBuilder(rowAllocator);
             unsigned numRows = rows.ordinality();
             const void * right = numRows ? rows.item(0) : defaultRight.get();
-            unsigned outSize = helper.transform(rowBuilder, left, right, numRows, (const void * *)rows.getArray());
+            if (numRows>0)
+                flags |= JTFmatchedright;
+            unsigned outSize = helper.transform(rowBuilder, left, right, numRows, (const void * *)rows.getArray(), flags);
             if (outSize)
                 return rowBuilder.finalizeRowClear(outSize);
             else
@@ -19100,7 +19104,7 @@ public:
         CRoxieServerTwoInputActivity::setInput(idx, _sourceIdx, _in);
     }
 
-    const void * joinRecords(const void * left, const void * right, unsigned counter)
+    const void * joinRecords(const void * left, const void * right, unsigned counter, unsigned flags)
     {
         // MORE - could share some code with lookup join
         if (cloneLeft)
@@ -19111,7 +19115,7 @@ public:
         try
         {
             RtlDynamicRowBuilder rowBuilder(rowAllocator);
-            unsigned outSize = helper.transform(rowBuilder, left, right, counter);
+            unsigned outSize = helper.transform(rowBuilder, left, right, counter, flags);
             if (outSize)
                 return rowBuilder.finalizeRowClear(outSize);
             else
@@ -19123,14 +19127,16 @@ public:
         }
     }
 
-    const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows)
+    const void * denormalizeRecords(const void * curLeft, ConstPointerArray & rows, unsigned flags)
     {
         try
         {
             RtlDynamicRowBuilder rowBuilder(rowAllocator);
             unsigned numRows = rows.ordinality();
             const void * right = numRows ? rows.item(0) : defaultRight.get();
-            unsigned outSize = helper.transform(rowBuilder, curLeft, right, numRows, rows.getArray());
+            if (numRows>0)
+                flags |= JTFmatchedright;
+            unsigned outSize = helper.transform(rowBuilder, curLeft, right, numRows, rows.getArray(), flags);
             if (outSize)
                 return rowBuilder.finalizeRowClear(outSize);
             else
@@ -19176,7 +19182,7 @@ public:
                     switch(activityKind)
                     {
                     case TAKalljoin:
-                        ret = joinRecords(left, defaultRight, 0);
+                        ret = joinRecords(left, defaultRight, 0, JTFmatchedleft);
                         break;
                     case TAKalldenormalize:
                         ret = left;
@@ -19184,7 +19190,7 @@ public:
                         break;
                     case TAKalldenormalizegroup:
                         filteredRight.kill();
-                        ret = denormalizeRecords(left, filteredRight);
+                        ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
                         break;
                     default:
                         throwUnexpected();
@@ -19239,7 +19245,7 @@ public:
                         matchedLeft = true;
                         matchedRight.replace(true, rightIndex);
                         if(!exclude)
-                            ret = joinRecords(left, right, ++joinCounter);
+                            ret = joinRecords(left, right, ++joinCounter, JTFmatchedleft|JTFmatchedright);
                     }
                     rightIndex++;
                     if(ret)
@@ -19269,7 +19275,7 @@ public:
                                 try
                                 {
                                     RtlDynamicRowBuilder rowBuilder(rowAllocator);
-                                    unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount);
+                                    unsigned thisSize = helper.transform(rowBuilder, newLeft, right, ++leftCount, JTFmatchedleft|JTFmatchedright);
                                     if(thisSize)
                                     {
                                         rowSize = thisSize;
@@ -19308,7 +19314,7 @@ public:
                 }
                 if(!exclude && filteredRight.ordinality())
                 {
-                    ret = denormalizeRecords(left, filteredRight);
+                    ret = denormalizeRecords(left, filteredRight, JTFmatchedleft);
                     filteredRight.kill();
                     if(ret)
                     {

+ 11 - 5
rtl/include/eclhelper.hpp

@@ -44,8 +44,8 @@ typedef unsigned short UChar;
 
 //Should be incremented whenever the virtuals in the context or a helper are changed, so
 //that a work unit can't be rerun.  Try as hard as possible to retain compatibility.
-#define ACTIVITY_INTERFACE_VERSION      163
-#define MIN_ACTIVITY_INTERFACE_VERSION  163             //minimum value that is compatible with current interface - without using selectInterface
+#define ACTIVITY_INTERFACE_VERSION      164
+#define MIN_ACTIVITY_INTERFACE_VERSION  164             //minimum value that is compatible with current interface - without using selectInterface
 
 typedef unsigned char byte;
 
@@ -1733,6 +1733,12 @@ enum {
     FFdynamicfilename            = 0x0004,
 };  
 
+// JoinTransformFlags
+enum {
+    JTFmatchedleft           = 0x0001,
+    JTFmatchedright          = 0x0002
+};
+
 struct IHThorAnyJoinBaseArg : public IHThorArg
 {
     virtual bool match(const void * _left, const void * _right) = 0;
@@ -1743,9 +1749,9 @@ struct IHThorAnyJoinBaseArg : public IHThorArg
 
 //Join:
 //Denormalize
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _count) { return 0; }
+    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _count, unsigned _flags) { return 0; }
 //Denormalize group
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _numRows, const void * * _rows) { return 0; }
+    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _numRows, const void * * _rows, unsigned _flags) { return 0; }
 
     inline bool isLeftAlreadyLocallySorted() { return (getJoinFlags() & JFleftSortedLocally) != 0; }
     inline bool isRightAlreadyLocallySorted() { return (getJoinFlags() & JFrightSortedLocally) != 0; }
@@ -1771,7 +1777,7 @@ struct IHThorJoinBaseArg : public IHThorAnyJoinBaseArg
     virtual ICompare * queryCompareLeftRightUpper() = 0;
     virtual ICompare * queryPrefixCompare() = 0;
 
-    virtual size32_t onFailTransform(ARowBuilder & rowBuilder, const void * _left, const void * _right, IException * e) { return 0; }
+    virtual size32_t onFailTransform(ARowBuilder & rowBuilder, const void * _left, const void * _right, IException * e, unsigned flags) { return 0; }
     virtual ICompare * queryCompareLeftKeyRightRow()=0;                         // compare serialized left key with right row
     virtual ICompare * queryCompareRightKeyLeftRow()=0;                         // as above if partition right selected
 };

+ 6 - 9
rtl/include/eclhelper_base.hpp

@@ -1816,11 +1816,10 @@ class CThorJoinArg : implements IHThorJoinArg, public CThorArg
     virtual size32_t onFailTransform(ARowBuilder & rowBuilder, const void * _left, const void * _right, IException * e) { return 0; }
 
 //Join:
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right) { return 0; }
 //Denormalize
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _count) { return 0; }
+    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _count, unsigned flags) { return 0; }
 //Denormalize group
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _numRows, const void * * _rows) { return 0; }
+    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _numRows, const void * * _rows, unsigned flags) { return 0; }
 };
 
 typedef CThorJoinArg CThorDenormalizeArg;
@@ -1852,11 +1851,10 @@ class CThorAllJoinArg : implements IHThorAllJoinArg, public CThorArg
     virtual unsigned getJoinFlags()                     { return 0; }
 
 //Join:
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right) { return 0; }
 //Denormalize
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _count) { return 0; }
+    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _count, unsigned flags) { return 0; }
 //Denormalize group
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _numRows, const void * * _rows) { return 0; }
+    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _numRows, const void * * _rows, unsigned flags) { return 0; }
 };
 
 typedef CThorAllJoinArg CThorAllDenormalizeArg;
@@ -1910,11 +1908,10 @@ class CThorHashJoinArg : implements IHThorHashJoinArg, public CThorArg
     virtual size32_t onFailTransform(ARowBuilder & rowBuilder, const void * _left, const void * _right, IException * e) { return 0; }
 
 //Join:
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right) { return 0; }
 //Denormalize
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _count) { return 0; }
+    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _count, unsigned flags) { return 0; }
 //Denormalize group
-    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _numRows, const void * * _rows) { return 0; }
+    virtual size32_t transform(ARowBuilder & rowBuilder, const void * _left, const void * _right, unsigned _numRows, const void * * _rows, unsigned flags) { return 0; }
 };
 
 

+ 17 - 17
testing/ecl/JoinTest.pm

@@ -1,19 +1,19 @@
-/*##############################################################################
-
-    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems(R).
-
-    This program is free software: you can redistribute it and/or modify
-    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.
-############################################################################## */
+##############################################################################
+#
+#    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems(R).
+#
+#    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.
+##############################################################################
 
 package JoinTest;
 
@@ -171,7 +171,7 @@ sub _setmatchxfm($ )
     my ($self) = @_;
     $self->{matcharg} = ($self->{type} eq 'ALL') ? 'allmatch' : 'match';
     $self->{xfmarg} = 'xfm';
-    my $xfmrightarg := 'RIGHT';
+    my $xfmrightarg = 'RIGHT';
     if($self->{activity} eq 'DENORMALIZEGROUP')
     {
         $self->{xfmarg} .= 'grp';

+ 36 - 18
testing/ecl/genjointest.pl

@@ -1,19 +1,19 @@
-/*##############################################################################
-
-    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems(R).
-
-    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.
-############################################################################## */
+##############################################################################
+#
+#    HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems(R).
+#
+#    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.
+##############################################################################
 
 use strict;
 use warnings;
@@ -105,9 +105,12 @@ foreach my $test (@tests)
     }
 }
 
+#giving output files more generic names all tests now seem to work on all platforms
+#we can reorganize this script to reflect that in future
+
 genfile('genjoin.ecl', \@decs, \@outs, []);
-genfile('genjoin_nothor.ecl', \@nothor_decs, \@nothor_outs, ['nothor']);
-genfile('genjoin_justroxie.ecl', \@justroxie_decs, \@justroxie_outs, ['nothor', 'nohthor']);
+genfile('genjoin2.ecl', \@nothor_decs, \@nothor_outs, []);
+genfile('genjoin3.ecl', \@justroxie_decs, \@justroxie_outs, []);
 
 my $posscount = @tests;
 my $deccount = @decs + @nothor_decs + @justroxie_decs;
@@ -134,6 +137,9 @@ jrec := RECORD,MAXLENGTH(100)
     STRING3 rstr;
     UNSIGNED1 c;
     STRING label;
+    BOOLEAN ml := false;
+    BOOLEAN mr := false;
+    INTEGER1 vr := 0;
 END;
 
 lhs := SORTED(DATASET([{3, 'aaa', '', 0, ''}, {4, 'bbb', '', 0, ''}, {5, 'ccc', '', 0, ''}, {6, 'ddd', '', 0, ''}, {7, 'eee', '', 0, ''}], jrec), i);
@@ -154,6 +160,9 @@ jrec xfm(jrec l, jrec r, STRING lab) := TRANSFORM
     SELF.rstr := r.rstr;
     SELF.c := l.c+1;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // skipping transform for joins and non-group denormalizes
@@ -164,6 +173,9 @@ jrec xfmskip(jrec l, jrec r, STRING lab) := TRANSFORM
     SELF.rstr := IF(r.rstr >= 'x', SKIP, r.rstr);
     SELF.c := l.c+1;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // transform for group denormalizes, to be used with match or allmatch
@@ -174,6 +186,9 @@ jrec xfmgrp(jrec l, DATASET(jrec) r, STRING lab) := TRANSFORM
     SELF.rstr := r[c].rstr;
     SELF.c := c;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // skipping transform for group denormalizes, to be used with match or allmatch
@@ -186,4 +201,7 @@ jrec xfmgrpskip(jrec l, DATASET(jrec) r, STRING lab) := TRANSFORM
     SELF.rstr := IF(skp > 0, SKIP, r[c].rstr);
     SELF.c := c;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;

+ 15 - 0
testing/regress/ecl/genjoin.ecl

@@ -27,6 +27,9 @@ jrec := RECORD,MAXLENGTH(100)
     STRING3 rstr;
     UNSIGNED1 c;
     STRING label;
+    BOOLEAN ml := false;
+    BOOLEAN mr := false;
+    INTEGER1 vr := 0;
 END;
 
 lhs := SORTED(DATASET([{3, 'aaa', '', 0, ''}, {4, 'bbb', '', 0, ''}, {5, 'ccc', '', 0, ''}, {6, 'ddd', '', 0, ''}, {7, 'eee', '', 0, ''}], jrec), i);
@@ -47,6 +50,9 @@ jrec xfm(jrec l, jrec r, STRING lab) := TRANSFORM
     SELF.rstr := r.rstr;
     SELF.c := l.c+1;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // skipping transform for joins and non-group denormalizes
@@ -57,6 +63,9 @@ jrec xfmskip(jrec l, jrec r, STRING lab) := TRANSFORM
     SELF.rstr := IF(r.rstr >= 'x', SKIP, r.rstr);
     SELF.c := l.c+1;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // transform for group denormalizes, to be used with match or allmatch
@@ -67,6 +76,9 @@ jrec xfmgrp(jrec l, DATASET(jrec) r, STRING lab) := TRANSFORM
     SELF.rstr := r[c].rstr;
     SELF.c := c;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // skipping transform for group denormalizes, to be used with match or allmatch
@@ -79,6 +91,9 @@ jrec xfmgrpskip(jrec l, DATASET(jrec) r, STRING lab) := TRANSFORM
     SELF.rstr := IF(skp > 0, SKIP, r[c].rstr);
     SELF.c := c;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 join____INN________ := JOIN(lhs, rhs, match(LEFT, RIGHT), xfm(LEFT, RIGHT, 'JOIN'), INNER);

+ 15 - 1
testing/regress/ecl/genjoin_nothor.ecl

@@ -16,7 +16,6 @@
 ############################################################################## */
 
 // IMPORTANT: this test is generated by the perl script genjointest.pl, so do not edit it by hand
-//nothor
 
 #option('convertJoinToLookup', 0);
 #option('noAllToLookupConversion', 1);
@@ -28,6 +27,9 @@ jrec := RECORD,MAXLENGTH(100)
     STRING3 rstr;
     UNSIGNED1 c;
     STRING label;
+    BOOLEAN ml := false;
+    BOOLEAN mr := false;
+    INTEGER1 vr := 0;
 END;
 
 lhs := SORTED(DATASET([{3, 'aaa', '', 0, ''}, {4, 'bbb', '', 0, ''}, {5, 'ccc', '', 0, ''}, {6, 'ddd', '', 0, ''}, {7, 'eee', '', 0, ''}], jrec), i);
@@ -48,6 +50,9 @@ jrec xfm(jrec l, jrec r, STRING lab) := TRANSFORM
     SELF.rstr := r.rstr;
     SELF.c := l.c+1;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // skipping transform for joins and non-group denormalizes
@@ -58,6 +63,9 @@ jrec xfmskip(jrec l, jrec r, STRING lab) := TRANSFORM
     SELF.rstr := IF(r.rstr >= 'x', SKIP, r.rstr);
     SELF.c := l.c+1;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // transform for group denormalizes, to be used with match or allmatch
@@ -68,6 +76,9 @@ jrec xfmgrp(jrec l, DATASET(jrec) r, STRING lab) := TRANSFORM
     SELF.rstr := r[c].rstr;
     SELF.c := c;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // skipping transform for group denormalizes, to be used with match or allmatch
@@ -80,6 +91,9 @@ jrec xfmgrpskip(jrec l, DATASET(jrec) r, STRING lab) := TRANSFORM
     SELF.rstr := IF(skp > 0, SKIP, r[c].rstr);
     SELF.c := c;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 deno____INN________ := DENORMALIZE(lhs, rhs, match(LEFT, RIGHT), xfm(LEFT, RIGHT, 'DENORMALIZE'), INNER);

+ 15 - 3
testing/regress/ecl/genjoin_justroxie.ecl

@@ -16,9 +16,6 @@
 ############################################################################## */
 
 // IMPORTANT: this test is generated by the perl script genjointest.pl, so do not edit it by hand
-//nothor
-//nothorlcr
-//nohthor
 
 #option('convertJoinToLookup', 0);
 #option('noAllToLookupConversion', 1);
@@ -30,6 +27,9 @@ jrec := RECORD,MAXLENGTH(100)
     STRING3 rstr;
     UNSIGNED1 c;
     STRING label;
+    BOOLEAN ml := false;
+    BOOLEAN mr := false;
+    INTEGER1 vr := 0;
 END;
 
 lhs := SORTED(DATASET([{3, 'aaa', '', 0, ''}, {4, 'bbb', '', 0, ''}, {5, 'ccc', '', 0, ''}, {6, 'ddd', '', 0, ''}, {7, 'eee', '', 0, ''}], jrec), i);
@@ -50,6 +50,9 @@ jrec xfm(jrec l, jrec r, STRING lab) := TRANSFORM
     SELF.rstr := r.rstr;
     SELF.c := l.c+1;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // skipping transform for joins and non-group denormalizes
@@ -60,6 +63,9 @@ jrec xfmskip(jrec l, jrec r, STRING lab) := TRANSFORM
     SELF.rstr := IF(r.rstr >= 'x', SKIP, r.rstr);
     SELF.c := l.c+1;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // transform for group denormalizes, to be used with match or allmatch
@@ -70,6 +76,9 @@ jrec xfmgrp(jrec l, DATASET(jrec) r, STRING lab) := TRANSFORM
     SELF.rstr := r[c].rstr;
     SELF.c := c;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 // skipping transform for group denormalizes, to be used with match or allmatch
@@ -82,6 +91,9 @@ jrec xfmgrpskip(jrec l, DATASET(jrec) r, STRING lab) := TRANSFORM
     SELF.rstr := IF(skp > 0, SKIP, r[c].rstr);
     SELF.c := c;
     SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
 END;
 
 join____INN_______p := JOIN(lhs, rhs, match(LEFT, RIGHT), xfm(LEFT, RIGHT, 'JOIN_PAR'), INNER, PARALLEL);

+ 388 - 388
testing/regress/ecl/key/genjoin.xml

@@ -1,556 +1,556 @@
 <Dataset name='JOIN'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_KEEP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_KEEP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_KEEP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_KEEP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_KEEP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_KEEP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ATMOST'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ATMOST</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ATMOST</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ATMOST</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ATMOST</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ATMOST_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ATMOST_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ATMOST_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ATMOST_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ATMOST_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LIMITSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LIMITSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LIMITSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LIMITSKIP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LIMITSKIP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LIMITONFAIL'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LIMITONFAIL</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LIMITONFAIL</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LIMITONFAIL</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LIMITONFAIL_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LIMITONFAIL_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LEFT_OUTER</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER_KEEP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER_KEEP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER_ATMOST'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER_ATMOST_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER_LIMITSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER_LIMITSKIP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER_LIMITONFAIL'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LEFT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_ONLY'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_ONLY_XFMSKIP'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_XFMSKIP</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_ONLY_ATMOST'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LEFT_ONLY_ATMOST_XFMSKIP'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST_XFMSKIP</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LEFT_ONLY_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_RIGHT_OUTER'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>xxx</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>xxx</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_RIGHT_OUTER_XFMSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_RIGHT_OUTER_LIMITSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITSKIP_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_RIGHT_OUTER_LIMITONFAIL'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_RIGHT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_RIGHT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_RIGHT_ONLY'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_ONLY</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>xxx</rstr><c>1</c><label>JOIN_RIGHT_ONLY</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_ONLY</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_ONLY</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_ONLY</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>xxx</rstr><c>1</c><label>JOIN_RIGHT_ONLY</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_ONLY</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_ONLY</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_RIGHT_ONLY_XFMSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_ONLY_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_ONLY_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_ONLY_XFMSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_RIGHT_ONLY_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_RIGHT_ONLY_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_RIGHT_ONLY_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_FULL_OUTER'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>xxx</rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>xxx</rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_FULL_OUTER_XFMSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_FULL_OUTER_LIMITSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITSKIP_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_FULL_OUTER_LIMITONFAIL'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_FULL_OUTER_LIMITONFAIL</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_FULL_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_OUTER_LIMITONFAIL_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_FULL_ONLY'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_ONLY</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_ONLY</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>xxx</rstr><c>1</c><label>JOIN_FULL_ONLY</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_ONLY</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_ONLY</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_ONLY</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_ONLY</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>xxx</rstr><c>1</c><label>JOIN_FULL_ONLY</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_ONLY</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_ONLY</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_FULL_ONLY_XFMSKIP'>
- <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label></Row>
- <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>fff</rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>lll</rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>0</i><lstr>   </lstr><rstr>mmm</rstr><c>1</c><label>JOIN_FULL_ONLY_XFMSKIP</label><ml>false</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_LEFT_OUTER'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_LEFT_OUTER_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_LEFT_ONLY'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_ONLY</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_ONLY</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_LEFT_ONLY_XFMSKIP'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_ONLY_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_ONLY_XFMSKIP</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_LEFT_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_KEEP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_KEEP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_ATMOST'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_ATMOST</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_ATMOST</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_ATMOST</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_ATMOST</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_ATMOST_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_ATMOST_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_ATMOST_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_ATMOST_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_ATMOST_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LIMITSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LIMITSKIP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITSKIP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LIMITONFAIL'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITONFAIL</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LOOKUP_MANY_LIMITONFAIL</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITONFAIL</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LOOKUP_MANY_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LIMITONFAIL_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LOOKUP_MANY_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITONFAIL_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LOOKUP_MANY_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_ATMOST_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITSKIP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>FAILED: JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_OUTER_LIMITONFAIL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_ONLY'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_ONLY_XFMSKIP'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_XFMSKIP</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST_XFMSKIP'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST_XFMSKIP</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_LOOKUP_MANY_LEFT_ONLY_ATMOST_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_ALL</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_ALL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL_KEEP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_KEEP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_KEEP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL_KEEP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_KEEP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_KEEP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL_LEFT_OUTER'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL_LEFT_OUTER_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL_LEFT_OUTER_KEEP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>hhh</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>JOIN_ALL_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL_LEFT_ONLY'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_ONLY</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_ONLY</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_ONLY</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='JOIN_ALL_LEFT_ONLY_XFMSKIP'>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_ONLY_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_ONLY_XFMSKIP</label></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>1</c><label>JOIN_ALL_LEFT_ONLY_XFMSKIP</label><ml>true</ml><mr>false</mr><vr>1</vr></Row>
 </Dataset>
 <Dataset name='DENORMALIZE_LEFT_OUTER'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>0</c><label></label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>3</c><label>DENORMALIZE_LEFT_OUTER</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>0</c><label></label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>0</c><label></label><ml>false</ml><mr>false</mr><vr>0</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>3</c><label>DENORMALIZE_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>0</c><label></label><ml>false</ml><mr>false</mr><vr>0</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='DENORMALIZE_LEFT_OUTER_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>0</c><label></label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>3</c><label>DENORMALIZE_LEFT_OUTER_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>0</c><label></label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>0</c><label></label><ml>false</ml><mr>false</mr><vr>0</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>jjj</rstr><c>3</c><label>DENORMALIZE_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>0</c><label></label><ml>false</ml><mr>false</mr><vr>0</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='DENORMALIZE_LEFT_OUTER_KEEP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_KEEP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>0</c><label></label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>2</c><label>DENORMALIZE_LEFT_OUTER_KEEP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>0</c><label></label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_KEEP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>0</c><label></label><ml>false</ml><mr>false</mr><vr>0</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>2</c><label>DENORMALIZE_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>0</c><label></label><ml>false</ml><mr>false</mr><vr>0</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_KEEP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>
 <Dataset name='DENORMALIZE_LEFT_OUTER_KEEP_XFMSKIP'>
- <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>0</c><label></label></Row>
- <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>2</c><label>DENORMALIZE_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
- <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>0</c><label></label></Row>
- <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_KEEP_XFMSKIP</label></Row>
+ <Row><i>3</i><lstr>aaa</lstr><rstr>ggg</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>4</i><lstr>bbb</lstr><rstr>   </rstr><c>0</c><label></label><ml>false</ml><mr>false</mr><vr>0</vr></Row>
+ <Row><i>5</i><lstr>ccc</lstr><rstr>iii</rstr><c>2</c><label>DENORMALIZE_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
+ <Row><i>6</i><lstr>ddd</lstr><rstr>   </rstr><c>0</c><label></label><ml>false</ml><mr>false</mr><vr>0</vr></Row>
+ <Row><i>7</i><lstr>eee</lstr><rstr>kkk</rstr><c>1</c><label>DENORMALIZE_LEFT_OUTER_KEEP_XFMSKIP</label><ml>true</ml><mr>true</mr><vr>-1</vr></Row>
 </Dataset>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 588 - 588
testing/regress/ecl/key/genjoin_nothor.xml


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 976 - 976
testing/regress/ecl/key/genjoin_justroxie.xml


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 13 - 0
testing/regress/ecl/key/nestedjoin.xml


+ 92 - 0
testing/regress/ecl/nestedjoin.ecl

@@ -0,0 +1,92 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2017 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.
+############################################################################## */
+
+// IMPORTANT: this test is generated by the perl script genjointest.pl, so do not edit it by hand
+
+#option('convertJoinToLookup', 0);
+#option('noAllToLookupConversion', 1);
+#option('spanMultipleCpp', 1);
+
+childrec := RECORD,MAXLENGTH(100)
+    UNSIGNED1 i;
+    STRING3 lstr;
+    STRING3 rstr;
+    UNSIGNED1 c;
+    STRING label;
+    BOOLEAN mpl := false;
+    BOOLEAN ml := false;
+    BOOLEAN mr := false;
+    INTEGER1 vr := 0;
+END;
+
+childlhs := SORTED(DATASET([{3, 'aaa', '', 0, ''}, {4, 'bbb', '', 0, ''}, {5, 'ccc', '', 0, ''}, {6, 'ddd', '', 0, ''}, {7, 'eee', '', 0, ''}], childrec), i);
+childrhs := SORTED(DATASET([{1, '', 'fff', 0, ''}, {3, '', 'ggg', 0, ''}, {5, '', 'hhh', 0, ''}, {5, '', 'iii', 0, ''}, {5, '', 'xxx', 0, ''}, {5, '', 'jjj', 0, ''}, {7, '', 'kkk', 0, ''}, {9, '', 'lll', 0, ''}, {9, '', 'mmm', 0, ''}], childrec), i);
+
+jrec := RECORD,MAXLENGTH(100)
+    UNSIGNED1 i;
+    STRING3 lstr;
+    STRING3 rstr;
+    UNSIGNED1 c;
+    STRING label;
+    dataset(childrec) children;
+    BOOLEAN ml := false;
+    BOOLEAN mr := false;
+    INTEGER1 vr := 0;
+END;
+
+lhs := SORTED(DATASET([{3, 'aaa', '', 0, '', childlhs}, {4, 'bbb', '', 0, '', childlhs}, {5, 'ccc', '', 0, '', childlhs}, {6, 'ddd', '', 0, '', childlhs}, {7, 'eee', '', 0, '', childlhs}], jrec), i);
+rhs := SORTED(DATASET([{1, '', 'fff', 0, '', childrhs}, {3, '', 'ggg', 0, '', childrhs}, {5, '', 'hhh', 0, '', childrhs}, {5, '', 'iii', 0, '', childrhs}, {5, '', 'xxx', 0, '', childrhs}, {5, '', 'jjj', 0, '', childrhs}, {7, '', 'kkk', 0, '', childrhs}, {9, '', 'lll', 0, '', childrhs}, {9, '', 'mmm', 0, '', childrhs}], jrec), i);
+
+trueval := true : stored('trueval');
+falseval := false : stored('falseval');
+
+BOOLEAN childmatch1(childrec l, childrec r) := (l.i = r.i);
+BOOLEAN childmatch2(childrec l, childrec r) := (r.rstr < 'x');
+BOOLEAN childmatch(childrec l, childrec r) := (childmatch1(l, r) AND childmatch2(l, r));
+
+BOOLEAN match1(jrec l, jrec r) := (l.i = r.i);
+BOOLEAN match2(jrec l, jrec r) := (r.rstr < 'x');
+BOOLEAN match(jrec l, jrec r) := (match1(l, r) AND match2(l, r));
+
+// transform for joins and non-group denormalizes, to be used with match
+childrec xfmchild(jrec lparent, childrec l, jrec rparent, childrec r, STRING lab) := TRANSFORM
+    SELF.i := l.i;
+    SELF.lstr := l.lstr;
+    SELF.rstr := r.rstr;
+    SELF.c := l.c+1;
+    SELF.label := lab;
+    SELF.mpl := MATCHED(lparent);
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
+END;
+
+jrec xfm(jrec l, jrec r, STRING lab) := TRANSFORM
+    SELF.i := l.i;
+    SELF.lstr := l.lstr;
+    SELF.rstr := r.rstr;
+    SELF.c := l.c+1;
+    SELF.label := lab;
+    SELF.ml := MATCHED(l);
+    SELF.mr := MATCHED(r);
+    SELF.vr := IF (MATCHED(r), -1, 1);
+    SELF.children := JOIN(l.children, r.children, childmatch(LEFT, RIGHT), xfmchild(l, LEFT, r, RIGHT, 'JOINCHILDREN'), FULL OUTER);
+END;
+
+join____FOU________ := JOIN(lhs, rhs, match(LEFT, RIGHT), xfm(LEFT, RIGHT, 'JOIN_FULL_OUTER'), FULL OUTER);
+output(join____FOU________);
+

+ 9 - 9
thorlcr/activities/lookupjoin/thlookupjoinslave.cpp

@@ -758,13 +758,13 @@ public:
     {
         return helper->match(lhs, rhsrow);
     }
-    inline const size32_t joinTransform(ARowBuilder &rowBuilder, const void *left, const void *right, unsigned numRows, const void **rows)
+    inline const size32_t joinTransform(ARowBuilder &rowBuilder, const void *left, const void *right, unsigned numRows, const void **rows, unsigned flags)
     {
-        return helper->transform(rowBuilder, left, right, numRows, rows);
+        return helper->transform(rowBuilder, left, right, numRows, rows, flags);
     }
-    inline const size32_t joinTransform(ARowBuilder &rowBuilder, const void *left, const void *right, unsigned count)
+    inline const size32_t joinTransform(ARowBuilder &rowBuilder, const void *left, const void *right, unsigned count, unsigned flags)
     {
-        return helper->transform(rowBuilder, left, right, count);
+        return helper->transform(rowBuilder, left, right, count, flags);
     }
 };
 
@@ -1188,7 +1188,7 @@ protected:
             const void *rightRow = numRows ? filteredRhs.item(0) : defaultRight.get();
             if (isGroupOp())
             {
-                size32_t sz = HELPERBASE::joinTransform(rowBuilder, leftRow, rightRow, numRows, filteredRhs.getArray());
+                size32_t sz = HELPERBASE::joinTransform(rowBuilder, leftRow, rightRow, numRows, filteredRhs.getArray(), JTFmatchedleft|(numRows ? JTFmatchedright : 0));
                 if (sz)
                     ret.setown(rowBuilder.finalizeRowClear(sz));
             }
@@ -1201,7 +1201,7 @@ protected:
                     for (;;)
                     {
                         const void *rightRow = filteredRhs.item(rcCount);
-                        size32_t sz = HELPERBASE::joinTransform(rowBuilder, ret, rightRow, ++rcCount);
+                        size32_t sz = HELPERBASE::joinTransform(rowBuilder, ret, rightRow, ++rcCount, JTFmatchedleft|JTFmatchedright);
                         if (sz)
                         {
                             rowSize = sz;
@@ -1270,7 +1270,7 @@ protected:
                             leftMatch = true;
                             if (!exclude)
                             {
-                                size32_t sz = HELPERBASE::joinTransform(rowBuilder, leftRow, rhsNext, ++joinCounter);
+                                size32_t sz = HELPERBASE::joinTransform(rowBuilder, leftRow, rhsNext, ++joinCounter, JTFmatchedleft|JTFmatchedright);
                                 if (sz)
                                 {
                                     OwnedConstThorRow row = rowBuilder.finalizeRowClear(sz);
@@ -1289,7 +1289,7 @@ protected:
                     }
                     if (!leftMatch && NULL == rhsNext && 0!=(flags & JFleftouter))
                     {
-                        size32_t sz = HELPERBASE::joinTransform(rowBuilder, leftRow, defaultRight, 0);
+                        size32_t sz = HELPERBASE::joinTransform(rowBuilder, leftRow, defaultRight, 0, JTFmatchedleft);
                         if (sz)
                             ret.setown(rowBuilder.finalizeRowClear(sz));
                     }
@@ -2645,7 +2645,7 @@ public:
                         e.setown(_e);
                     }
                     RtlDynamicRowBuilder ret(allocator);
-                    size32_t transformedSize = helper->onFailTransform(ret, leftRow, defaultRight, e.get());
+                    size32_t transformedSize = helper->onFailTransform(ret, leftRow, defaultRight, e.get(), JTFmatchedleft);
                     if (transformedSize)
                         failRow = ret.finalizeRowClear(transformedSize);
                 }

+ 23 - 23
thorlcr/activities/msort/thsortu.cpp

@@ -558,7 +558,7 @@ public:
                         {
                             const void *lhs = defaultLeft;
                             do {
-                                gotsz = helper->transform(denormTmp, lhs, nextright, ++denormCount);
+                                gotsz = helper->transform(denormTmp, lhs, nextright, ++denormCount, JTFmatchedright); //manufactured left
                                 if (gotsz) {
                                     swapRows(denormTmp, ret);
                                     lhs = (const void *)ret.getSelf();
@@ -579,7 +579,7 @@ public:
                                 nextR();
                             }
                             while (getR()&&(0 == compareR->docompare(prevright,nextright)));
-                            gotsz = helper->transform(ret, defaultLeft, denormRows.query(0), denormRows.ordinality(), denormRows.getRowArray());
+                            gotsz = helper->transform(ret, defaultLeft, denormRows.query(0), denormRows.ordinality(), denormRows.getRowArray(), JTFmatchedright);
                             denormRows.kill();
                             break;
                         case TAKjoin:
@@ -588,7 +588,7 @@ public:
                         case TAKselfjoinlight:
                         case TAKlookupjoin:
                         case TAKsmartjoin:
-                            gotsz = helper->transform(ret, defaultLeft, nextright, 0);
+                            gotsz = helper->transform(ret, defaultLeft, nextright, 0, JTFmatchedright);
                             nextR();
                             break;
                         default:
@@ -608,7 +608,7 @@ public:
                         const void *lhs = defaultLeft;
                         do {
                             if (!rightgroupmatched[rightidx]) {
-                                gotsz = helper->transform(denormTmp, lhs, rightgroup.query(rightidx), ++denormCount);
+                                gotsz = helper->transform(denormTmp, lhs, rightgroup.query(rightidx), ++denormCount, JTFmatchedright); //manufactured left
                                 if (gotsz) {
                                     swapRows(denormTmp, ret);
                                     lhs = (const void *)ret.getSelf();
@@ -633,7 +633,7 @@ public:
                         while (rightidx<rightgroup.ordinality());
                         if (denormRows.ordinality())
                         {
-                            gotsz = helper->transform(ret, defaultLeft, denormRows.query(0), denormRows.ordinality(), denormRows.getRowArray());
+                            gotsz = helper->transform(ret, defaultLeft, denormRows.query(0), denormRows.ordinality(), denormRows.getRowArray(), JTFmatchedright);
                             denormRows.kill();
                         }
                         denormCount = 0;
@@ -645,7 +645,7 @@ public:
                     case TAKlookupjoin:
                     case TAKsmartjoin:
                         if (!rightgroupmatched[rightidx]) 
-                            gotsz = helper->transform(ret, defaultLeft, rightgroup.query(rightidx), 0);
+                            gotsz = helper->transform(ret, defaultLeft, rightgroup.query(rightidx), 0, JTFmatchedright);
                         rightidx++;
                         break;
                     default:
@@ -667,7 +667,7 @@ public:
                     case TAKhashdenormalizegroup:
                     case TAKlookupdenormalizegroup:
                     case TAKsmartdenormalizegroup:
-                        gotsz = helper->transform(ret, nextleft, defaultRight, 0, (const void **)NULL);
+                        gotsz = helper->transform(ret, nextleft, defaultRight, 0, (const void **)NULL, JTFmatchedleft);
                         break;
                     case TAKjoin:
                     case TAKhashjoin:
@@ -675,7 +675,7 @@ public:
                     case TAKselfjoinlight:
                     case TAKlookupjoin:
                     case TAKsmartjoin:
-                        gotsz = helper->transform(ret, nextleft, defaultRight, 0);
+                        gotsz = helper->transform(ret, nextleft, defaultRight, 0, JTFmatchedleft);
                         break;
                     default:
                         throwUnexpected();
@@ -700,7 +700,7 @@ public:
                     case TAKsmartdenormalizegroup:
                         if (denormRows.ordinality())
                         {
-                            gotsz = helper->transform(ret, nextleft, denormRows.query(0), denormRows.ordinality(), denormRows.getRowArray());
+                            gotsz = helper->transform(ret, nextleft, denormRows.query(0), denormRows.ordinality(), denormRows.getRowArray(), JTFmatchedleft|JTFmatchedright);
                             denormRows.kill();
                         }
                         break;
@@ -714,7 +714,7 @@ public:
             if (r==Onext) {
                 // JCSMORE - I can't see when this can happen? if r==Onext, l is always Oouter.
                 if (!exclude) 
-                    gotsz = helper->transform(ret,nextleft,nextright,++joinCounter);
+                    gotsz = helper->transform(ret,nextleft,nextright,++joinCounter, JTFmatchedleft|JTFmatchedright);
                 rightmatched = true;
             }
             else {
@@ -726,7 +726,7 @@ public:
                         case TAKlookupdenormalize:
                         case TAKsmartdenormalize:
                         {
-                            size32_t sz = helper->transform(ret, denormLhs, rightgroup.query(rightidx), ++denormCount);
+                            size32_t sz = helper->transform(ret, denormLhs, rightgroup.query(rightidx), ++denormCount, JTFmatchedleft|JTFmatchedright);
                             if (sz)
                             {
                                 denormLhs.setown(ret.finalizeRowClear(sz));
@@ -752,7 +752,7 @@ public:
                         case TAKselfjoinlight:
                         case TAKlookupjoin:
                         case TAKsmartjoin:
-                            gotsz = helper->transform(ret,nextleft,rightgroup.query(rightidx), ++joinCounter);
+                            gotsz = helper->transform(ret,nextleft,rightgroup.query(rightidx), ++joinCounter, JTFmatchedleft|JTFmatchedright);
                             break;
                         default:
                             throwUnexpected();
@@ -805,7 +805,7 @@ public:
                 case JSonfail:
                     do
                     {
-                        size32_t transformedSize = helper->onFailTransform(failret.ensureRow(), nextleft, defaultRight, onFailException.get());
+                        size32_t transformedSize = helper->onFailTransform(failret.ensureRow(), nextleft, defaultRight, onFailException.get(), JTFmatchedleft);
                         nextL();
                         if (!getL()||0!=compareL->docompare(nextleft,prevleft))
                             state = JScompare;
@@ -1113,7 +1113,7 @@ retry:
                 switch (state) {
                 case JSonfail:
                     if (leftidx<curgroup.ordinality()) {
-                        size32_t transformedSize = helper->onFailTransform(failret.ensureRow(), curgroup.query(leftidx), defaultRight, onFailException.get());
+                        size32_t transformedSize = helper->onFailTransform(failret.ensureRow(), curgroup.query(leftidx), defaultRight, onFailException.get(), JTFmatchedleft);
                         leftidx++;
                         if (transformedSize) {
                             if (mcoreintercept) {
@@ -1125,7 +1125,7 @@ retry:
                         break;
                     }
                     else if (getRow() && (compare->docompare(nextrow,curgroup.query(0))==0)) {
-                        size32_t transformedSize = helper->onFailTransform(failret, nextrow, defaultRight, onFailException.get());
+                        size32_t transformedSize = helper->onFailTransform(failret, nextrow, defaultRight, onFailException.get(), JTFmatchedleft);
                         next();
                         if (transformedSize) {
                             if (mcoreintercept) {
@@ -1223,7 +1223,7 @@ retry:
                                 if (keepremaining>0) {
                                     if (!exclude) {
                                         RtlDynamicRowBuilder rtmp(allocator);
-                                        size32_t sz = helper->transform(rtmp,l,r,++joinCounter);
+                                        size32_t sz = helper->transform(rtmp,l,r,++joinCounter, JTFmatchedleft|JTFmatchedright);
                                         if (sz)
                                             ret.setown(rtmp.finalizeRowClear(sz));
                                     }
@@ -1242,7 +1242,7 @@ retry:
                         else { // right all done
                             if (leftouter&&!leftmatched) {
                                 RtlDynamicRowBuilder rtmp(allocator);
-                                size32_t sz = helper->transform(rtmp, l, defaultRight, 0);
+                                size32_t sz = helper->transform(rtmp, l, defaultRight, 0, JTFmatchedleft);
                                 if (sz)
                                     ret.setown(rtmp.finalizeRowClear(sz));
                             }
@@ -1261,14 +1261,14 @@ retry:
                     // must be left outer after atmost to get here
                     if (leftidx<curgroup.ordinality()) {
                         RtlDynamicRowBuilder rtmp(allocator);
-                        size32_t sz = helper->transform(rtmp, curgroup.query(leftidx), defaultRight, 0);
+                        size32_t sz = helper->transform(rtmp, curgroup.query(leftidx), defaultRight, 0, JTFmatchedleft);
                         if (sz)
                             ret.setown(rtmp.finalizeRowClear(sz));
                         leftidx++;
                     }
                     else if (getRow() && (compare->docompare(nextrow,curgroup.query(0))==0)) {
                         RtlDynamicRowBuilder rtmp(allocator);
-                        size32_t sz = helper->transform(rtmp, nextrow, defaultRight, 0);
+                        size32_t sz = helper->transform(rtmp, nextrow, defaultRight, 0, JTFmatchedleft);
                         if (sz)
                             ret.setown(rtmp.finalizeRowClear(sz));
                         next();
@@ -1281,7 +1281,7 @@ retry:
                     if (rightouter&&(rightidx<curgroup.ordinality())) {
                         if (!rightmatched[rightidx]) {
                             RtlDynamicRowBuilder rtmp(allocator);
-                            size32_t sz = helper->transform(rtmp, defaultLeft,curgroup.query(rightidx), 0);
+                            size32_t sz = helper->transform(rtmp, defaultLeft,curgroup.query(rightidx), 0, JTFmatchedright);
                             if (sz)
                                 ret.setown(rtmp.finalizeRowClear(sz));
                         }
@@ -1542,7 +1542,7 @@ public:
                     if (rightouter)
                         rmatched[rightidx] = true;
                     RtlDynamicRowBuilder ret(theAllocator);
-                    size32_t sz = exclude?0:helper->transform(ret,work.lgroup.query(leftidx),rgroup.query(rightidx),++joinCounter);
+                    size32_t sz = exclude?0:helper->transform(ret,work.lgroup.query(leftidx),rgroup.query(rightidx),++joinCounter,JTFmatchedleft|JTFmatchedright);
                     if (sz)
                         writer.putRow(ret.finalizeRowClear(sz));
 
@@ -1550,7 +1550,7 @@ public:
             }
             if (!lmatched) {
                 RtlDynamicRowBuilder ret(theAllocator);
-                size32_t sz =  helper->transform(ret, work.lgroup.query(leftidx), defaultRight, 0);
+                size32_t sz =  helper->transform(ret, work.lgroup.query(leftidx), defaultRight, 0, JTFmatchedleft);
                 if (sz)
                     writer.putRow(ret.finalizeRowClear(sz));
             }
@@ -1559,7 +1559,7 @@ public:
             ForEachItemIn(rightidx2,rgroup) {
                 if (!rmatched[rightidx2]) {
                     RtlDynamicRowBuilder ret(theAllocator);
-                    size32_t sz =  helper->transform(ret, defaultLeft, rgroup.query(rightidx2), 0);
+                    size32_t sz =  helper->transform(ret, defaultLeft, rgroup.query(rightidx2), 0, JTFmatchedright);
                     if (sz)
                         writer.putRow(ret.finalizeRowClear(sz));
                 }