瀏覽代碼

Merge pull request #4072 from ghalliday/issue8352

HPCC-8352 Allow divide by zero action to be configured

Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 12 年之前
父節點
當前提交
16c6ad9c0c
共有 54 個文件被更改,包括 1300 次插入392 次删除
  1. 1 1
      common/deftype/deftype.cpp
  2. 51 80
      common/deftype/defvalue.cpp
  3. 2 2
      common/deftype/defvalue.hpp
  4. 1 1
      common/fileview2/fvresultset.cpp
  5. 1 1
      common/thorhelper/thorxmlwrite.cpp
  6. 1 0
      common/workunit/workunit.cpp
  7. 2 0
      ecl/hql/hqlatoms.cpp
  8. 1 0
      ecl/hql/hqlatoms.hpp
  9. 16 2
      ecl/hql/hqlfold.cpp
  10. 11 4
      ecl/hql/hqlutil.cpp
  11. 6 0
      ecl/hqlcpp/hqlcatom.cpp
  12. 3 0
      ecl/hqlcpp/hqlcatom.hpp
  13. 2 0
      ecl/hqlcpp/hqlcerrors.hpp
  14. 85 25
      ecl/hqlcpp/hqlcpp.cpp
  15. 3 0
      ecl/hqlcpp/hqlcpp.ipp
  16. 51 48
      ecl/hqlcpp/hqlcppsys.ecl
  17. 5 5
      ecl/hqlcpp/hqlwcpp.cpp
  18. 43 0
      ecl/regress/issue8352a.ecl
  19. 43 0
      ecl/regress/issue8352b.ecl
  20. 30 0
      ecl/regress/issue8352c1.ecl
  21. 30 0
      ecl/regress/issue8352c2.ecl
  22. 30 0
      ecl/regress/issue8352c3.ecl
  23. 29 0
      ecl/regress/issue8352c4.ecl
  24. 78 0
      ecl/regress/issue8352d.ecl
  25. 25 0
      ecl/regress/issue8352e1.ecl
  26. 25 0
      ecl/regress/issue8352e2.ecl
  27. 25 0
      ecl/regress/issue8352e3.ecl
  28. 25 0
      ecl/regress/issue8352e4.ecl
  29. 22 0
      ecl/regress/issue8352f.ecl
  30. 19 1
      rtl/eclrtl/CMakeLists.txt
  31. 1 8
      rtl/eclrtl/eclinclude.hpp
  32. 20 9
      rtl/eclrtl/eclrtl.cpp
  33. 4 0
      rtl/eclrtl/eclrtl.hpp
  34. 99 60
      rtl/nbcd/nbcds.cpp
  35. 101 0
      rtl/eclrtl/rtlbcd.hpp
  36. 4 4
      rtl/nbcd/nbcdtest.cpp
  37. 1 1
      rtl/eclrtl/rtlint.cpp
  38. 1 18
      rtl/eclrtl/rtlqstr.cpp
  39. 1 9
      rtl/eclrtl/rtlxml.cpp
  40. 3 2
      rtl/nbcd/CMakeLists.txt
  41. 0 105
      rtl/nbcd/bcd.hpp
  42. 11 1
      rtl/nbcd/nbcd.cpp
  43. 12 5
      rtl/nbcd/nbcd.hpp
  44. 4 0
      system/jlib/jstring.cpp
  45. 47 0
      testing/ecl/dbz1.ecl
  46. 33 0
      testing/ecl/dbz2a.ecl
  47. 33 0
      testing/ecl/dbz2b.ecl
  48. 33 0
      testing/ecl/dbz2c.ecl
  49. 79 0
      testing/ecl/dbz3.ecl
  50. 36 0
      testing/ecl/key/dbz1.xml
  51. 1 0
      testing/ecl/key/dbz2a.xml
  52. 1 0
      testing/ecl/key/dbz2b.xml
  53. 1 0
      testing/ecl/key/dbz2c.xml
  54. 108 0
      testing/ecl/key/dbz3.xml

+ 1 - 1
common/deftype/deftype.cpp

@@ -33,7 +33,7 @@
 #include <math.h>
 #include <algorithm>
 
-#include "bcd.hpp"
+#include "rtlbcd.hpp"
 #include "eclrtl.hpp"
 #include "eclrtl_imp.hpp"
 

+ 51 - 80
common/deftype/defvalue.cpp

@@ -26,7 +26,7 @@
 #include <math.h>
 #include <limits.h>
 
-#include "bcd.hpp"
+#include "rtlbcd.hpp"
 #include "eclrtl_imp.hpp"
 
 #if defined(_DEBUG) && defined(_WIN32) && !defined(USING_MPATROL)
@@ -2462,11 +2462,6 @@ IValue * addValues(IValue * left, IValue * right)
                                     return res;                         
 
 
-IValue * addValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(addValues);
-}
-
 IValue * subtractValues(IValue * left, IValue * right)
 {
     IValue * ret;
@@ -2498,11 +2493,6 @@ IValue * subtractValues(IValue * left, IValue * right)
     return ret;
 }
 
-IValue * substractValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(subtractValues);
-}
-
 IValue * multiplyValues(IValue * left, IValue * right)
 {
     IValue * ret;
@@ -2534,14 +2524,20 @@ IValue * multiplyValues(IValue * left, IValue * right)
     return ret;
 }
 
-IValue * multiplyValues(unsigned num, IValue * * values)
+IValue * divideValues(IValue * left, IValue * right, byte dbz)
 {
-    CALCULATE_AND_RETURN(multiplyValues);
-}
+    Owned<ITypeInfo> pnt = getPromotedMulDivType(left->queryType(), right->queryType());
 
-IValue * divideValues(IValue * left, IValue * right)
-{
-    ITypeInfo * pnt = getPromotedMulDivType(left->queryType(), right->queryType());
+    //Use a cast to a boolean as a shortcut for testing against zero
+    if (!right->getBoolValue())
+    {
+        //If no action is selected, return NULL so the expression doesn't get constant folded.
+        if (dbz == DBZnone)
+            return NULL;
+
+        if (dbz == DBZfail)
+            rtlFailDivideByZero();
+    }
 
     switch(pnt->getTypeCode())
     {
@@ -2559,24 +2555,29 @@ IValue * divideValues(IValue * left, IValue * right)
             else
                 res = (__int64)((unsigned __int64)lv / (unsigned __int64)rv);
         }
-        return createTruncIntValue(res, pnt);
+        return createTruncIntValue(res, pnt.getClear());
     }
     case type_real:
     {
         double lv = left->getRealValue();
         double rv = right->getRealValue();
-        double res = rv ? lv / rv : 0;
-        return createRealValue(res, pnt);
+        double res;
+        if (rv)
+            res = lv / rv;
+        else if (dbz == DBZnan)
+            res =  rtlCreateRealNull();
+        else
+            res = 0.0;
+
+        return createRealValue(res, pnt.getClear());
     }
     case type_decimal:
     {
         BcdCriticalBlock bcdBlock;
         left->pushDecimalValue();
         right->pushDecimalValue();
-        DecDivide();   // returns 0 if divide by zero
-        IValue * ret = ((CDecimalTypeInfo*)pnt)->createValueFromStack();
-        pnt->Release();
-        return ret;
+        DecDivide(dbz);
+        return createDecimalValueFromStack(pnt);
     }
     default:
         assertThrow(false);
@@ -2584,16 +2585,21 @@ IValue * divideValues(IValue * left, IValue * right)
     }
 }
 
-IValue * divideValues(unsigned num, IValue * * values)
+IValue * modulusValues(IValue * left, IValue * right, byte dbz)
 {
-    CALCULATE_AND_RETURN(divideValues);
-}
-
-IValue * modulusValues(IValue * left, IValue * right)
-{
-    IValue * ret;
-    ITypeInfo * pnt = getPromotedMulDivType(left->queryType(), right->queryType());
+    Owned<ITypeInfo> pnt = getPromotedMulDivType(left->queryType(), right->queryType());
     
+    //Use a cast to a boolean as a shortcut for testing against zero
+    if (!right->getBoolValue())
+    {
+        //If no action is selected, return NULL so the expression doesn't get constant folded.
+        if (dbz == DBZnone)
+            return NULL;
+
+        if (dbz == DBZfail)
+            rtlFailDivideByZero();
+    }
+
     switch(pnt->getTypeCode())
     {
     case type_int:
@@ -2610,33 +2616,33 @@ IValue * modulusValues(IValue * left, IValue * right)
             else
                 res = (__int64)((unsigned __int64)lv % (unsigned __int64)rv);
         }
-        return createTruncIntValue(res, pnt);
+        return createTruncIntValue(res, pnt.getClear());
     }
     case type_real:
     {
         double rv = right->getRealValue();
-        double res = rv ? fmod(left->getRealValue(), rv) : 0;
-        return createRealValue(res, pnt);
+        double res;
+        if (rv)
+            res = fmod(left->getRealValue(), rv);
+        else if (dbz == DBZnan)
+            res =  rtlCreateRealNull();
+        else
+            res = 0.0;
+
+        return createRealValue(res, pnt.getClear());
     }
     case type_decimal:
     {
         BcdCriticalBlock bcdBlock;
         left->pushDecimalValue();
         right->pushDecimalValue();
-        DecModulus();
-        ret = ((CDecimalTypeInfo*)pnt)->createValueFromStack();
-        pnt->Release();
-        break;
+        DecModulus(dbz);
+        return createDecimalValueFromStack(pnt);
     }
     default:
         assertThrow(false);
+        return NULL;
     }
-    return ret;
-}
-
-IValue * modulusValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(modulusValues);
 }
 
 IValue * powerValues(IValue * left, IValue * right)
@@ -2669,11 +2675,6 @@ IValue * powerValues(IValue * left, IValue * right)
     return ret;
 }
 
-IValue * powerValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(powerValues);
-}
-
 IValue * negateValue(IValue * v)
 {
     switch(v->getTypeCode())
@@ -3105,11 +3106,6 @@ IValue * concatValues(IValue * left, IValue * right)
     }
 }
 
-IValue * concatValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(concatValues);
-}
-
 IValue * binaryAndValues(IValue * left, IValue * right)
 {
     IValue * ret;
@@ -3130,11 +3126,6 @@ IValue * binaryAndValues(IValue * left, IValue * right)
     return ret;
 }
 
-IValue * binaryAndValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(binaryAndValues);
-}
-
 IValue * binaryOrValues(IValue * left, IValue * right)
 {
     IValue * ret;
@@ -3155,11 +3146,6 @@ IValue * binaryOrValues(IValue * left, IValue * right)
     return ret;
 }
 
-IValue * binaryOrValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(binaryOrValues);
-}
-
 IValue * binaryXorValues(IValue * left, IValue * right)
 {
     IValue * ret;
@@ -3178,11 +3164,6 @@ IValue * binaryXorValues(IValue * left, IValue * right)
     return ret;
 }
 
-IValue * binaryXorValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(concatValues);
-}
-
 IValue * binaryNotValues(IValue * v)
 {
     switch(v->getTypeCode())
@@ -3206,21 +3187,11 @@ IValue * logicalAndValues(IValue * left, IValue * right)
     return createBoolValue(left->getBoolValue() && right->getBoolValue());
 }
 
-IValue * logicalAndValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(logicalAndValues);
-}
-
 IValue * logicalOrValues(IValue * left, IValue * right)
 {
     return createBoolValue(left->getBoolValue() || right->getBoolValue());
 }
 
-IValue * logicalOrValues(unsigned num, IValue * * values)
-{
-    CALCULATE_AND_RETURN(logicalOrValues);
-}
-
 int orderValues(IValue * left, IValue * right)
 {
     //The following line can be uncommented to check that the types are consistent everywhere

+ 2 - 2
common/deftype/defvalue.hpp

@@ -110,8 +110,8 @@ extern DEFTYPE_API IValue * createMinUIntValue(unsigned __int64 value);
 extern DEFTYPE_API IValue * addValues(IValue * left, IValue * right);
 extern DEFTYPE_API IValue * subtractValues(IValue * left, IValue * right);
 extern DEFTYPE_API IValue * multiplyValues(IValue * left, IValue * right);
-extern DEFTYPE_API IValue * divideValues(IValue * left, IValue * right);
-extern DEFTYPE_API IValue * modulusValues(IValue * left, IValue * right);
+extern DEFTYPE_API IValue * divideValues(IValue * left, IValue * right, byte dbz);
+extern DEFTYPE_API IValue * modulusValues(IValue * left, IValue * right, byte dbz);
 extern DEFTYPE_API IValue * powerValues(IValue * left, IValue * right);
 extern DEFTYPE_API IValue * shiftLeftValues(IValue * left, IValue * right);
 extern DEFTYPE_API IValue * shiftRightValues(IValue * left, IValue * right);

+ 1 - 1
common/fileview2/fvresultset.cpp

@@ -17,7 +17,7 @@
 
 #include "platform.h"
 #include "jliball.hpp"
-#include "bcd.hpp"
+#include "rtlbcd.hpp"
 #include "workunit.hpp"
 #include "seclib.hpp"
 #include "eclrtl.hpp"

+ 1 - 1
common/thorhelper/thorxmlwrite.cpp

@@ -22,7 +22,7 @@
 #include "rtlkey.hpp"
 #include "eclhelper.hpp"
 #include "deftype.hpp"
-#include "bcd.hpp"
+#include "rtlbcd.hpp"
 
 CommonXmlWriter::CommonXmlWriter(unsigned _flags, unsigned initialIndent, IXmlStreamFlusher *_flusher) 
 {

+ 1 - 0
common/workunit/workunit.cpp

@@ -39,6 +39,7 @@
 #include "dllserver.hpp"
 #include "thorhelper.hpp"
 #include "workflow.hpp"
+
 #include "nbcd.hpp"
 #include "seclib.hpp"
 

+ 2 - 0
ecl/hql/hqlatoms.cpp

@@ -122,6 +122,7 @@ _ATOM externalAtom;
 _ATOM failAtom;
 _ATOM failureAtom;
 _ATOM falseAtom;
+_ATOM fastAtom;
 _ATOM fewAtom;
 _ATOM fieldAtom;
 _ATOM fieldsAtom;
@@ -531,6 +532,7 @@ MODULE_INIT(INIT_PRIORITY_HQLATOM)
     MAKEATOM(fail);
     MAKEATOM(failure);
     MAKEATOM(false);
+    MAKEATOM(fast);
     MAKEATOM(few);
     MAKEATOM(field);
     MAKEATOM(fields);

+ 1 - 0
ecl/hql/hqlatoms.hpp

@@ -125,6 +125,7 @@ extern HQL_API _ATOM externalAtom;
 extern HQL_API _ATOM failAtom;
 extern HQL_API _ATOM failureAtom;
 extern HQL_API _ATOM falseAtom;
+extern HQL_API _ATOM fastAtom;
 extern HQL_API _ATOM fewAtom;
 extern HQL_API _ATOM fieldAtom;
 extern HQL_API _ATOM fieldsAtom;

+ 16 - 2
ecl/hql/hqlfold.cpp

@@ -1749,9 +1749,23 @@ IHqlExpression * foldConstantOperator(IHqlExpression * expr, unsigned foldOption
             return applyBinaryFold(expr, multiplyValues);
         }
     case no_div:
-        return applyBinaryFold(expr, divideValues);
     case no_modulus:
-        return applyBinaryFold(expr, modulusValues);
+        {
+            IValue * leftValue = expr->queryChild(0)->queryValue();
+            IValue * rightValue = expr->queryChild(1)->queryValue();
+            if (leftValue && rightValue)
+            {
+                DBZaction onZero = (foldOptions & HFOforcefold) ? DBZfail : DBZnone;
+                IValue * res;
+                if (op == no_div)
+                    res = divideValues(leftValue, rightValue, onZero);
+                else
+                    res = modulusValues(leftValue, rightValue, onZero);
+                if (res)
+                    return createConstant(res);
+            }
+            return LINK(expr);
+        }
     case no_concat:
         return applyBinaryFold(expr, concatValues);
     case no_band:

+ 11 - 4
ecl/hql/hqlutil.cpp

@@ -2805,10 +2805,16 @@ IHqlExpression * getInverse(IHqlExpression * op)
 {
     node_operator opKind = op->getOperator();
     if (opKind == no_not)
-        return LINK(op->queryChild(0));
-    else if (opKind == no_constant)
+    {
+        IHqlExpression * arg0 = op->queryChild(0);
+        if (arg0->isBoolean())
+            return LINK(arg0);
+    }
+
+    if (opKind == no_constant)
         return createConstant(!op->queryValue()->getBoolValue());
-    else if (opKind == no_alias_scope)
+
+    if (opKind == no_alias_scope)
     {
         HqlExprArray args;
         args.append(*getInverse(op->queryChild(0)));
@@ -2830,7 +2836,8 @@ IHqlExpression * getInverse(IHqlExpression * op)
         return createBoolExpr(no_if, LINK(op->queryChild(0)), getInverse(op->queryChild(1)), getInverse(op->queryChild(2)));
     }
 
-    return createValue(no_not, makeBoolType(), LINK(op));
+    Owned<ITypeInfo> boolType = makeBoolType();
+    return createValue(no_not, LINK(boolType), ensureExprType(op, boolType));
 }
 
 IHqlExpression * getNormalizedCondition(IHqlExpression * expr)

+ 6 - 0
ecl/hqlcpp/hqlcatom.cpp

@@ -147,6 +147,7 @@ _ATOM createQStrRangeHighAtom;
 _ATOM createQuotedStringAtom;
 _ATOM createRangeLowAtom;
 _ATOM createRangeHighAtom;
+_ATOM createRealNullAtom;
 _ATOM createRowFromXmlAtom;
 _ATOM createStrRangeLowAtom;
 _ATOM createStrRangeHighAtom;
@@ -203,6 +204,7 @@ _ATOM DecSubAtom;
 _ATOM DecTruncateAtom;
 _ATOM DecTruncateAtAtom;
 _ATOM DecValidAtom;
+_ATOM DecValidTosAtom;
 _ATOM delayedAtom;
 _ATOM deleteFileAtom;
 _ATOM dependencyAtom;
@@ -272,6 +274,7 @@ _ATOM f2anAtom;
 _ATOM f2axAtom;
 _ATOM f2vnAtom;
 _ATOM f2vxAtom;
+_ATOM failDivideByZeroAtom;
 _ATOM _failIdAtom;
 _ATOM fileAtom;
 _ATOM fileExistsAtom;
@@ -867,6 +870,7 @@ MODULE_INIT(INIT_PRIORITY_HQLATOM-1)
     MAKEATOM(createQuotedString);
     MAKEATOM(createRangeLow);
     MAKEATOM(createRangeHigh);
+    MAKEATOM(createRealNull);
     MAKEATOM(createRegex);
     MAKEATOM(createRowFromXml);
     MAKEATOM(createStrRangeLow);
@@ -923,6 +927,7 @@ MODULE_INIT(INIT_PRIORITY_HQLATOM-1)
     MAKEATOM(DecTruncate);
     MAKEATOM(DecTruncateAt);
     MAKEATOM(DecValid);
+    MAKEATOM(DecValidTos);
     MAKEATOM(delayed);
     MAKEATOM(deleteFile);
     MAKEATOM(dependency);
@@ -992,6 +997,7 @@ MODULE_INIT(INIT_PRIORITY_HQLATOM-1)
     f2axAtom = createAtom("_f2ax");
     MAKEATOM(f2vn);
     MAKEATOM(f2vx);
+    MAKEATOM(failDivideByZero);
     MAKEID(_fail);
     MAKEATOM(file);
     MAKEATOM(fileExists);

+ 3 - 0
ecl/hqlcpp/hqlcatom.hpp

@@ -147,6 +147,7 @@ extern _ATOM createQStrRangeHighAtom;
 extern _ATOM createQuotedStringAtom;
 extern _ATOM createRangeLowAtom;
 extern _ATOM createRangeHighAtom;
+extern _ATOM createRealNullAtom;
 extern _ATOM createRegexAtom;
 extern _ATOM createRowFromXmlAtom;
 extern _ATOM createStrRangeLowAtom;
@@ -203,6 +204,7 @@ extern _ATOM DecSubAtom;
 extern _ATOM DecTruncateAtom;
 extern _ATOM DecTruncateAtAtom;
 extern _ATOM DecValidAtom;
+extern _ATOM DecValidTosAtom;
 extern _ATOM delayedAtom;
 extern _ATOM deleteFileAtom;
 extern _ATOM dependencyAtom;
@@ -272,6 +274,7 @@ extern _ATOM f2anAtom;
 extern _ATOM f2axAtom;
 extern _ATOM f2vnAtom;
 extern _ATOM f2vxAtom;
+extern _ATOM failDivideByZeroAtom;
 extern _ATOM _failIdAtom;
 extern _ATOM fileAtom;
 extern _ATOM fileExistsAtom;

+ 2 - 0
ecl/hqlcpp/hqlcerrors.hpp

@@ -208,6 +208,7 @@
 #define HQLERR_ScalarOutputWithinApply          4186
 #define HQLERR_EmbeddedTypeNotSupported_X       4187
 #define HQLERR_MaximumSizeLessThanMinimum_XY    4188
+#define HQLERR_UnexpectedOptionValue_XY         4189
 
 //Warnings....
 #define HQLWRN_PersistDataNotLikely             4500
@@ -488,6 +489,7 @@
 #define HQLERR_KeyedJoinNoRightIndex_X_Text     "Right dataset (%s) for a keyed join isn't a key"
 #define HQLERR_EmbeddedTypeNotSupported_X_Text  "Type %s not supported for embedded/external scripts"
 #define HQLERR_MaximumSizeLessThanMinimum_XY_Text "Maximum size (%u) for this record is lower than the minimum (%u)"
+#define HQLERR_UnexpectedOptionValue_XY_Text    "Unexpected value for option %s: %s"
 
 //Warnings.
 #define HQLWRN_CannotRecreateDistribution_Text  "Cannot recreate the distribution for a persistent dataset"

+ 85 - 25
ecl/hqlcpp/hqlcpp.cpp

@@ -1720,6 +1720,18 @@ void HqlCppTranslator::cacheOptions()
         }
     }
 
+    //Configure the divide by zero action
+    options.divideByZeroAction = DBZzero;
+    const char * dbz = wu()->getDebugValue("divideByZero",val).str();
+    if (strieq(val.str(), "0") || strieq(val.str(), "zero"))
+        options.divideByZeroAction = DBZzero;
+    else if (strieq(val.str(), "nan"))
+        options.divideByZeroAction = DBZnan;
+    else if (strieq(val.str(), "fail") || strieq(val.str(), "throw"))
+        options.divideByZeroAction = DBZfail;
+    else if (val.length())
+        throwError2(HQLERR_UnexpectedOptionValue_XY, "divideByZero", val.str());
+
     //The following cases handle options whose default values are dependent on other options.  
     //Or where one debug options sets more than one option
     options.hasResourceUseMpForDistribute = wu()->hasDebugValue("resourceUseMpForDistribute");
@@ -5145,11 +5157,23 @@ void HqlCppTranslator::doBuildExprArith(BuildCtx & ctx, IHqlExpression * expr, C
             _ATOM func;
             switch (expr->getOperator())
             {
-            case no_add: func = DecAddAtom; break;
-            case no_div: func = DecDivideAtom; break;
-            case no_modulus: func = DecModulusAtom; break;
-            case no_mul: func = DecMulAtom; break;
-            case no_sub: func = DecSubAtom; break;
+            case no_add:
+                func = DecAddAtom;
+                break;
+            case no_div:
+                func = DecDivideAtom;
+                args.append(*getSizetConstant(options.divideByZeroAction));
+                break;
+            case no_modulus:
+                func = DecModulusAtom;
+                args.append(*getSizetConstant(options.divideByZeroAction));
+                break;
+            case no_mul:
+                func = DecMulAtom;
+                break;
+            case no_sub:
+                func = DecSubAtom;
+                break;
             default: UNIMPLEMENTED;
             }
             callProcedure(ctx, func, args);
@@ -6980,7 +7004,10 @@ void HqlCppTranslator::doBuildExprDivide(BuildCtx & ctx, IHqlExpression * expr,
         int cmp = value->compare(zero);
 
         if (cmp == 0)
-            tgt.expr.setown(createConstant(zero.getClear()));
+        {
+            OwnedHqlExpr eZero = createConstant(LINK(zero));
+            doBuildDivideByZero(ctx, NULL, eZero, &tgt);
+        }
         else
             doBuildPureSubExpr(ctx, expr, tgt);
     }
@@ -6991,6 +7018,45 @@ void HqlCppTranslator::doBuildExprDivide(BuildCtx & ctx, IHqlExpression * expr,
 }
 
 
+
+void HqlCppTranslator::doBuildDivideByZero(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * zero, CHqlBoundExpr * bound)
+{
+    //Always assign something to bound - even if it is replaced further down.
+    if (bound)
+        buildExpr(ctx, zero, *bound);
+
+    switch (options.divideByZeroAction)
+    {
+    case DBZzero:
+        if (target)
+            assignBound(ctx, *target, zero);
+        break;
+    case DBZfail:
+        {
+            HqlExprArray noArgs;
+            buildFunctionCall(ctx, failDivideByZeroAtom, noArgs);
+            break;
+        }
+    case DBZnan:
+        {
+            LinkedHqlExpr nan = zero;
+            if (zero->queryType()->getTypeCode() == type_real)
+            {
+                HqlExprArray noArgs;
+                nan.setown(bindFunctionCall(createRealNullAtom, noArgs));
+            }
+
+            if (target)
+                assignBound(ctx, *target, nan);
+            else
+                buildExpr(ctx, nan, *bound);
+            break;
+        }
+    default:
+        throwUnexpected();
+    }
+}
+
 void HqlCppTranslator::doBuildAssignDivide(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr)
 {
     if (expr->queryType()->getTypeCode() == type_decimal)
@@ -7017,7 +7083,7 @@ void HqlCppTranslator::doBuildAssignDivide(BuildCtx & ctx, const CHqlBoundTarget
         int cmp = value->compare(eZero->queryValue());
 
         if (cmp == 0)
-            assignBound(ctx, target, eZero);
+            doBuildDivideByZero(ctx, &target, eZero, NULL);
         else
             assignBound(ctx, target, pureExpr);
     }
@@ -7027,7 +7093,7 @@ void HqlCppTranslator::doBuildAssignDivide(BuildCtx & ctx, const CHqlBoundTarget
         IHqlStmt * stmt = subctx.addFilter(divisor);
         assignBound(subctx, target, pureExpr);
         subctx.selectElse(stmt);
-        assignBound(subctx, target, eZero);
+        doBuildDivideByZero(subctx, &target, eZero, NULL);
     }
 }
 
@@ -7544,22 +7610,8 @@ void HqlCppTranslator::doBuildAssignAll(BuildCtx & ctx, const CHqlBoundTarget &
 
 void HqlCppTranslator::doBuildExprNot(BuildCtx & ctx, IHqlExpression * expr, CHqlBoundExpr & tgt)
 {
-    ITypeInfo * type = expr->queryChild(0)->queryType();
-    switch (type->getTypeCode())
-    {
-    case type_decimal:
-        {
-            //MORE: Could leak decimal stack....  Is the last line correct?
-            HqlExprArray args;              
-            bindAndPush(ctx, expr->queryChild(0));
-            IHqlExpression * op = bindTranslatedFunctionCall(DecCompareNullAtom, args);
-            tgt.expr.setown(createValue(expr->getOperator(), LINK(boolType), op, getZero()));
-        }
-        break;
-    default:
-        doBuildPureSubExpr(ctx, expr, tgt);
-        break;
-    }
+    assertex(expr->queryChild(0)->isBoolean());
+    doBuildPureSubExpr(ctx, expr, tgt);
 }
 
 
@@ -9774,10 +9826,18 @@ void HqlCppTranslator::doBuildExprIsValid(BuildCtx & ctx, IHqlExpression * expr,
 
     CHqlBoundExpr bound;
     buildExpr(ctx, value, bound);
+
+    type_t tc = type->getTypeCode();
+    if ((tc == type_decimal) && (bound.expr->getOperator() == no_decimalstack))
+    {
+        tgt.expr.setown(bindTranslatedFunctionCall(DecValidTosAtom, args));
+        return;
+    }
+
     ensureHasAddress(ctx, bound);
 
     OwnedHqlExpr address = getPointer(bound.expr);
-    switch (type->getTypeCode())
+    switch (tc)
     {
     case type_decimal:
         args.append(*createConstant(type->isSigned()));

+ 3 - 0
ecl/hqlcpp/hqlcpp.ipp

@@ -28,6 +28,7 @@
 #include "hqlwcpp.hpp"
 #include "hqltrans.ipp"
 #include "hqlusage.hpp"
+#include "eclrtl.hpp"
 
 #define DEBUG_TIMER(name, time)                     if (options.addTimingToWorkunit) { timeReporter->addTiming(name, time); }
 #define DEBUG_TIMERX(timeReporter, name, time)      if (timeReporter) { timeReporter->addTiming(name, time); }
@@ -555,6 +556,7 @@ struct HqlCppOptions
     unsigned            complexClassesThreshold;
     unsigned            complexClassesActivityFilter;
     CompilerType        targetCompiler;
+    DBZaction           divideByZeroAction;
     bool                peephole;
     bool                foldConstantCast;
     bool                optimizeBoolReturn;
@@ -1129,6 +1131,7 @@ public:
 
     void buildExprAssignViaType(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, ITypeInfo * type);
     void buildExprAssignViaString(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr, unsigned len);
+    void doBuildDivideByZero(BuildCtx & ctx, const CHqlBoundTarget * target, IHqlExpression * zero, CHqlBoundExpr * bound);
 
     void doBuildAssignAddSets(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * value);
     void doBuildAssignAggregate(BuildCtx & ctx, const CHqlBoundTarget & target, IHqlExpression * expr);

+ 51 - 48
ecl/hqlcpp/hqlcppsys.ecl

@@ -306,54 +306,55 @@ const char * cppSystemText[]  = {
     "   unsigned8 castUInt6(unsigned8 value) :  eclrtl,pure,library='eclrtl',include,entrypoint='rtliCastUInt6';",
     "   unsigned8 castUInt7(unsigned8 value) :  eclrtl,pure,library='eclrtl',include,entrypoint='rtliCastUInt7';",
 
-    "   DecAbs() :  bcd,library='nbcd',entrypoint='DecAbs';",
-    "   DecAdd() :  bcd,library='nbcd',entrypoint='DecAdd';",
-    "   integer4 DecCompareDecimal(const data v1, const data1 v2) : bcd,pure,library='nbcd',entrypoint='DecCompareDecimal';",
-    "   integer4 DecCompareUDecimal(const data v1, const data1 v2) : bcd,pure,library='nbcd',entrypoint='DecCompareUDecimal';",
-    "   integer4 DecCompareNull() : bcd,library='nbcd',entrypoint='DecCompareNull';",
-    "   integer4 DecDistinct() :    bcd,library='nbcd',entrypoint='DecDistinct';",
-    "   integer4 DecDistinctR() :   bcd,library='nbcd',entrypoint='DecDistinctR';",
-    "   DecDivide() :   bcd,library='nbcd',entrypoint='DecDivide';",
-    "   DecModulus() :  bcd,library='nbcd',entrypoint='DecModulus';",
-    "   DecSub() :  bcd,library='nbcd',entrypoint='DecSub';",
-    "   DecSubR() : bcd,library='nbcd',entrypoint='DecSubR';",
-    "   DecNegate() :   bcd,library='nbcd',entrypoint='DecNegate';",
-    "   unsigned4 DecPopString(string tgt) :    bcd,library='nbcd',entrypoint='DecPopString';",
-    "   DecPopVString(string tgt) : bcd,library='nbcd',entrypoint='DecPopCString';",
-    "   varstring DecPopVStringX() :    bcd,library='nbcd',entrypoint='DecPopCStringX';",
-    "   integer8 DecPopInt64() :    bcd,library='nbcd',entrypoint='DecPopInt64';",
-    "   DecPopDecimal(data1 tgt,unsigned1 len,unsigned1 prec) : bcd,library='nbcd',entrypoint='DecPopDecimal';",
-    "   DecPopUDecimal(data1 tgt,unsigned1 len,unsigned1 prec) : bcd,library='nbcd',entrypoint='DecPopUDecimal';",
-    "   unsigned4 DecPopUlong() :   bcd,library='nbcd',entrypoint='DecPopUlong';",
-    "   real8 DecPopReal() :    bcd,library='nbcd',entrypoint='DecPopReal';",
-    "   DecPushString(const string tgt) :   bcd,library='nbcd',entrypoint='DecPushString';",
-    "   DecPushCString(const varstring src) :   bcd,library='nbcd',entrypoint='DecPushCString';",
-    "   DecPushInt64(integer8 src) :    bcd,library='nbcd',entrypoint='DecPushInt64';",
-    "   DecPushLong(integer4 src) : bcd,library='nbcd',entrypoint='DecPushLong';",
-    "   DecPushDecimal(const data1 src, unsigned1 declen, unsigned1 prec) : bcd,library='nbcd',entrypoint='DecPushDecimal';",
-    "   DecPushUDecimal(const data1 src, unsigned1 declen, unsigned1 prec) : bcd,library='nbcd',entrypoint='DecPushUDecimal';",
-    "   DecPushUInt64(unsigned8 src) :  bcd,library='nbcd',entrypoint='DecPushUInt64';",
-    "   DecPushULong(unsigned4 src) :   bcd,library='nbcd',entrypoint='DecPushULong';",
-    "   DecRound() :    bcd,library='nbcd',entrypoint='DecRound';",
-    "   DecRoundUp() :  bcd,library='nbcd',entrypoint='DecRoundUp';",
-    "   DecRoundTo(unsigned4 places) :  bcd,library='nbcd',entrypoint='DecRoundTo';",
-    "   DecDup() :  bcd,library='nbcd',entrypoint='DecDup';",
-    "   DecMul() :  bcd,library='nbcd',entrypoint='DecMul';",
-    "   DecDivideR() :  bcd,library='nbcd',entrypoint='DecDivideR';",
-    "   DecLongPower(integer4 pow) :    bcd,library='nbcd',entrypoint='DecLongPower';",
-    "   DecPushReal(real8 d) :  bcd,library='nbcd',entrypoint='DecPushReal';",
-    "   DecPushUtf8(utf8 d) :   bcd,library='nbcd',entrypoint='rtlDecPushUtf8';",
-    "   DecTruncate() :    bcd,library='nbcd',entrypoint='DecTruncate';",
-    "   DecTruncateAt(unsigned4 places) :  bcd,library='nbcd',entrypoint='DecTruncateAt';",
-
-    "   DecSetPrecision(unsigned1 len, unsigned1 prec) : bcd,library='nbcd',entrypoint='DecSetPrecision';",
-    "   integer4 DecPopLong() : bcd,library='nbcd',entrypoint='DecPopLong';",
-    "   DecSwap() : bcd,library='nbcd',entrypoint='DecSwap';",
-    "   DecUint4Power(unsigned4 pow) :  bcd,library='nbcd',entrypoint='DecUint4Power';",
-    "   string DecPopStringX() :    bcd,library='nbcd',entrypoint='DecPopStringX';",
-    "   DecLock() : bcd,library='nbcd',entrypoint='DecLock';",
-    "   DecUnlock() :   bcd,library='nbcd',entrypoint='DecUnlock';",
-    "   boolean DecValid(boolean isSigned, const data src) : bcd,pure,library='nbcd',entrypoint='DecValid';",
+    "   DecAbs() :  eclrtl,library='eclrtl',entrypoint='DecAbs';",
+    "   DecAdd() :  eclrtl,library='eclrtl',entrypoint='DecAdd';",
+    "   integer4 DecCompareDecimal(const data v1, const data1 v2) : eclrtl,pure,library='eclrtl',entrypoint='DecCompareDecimal';",
+    "   integer4 DecCompareUDecimal(const data v1, const data1 v2) : eclrtl,pure,library='eclrtl',entrypoint='DecCompareUDecimal';",
+    "   integer4 DecCompareNull() : eclrtl,library='eclrtl',entrypoint='DecCompareNull';",
+    "   integer4 DecDistinct() :    eclrtl,library='eclrtl',entrypoint='DecDistinct';",
+    "   integer4 DecDistinctR() :   eclrtl,library='eclrtl',entrypoint='DecDistinctR';",
+    "   DecDivide(unsigned1 dbz) :   eclrtl,library='eclrtl',entrypoint='DecDivide';",
+    "   DecModulus(unsigned1 dbz) :  eclrtl,library='eclrtl',entrypoint='DecModulus';",
+    "   DecSub() :  eclrtl,library='eclrtl',entrypoint='DecSub';",
+    "   DecSubR() : eclrtl,library='eclrtl',entrypoint='DecSubR';",
+    "   DecNegate() :   eclrtl,library='eclrtl',entrypoint='DecNegate';",
+    "   unsigned4 DecPopString(string tgt) :    eclrtl,library='eclrtl',entrypoint='DecPopString';",
+    "   DecPopVString(string tgt) : eclrtl,library='eclrtl',entrypoint='DecPopCString';",
+    "   varstring DecPopVStringX() :    eclrtl,library='eclrtl',entrypoint='DecPopCStringX';",
+    "   integer8 DecPopInt64() :    eclrtl,library='eclrtl',entrypoint='DecPopInt64';",
+    "   DecPopDecimal(data1 tgt,unsigned1 len,unsigned1 prec) : eclrtl,library='eclrtl',entrypoint='DecPopDecimal';",
+    "   DecPopUDecimal(data1 tgt,unsigned1 len,unsigned1 prec) : eclrtl,library='eclrtl',entrypoint='DecPopUDecimal';",
+    "   unsigned4 DecPopUlong() :   eclrtl,library='eclrtl',entrypoint='DecPopUlong';",
+    "   real8 DecPopReal() :    eclrtl,library='eclrtl',entrypoint='DecPopReal';",
+    "   DecPushString(const string tgt) :   eclrtl,library='eclrtl',entrypoint='DecPushString';",
+    "   DecPushCString(const varstring src) :   eclrtl,library='eclrtl',entrypoint='DecPushCString';",
+    "   DecPushInt64(integer8 src) :    eclrtl,library='eclrtl',entrypoint='DecPushInt64';",
+    "   DecPushLong(integer4 src) : eclrtl,library='eclrtl',entrypoint='DecPushLong';",
+    "   DecPushDecimal(const data1 src, unsigned1 declen, unsigned1 prec) : eclrtl,library='eclrtl',entrypoint='DecPushDecimal';",
+    "   DecPushUDecimal(const data1 src, unsigned1 declen, unsigned1 prec) : eclrtl,library='eclrtl',entrypoint='DecPushUDecimal';",
+    "   DecPushUInt64(unsigned8 src) :  eclrtl,library='eclrtl',entrypoint='DecPushUInt64';",
+    "   DecPushULong(unsigned4 src) :   eclrtl,library='eclrtl',entrypoint='DecPushULong';",
+    "   DecRound() :    eclrtl,library='eclrtl',entrypoint='DecRound';",
+    "   DecRoundUp() :  eclrtl,library='eclrtl',entrypoint='DecRoundUp';",
+    "   DecRoundTo(unsigned4 places) :  eclrtl,library='eclrtl',entrypoint='DecRoundTo';",
+    "   DecDup() :  eclrtl,library='eclrtl',entrypoint='DecDup';",
+    "   DecMul() :  eclrtl,library='eclrtl',entrypoint='DecMul';",
+    "   DecDivideR(unsigned1 dbz) :  eclrtl,library='eclrtl',entrypoint='DecDivideR';",
+    "   DecLongPower(integer4 pow) :    eclrtl,library='eclrtl',entrypoint='DecLongPower';",
+    "   DecPushReal(real8 d) :  eclrtl,library='eclrtl',entrypoint='DecPushReal';",
+    "   DecPushUtf8(utf8 d) :   eclrtl,library='eclrtl',entrypoint='rtlDecPushUtf8';",
+    "   DecTruncate() :    eclrtl,library='eclrtl',entrypoint='DecTruncate';",
+    "   DecTruncateAt(unsigned4 places) :  eclrtl,library='eclrtl',entrypoint='DecTruncateAt';",
+
+    "   DecSetPrecision(unsigned1 len, unsigned1 prec) : eclrtl,library='eclrtl',entrypoint='DecSetPrecision';",
+    "   integer4 DecPopLong() : eclrtl,library='eclrtl',entrypoint='DecPopLong';",
+    "   DecSwap() : eclrtl,library='eclrtl',entrypoint='DecSwap';",
+    "   DecUint4Power(unsigned4 pow) :  eclrtl,library='eclrtl',entrypoint='DecUint4Power';",
+    "   string DecPopStringX() :    eclrtl,library='eclrtl',entrypoint='DecPopStringX';",
+    "   DecLock() : eclrtl,library='eclrtl',entrypoint='DecLock';",
+    "   DecUnlock() :   eclrtl,library='eclrtl',entrypoint='DecUnlock';",
+    "   boolean DecValid(boolean isSigned, const data src) : eclrtl,pure,library='eclrtl',entrypoint='DecValid';",
+    "   boolean DecValidTos() : eclrtl,pure,library='eclrtl',entrypoint='DecValidTos';",
 
     "   integer8 _ROUND(real8 arg) :    eclrtl,pure,library='eclrtl',entrypoint='rtlRound';",
     "   real8 roundTo(real8 arg, integer4 _places) : eclrtl,pure,library='eclrtl',entrypoint='rtlRoundTo';",
@@ -362,6 +363,7 @@ const char * cppSystemText[]  = {
     "   unsigned4 rtlRandom() : eclrtl,library='eclrtl',entrypoint='rtlRandom';",
     "   _fail(integer4 code, const varstring msg) : eclrtl,library='eclrtl',entrypoint='rtlFail';",
     "   sysFail(integer4 code, const varstring msg) :   eclrtl,library='eclrtl',entrypoint='rtlSysFail';",
+    "   failDivideByZero() : eclrtl,library='eclrtl',entrypoint='rtlFailDivideByZero';",
 
     "   unsigned4 crcData(const data src, unsigned4 initval) :  eclrtl,pure,library='eclrtl',entrypoint='rtlCrcData';",
     "   unsigned4 crcUnicode(const unicode src, unsigned4 initval) :    eclrtl,pure,library='eclrtl',entrypoint='rtlCrcUnicode';",
@@ -401,6 +403,7 @@ const char * cppSystemText[]  = {
     "   data16 hashMd5Finish(data _state) : eclrtl,entrypoint='rtlHashMd5Finish';",
 
     "   boolean validReal(const data src) : eclrtl,pure,library='eclrtl',entrypoint='rtlIsValidReal';",
+    "   real8 createRealNull() : eclrtl,pure,library='eclrtl',entrypoint='rtlCreateRealNull';",
 
     "   deserializeRaw(data field, boolean o) : eclrtl,include='eclrtl.hpp',library='eclrtl',entrypoint='deserializeRaw';",
     "   data deserializeDataX(boolean o) :  eclrtl,include='eclrtl.hpp',library='eclrtl',entrypoint='deserializeDataX';",

+ 5 - 5
ecl/hqlcpp/hqlwcpp.cpp

@@ -598,13 +598,13 @@ bool HqlCppWriter::generateFunctionPrototype(IHqlExpression * funcdef, const cha
         out.append(s);
         return true;
     }
-    enum { ServiceApi, RtlApi, BcdApi, CApi, CppApi, LocalApi } api = ServiceApi;
+    enum { ServiceApi, RtlApi, FastApi, CApi, CppApi, LocalApi } api = ServiceApi;
     bool isVirtual = funcdef->hasProperty(virtualAtom);
     bool isLocal = body->hasProperty(localAtom);
     if (body->hasProperty(eclrtlAtom))
         api = RtlApi;
-    else if (body->hasProperty(bcdAtom))
-        api = BcdApi;
+    else if (body->hasProperty(fastAtom))
+        api = FastApi;
     else if (body->hasProperty(cAtom))
         api = CApi;
     else if (body->hasProperty(cppAtom))
@@ -624,7 +624,7 @@ bool HqlCppWriter::generateFunctionPrototype(IHqlExpression * funcdef, const cha
     {
     case ServiceApi: out.append(" SERVICE_API"); break;
     case RtlApi:     out.append(" RTL_API"); break;
-    case BcdApi:     out.append(" BCD_API"); break;
+    case FastApi:     out.append(" BCD_API"); break;
     }
     out.append(" ");
 
@@ -642,7 +642,7 @@ bool HqlCppWriter::generateFunctionPrototype(IHqlExpression * funcdef, const cha
             break;
         }
         break;
-    case BcdApi:
+    case FastApi:
         switch (compiler)
         {
         case Vs6CppCompiler:

+ 43 - 0
ecl/regress/issue8352a.ecl

@@ -0,0 +1,43 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - default action to return 0
+#option ('divideByZero', '0'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100 DIV 1);
+output(100.0 / 1.0);
+output(100.1D / 1.0D);
+
+output(100 DIV cintZero);
+output(100.0 / crealZero);
+output(100.1D / cdecZero);
+            
+output(5 * (101 DIV cintZero));
+output(5 * (101.0 / crealZero));
+output(5D * (101.1D / cdecZero));
+            
+output(100 DIV intZero);
+output(100.0 / realZero);
+output(100.1D / decZero);

+ 43 - 0
ecl/regress/issue8352b.ecl

@@ -0,0 +1,43 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - default action to return 0
+#option ('divideByZero', 'fail'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100 DIV 1);
+output(100.0 / 1.0);
+output(100.1D / 1.0D);
+
+output(100 DIV cintZero);
+output(100.0 / crealZero);
+output(100.1D / cdecZero);
+            
+output(5 * (101 DIV cintZero));
+output(5 * (101.0 / crealZero));
+output(5D * (101.1D / cdecZero));
+            
+output(100 DIV intZero);
+output(100.0 / realZero);
+output(100.1D / decZero);

+ 30 - 0
ecl/regress/issue8352c1.ecl

@@ -0,0 +1,30 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - fail instead of returning 0
+#option ('divideByZero', 'fail'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+//The constant folding in the pre-processor defaults to throwing an error
+#IF (100 DIV cintZero = 0)
+OUTPUT('success');
+#else
+OUTPUT('failure');
+#END

+ 30 - 0
ecl/regress/issue8352c2.ecl

@@ -0,0 +1,30 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - fail instead of returning 0
+#option ('divideByZero', 'fail'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+//The constant folding in the pre-processor defaults to throwing an error
+#IF (100.0 / crealZero = 0)
+OUTPUT('success');
+#else
+OUTPUT('failure');
+#END

+ 30 - 0
ecl/regress/issue8352c3.ecl

@@ -0,0 +1,30 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - fail instead of returning 0
+#option ('divideByZero', 'fail'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+//The constant folding in the pre-processor defaults to throwing an error
+#IF (100.1D / cdecZero = 0)
+OUTPUT('success');
+#else
+OUTPUT('failure');
+#END

+ 29 - 0
ecl/regress/issue8352c4.ecl

@@ -0,0 +1,29 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+#option ('divideByZero', '0'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+//The constant folding in the pre-processor defaults to throwing an error
+#IF (100.0 / crealZero = 0)
+OUTPUT('success');
+#else
+OUTPUT('failure');
+#END

+ 78 - 0
ecl/regress/issue8352d.ecl

@@ -0,0 +1,78 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - fail instead of returning 0
+#option ('divideByZero', 'nan'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(NOT ISNULL(100 DIV 1));
+output(NOT ISNULL(100.0 / 1.0));
+output(NOT ISNULL(100.1D / 1.0D));
+
+output('Constant Divide:');
+output(ISNULL(100 DIV cintZero));
+output(ISNULL(100.0 / crealZero));
+output(ISNULL(100.1D / cdecZero));
+            
+output('Constant Divide Multiply:');
+output(ISNULL(5 * (101 DIV cintZero)));
+output(ISNULL(5 * (101.0 / crealZero)));
+output(ISNULL(5D * (101.1D / cdecZero)));
+            
+output('Runtime Divide:');
+output(ISNULL(100 DIV intZero));
+output(ISNULL(100.0 / realZero));
+output(ISNULL(100.1D / decZero));
+
+//--- check modulus
+output('Modulus:');
+
+output(NOT ISNULL(100 % 1));
+output(NOT ISNULL(100.0 % 1.0));
+output(NOT ISNULL(100.1D % 1.0D));
+
+output('Constant Modulus:');
+output(ISNULL(100 % cintZero));
+output(ISNULL(100.0 % crealZero));
+output(ISNULL(100.1D % cdecZero));
+            
+output('Constant Modulus Multiply:');
+output(ISNULL(5 * (101 % cintZero)));
+output(ISNULL(5 * (101.0 % crealZero)));
+output(ISNULL(5D * (101.1D % cdecZero)));
+            
+output('Runtime Modulus:');
+output(ISNULL(100 % intZero));
+output(ISNULL(100.0 % realZero));
+output(ISNULL(100.1D % decZero));
+
+output('Miscellaneous');
+output(100.0 / crealZero);
+output(100.0 / realZero);
+output(1.0e300 * nofold(1.0e300));
+output(-1.0e300 * nofold(1.0e300));
+
+output((unsigned)(100.0 / crealZero));
+output((unsigned)(100.0 / realZero));
+

+ 25 - 0
ecl/regress/issue8352e1.ecl

@@ -0,0 +1,25 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - fail instead of returning 0
+#option ('divideByZero', 'fail'); 
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100 DIV intZero);

+ 25 - 0
ecl/regress/issue8352e2.ecl

@@ -0,0 +1,25 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - fail instead of returning 0
+#option ('divideByZero', 'fail'); 
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100.0 / realZero);

+ 25 - 0
ecl/regress/issue8352e3.ecl

@@ -0,0 +1,25 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - fail instead of returning 0
+#option ('divideByZero', 'fail'); 
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100.1D / decZero);

+ 25 - 0
ecl/regress/issue8352e4.ecl

@@ -0,0 +1,25 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//Test division by zero - fail instead of returning 0
+#option ('divideByZero', 'fail'); 
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100.1D % decZero);

+ 22 - 0
ecl/regress/issue8352f.ecl

@@ -0,0 +1,22 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+decimal10_2 myDec := 10.01D : stored('mydec');
+
+output((boolean) NOFOLD(100.1D));
+output(NOT NOFOLD(100.1D)); // Strangely this is done as a integer bitwise not
+output(NOT myDec);          // Strangely this is done as a integer bitwise not

+ 19 - 1
rtl/eclrtl/CMakeLists.txt

@@ -27,6 +27,7 @@ project( eclrtl )
 
 set (    SRCS 
          eclrtl.cpp 
+         rtlbcd.cpp 
          rtldistr.cpp 
          rtlds.cpp 
          rtlint.cpp 
@@ -36,7 +37,23 @@ set (    SRCS
          rtlfield.cpp 
          rtlread.cpp 
          rtltype.cpp 
-         rtlxml.cpp 
+         rtlxml.cpp
+         
+         eclinclude.hpp
+         eclrtl.hpp
+         eclrtl_imp.hpp
+         rtlbcd.hpp
+         rtldistr.hpp
+         rtlds_imp.hpp
+         rtlfield_imp.hpp
+         rtlkey2.hpp
+         rtlkey.hpp
+         rtlread_imp.hpp
+         rtlsize.hpp
+         rtltype.hpp
+
+         rtlbcdtest.cpp 
+
     )
 
 include_directories ( 
@@ -71,6 +88,7 @@ FOREACH( iFILES
     ${CMAKE_CURRENT_SOURCE_DIR}/eclinclude.hpp
     ${CMAKE_CURRENT_SOURCE_DIR}/eclrtl.hpp
     ${CMAKE_CURRENT_SOURCE_DIR}/eclrtl_imp.hpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/rtlbcd.hpp
     ${CMAKE_CURRENT_SOURCE_DIR}/rtldistr.hpp
     ${CMAKE_CURRENT_SOURCE_DIR}/rtlds_imp.hpp
     ${CMAKE_CURRENT_SOURCE_DIR}/rtlfield_imp.hpp

+ 1 - 8
rtl/eclrtl/eclinclude.hpp

@@ -67,13 +67,6 @@ typedef unsigned __int64 hash64_t;
 #include "rtlfield_imp.hpp"
 #include "rtlds_imp.hpp"
 #include "eclhelper_base.hpp"
-
-extern __declspec(dllimport) void _fastcall DecLock();
-extern __declspec(dllimport) void _fastcall DecUnlock();
-struct BcdCriticalBlock
-{
-    BcdCriticalBlock()      { DecLock(); }
-    ~BcdCriticalBlock()     { DecUnlock(); }
-};
+#include "rtlbcd.hpp"
 
 #endif

+ 20 - 9
rtl/eclrtl/eclrtl.cpp

@@ -29,7 +29,7 @@
 #include "jptree.hpp"
 #include "junicode.hpp"
 #include "eclrtl.hpp"
-#include "bcd.hpp"
+#include "rtlbcd.hpp"
 #include "eclrtl_imp.hpp"
 #include "unicode/uchar.h"
 #include "unicode/ucol.h"
@@ -45,14 +45,6 @@
 
 #include "roxiemem.hpp"
 
-#ifndef _WIN32
-//typedef long long __int64;
-#define _fastcall
-#define __fastcall
-#define _stdcall
-#define __stdcall
-#endif
-
 #define UTF8_CODEPAGE "UTF-8"
 #define UTF8_MAXSIZE     4
 
@@ -3731,6 +3723,12 @@ void rtlFailOnAssert()
 {
     throw MakeStringException(MSGAUD_user, -1, "Abort execution");
 }
+
+void rtlFailDivideByZero()
+{
+    throw MakeStringException(MSGAUD_user, -1, "Division by zero");
+}
+
 //---------------------------------------------------------------------------
 
 void deserializeRaw(unsigned recordSize, void *record, MemoryBuffer &in)
@@ -4068,6 +4066,19 @@ ECLRTL_API bool rtlIsValidReal(unsigned size, const void * data)
     return true;
 }
 
+double rtlCreateRealNull()
+{
+    union
+    {
+        byte data[8];
+        double r;
+    } u;
+    //Use a non-signaling NaN
+    memcpy(u.data, "\x01\x00\x00\x00\x00\x00\xF0\x7f", 8);
+    return u.r;
+}
+
+
 void rtlUnicodeToUnicode(size32_t outlen, UChar * out, size32_t inlen, UChar const *in)
 {
     if(inlen>outlen) inlen = outlen;

+ 4 - 0
rtl/eclrtl/eclrtl.hpp

@@ -60,6 +60,8 @@ interface IException;
 class StringBuffer;
 class MemoryBuffer;
 
+enum DBZaction { DBZnone, DBZzero, DBZnan, DBZfail }; // Different actions on divide by zero
+
 //-----------------------------------------------------------------------------
 
 // RegEx Compiler for ansii  strings (uses BOOST)
@@ -380,6 +382,7 @@ ECLRTL_API void rtlFail(int code, const char *msg);
 ECLRTL_API void rtlSysFail(int code, const char *msg);
 ECLRTL_API void rtlFailUnexpected();
 ECLRTL_API void rtlFailOnAssert();
+ECLRTL_API void rtlFailDivideByZero();
 
 ECLRTL_API void rtlReportFieldOverflow(unsigned size, unsigned max, const char * name);
 ECLRTL_API void rtlReportRowOverflow(unsigned size, unsigned max);
@@ -579,6 +582,7 @@ ECLRTL_API double rtlACos(double x);
 ECLRTL_API double rtlASin(double x);
 
 ECLRTL_API bool rtlIsValidReal(unsigned size, const void * data);
+ECLRTL_API double rtlCreateRealNull();
 
 ECLRTL_API unsigned rtlQStrLength(unsigned size);
 ECLRTL_API unsigned rtlQStrSize(unsigned length);

+ 99 - 60
rtl/nbcd/nbcds.cpp

@@ -16,241 +16,277 @@
 ############################################################################## */
 
 #include "platform.h"
-#include "nbcd.hpp"
 #include "jlib.hpp"
-#include "bcd.hpp"
+#include "rtlbcd.hpp"
+#include "nbcd.hpp"
 #include "jmutex.hpp"
 #include "jexcept.hpp"
 
-CriticalSection bcdCriticalSection;
+static CriticalSection bcdCriticalSection;
+static Decimal stack[32];
+static unsigned curStack;
 
-nbcd_decl void _fastcall  DecLock()
+//---------------------------------------------------------------------------------------------------------------------
+
+void DecLock()
 {
     bcdCriticalSection.enter();
 }
 
-nbcd_decl void _fastcall  DecUnlock()
+void DecUnlock()
 {
     bcdCriticalSection.leave();
 }
 
-static Decimal stack[32];
-unsigned  curStack;
+unsigned DecMarkStack()
+{
+    return curStack;
+}
+
+void DecReleaseStack(unsigned mark)
+{
+    curStack = mark;
+}
 
+//---------------------------------------------------------------------------------------------------------------------
 
-nbcd_decl void _fastcall  DecAbs()
+static void setDivideByZero(Decimal & tos, DBZaction dbz)
+{
+    switch (dbz)
+    {
+    case DBZfail:
+        rtlFailDivideByZero();
+        break;
+    case DBZnan:
+    case DBZzero:
+        tos.setZero();
+        break;
+    default:
+        throwUnexpected();
+    }
+}
+
+
+
+nbcd_decl void DecAbs()
 {
     stack[curStack-1].abs();
 }
 
-nbcd_decl void _fastcall  DecAdd()
+nbcd_decl void DecAdd()
 {
     curStack--;
     stack[curStack-1].add(stack[curStack]);
 }
 
-nbcd_decl int _fastcall  DecCompareNull()
+nbcd_decl int DecCompareNull()
 {
     curStack--;
     return stack[curStack].compareNull();
 }
 
-nbcd_decl int _fastcall  DecDistinct()
+nbcd_decl int DecDistinct()
 {
     curStack -= 2;
     return stack[curStack].compare(stack[curStack+1]);
 }
 
-nbcd_decl int _fastcall  DecDistinctR()
+nbcd_decl int DecDistinctR()
 {
     curStack -= 2;
     return stack[curStack+1].compare(stack[curStack]);
 }
 
-nbcd_decl void _fastcall  DecDivide()
+nbcd_decl void DecDivide(byte dbz)
 {
     curStack--;
-    stack[curStack-1].divide(stack[curStack]);
+    if (stack[curStack].isZero())
+        setDivideByZero(stack[curStack-1], (DBZaction)dbz);
+    else
+        stack[curStack-1].divide(stack[curStack]);
 }
 
-nbcd_decl void _fastcall  DecDivideR()
+nbcd_decl void DecDivideR(byte dbz)
 {
     DecSwap();
-    DecDivide();
+    DecDivide(dbz);
 }
 
-nbcd_decl void _fastcall  DecDup()
+nbcd_decl void DecDup()
 {
     stack[curStack].set(stack[curStack-1]);
     curStack++;
 }
 
-nbcd_decl void _fastcall  DecSetPrecision(unsigned char declen, unsigned char prec)
+nbcd_decl void DecSetPrecision(unsigned char declen, unsigned char prec)
 {
     stack[curStack-1].round(prec).setPrecision(declen, prec);
 }
 
-nbcd_decl void _fastcall  DecSub()
+nbcd_decl void DecSub()
 {
     curStack--;
     stack[curStack-1].subtract(stack[curStack]);
 }
 
-nbcd_decl void _fastcall  DecSubR()
+nbcd_decl void DecSubR()
 {
     DecSwap();
     DecSub();
 }
 
-nbcd_decl void _fastcall  DecInfo (unsigned & digits, unsigned & prec)
+nbcd_decl void DecInfo (unsigned & digits, unsigned & prec)
 {
     stack[curStack-1].getPrecision(digits, prec);
 }
 
-nbcd_decl void _fastcall  DecClipInfo (unsigned & digits, unsigned & prec)
+nbcd_decl void DecClipInfo (unsigned & digits, unsigned & prec)
 {
     stack[curStack-1].getClipPrecision(digits, prec);
 }
 
-nbcd_decl void _fastcall  DecLongPower(long pow)
+nbcd_decl void DecLongPower(long pow)
 {
     stack[curStack-1].power((int)pow);
 }
 
-nbcd_decl void _fastcall  DecUlongPower(unsigned long pow)
+nbcd_decl void DecUlongPower(unsigned long pow)
 {
     stack[curStack-1].power((unsigned)pow);
 }
 
-nbcd_decl void  _fastcall  DecModulus()
+nbcd_decl void  DecModulus(byte dbz)
 {
     curStack--;
-    stack[curStack-1].modulus(stack[curStack]);
+    if (stack[curStack].isZero())
+        setDivideByZero(stack[curStack-1], (DBZaction)dbz);
+    else
+        stack[curStack-1].modulus(stack[curStack]);
 }
 
-nbcd_decl void _fastcall  DecMul()
+nbcd_decl void DecMul()
 {
     curStack--;
     stack[curStack-1].multiply(stack[curStack]);
 }
 
-nbcd_decl void _fastcall  DecNegate()
+nbcd_decl void DecNegate()
 {
     stack[curStack-1].negate();
 }
 
-nbcd_decl void _fastcall  DecPopCString (unsigned length, char * buffer)
+nbcd_decl void DecPopCString (unsigned length, char * buffer)
 {
     stack[--curStack].getCString(length, buffer);
 }
 
-nbcd_decl char * _fastcall  DecPopCStringX()
+nbcd_decl char * DecPopCStringX()
 {
     return stack[--curStack].getCString();
 }
 
-nbcd_decl __int64 _fastcall  DecPopInt64()
+nbcd_decl __int64 DecPopInt64()
 {
     return stack[--curStack].getInt64();
 }
 
-nbcd_decl void _fastcall  DecPopDecimal(void * buffer,unsigned char declen,unsigned char prec)
+nbcd_decl void DecPopDecimal(void * buffer,unsigned char declen,unsigned char prec)
 {
     stack[--curStack].round(prec).getDecimal(declen, prec, buffer);
 }
 
-nbcd_decl void _fastcall  DecPopUDecimal(void * buffer,unsigned char declen,unsigned char prec)
+nbcd_decl void DecPopUDecimal(void * buffer,unsigned char declen,unsigned char prec)
 {
     stack[--curStack].round(prec).getUDecimal(declen, prec, buffer);
 }
 
-nbcd_decl int    _fastcall  DecPopLong()
+nbcd_decl int    DecPopLong()
 {
     return stack[--curStack].getInt();
 }
 
-nbcd_decl unsigned long _fastcall  DecPopUlong()
+nbcd_decl unsigned long DecPopUlong()
 {
     return stack[--curStack].getUInt();
 }
 
-nbcd_decl double _fastcall  DecPopReal()
+nbcd_decl double DecPopReal()
 {
     return stack[--curStack].getReal();
 }
 
-nbcd_decl unsigned _fastcall  DecPopString( unsigned length, char * buffer)
+nbcd_decl unsigned DecPopString( unsigned length, char * buffer)
 {
     stack[--curStack].getString(length, buffer);
     return length;  // significant length??
 }
 
-nbcd_decl void _fastcall  DecPopStringX( unsigned & length, char * & buffer)
+nbcd_decl void DecPopStringX( unsigned & length, char * & buffer)
 {
     stack[--curStack].getStringX(length, buffer);
 }
 
-nbcd_decl void _fastcall  DecPushCString(const char *s)
+nbcd_decl void DecPushCString(const char *s)
 {
     stack[curStack++].setCString(s);
 }
 
-nbcd_decl void _fastcall  DecPushInt64(__int64 value)
+nbcd_decl void DecPushInt64(__int64 value)
 {
     stack[curStack++].setInt64(value);
 }
 
-nbcd_decl void _fastcall  DecPushUInt64(unsigned __int64 value)
+nbcd_decl void DecPushUInt64(unsigned __int64 value)
 {
     stack[curStack++].setUInt64(value);
 }
 
-nbcd_decl void _fastcall  DecPushLong( long value)
+nbcd_decl void DecPushLong( long value)
 {
     stack[curStack++].setInt(value);
 }
 
-nbcd_decl void _fastcall  DecPushDecimal(const void * buffer,unsigned char declen,unsigned char prec)
+nbcd_decl void DecPushDecimal(const void * buffer,unsigned char declen,unsigned char prec)
 {
     stack[curStack++].setDecimal(declen, prec, buffer);
 }
 
-nbcd_decl void _fastcall  DecPushUDecimal(const void * buffer,unsigned char declen,unsigned char prec)
+nbcd_decl void DecPushUDecimal(const void * buffer,unsigned char declen,unsigned char prec)
 {
     stack[curStack++].setUDecimal(declen, prec, buffer);
 }
 
-nbcd_decl void _fastcall  DecPushReal( double value )
+nbcd_decl void DecPushReal( double value )
 {
     stack[curStack++].setReal(value);
 }
 
-nbcd_decl void _fastcall  DecPushString(unsigned length, const char * text)
+nbcd_decl void DecPushString(unsigned length, const char * text)
 {
     stack[curStack++].setString(length, text);
 }
 
-nbcd_decl void _fastcall  DecPushUlong( unsigned long value)
+nbcd_decl void DecPushUlong( unsigned long value)
 {
     stack[curStack++].setUInt(value);
 }
 
-nbcd_decl void _fastcall  DecRound()
+nbcd_decl void DecRound()
 {
     stack[curStack-1].round(0);
 }
 
-nbcd_decl void _fastcall  DecRoundUp()
+nbcd_decl void DecRoundUp()
 {
     stack[curStack-1].roundup(0);
 }
 
-nbcd_decl void _fastcall  DecRoundTo(unsigned places)
+nbcd_decl void DecRoundTo(unsigned places)
 {
     stack[curStack-1].round(places);
 }
 
-nbcd_decl void _fastcall  DecSwap()
+nbcd_decl void DecSwap()
 {
     char temp[sizeof(Decimal)];
     memcpy(&temp, &stack[curStack-1], sizeof(Decimal));
@@ -259,42 +295,45 @@ nbcd_decl void _fastcall  DecSwap()
 }
 
 
-nbcd_decl void _fastcall  DecTruncate()
+nbcd_decl void DecTruncate()
 {
     stack[curStack-1].truncate(0);
 }
 
-nbcd_decl void _fastcall  DecTruncateAt(unsigned places)
+nbcd_decl void DecTruncateAt(unsigned places)
 {
     stack[curStack-1].truncate(places);
 }
 
-nbcd_decl bool _fastcall  DecValid(bool isSigned, unsigned digits, const void * data)
+nbcd_decl bool DecValid(bool isSigned, unsigned digits, const void * data)
 {
     return decValid(isSigned, digits, data);
 }
 
-nbcd_decl bool _fastcall  Dec2Bool(size32_t bytes, const void * data)
+nbcd_decl bool DecValidTos()
+{
+    return stack[--curStack].isValid();
+}
+
+nbcd_decl bool Dec2Bool(size32_t bytes, const void * data)
 {
     return dec2Bool(bytes, data);
 }
 
-nbcd_decl bool _fastcall  UDec2Bool(size32_t bytes, const void * data)
+nbcd_decl bool UDec2Bool(size32_t bytes, const void * data)
 {
     return udec2Bool(bytes, data);
 }
 
-nbcd_decl int _fastcall  DecCompareDecimal(size32_t bytes, const void * _left, const void * _right)
+nbcd_decl int DecCompareDecimal(size32_t bytes, const void * _left, const void * _right)
 {
     return decCompareDecimal(bytes, _left, _right);
 }
 
-nbcd_decl int    _fastcall  DecCompareUDecimal(size32_t bytes, const void * _left, const void * _right)
+nbcd_decl int    DecCompareUDecimal(size32_t bytes, const void * _left, const void * _right)
 {
     return decCompareUDecimal(bytes, _left, _right);
 }
 
 // internal
 
-nbcd_decl void * _fastcall  DecSaveStack( void )            { UNIMPLEMENTED; }
-nbcd_decl void _fastcall  DecRestoreStack( void * )     { UNIMPLEMENTED; }

+ 101 - 0
rtl/eclrtl/rtlbcd.hpp

@@ -0,0 +1,101 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2012 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.
+############################################################################## */
+
+#ifndef _RTLBCD_HPP_
+#define _RTLBCD_HPP_
+
+#include "eclrtl.hpp"
+
+ECLRTL_API void  DecAbs( void );         // make top of stack absolute
+ECLRTL_API void  DecAdd( void );         // add top two values on stack and replace with result
+ECLRTL_API int   DecCompareNull( void ); // compare top of stack to NULL, returns result, takes value of stack
+ECLRTL_API int   DecDistinct( void );    // compares second to top value on stack, removes them and returns result
+ECLRTL_API int   DecDistinctR( void );   // compares top to second value on stack, removes them and returns result
+ECLRTL_API void  DecDivide(byte dbz);      // divide second by top value on stack and replace with result
+ECLRTL_API void  DecDivideR(byte dbz);     // divide top by second value on stack and replace with result
+ECLRTL_API void  DecDup( void );         // duplicate value on top of decimal stack
+ECLRTL_API void  DecSetPrecision(unsigned char declen, unsigned char prec); // changes length and precision of top value on stack
+ECLRTL_API void  DecSub( void );         // substract top from second value on stack and replace with result
+ECLRTL_API void  DecSubR( void );        // substract second from top value on stack and replace with result
+ECLRTL_API void  DecInfo(unsigned & digits, unsigned & prec); // returns the digits and precision of top value on stack
+ECLRTL_API void  DecClipInfo(unsigned & digits, unsigned & prec);
+ECLRTL_API void  DecLongPower(long pow);   // calculates top of stack to the power of long and replaces with result
+ECLRTL_API void  DecModulus(byte dbz);   // modulus second by top value on stack and replace with result
+ECLRTL_API void  DecMul( void );         // multiply values top and second on the stack and replace with result
+ECLRTL_API void  DecNegate( void );      // negate value on top of the decimal stack
+ECLRTL_API void  DecPopCString (unsigned, char *); // Pops decimal accumulator into CString
+ECLRTL_API char * DecPopCStringX();       // Pop decimal accumulator into CString allocated on heap
+ECLRTL_API __int64 DecPopInt64( void );    // Pops decimal accumulator into __Int64
+ECLRTL_API void  DecPopDecimal(void * tgt,unsigned char declen,unsigned char prec); // Pops decimal value of the stack
+ECLRTL_API void  DecPopUDecimal(void * tgt,unsigned char declen,unsigned char prec); // Pops unsigned decimal value of the stack
+ECLRTL_API int   DecPopLong( void );       // Pops decimal accumulator into long
+ECLRTL_API unsigned long  DecPopUlong( void );    // Pops decimal accumulator into unsigned long
+ECLRTL_API double         DecPopReal( void );     // Pops decimal accumulator into real (double)
+ECLRTL_API unsigned     DecPopString( unsigned, char * );   // Pops decimal accumulator into string
+ECLRTL_API void  DecPopStringX( unsigned &, char * & );   // Pops decimal accumulator into string, determines size and allocates string
+ECLRTL_API void  DecPushCString(const char *s);  // Pushes CString onto decimal stack
+ECLRTL_API void  DecPushInt64(__int64 ); // Pushes __Int64 onto decimal stack
+ECLRTL_API void  DecPushUInt64(unsigned __int64 ); // Pushes unsigned __Int64 onto decimal stack
+ECLRTL_API void  DecPushLong( long );    // Pushes long value onto decimal stack
+ECLRTL_API void  DecPushDecimal(const void *,unsigned char declen,unsigned char prec); // Pushes decimal value onto the stack
+ECLRTL_API void  DecPushUDecimal(const void *,unsigned char declen,unsigned char prec); // Pushes unsigned decimal value onto the stack
+ECLRTL_API void  DecPushReal( double d );  // pushes real (double) onto decimal stack
+ECLRTL_API void  DecPushString(unsigned, const char * ); // Pushes string onto decimal stack
+ECLRTL_API void  DecPushUlong( unsigned long ); // Pushes unsigned long value onto decimal stack
+ECLRTL_API void  DecRestoreStack( void * ); // Restore decimal stack
+ECLRTL_API void  DecRound( void );       // round value on top of decimal stack
+ECLRTL_API void  DecRoundUp( void );       // round value on top of decimal stack
+ECLRTL_API void  DecRoundTo( unsigned places );       // round value on top of decimal stack
+ECLRTL_API void  * DecSaveStack( void );   // Save decimal stack
+ECLRTL_API void  DecSwap( void );          // swap top and second values on decimal stack
+ECLRTL_API void  DecTruncate( void );       // truncate value on top of decimal stack
+ECLRTL_API void  DecTruncateAt(unsigned places);       // truncate value on top of decimal stack
+ECLRTL_API void  DecUlongPower(unsigned long pow); // calculates top of stack to the power of unsigned long and replaces with result
+
+ECLRTL_API void  DecLock();
+ECLRTL_API void  DecUnlock();
+ECLRTL_API bool  DecValid(bool isSigned, unsigned digits, const void * data);
+ECLRTL_API bool  DecValidTos();
+ECLRTL_API bool  Dec2Bool(size32_t bytes, const void * data);
+ECLRTL_API bool  UDec2Bool(size32_t bytes, const void * data);
+
+ECLRTL_API int   DecCompareDecimal(size32_t bytes, const void * _left, const void * _right);
+ECLRTL_API int   DecCompareUDecimal(size32_t bytes, const void * _left, const void * _right);
+
+// internal
+void                     AddBytes(unsigned dest,unsigned src,unsigned num); 
+ECLRTL_API char  DecClip(void *);
+ECLRTL_API void  DecRoundPos(void *,int by);
+ECLRTL_API void  SetMAccum(unsigned char c);
+
+ECLRTL_API void  DecLock();
+ECLRTL_API void  DecUnlock();
+ECLRTL_API unsigned DecMarkStack();
+ECLRTL_API void DecReleaseStack(unsigned mark);
+
+class ECLRTL_API BcdCriticalBlock
+{
+public:
+    inline BcdCriticalBlock()       { DecLock(); mark = DecMarkStack(); }
+    inline ~BcdCriticalBlock()      { DecReleaseStack(mark); DecUnlock(); }
+
+protected:
+    unsigned mark;
+};
+
+
+#endif

+ 4 - 4
rtl/nbcd/nbcdtest.cpp

@@ -16,10 +16,10 @@
 ############################################################################## */
 
 #include "platform.h"
-#define DECIMAL_OVERLOAD
-#include "nbcd.hpp"
-#include "bcd.hpp"
 #include "jlog.hpp"
+#include "rtlbcd.hpp"
+
+#include "nbcd.hpp"
 
 #define _elements_in(a) (sizeof(a)/sizeof((a)[0]))
 
@@ -113,7 +113,7 @@ protected:
         cppunit_assert(strcmp(expected, temp) == 0, "ERROR: testDivide/getCString: expected '%s', got '%s'", expected, temp);
         DecPushCString(left);
         DecPushCString(right);
-        DecDivide();
+        DecDivide(DBZzero);
         DecPopCString(sizeof(temp),temp);
         cppunit_assert(strcmp(expected, temp) == 0, "ERROR: testDivide/DecDivide: expected '%s', got '%s'", expected, temp);
     }

+ 1 - 1
rtl/eclrtl/rtlint.cpp

@@ -24,7 +24,7 @@
 #include "jlib.hpp"
 #include "jptree.hpp"
 #include "eclrtl.hpp"
-#include "bcd.hpp"
+#include "rtlbcd.hpp"
 
 //#define _FAST_AND_LOOSE_
 

+ 1 - 18
rtl/eclrtl/rtlqstr.cpp

@@ -25,7 +25,7 @@
 #include "jlib.hpp"
 #include "jptree.hpp"
 #include "eclrtl.hpp"
-#include "bcd.hpp"
+#include "rtlbcd.hpp"
 #include "unicode/uchar.h"
 #include "unicode/ucol.h"
 #include "unicode/ustring.h"
@@ -37,14 +37,6 @@
 #include "jlog.hpp"
 #include "jmd5.hpp"
 
-#ifndef _WIN32
-//typedef long long __int64;
-#define _fastcall
-#define __fastcall
-#define _stdcall
-#define __stdcall
-#endif
-
 //=============================================================================
 // Miscellaneous string functions...
 
@@ -520,15 +512,6 @@ bool rtlQStrToBool(size32_t inlen, const char *in)
     return false;
 }
 
-#ifndef _WIN32
-extern "C" ECLRTL_API void cw_rtlQStrToStr(unsigned outlen, char * out, unsigned inlen, const char * in)
-#else
-extern "C" ECLRTL_API void __stdcall cw_rtlQStrToStr(unsigned outlen, char * out, unsigned inlen, const char * in)
-#endif
-{
-    rtlQStrToStr(QStrLength(outlen), out, QStrLength(inlen), in);
-}
-
 //---------------------------------------------------------------------------
 
 ECLRTL_API void rtlCreateQStrRange(size32_t & outlen, char * & out, unsigned fieldLen, unsigned compareLen, size32_t len, const char * qstr, byte fill)

+ 1 - 9
rtl/eclrtl/rtlxml.cpp

@@ -25,7 +25,7 @@
 #include "jlib.hpp"
 #include "jptree.hpp"
 #include "eclrtl.hpp"
-#include "bcd.hpp"
+#include "rtlbcd.hpp"
 #include "unicode/uchar.h"
 #include "unicode/ucol.h"
 #include "unicode/ustring.h"
@@ -38,14 +38,6 @@
 #include "jmd5.hpp"
 #include "rtlqstr.ipp"
 
-#ifndef _WIN32
-//typedef long long __int64;
-#define _fastcall
-#define __fastcall
-#define _stdcall
-#define __stdcall
-#endif
-
 //---------------------------------------------------------------------------
 
 void outputXmlString(unsigned len, const char *field, const char *fieldname, StringBuffer &out)

+ 3 - 2
rtl/nbcd/CMakeLists.txt

@@ -27,8 +27,9 @@ project( nbcd )
 
 set ( SRCS 
       nbcd.cpp 
-      nbcds.cpp 
-      nbcdtest.cpp 
+
+      nbcd.hpp 
+
       sourcedoc.xml
     )
 

+ 0 - 105
rtl/nbcd/bcd.hpp

@@ -1,105 +0,0 @@
-/*##############################################################################
-
-    HPCC SYSTEMS software Copyright (C) 2012 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.
-############################################################################## */
-
-#ifndef _BCD_
-#define _BCD_
-#include "platform.h"
-
-#ifdef _WIN32
- #ifdef NBCD_EXPORTS
-  #define nbcd_decl __declspec(dllexport)
- #else
-  #define nbcd_decl __declspec(dllimport)
- #endif
-#else
- #define nbcd_decl
-#endif
-
-#ifndef _WIN32
-#define _fastcall
-#define __fastcall
-#endif
-
-nbcd_decl void  _fastcall  DecAbs( void );         // make top of stack absolute
-nbcd_decl void  _fastcall  DecAdd( void );         // add top two values on stack and replace with result
-nbcd_decl int   _fastcall  DecCompareNull( void ); // compare top of stack to NULL, returns result, takes value of stack
-nbcd_decl int   _fastcall  DecDistinct( void );    // compares second to top value on stack, removes them and returns result
-nbcd_decl int   _fastcall  DecDistinctR( void );   // compares top to second value on stack, removes them and returns result
-nbcd_decl void  _fastcall  DecDivide( void );      // divide second by top value on stack and replace with result
-nbcd_decl void  _fastcall  DecDivideR( void );     // divide top by second value on stack and replace with result
-nbcd_decl void  _fastcall  DecDup( void );         // duplicate value on top of decimal stack
-nbcd_decl void  _fastcall  DecSetPrecision(unsigned char declen, unsigned char prec); // changes length and precision of top value on stack
-nbcd_decl void  _fastcall  DecSub( void );         // substract top from second value on stack and replace with result
-nbcd_decl void  _fastcall  DecSubR( void );        // substract second from top value on stack and replace with result
-nbcd_decl void  _fastcall  DecInfo(unsigned & digits, unsigned & prec); // returns the digits and precision of top value on stack
-nbcd_decl void  _fastcall  DecClipInfo(unsigned & digits, unsigned & prec);
-nbcd_decl void  _fastcall  DecLongPower(long pow);   // calculates top of stack to the power of long and replaces with result
-nbcd_decl void  _fastcall  DecModulus( void );   // modulus second by top value on stack and replace with result
-nbcd_decl void  _fastcall  DecMul( void );         // multiply values top and second on the stack and replace with result
-nbcd_decl void  _fastcall  DecNegate( void );      // negate value on top of the decimal stack
-nbcd_decl void  _fastcall  DecPopCString (unsigned, char *); // Pops decimal accumulator into CString
-nbcd_decl char * _fastcall  DecPopCStringX();       // Pop decimal accumulator into CString allocated on heap
-nbcd_decl __int64 _fastcall  DecPopInt64( void );    // Pops decimal accumulator into __Int64 
-nbcd_decl void  _fastcall  DecPopDecimal(void * tgt,unsigned char declen,unsigned char prec); // Pops decimal value of the stack
-nbcd_decl void  _fastcall  DecPopUDecimal(void * tgt,unsigned char declen,unsigned char prec); // Pops unsigned decimal value of the stack
-nbcd_decl int   _fastcall  DecPopLong( void );       // Pops decimal accumulator into long
-nbcd_decl unsigned long  _fastcall  DecPopUlong( void );    // Pops decimal accumulator into unsigned long
-nbcd_decl double         _fastcall  DecPopReal( void );     // Pops decimal accumulator into real (double)
-nbcd_decl unsigned     _fastcall  DecPopString( unsigned, char * );   // Pops decimal accumulator into string
-nbcd_decl void  _fastcall  DecPopStringX( unsigned &, char * & );   // Pops decimal accumulator into string, determines size and allocates string
-nbcd_decl void  _fastcall  DecPushCString(const char *s);  // Pushes CString onto decimal stack
-nbcd_decl void  _fastcall  DecPushInt64(__int64 ); // Pushes __Int64 onto decimal stack
-nbcd_decl void  _fastcall  DecPushUInt64(unsigned __int64 ); // Pushes unsigned __Int64 onto decimal stack
-nbcd_decl void  _fastcall  DecPushLong( long );    // Pushes long value onto decimal stack 
-nbcd_decl void  _fastcall  DecPushDecimal(const void *,unsigned char declen,unsigned char prec); // Pushes decimal value onto the stack
-nbcd_decl void  _fastcall  DecPushUDecimal(const void *,unsigned char declen,unsigned char prec); // Pushes unsigned decimal value onto the stack
-nbcd_decl void  _fastcall  DecPushReal( double d );  // pushes real (double) onto decimal stack
-nbcd_decl void  _fastcall  DecPushString(unsigned, const char * ); // Pushes string onto decimal stack
-nbcd_decl void  _fastcall  DecPushUlong( unsigned long ); // Pushes unsigned long value onto decimal stack
-nbcd_decl void  _fastcall  DecRestoreStack( void * ); // Restore decimal stack
-nbcd_decl void  _fastcall  DecRound( void );       // round value on top of decimal stack
-nbcd_decl void  _fastcall  DecRoundUp( void );       // round value on top of decimal stack
-nbcd_decl void  _fastcall  DecRoundTo( unsigned places );       // round value on top of decimal stack
-nbcd_decl void  * _fastcall  DecSaveStack( void );   // Save decimal stack
-nbcd_decl void  _fastcall  DecSwap( void );          // swap top and second values on decimal stack 
-nbcd_decl void  _fastcall  DecTruncate( void );       // truncate value on top of decimal stack
-nbcd_decl void  _fastcall  DecTruncateAt(unsigned places);       // truncate value on top of decimal stack
-nbcd_decl void  _fastcall  DecUlongPower(unsigned long pow); // calculates top of stack to the power of unsigned long and replaces with result
-
-nbcd_decl void  _fastcall  DecLock();
-nbcd_decl void  _fastcall  DecUnlock();
-nbcd_decl bool  _fastcall  DecValid(bool isSigned, unsigned digits, const void * data);
-nbcd_decl bool  _fastcall  Dec2Bool(size32_t bytes, const void * data);
-nbcd_decl bool  _fastcall  UDec2Bool(size32_t bytes, const void * data);
-
-nbcd_decl int   _fastcall  DecCompareDecimal(size32_t bytes, const void * _left, const void * _right);
-nbcd_decl int   _fastcall  DecCompareUDecimal(size32_t bytes, const void * _left, const void * _right);
-
-// internal
-void                     AddBytes(unsigned dest,unsigned src,unsigned num); 
-nbcd_decl char  _fastcall  DecClip(void *);       
-nbcd_decl void  _fastcall  DecRoundPos(void *,int by);        
-nbcd_decl void  _fastcall  SetMAccum(unsigned char c);                       
-
-struct nbcd_decl BcdCriticalBlock
-{
-    inline BcdCriticalBlock()       { DecLock(); }
-    inline ~BcdCriticalBlock()      { DecUnlock(); }
-};
-
-
-#endif

+ 11 - 1
rtl/nbcd/nbcd.cpp

@@ -18,6 +18,7 @@
 #include "platform.h"
 #include "nbcd.hpp"
 #include "jlib.hpp"
+#include "jexcept.hpp"
 
 #ifdef _WIN32
  #define NOMEMCPY volatile          // stop VC++ doing a stupid optimization
@@ -159,7 +160,7 @@ Decimal & Decimal::divide(const Decimal & other)
     }
     if (hi2 < lo2)
     {
-        //divide by zero
+        //Division by zero defined to return 0 instead of throw an exception
         setZero();
         return *this;
     }
@@ -250,6 +251,14 @@ void Decimal::extendRange(byte oLsb, byte oMsb)
 }
 
 
+bool Decimal::isZero() const
+{
+    //NB: Round towards zero
+    int lo, hi;
+    clip(lo, hi);
+    return (hi < lo);
+}
+
 Decimal & Decimal::modulus(const Decimal & other)
 {
     Decimal left(*this);
@@ -1157,6 +1166,7 @@ void Decimal::setZero()
     digits[zeroDigit] = 0;
 }
 
+
 //---------------------------------------------------------------------------
 
 

+ 12 - 5
rtl/nbcd/nbcd.hpp

@@ -28,6 +28,8 @@
  #define nbcd_decl
 #endif
 
+#define DECIMAL_OVERLOAD
+
 template <byte length, byte precision> class decimal;
 
 /*
@@ -84,6 +86,10 @@ public:
     void getClipPrecision(unsigned & digits, unsigned & precision);
     void getPrecision(unsigned & digits, unsigned & precison);
 
+    // MORE: We could support NaNs for decimals at a later date by adding a member to this class.
+    bool isZero() const;
+    bool isValid() const { return true; }
+
     void set(const Decimal & value);
     void setCString(const char * buffer);
     void setDecimal(byte length, byte precision, const void * buffer);
@@ -181,10 +187,11 @@ inline bool operator > (const Decimal & left, const Decimal & right) { return le
 inline bool operator < (const Decimal & left, const Decimal & right) { return left.compare(right) < 0; }
 #endif
 
-bool dec2Bool(size32_t bytes, const void * data);
-bool udec2Bool(size32_t bytes, const void * data);
-int decCompareDecimal(size32_t bytes, const void * _left, const void * _right);
-int decCompareUDecimal(size32_t bytes, const void * _left, const void * _right);
-bool decValid(bool isSigned, unsigned digits, const void * data);
+//Various utility helper functions:
+nbcd_decl bool dec2Bool(size32_t bytes, const void * data);
+nbcd_decl bool udec2Bool(size32_t bytes, const void * data);
+nbcd_decl int decCompareDecimal(size32_t bytes, const void * _left, const void * _right);
+nbcd_decl int decCompareUDecimal(size32_t bytes, const void * _left, const void * _right);
+nbcd_decl bool decValid(bool isSigned, unsigned digits, const void * data);
 
 #endif

+ 4 - 0
system/jlib/jstring.cpp

@@ -218,6 +218,8 @@ StringBuffer & StringBuffer::append(double value)
         case '.':
         case 'E':
         case 'e':
+        case 'N': // Not a number/infinity
+        case 'n':
             return *this;
         }
         len++;
@@ -236,6 +238,8 @@ StringBuffer & StringBuffer::append(float value)
         case '.':
         case 'E':
         case 'e':
+        case 'N': // Not a number/infinity
+        case 'n':
             return *this;
         }
         len++;

+ 47 - 0
testing/ecl/dbz1.ecl

@@ -0,0 +1,47 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//nothor
+//nothorlcr
+//noroxie
+
+//Test division by zero - default action to return 0
+#option ('divideByZero', '0'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100 DIV 1);
+output(100.0 / 1.0);
+output(100.1D / 1.0D);
+
+output(100 DIV cintZero);
+output(100.0 / crealZero);
+output(100.1D / cdecZero);
+            
+output(5 * (101 DIV cintZero));
+output(5 * (101.0 / crealZero));
+output(5D * (101.1D / cdecZero));
+            
+output(100 DIV intZero);
+output(100.0 / realZero);
+output(100.1D / decZero);

+ 33 - 0
testing/ecl/dbz2a.ecl

@@ -0,0 +1,33 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//nothor
+//nothorlcr
+//noroxie
+
+//Test division by zero - default action to return 0
+#option ('divideByZero', 'fail'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100 DIV intZero);

+ 33 - 0
testing/ecl/dbz2b.ecl

@@ -0,0 +1,33 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//nothor
+//nothorlcr
+//noroxie
+
+//Test division by zero - default action to return 0
+#option ('divideByZero', 'fail'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100.0 / realZero);

+ 33 - 0
testing/ecl/dbz2c.ecl

@@ -0,0 +1,33 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//nothor
+//nothorlcr
+//noroxie
+
+//Test division by zero - default action to return 0
+#option ('divideByZero', 'fail'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(100.1D / decZero);

+ 79 - 0
testing/ecl/dbz3.ecl

@@ -0,0 +1,79 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2013 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.
+############################################################################## */
+
+//nothor
+//nothorlcr
+//noroxie
+
+//Test division by zero - fail instead of returning 0
+#option ('divideByZero', 'nan'); 
+
+unsigned cintZero := 0;
+real crealZero := 0.0;
+decimal10_2 cdecZero := 0.0D;
+
+unsigned intZero := 0 : stored('intZero');
+real realZero := 0.0 : stored('realZero');
+decimal10_2 decZero := 0.0D : stored('decZero');
+
+output(NOT ISNULL(100 DIV 1));
+output(NOT ISNULL(100.0 / 1.0));
+output(NOT ISNULL(100.1D / 1.0D));
+
+output('Constant Divide:');
+output(ISNULL(100 DIV cintZero));
+output(ISNULL(100.0 / crealZero));
+output(ISNULL(100.1D / cdecZero));
+            
+output('Constant Divide Multiply:');
+output(ISNULL(5 * (101 DIV cintZero)));
+output(ISNULL(5 * (101.0 / crealZero)));
+output(ISNULL(5D * (101.1D / cdecZero)));
+            
+output('Runtime Divide:');
+output(ISNULL(100 DIV intZero));
+output(ISNULL(100.0 / realZero));
+output(ISNULL(100.1D / decZero));
+
+//--- check modulus
+output('Modulus:');
+
+output(NOT ISNULL(100 % 1));
+output(NOT ISNULL(100.0 % 1.0));
+output(NOT ISNULL(100.1D % 1.0D));
+
+output('Constant Modulus:');
+output(ISNULL(100 % cintZero));
+output(ISNULL(100.0 % crealZero));
+output(ISNULL(100.1D % cdecZero));
+            
+output('Constant Modulus Multiply:');
+output(ISNULL(5 * (101 % cintZero)));
+output(ISNULL(5 * (101.0 % crealZero)));
+output(ISNULL(5D * (101.1D % cdecZero)));
+            
+output('Runtime Modulus:');
+output(ISNULL(100 % intZero));
+output(ISNULL(100.0 % realZero));
+output(ISNULL(100.1D % decZero));
+
+output('Miscellaneous');
+output(100.0 / crealZero);
+output(100.0 / realZero);
+output(1.0e300 * nofold(1.0e300));
+output(-1.0e300 * nofold(1.0e300));
+

+ 36 - 0
testing/ecl/key/dbz1.xml

@@ -0,0 +1,36 @@
+<Dataset name='Result 1'>
+ <Row><Result_1>100</Result_1></Row>
+</Dataset>
+<Dataset name='Result 2'>
+ <Row><Result_2>100.0</Result_2></Row>
+</Dataset>
+<Dataset name='Result 3'>
+ <Row><Result_3>100.1</Result_3></Row>
+</Dataset>
+<Dataset name='Result 4'>
+ <Row><Result_4>0</Result_4></Row>
+</Dataset>
+<Dataset name='Result 5'>
+ <Row><Result_5>0.0</Result_5></Row>
+</Dataset>
+<Dataset name='Result 6'>
+ <Row><Result_6>0</Result_6></Row>
+</Dataset>
+<Dataset name='Result 7'>
+ <Row><Result_7>0</Result_7></Row>
+</Dataset>
+<Dataset name='Result 8'>
+ <Row><Result_8>0.0</Result_8></Row>
+</Dataset>
+<Dataset name='Result 9'>
+ <Row><Result_9>0</Result_9></Row>
+</Dataset>
+<Dataset name='Result 10'>
+ <Row><Result_10>0</Result_10></Row>
+</Dataset>
+<Dataset name='Result 11'>
+ <Row><Result_11>0.0</Result_11></Row>
+</Dataset>
+<Dataset name='Result 12'>
+ <Row><Result_12>0</Result_12></Row>
+</Dataset>

+ 1 - 0
testing/ecl/key/dbz2a.xml

@@ -0,0 +1 @@
+<Error><source>eclagent</source><code>-1</code><message>System error: -1: Division by zero</message></Error>

+ 1 - 0
testing/ecl/key/dbz2b.xml

@@ -0,0 +1 @@
+<Error><source>eclagent</source><code>-1</code><message>System error: -1: Division by zero</message></Error>

+ 1 - 0
testing/ecl/key/dbz2c.xml

@@ -0,0 +1 @@
+<Error><source>eclagent</source><code>-1</code><message>System error: -1: Division by zero</message></Error>

+ 108 - 0
testing/ecl/key/dbz3.xml

@@ -0,0 +1,108 @@
+<Dataset name='Result 1'>
+ <Row><Result_1>true</Result_1></Row>
+</Dataset>
+<Dataset name='Result 2'>
+ <Row><Result_2>true</Result_2></Row>
+</Dataset>
+<Dataset name='Result 3'>
+ <Row><Result_3>true</Result_3></Row>
+</Dataset>
+<Dataset name='Result 4'>
+ <Row><Result_4>Constant Divide:</Result_4></Row>
+</Dataset>
+<Dataset name='Result 5'>
+ <Row><Result_5>false</Result_5></Row>
+</Dataset>
+<Dataset name='Result 6'>
+ <Row><Result_6>true</Result_6></Row>
+</Dataset>
+<Dataset name='Result 7'>
+ <Row><Result_7>false</Result_7></Row>
+</Dataset>
+<Dataset name='Result 8'>
+ <Row><Result_8>Constant Divide Multiply:</Result_8></Row>
+</Dataset>
+<Dataset name='Result 9'>
+ <Row><Result_9>false</Result_9></Row>
+</Dataset>
+<Dataset name='Result 10'>
+ <Row><Result_10>true</Result_10></Row>
+</Dataset>
+<Dataset name='Result 11'>
+ <Row><Result_11>false</Result_11></Row>
+</Dataset>
+<Dataset name='Result 12'>
+ <Row><Result_12>Runtime Divide:</Result_12></Row>
+</Dataset>
+<Dataset name='Result 13'>
+ <Row><Result_13>false</Result_13></Row>
+</Dataset>
+<Dataset name='Result 14'>
+ <Row><Result_14>true</Result_14></Row>
+</Dataset>
+<Dataset name='Result 15'>
+ <Row><Result_15>false</Result_15></Row>
+</Dataset>
+<Dataset name='Result 16'>
+ <Row><Result_16>Modulus:</Result_16></Row>
+</Dataset>
+<Dataset name='Result 17'>
+ <Row><Result_17>true</Result_17></Row>
+</Dataset>
+<Dataset name='Result 18'>
+ <Row><Result_18>true</Result_18></Row>
+</Dataset>
+<Dataset name='Result 19'>
+ <Row><Result_19>true</Result_19></Row>
+</Dataset>
+<Dataset name='Result 20'>
+ <Row><Result_20>Constant Modulus:</Result_20></Row>
+</Dataset>
+<Dataset name='Result 21'>
+ <Row><Result_21>false</Result_21></Row>
+</Dataset>
+<Dataset name='Result 22'>
+ <Row><Result_22>false</Result_22></Row>
+</Dataset>
+<Dataset name='Result 23'>
+ <Row><Result_23>false</Result_23></Row>
+</Dataset>
+<Dataset name='Result 24'>
+ <Row><Result_24>Constant Modulus Multiply:</Result_24></Row>
+</Dataset>
+<Dataset name='Result 25'>
+ <Row><Result_25>false</Result_25></Row>
+</Dataset>
+<Dataset name='Result 26'>
+ <Row><Result_26>false</Result_26></Row>
+</Dataset>
+<Dataset name='Result 27'>
+ <Row><Result_27>false</Result_27></Row>
+</Dataset>
+<Dataset name='Result 28'>
+ <Row><Result_28>Runtime Modulus:</Result_28></Row>
+</Dataset>
+<Dataset name='Result 29'>
+ <Row><Result_29>false</Result_29></Row>
+</Dataset>
+<Dataset name='Result 30'>
+ <Row><Result_30>false</Result_30></Row>
+</Dataset>
+<Dataset name='Result 31'>
+ <Row><Result_31>false</Result_31></Row>
+</Dataset>
+<Dataset name='Result 32'>
+ <Row><Result_32>Miscellaneous</Result_32></Row>
+</Dataset>
+<Dataset name='Result 33'>
+ <Row><Result_33>nan</Result_33></Row>
+</Dataset>
+<Dataset name='Result 34'>
+ <Row><Result_34>nan</Result_34></Row>
+</Dataset>
+<Dataset name='Result 35'>
+ <Row><Result_35>inf</Result_35></Row>
+</Dataset>
+<Dataset name='Result 36'>
+ <Row><Result_36>-inf</Result_36></Row>
+</Dataset>