Explorar el Código

Merge branch 'candidate-6.4.0'

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman hace 8 años
padre
commit
74145770dc
Se han modificado 40 ficheros con 394 adiciones y 250 borrados
  1. 3 1
      cmake_modules/FindICU.cmake
  2. 1 1
      common/thorhelper/layouttrans.cpp
  3. 9 1
      common/thorhelper/roxiehelper.cpp
  4. 9 9
      common/thorhelper/thorsoapcall.cpp
  5. 12 4
      common/workunit/referencedfilelist.cpp
  6. 2 2
      deployment/deploy/DeployTask.cpp
  7. 8 5
      docs/ECLLanguageReference/ECLR-includer.xml
  8. 4 4
      docs/common/Version.xml
  9. 4 4
      docs/common/Version.xml.in
  10. 4 2
      ecl/hqlcpp/hqlhtcpp.cpp
  11. 1 1
      esp/bindings/SOAP/Platform/soapmessage.cpp
  12. 1 1
      esp/bindings/SOAP/client/soapclient.cpp
  13. 1 1
      esp/esdllib/esdl_def.cpp
  14. 1 1
      esp/esdllib/esdl_transformer2.cpp
  15. 1 1
      esp/logging/logginglib/logthread.hpp
  16. 1 0
      esp/platform/tokenserialization.hpp
  17. 4 2
      esp/scm/ws_workunits.ecm
  18. 102 93
      esp/services/ws_workunits/ws_workunitsHelpers.cpp
  19. 2 0
      esp/services/ws_workunits/ws_workunitsHelpers.hpp
  20. 21 4
      esp/services/ws_workunits/ws_workunitsQuerySets.cpp
  21. 10 1
      initfiles/sbin/hpcc_setenv.in
  22. 7 7
      plugins/couchbase/couchbaseembed.cpp
  23. 19 12
      plugins/timelib/timelib.cpp
  24. 14 3
      roxie/ccd/ccdprotocol.cpp
  25. 3 3
      roxie/ccd/ccdserver.cpp
  26. 6 0
      roxie/ccd/ccdserver.hpp
  27. 89 70
      system/jlib/jdebug.cpp
  28. 1 1
      system/security/LdapSecurity/ldapconnection.cpp
  29. 2 1
      system/security/shared/caching.cpp
  30. 4 1
      system/security/shared/secloader.hpp
  31. 2 2
      testing/regress/ecl/aaalibrary2.ecl
  32. 8 1
      testing/regress/ecl/httpcall_multiheader.ecl
  33. 4 1
      testing/regress/ecl/key/httpcall_multiheader.xml
  34. 3 0
      testing/regress/ecl/key/library1.xml
  35. 7 1
      testing/regress/ecl/key/soapcall_multihttpheader.xml
  36. 6 3
      testing/regress/ecl/library1.ecl
  37. 3 2
      testing/regress/ecl/library2.ecl
  38. 4 2
      testing/regress/ecl/library2a.ecl
  39. 10 1
      testing/regress/ecl/soapcall_multihttpheader.ecl
  40. 1 1
      testing/unittests/jlibtests.cpp

+ 3 - 1
cmake_modules/FindICU.cmake

@@ -63,7 +63,9 @@ IF (NOT ICU_FOUND)
     ELSE()
       STRING(REPLACE "icuuc" "icuin" ICU_EXTRA1 "${ICU_LIBRARIES}")
     ENDIF()
-    set (ICU_LIBRARIES ${ICU_LIBRARIES} ${ICU_EXTRA1} ${ICU_EXTRA2} )
+    # The order is important for lib2 processing:
+    # depender, such as icuil8n, should be placed before the dependee
+    set (ICU_LIBRARIES ${ICU_EXTRA1} ${ICU_LIBRARIES} ${ICU_EXTRA2} )
   ENDIF()
 
 

+ 1 - 1
common/thorhelper/layouttrans.cpp

@@ -794,7 +794,7 @@ public:
             Owned<ITypeInfo> type;
             IAtom * name;
             size32_t size;
-            unsigned keyed;
+            unsigned keyed = 0;
             unsigned f;
             for(f = 0; getFieldData(m, f, type, name, size, keyed); ++f)
             {

+ 9 - 1
common/thorhelper/roxiehelper.cpp

@@ -527,7 +527,10 @@ public:
     {
         sorter->reset();
     }
-
+    ~SortedInputReader()
+    {
+        sorter->reset();
+    }
     virtual const void *nextRow()
     {
         if (!firstRead)
@@ -613,6 +616,11 @@ class CSortAlgorithm : implements CInterfaceOf<ISortAlgorithm>
 public:
     CSortAlgorithm() { elapsedCycles = 0; }
 
+    virtual void beforeDispose() override
+    {
+        reset();
+    }
+
     virtual void getSortedGroup(ConstPointerArray & result)
     {
         loop

+ 9 - 9
common/thorhelper/thorsoapcall.cpp

@@ -766,6 +766,15 @@ public:
         if (flags & SOAPFhttpheaders)
             httpHeaders.set(s.setown(helper->getHttpHeaders()));
 
+        StringAttr proxyAddress;
+        proxyAddress.set(s.setown(helper->getProxyAddress()));
+        if (!proxyAddress.isEmpty())
+        {
+            UrlListParser proxyUrlListParser(proxyAddress);
+            if (0 == proxyUrlListParser.getUrls(proxyUrlArray))
+                throw MakeStringException(0, "SOAPCALL PROXYADDRESS specified no URLs");
+        }
+
         if (wscType == STsoap)
         {
             soapaction.set(s.setown(helper->getSoapAction()));
@@ -780,15 +789,6 @@ public:
             if(httpHeaderValue.get() && !isValidHttpValue(httpHeaderValue.get()))
                 throw MakeStringException(-1, "HTTPHEADER value contained illegal characters: %s", httpHeaderValue.get());
 
-            StringAttr proxyAddress;
-            proxyAddress.set(s.setown(helper->getProxyAddress()));
-            if (!proxyAddress.isEmpty())
-            {
-                UrlListParser proxyUrlListParser(proxyAddress);
-                if (0 == proxyUrlListParser.getUrls(proxyUrlArray))
-                    throw MakeStringException(0, "SOAPCALL PROXYADDRESS specified no URLs");
-            }
-
             if ((flags & SOAPFliteral) && (flags & SOAPFencoding))
                 throw MakeStringException(0, "SOAPCALL 'LITERAL' and 'ENCODING' options are mutually exclusive");
 

+ 12 - 4
common/workunit/referencedfilelist.cpp

@@ -337,7 +337,10 @@ void ReferencedFile::resolveLocal(const char *dstCluster, const char *srcCluster
     if(df)
         processLocalFileInfo(df, dstCluster, srcCluster, subfiles);
     else
+    {
         flags |= RefFileNotFound;
+        DBGLOG("ReferencedFile not found (local) %s", logicalName.str());
+    }
 }
 
 IPropertyTree *ReferencedFile::getRemoteFileTree(IUserDescriptor *user, INode *remote, const char *remotePrefix)
@@ -404,6 +407,9 @@ void ReferencedFile::resolveRemote(IUserDescriptor *user, INode *remote, const c
     }
 
     flags |= RefFileNotFound;
+
+    StringBuffer dest;
+    DBGLOG("ReferencedFile not found %s [dali=%s, remote=%s, prefix=%s]", logicalName.str(), daliip.get(), remote ? remote->endpoint().getUrlStr(dest).str() : nullptr, remotePrefix);
 }
 
 void ReferencedFile::resolve(const char *dstCluster, const char *srcCluster, IUserDescriptor *user, INode *remote, const char *remotePrefix, bool checkLocalFirst, StringArray *subfiles, bool _trackSubFiles, bool resolveForeign)
@@ -438,13 +444,13 @@ void ReferencedFile::cloneInfo(unsigned updateFlags, IDFUhelper *helper, IUserDe
     catch (IException *e)
     {
         flags |= RefFileCopyInfoFailed;
-        DBGLOG(e);
+        DBGLOG(e, "ReferencedFile ");
         e->Release();
     }
     catch (...)
     {
         flags |= RefFileCopyInfoFailed;
-        DBGLOG("Unknown error copying file info for [%s::] %s, from %s on dfs-dali %s", filePrefix.str(), logicalName.str(), fileSrcCluster.length() ? fileSrcCluster.get() : "*", daliip.str());
+        DBGLOG("ReferencedFile Unknown error copying file info for [%s::] %s, from %s on dfs-dali %s", filePrefix.str(), logicalName.str(), fileSrcCluster.length() ? fileSrcCluster.get() : "*", daliip.str());
     }
 }
 
@@ -489,13 +495,13 @@ void ReferencedFile::cloneSuperInfo(unsigned updateFlags, ReferencedFileList *li
     catch (IException *e)
     {
         flags |= RefFileCopyInfoFailed;
-        DBGLOG(e);
+        DBGLOG(e, "ReferencedFile ");
         e->Release();
     }
     catch (...)
     {
         flags |= RefFileCopyInfoFailed;
-        DBGLOG("Unknown error copying superfile info for %s", logicalName.str());
+        DBGLOG("ReferencedFile Unknown error copying superfile info for %s", logicalName.str());
     }
 }
 
@@ -625,6 +631,8 @@ bool ReferencedFileList::addFilesFromQuery(IConstWorkUnit *cw, const IHpccPackag
             bool isOpt = false;
             const char *logicalName = node.queryProp("att[@name='_fileName']/@value");
             if (!logicalName)
+                logicalName = node.queryProp("att[@name='_indexFileName']/@value");
+            if (!logicalName)
                 continue;
 
             isOpt = node.getPropBool("att[@name='_isIndexOpt']/@value");

+ 2 - 2
deployment/deploy/DeployTask.cpp

@@ -1089,8 +1089,8 @@ public:
       Owned<IFile> pDstFile = createIFile(target);
       CDateTime dtSrc;
       CDateTime dtDst;
-      offset_t  szSrc;
-      offset_t  szDst;
+      offset_t  szSrc = 0;
+      offset_t  szDst = 0;
 
       if (!getFileAttributes(pSrcFile, dtSrc, szSrc, mode) ||
           !getFileAttributes(pDstFile, dtDst, szDst, mode))

+ 8 - 5
docs/ECLLanguageReference/ECLR-includer.xml

@@ -41,7 +41,7 @@
     <xi:include href="common/Version.xml" xpointer="DateVer"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
 
-    <releaseinfo>© 2015 HPCC Systems<superscript>®</superscript>. All rights
+    <releaseinfo>© 2017 HPCC Systems<superscript>®</superscript>. All rights
     reserved. Except where otherwise noted, ECL Language Reference content
     licensed under Creative Commons public license.</releaseinfo>
 
@@ -549,8 +549,9 @@
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-FETCH.xml"
                 xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
+
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-FROMJSON.xml"
-		xpointer="element(/1)"
+                xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
 
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-FROMUNICODE.xml"
@@ -724,6 +725,7 @@
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-ORDERED.xml"
                 xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
+
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-OUTPUT.xml"
                 xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
@@ -887,8 +889,9 @@
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-THISNODE.xml"
                 xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
+
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-TOJSON.xml"
-		xpointer="element(/1)"
+                xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
 
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-TOPN.xml"
@@ -922,6 +925,7 @@
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-UNICODEORDER.xml"
                 xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
+
     <xi:include href="ECLLanguageReference/ECLR_mods/BltInFunc-UNORDERED.xml"
                 xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
@@ -1101,12 +1105,11 @@
     <xi:include href="ECLLanguageReference/ECLR_mods/Templ-WARNING.xml"
                 xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
- 
 
     <xi:include href="ECLLanguageReference/ECLR_mods/Templ-WEBSERVICE.xml"
                 xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />
- 
+
     <xi:include href="ECLLanguageReference/ECLR_mods/Templ-WORKUNIT.xml"
                 xpointer="element(/1)"
                 xmlns:xi="http://www.w3.org/2001/XInclude" />

+ 4 - 4
docs/common/Version.xml

@@ -5,11 +5,11 @@
   <chapterinfo>
     <date id="DateVer">DEVELOPER NON-GENERATED VERSION</date>
 
-    <releaseinfo id="FooterInfo">© 2016 HPCC
+    <releaseinfo id="FooterInfo">© 2017 HPCC
     Systems<superscript>®</superscript>. All rights reserved</releaseinfo>
 
     <copyright id="Copyright">
-      <year>2016 HPCC Systems<superscript>®</superscript>. All rights
+      <year>2017 HPCC Systems<superscript>®</superscript>. All rights
       reserved</year>
     </copyright>
   </chapterinfo>
@@ -24,7 +24,7 @@
     and that is to store the chapterinfo the above sections that are being
     used by several other documents.</para>
 
-    <para id="CHMVer">2016 Version X.X</para>
+    <para id="CHMVer">2017 Version X.X</para>
 
     <para>The following line is the code to be put into the document you wish
     to include the above version info in:</para>
@@ -40,6 +40,6 @@
     structure that we can use bookinfo/date and other elements for other
     purposes.</para>
 
-    <para>☺</para>
+    <para>☺ © Γ∏</para>
   </section>
 </chapter>

+ 4 - 4
docs/common/Version.xml.in

@@ -3,13 +3,13 @@
 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
 <chapter>
   <chapterinfo>
-    <date id="DateVer">2016 Version ${DOC_VERSION}</date>
+    <date id="DateVer">2017 Version ${DOC_VERSION}</date>
 
-    <releaseinfo id="FooterInfo">© 2016 HPCC
+    <releaseinfo id="FooterInfo">© 2017 HPCC
     Systems<superscript>®</superscript>. All rights reserved</releaseinfo>
 
     <copyright id="Copyright">
-      <year>2016 HPCC Systems<superscript>®</superscript>. All rights
+      <year>2017 HPCC Systems<superscript>®</superscript>. All rights
       reserved</year>
     </copyright>
   </chapterinfo>
@@ -24,7 +24,7 @@
     serve one purpose and that is to store the chapterinfo the above sections
     that are being used by several other documents.</para>
 
-    <para id="CHMVer">2016 Version ${DOC_VERSION}</para>
+    <para id="CHMVer">2017 Version ${DOC_VERSION}</para>
 
     <para>The following line is the code to be put into the document you wish
     to include the above version info in:</para>

+ 4 - 2
ecl/hqlcpp/hqlhtcpp.cpp

@@ -17523,9 +17523,7 @@ ABoundActivity * HqlCppTranslator::doBuildActivitySOAP(BuildCtx & ctx, IHqlExpre
 
     IHqlExpression * proxyAddress = expr->queryAttribute(proxyAddressAtom);
     if (proxyAddress)
-    {
         doBuildVarStringFunction(instance->startctx, "getProxyAddress", proxyAddress->queryChild(0));
-    }
 
     IHqlExpression * namespaceAttr = expr->queryAttribute(namespaceAtom);
     IHqlExpression * responseAttr = expr->queryAttribute(responseAtom);
@@ -17681,6 +17679,10 @@ ABoundActivity * HqlCppTranslator::doBuildActivityHTTP(BuildCtx & ctx, IHqlExpre
 
     doBuildHttpHeaderStringFunction(instance->startctx, expr);
 
+    IHqlExpression * proxyAddress = expr->queryAttribute(proxyAddressAtom);
+    if (proxyAddress)
+        doBuildVarStringFunction(instance->startctx, "getProxyAddress", proxyAddress->queryChild(0));
+
     //virtual const char * queryOutputIteratorPath()
     IHqlExpression * separator = expr->queryAttribute(separatorAtom);
     if (separator)

+ 1 - 1
esp/bindings/SOAP/Platform/soapmessage.cpp

@@ -326,7 +326,7 @@ IRpcMessage* createRpcMessage(const char* rootTag, StringBuffer& xml)
 {
     CRpcMessage* rpc = new  CRpcMessage(rootTag);
 
-    auto_ptr<XmlPullParser> xpp(new XmlPullParser(xml.str(), xml.length()));
+    std::unique_ptr<XmlPullParser> xpp(new XmlPullParser(xml.str(), xml.length()));
     xpp->setSupportNamespaces(true);
 
     rpc->unmarshall(xpp.get());

+ 1 - 1
esp/bindings/SOAP/client/soapclient.cpp

@@ -237,7 +237,7 @@ int CSoapClient::postRequest(const char* contenttype, const char* soapaction, IR
         return rt;
 
 //  DBGLOG("response SoapClient got from soap server = \n%s", responsebuf.str());
-    auto_ptr<XmlPullParser> xpp(new XmlPullParser());
+    std::unique_ptr<XmlPullParser> xpp(new XmlPullParser());
     int bufSize = responsebuf.length();
     xpp->setSupportNamespaces(true);
     xpp->setInput(responsebuf.str(), bufSize);

+ 1 - 1
esp/esdllib/esdl_def.cpp

@@ -1838,7 +1838,7 @@ public:
 
         if (xmlDef.length())
         {
-            auto_ptr<XmlPullParser> xpp(new XmlPullParser());
+            std::unique_ptr<XmlPullParser> xpp(new XmlPullParser());
 
             int bufSize = xmlDef.length();
             xpp->setSupportNamespaces(true);

+ 1 - 1
esp/esdllib/esdl_transformer2.cpp

@@ -1781,7 +1781,7 @@ static const char * gotoNextHPCCDataset(XmlPullParser &xppx, StartTag &stag)
 
 void Esdl2Transformer::processHPCCResult(IEspContext &ctx, IEsdlDefMethod &mthdef, const char *xml, IXmlWriterExt* writer, StringBuffer &logdata, unsigned int flags, const char *ns, const char *schema_location)
 {
-    auto_ptr<XmlPullParser> xpp(new XmlPullParser());
+    std::unique_ptr<XmlPullParser> xpp(new XmlPullParser());
 
     xpp->setSupportNamespaces(true);
     xpp->setInput(xml, strlen(xml));

+ 1 - 1
esp/logging/logginglib/logthread.hpp

@@ -47,7 +47,7 @@ class CLogThread : public Thread , implements IUpdateLogThread
 
     Owned<IEspLogAgent> logAgent;
     LOGServiceType services[MAXLOGSERVICES];
-    SafeQueueOf<IInterface, false> logQueue;
+    QueueOf<IInterface, false> logQueue;
     CriticalSection logQueueCrit;
     Semaphore       m_sem;
 

+ 1 - 0
esp/platform/tokenserialization.hpp

@@ -159,6 +159,7 @@ public:
         skipWhitespace(ptr);
         if (!*ptr)
         {
+            value = false;
             result = Deserialization_INVALID_TOKEN;
         }
         else

+ 4 - 2
esp/scm/ws_workunits.ecm

@@ -1472,9 +1472,11 @@ ESPresponse [exceptions_inline] WUQueryDetailsResponse
     [min_ver("1.46")] string CompileTime;
     [min_ver("1.46")] ESParray<string> LibrariesUsed;
     [min_ver("1.46")] int CountGraphs;
-    [min_ver("1.46")] ESParray<string> GraphIds;
+    [min_ver("1.46"), depr_ver("1.64")] ESParray<string> GraphIds;
     [min_ver("1.50")] int ResourceURLCount;
     [min_ver("1.51")] ESParray<string, Address> WsEclAddresses;
+    [min_ver("1.64")] ESParray<ESPstruct ECLGraph> WUGraphs;
+    [min_ver("1.64")] ESParray<ESPstruct ECLTimer> WUTimers;
 };
 
 ESPrequest WUMultiQuerySetDetailsRequest
@@ -1792,7 +1794,7 @@ ESPresponse [exceptions_inline, nil_remove] WUGetNumFileToCopyResponse
 
 ESPservice [
     auth_feature("DEFERRED"), //This declares that the method logic handles feature level authorization
-    version("1.63"), default_client_version("1.63"),
+    version("1.64"), default_client_version("1.64"),
     noforms,exceptions_inline("./smc_xslt/exceptions.xslt"),use_method_name] WsWorkunits
 {
     ESPmethod [resp_xsl_default("/esp/xslt/workunits.xslt")]     WUQuery(WUQueryRequest, WUQueryResponse);

+ 102 - 93
esp/services/ws_workunits/ws_workunitsHelpers.cpp

@@ -370,66 +370,70 @@ void WsWuInfo::addTimerToList(SCMStringBuffer& name, const char * scope, IConstW
     timers.append(*t.getLink());
 }
 
-void WsWuInfo::getTimers(IEspECLWorkunit &info, unsigned flags)
+void WsWuInfo::doGetTimers(IArrayOf<IEspECLTimer>& timers)
 {
-    if (!(flags & WUINFO_IncludeTimers))
-        return;
-    try
-    {
-        unsigned __int64 totalThorTimeValue = 0;
-        unsigned __int64 totalThorTimerCount = 0; //Do we need this?
+    unsigned __int64 totalThorTimeValue = 0;
+    unsigned __int64 totalThorTimerCount = 0; //Do we need this?
 
-        IArrayOf<IEspECLTimer> timers;
-        StatisticsFilter filter;
-        filter.setScopeDepth(1, 2);
-        filter.setMeasure(SMeasureTimeNs);
-        Owned<IConstWUStatisticIterator> it = &cw->getStatistics(&filter);
-        if (it->first())
+    StatisticsFilter filter;
+    filter.setScopeDepth(1, 2);
+    filter.setMeasure(SMeasureTimeNs);
+    Owned<IConstWUStatisticIterator> it = &cw->getStatistics(&filter);
+    if (it->first())
+    {
+        ForEach(*it)
         {
-            ForEach(*it)
-            {
-                IConstWUStatistic & cur = it->query();
-                SCMStringBuffer name, scope;
-                cur.getDescription(name, true);
-                cur.getScope(scope);
+            IConstWUStatistic & cur = it->query();
+            SCMStringBuffer name, scope;
+            cur.getDescription(name, true);
+            cur.getScope(scope);
 
-                bool isThorTiming = false;//Should it be renamed as isClusterTiming?
-                if ((cur.getCreatorType() == SCTsummary) && (cur.getKind() == StTimeElapsed) && streq(scope.str(), GLOBAL_SCOPE))
-                {
-                    SCMStringBuffer creator;
-                    cur.getCreator(creator);
-                    if (streq(creator.str(), "thor") || streq(creator.str(), "hthor") ||
-                        streq(creator.str(), "roxie"))
-                        isThorTiming = true;
-                }
-                else if (strieq(name.str(), TOTALTHORTIME)) // legacy
+            bool isThorTiming = false;//Should it be renamed as isClusterTiming?
+            if ((cur.getCreatorType() == SCTsummary) && (cur.getKind() == StTimeElapsed) && streq(scope.str(), GLOBAL_SCOPE))
+            {
+                SCMStringBuffer creator;
+                cur.getCreator(creator);
+                if (streq(creator.str(), "thor") || streq(creator.str(), "hthor") ||
+                    streq(creator.str(), "roxie"))
                     isThorTiming = true;
+            }
+            else if (strieq(name.str(), TOTALTHORTIME)) // legacy
+                isThorTiming = true;
 
-                if (isThorTiming)
-                {
-                    totalThorTimeValue += cur.getValue();
-                    totalThorTimerCount += cur.getCount();
-                }
-                else
-                    addTimerToList(name, scope.str(), cur, timers);
+            if (isThorTiming)
+            {
+                totalThorTimeValue += cur.getValue();
+                totalThorTimerCount += cur.getCount();
             }
+            else
+                addTimerToList(name, scope.str(), cur, timers);
         }
+    }
 
-        if (totalThorTimeValue > 0)
-        {
-            StringBuffer totalThorTimeText;
-            formatStatistic(totalThorTimeText, totalThorTimeValue, SMeasureTimeNs);
+    if (totalThorTimeValue > 0)
+    {
+        StringBuffer totalThorTimeText;
+        formatStatistic(totalThorTimeText, totalThorTimeValue, SMeasureTimeNs);
 
-            Owned<IEspECLTimer> t= createECLTimer("","");
-            if (version > 1.52)
-                t->setName(TOTALCLUSTERTIME);
-            else
-                t->setName(TOTALTHORTIME);
-            t->setValue(totalThorTimeText.str());
-            t->setCount((unsigned)totalThorTimerCount);
-            timers.append(*t.getLink());
-        }
+        Owned<IEspECLTimer> t= createECLTimer("","");
+        if (version > 1.52)
+            t->setName(TOTALCLUSTERTIME);
+        else
+            t->setName(TOTALTHORTIME);
+        t->setValue(totalThorTimeText.str());
+        t->setCount((unsigned)totalThorTimerCount);
+        timers.append(*t.getLink());
+    }
+}
 
+void WsWuInfo::getTimers(IEspECLWorkunit &info, unsigned flags)
+{
+    if (!(flags & WUINFO_IncludeTimers))
+        return;
+    try
+    {
+        IArrayOf<IEspECLTimer> timers;
+        doGetTimers(timers);
         info.setTimers(timers);
     }
     catch(IException* e)
@@ -701,6 +705,54 @@ bool WsWuInfo::legacyHasSubGraphTimings()
     return false;
 }
 
+void WsWuInfo::doGetGraphs(IArrayOf<IEspECLGraph>& graphs)
+{
+    SCMStringBuffer runningGraph;
+    WUGraphIDType id;
+
+    WUState st = cw->getState();
+    bool running = (!(st==WUStateFailed || st==WUStateAborted || st==WUStateCompleted) && cw->getRunningGraph(runningGraph,id));
+
+    Owned<IConstWUGraphMetaIterator> it = &cw->getGraphsMeta(GraphTypeAny);
+    ForEach(*it)
+    {
+        IConstWUGraphMeta &graph = it->query();
+
+        SCMStringBuffer name, label, type;
+        graph.getName(name);
+        graph.getLabel(label);
+
+        graph.getTypeName(type);
+        WUGraphState graphState = graph.getState();
+
+        Owned<IEspECLGraph> g= createECLGraph();
+        g->setName(name.str());
+        g->setLabel(label.str());
+        g->setType(type.str());
+        if (WUGraphComplete == graphState)
+            g->setComplete(true);
+        else if (running && (WUGraphRunning == graphState))
+        {
+            g->setRunning(true);
+            g->setRunningId(id);
+        }
+        else if (WUGraphFailed == graphState)
+            g->setFailed(true);
+
+        if (version >= 1.53)
+        {
+            SCMStringBuffer s;
+            Owned<IConstWUStatistic> whenGraphStarted = cw->getStatistic(NULL, name.str(), StWhenGraphStarted);
+            Owned<IConstWUStatistic> whenGraphFinished = cw->getStatistic(NULL, name.str(), StWhenGraphFinished);
+            if (whenGraphStarted)
+                g->setWhenStarted(whenGraphStarted->getFormattedValue(s).str());
+            if (whenGraphFinished)
+                g->setWhenFinished(whenGraphFinished->getFormattedValue(s).str());
+        }
+        graphs.append(*g.getLink());
+    }
+}
+
 void WsWuInfo::getGraphInfo(IEspECLWorkunit &info, unsigned flags)
 {
      if (version > 1.01)
@@ -716,51 +768,8 @@ void WsWuInfo::getGraphInfo(IEspECLWorkunit &info, unsigned flags)
 
     try
     {
-        SCMStringBuffer runningGraph;
-        WUGraphIDType id;
-
-        WUState st = cw->getState();
-        bool running = (!(st==WUStateFailed || st==WUStateAborted || st==WUStateCompleted) && cw->getRunningGraph(runningGraph,id));
-
         IArrayOf<IEspECLGraph> graphs;
-        Owned<IConstWUGraphMetaIterator> it = &cw->getGraphsMeta(GraphTypeAny);
-        ForEach(*it)
-        {
-            IConstWUGraphMeta &graph = it->query();
-
-            SCMStringBuffer name, label, type;
-            graph.getName(name);
-            graph.getLabel(label);
-
-            graph.getTypeName(type);
-            WUGraphState graphState = graph.getState();
-
-            Owned<IEspECLGraph> g= createECLGraph();
-            g->setName(name.str());
-            g->setLabel(label.str());
-            g->setType(type.str());
-            if (WUGraphComplete == graphState)
-                g->setComplete(true);
-            else if (running && (WUGraphRunning == graphState))
-            {
-                g->setRunning(true);
-                g->setRunningId(id);
-            }
-            else if (WUGraphFailed == graphState)
-                g->setFailed(true);
-
-            if (version >= 1.53)
-            {
-                SCMStringBuffer s;
-                Owned<IConstWUStatistic> whenGraphStarted = cw->getStatistic(NULL, name.str(), StWhenGraphStarted);
-                Owned<IConstWUStatistic> whenGraphFinished = cw->getStatistic(NULL, name.str(), StWhenGraphFinished);
-                if (whenGraphStarted)
-                    g->setWhenStarted(whenGraphStarted->getFormattedValue(s).str());
-                if (whenGraphFinished)
-                    g->setWhenFinished(whenGraphFinished->getFormattedValue(s).str());
-            }
-            graphs.append(*g.getLink());
-        }
+        doGetGraphs(graphs);
         info.setGraphs(graphs);
     }
     catch(IException* e)

+ 2 - 0
esp/services/ws_workunits/ws_workunitsHelpers.hpp

@@ -166,8 +166,10 @@ public:
     void getSourceFiles(IEspECLWorkunit &info, unsigned flags);
     unsigned getTimerCount();
     void getTimers(IEspECLWorkunit &info, unsigned flags);
+    void doGetTimers(IArrayOf<IEspECLTimer>& timers);
     void getHelpers(IEspECLWorkunit &info, unsigned flags);
     void getGraphInfo(IEspECLWorkunit &info, unsigned flags);
+    void doGetGraphs(IArrayOf<IEspECLGraph>& graphs);
     void getWUGraphNameAndTypes(WUGraphType graphType, IArrayOf<IEspNameAndType>& graphNameAndTypes);
     void getGraphTimingData(IArrayOf<IConstECLTimingData> &timingData, unsigned flags);
     bool getFileSize(const char* fileName, const char* IPAddress, offset_t& fileSize);

+ 21 - 4
esp/services/ws_workunits/ws_workunitsQuerySets.cpp

@@ -1642,10 +1642,13 @@ bool CWsWorkunitsEx::onWUQueryDetails(IEspContext &context, IEspWUQueryDetailsRe
             libUsed.append(libs->query().getName(s).str());
         if (libUsed.length())
             resp.setLibrariesUsed(libUsed);
-        unsigned numGraphIds = getGraphIdsByQueryId(querySet, queryId, graphIds);
-        resp.setCountGraphs(numGraphIds);
-        if (numGraphIds > 0)
-            resp.setGraphIds(graphIds);
+        if (version < 1.64)
+        {
+            unsigned numGraphIds = getGraphIdsByQueryId(querySet, queryId, graphIds);
+            resp.setCountGraphs(numGraphIds);
+            if (numGraphIds > 0)
+                resp.setGraphIds(graphIds);
+        }
     }
 
     StringArray logicalFiles;
@@ -1679,6 +1682,20 @@ bool CWsWorkunitsEx::onWUQueryDetails(IEspContext &context, IEspWUQueryDetailsRe
     {
         WsWuInfo winfo(context, wuid);
         resp.setResourceURLCount(winfo.getResourceURLCount());
+        if (version >= 1.64)
+        {
+            IArrayOf<IEspECLTimer> timers;
+            winfo.doGetTimers(timers); //Graph Duration
+            if (timers.length())
+                resp.setWUTimers(timers);
+
+            IArrayOf<IEspECLGraph> graphs;
+            winfo.doGetGraphs(graphs); //Graph Name, Label, Started, Finished, Type
+            unsigned numGraphIds = graphs.length();
+            resp.setCountGraphs(numGraphIds);
+            if (numGraphIds > 0)
+                resp.setWUGraphs(graphs);
+        }
     }
     if (req.getIncludeWsEclAddresses())
     {

+ 10 - 1
initfiles/sbin/hpcc_setenv.in

@@ -102,7 +102,16 @@ IFS="${OIFS}"
 umask ${OUMASK}
 
 # use less heap when threaded
-export MALLOC_ARENA_MAX=8
+# but if set too low it can affect performance significantly
+num_arenas=$(getconf _NPROCESSORS_ONLN 2>/dev/null)
+if [ -z "$num_arenas" ] ; then
+    num_arenas = 8
+elif [ $num_arenas -lt 8 ] ; then
+    num_arenas = 8
+elif [ $num_arenas -gt 32 ] ; then
+    num_arenas = 32
+fi
+export MALLOC_ARENA_MAX=$num_arenas
 
 PATH_PREFIX=`cat ${HPCC_CONFIG} | sed -n "/\[${SECTION}\]/,/\[/p" | grep "^path *= *" | sed -e 's/^path *= *//'`
 

+ 7 - 7
plugins/couchbase/couchbaseembed.cpp

@@ -492,7 +492,7 @@ namespace couchbaseembed
 
     double CouchbaseEmbedFunctionContext::getRealResult()
     {
-        double mydouble;
+        double mydouble = 0.0;
         auto value = nextResultScalar();
         handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, mydouble), "real", value);
 
@@ -501,7 +501,7 @@ namespace couchbaseembed
 
     __int64 CouchbaseEmbedFunctionContext::getSignedResult()
     {
-        __int64 myint64;
+        __int64 myint64 = 0;
         auto value = nextResultScalar();
         handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, myint64), "signed", value);
 
@@ -510,7 +510,7 @@ namespace couchbaseembed
 
     unsigned __int64 CouchbaseEmbedFunctionContext::getUnsignedResult()
     {
-        unsigned __int64 myuint64;
+        unsigned __int64 myuint64 = 0;
         auto value = nextResultScalar();
         handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, myuint64), "unsigned", value);
 
@@ -806,7 +806,7 @@ namespace couchbaseembed
             return p.doubleResult;
         }
 
-        double mydouble;
+        double mydouble = 0.0;
         couchbaseembed::handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, mydouble), "real", value);
         return mydouble;
     }
@@ -820,7 +820,7 @@ namespace couchbaseembed
             return p.uintResult;
         }
 
-        __int64 myint64;
+        __int64 myint64 = 0;
         couchbaseembed::handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, myint64), "signed", value);
         return myint64;
     }
@@ -834,14 +834,14 @@ namespace couchbaseembed
             return p.uintResult;
         }
 
-        unsigned __int64 myuint64;
+        unsigned __int64 myuint64 = 0;
         couchbaseembed::handleDeserializeOutcome(m_tokenDeserializer.deserialize(value, myuint64), "unsigned", value);
         return myuint64;
     }
 
     void CouchbaseRowBuilder::getStringResult(const RtlFieldInfo *field, size32_t &chars, char * &result)
     {
-         const char * value = nextField(field);
+        const char * value = nextField(field);
 
         if (!value || !*value)
         {

+ 19 - 12
plugins/timelib/timelib.cpp

@@ -555,21 +555,28 @@ TIMELIB_API unsigned int TIMELIB_CALL tlGetDayOfWeek(short year, unsigned short
 
 TIMELIB_API void TIMELIB_CALL tlDateToString(size32_t &__lenResult, char* &__result, unsigned int date, const char* format)
 {
-    struct tm       timeInfo;
-    const size_t    kBufferSize = 256;
-    char            buffer[kBufferSize];
-
-    memset(&timeInfo, 0, sizeof(timeInfo));
-    tlInsertDateIntoTimeStruct(&timeInfo, date);
-    tlMKTime(&timeInfo);
+    __result = NULL;  // Return blank string on error
+    __lenResult = 0;
 
-    __lenResult = strftime(buffer, kBufferSize, format, &timeInfo);
-    __result = NULL;
+    // date is expected to be in form year*10000 + month * 100 + day, and must be later than 1900
+    // or we can't store it in a struct tm
 
-    if (__lenResult > 0)
+    if (date >= 1900 * 10000)
     {
-        __result = reinterpret_cast<char*>(CTXMALLOC(parentCtx, __lenResult));
-        memcpy(__result, buffer, __lenResult);
+        struct tm       timeInfo;
+        const size_t    kBufferSize = 256;
+        char            buffer[kBufferSize];
+
+        memset(&timeInfo, 0, sizeof(timeInfo));
+        tlInsertDateIntoTimeStruct(&timeInfo, date);
+        tlMKTime(&timeInfo);
+
+        __lenResult = strftime(buffer, kBufferSize, format, &timeInfo);
+        if (__lenResult > 0)
+        {
+            __result = reinterpret_cast<char*>(CTXMALLOC(parentCtx, __lenResult));
+            memcpy(__result, buffer, __lenResult);
+        }
     }
 }
 

+ 14 - 3
roxie/ccd/ccdprotocol.cpp

@@ -1372,7 +1372,7 @@ public:
         if (name.isEmpty())
         {
             const char *fmt = mlFmt==MarkupFmt_XML ? "XML" : "JSON";
-            IException *E = MakeStringException(-1, "ERROR: Invalid %s received from %s:%d - %s queryName not found", fmt, peer, port, msg);
+            IException *E = MakeStringException(-1, "ERROR: Invalid %s queryName not found - received from %s:%d - %s", fmt, peer, port, msg);
             logctx.logOperatorException(E, __FILE__, __LINE__, "Invalid query %s", fmt);
             throw E;
         }
@@ -1435,8 +1435,16 @@ public:
     {
         if (!name.isEmpty())
             more = false;
-        else if (headerDepth && streq(tag, "Header"))
-            headerDepth--;
+        else if (headerDepth) //will never be true if !isSoap
+        {
+            const char *local = strchr(tag, ':');
+            if (local)
+                local++;
+            else
+                local = tag;
+            if (streq(local, "Header"))
+                headerDepth--;
+        }
     }
 
 };
@@ -1848,11 +1856,14 @@ readAnother:
                                 if (stricmp(format, "raw") == 0)
                                 {
                                     protocolFlags |= HPCC_PROTOCOL_NATIVE_RAW;
+                                    if (client) //not stand alone roxie exe
+                                        protocolFlags |= HPCC_PROTOCOL_BLOCKED;
                                     mlResponseFmt = MarkupFmt_Unknown;
                                 }
                                 else if (stricmp(format, "bxml") == 0)
                                 {
                                     protocolFlags |= HPCC_PROTOCOL_BLOCKED;
+                                    mlResponseFmt = MarkupFmt_XML;
                                 }
                                 else if (stricmp(format, "ascii") == 0)
                                 {

+ 3 - 3
roxie/ccd/ccdserver.cpp

@@ -16060,7 +16060,7 @@ public:
                 if (inputUsed[i1])
                     inputAdaptors[i1]->setParentExtract(parentExtractSize, parentExtract);
                 else
-                    inputAdaptors[i1]->stop();
+                    inputAdaptors[i1]->queryInput()->stopall();
             }
 
             for (unsigned i2 = 0; i2 < numOutputs; i2++)
@@ -16072,7 +16072,7 @@ public:
             ForEachItemIn(i3, extra.unusedOutputs)
             {
                 Owned<IFinalRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
-                // output->queryStream().stop(); Is this needed??
+                output->stopall();
             }
         }
     }
@@ -16088,7 +16088,7 @@ public:
             ForEachItemIn(i3, extra.unusedOutputs)
             {
                 Owned<IFinalRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
-                // Is this needed ?? output->queryStream().stop();
+                output->stopall();
             }
             CRoxieServerActivity::stop();
         }

+ 6 - 0
roxie/ccd/ccdserver.hpp

@@ -108,6 +108,12 @@ interface IFinalRoxieInput : extends IInputBase
     virtual IIndexReadActivityInfo *queryIndexReadActivity() = 0;
 
     virtual IStrandJunction *getOutputStreams(IRoxieSlaveContext *ctx, unsigned idx, PointerArrayOf<IEngineRowStream> &streams, const StrandOptions * consumerOptions, bool consumerOrdered, IOrderedCallbackCollection * orderedCallbacks) = 0;  // Use StrandFlags values for flags
+
+    inline void stopall()
+    {
+        for (int i = 0; i < numConcreteOutputs(); i++)
+            queryConcreteOutputStream(i)->stop();
+    }
 };
 
 extern IEngineRowStream *connectSingleStream(IRoxieSlaveContext *ctx, IFinalRoxieInput *input, unsigned idx, Owned<IStrandJunction> &junction, bool consumerOrdered);

+ 89 - 70
system/jlib/jdebug.cpp

@@ -1668,8 +1668,8 @@ class CExtendedStats  // Disk network and cpu stats
     unsigned ncpu;
     bool first;
     char *kbuf;
-    size32_t kbufsz;
     size32_t kbufmax;
+    int kbadcnt;
     unsigned short kbufcrc;
     __uint64 totalcpu;
 
@@ -1858,70 +1858,80 @@ class CExtendedStats  // Disk network and cpu stats
         return true;
     }
 
-    size32_t  getKLog(const char *&data)
+    size32_t getKLog(const char *&data)
     {
 #ifdef __linux__
-        if (kbufmax) {
-            loop {
-                char *newkbuf = (char *)malloc(kbufmax);
-                if (!newkbuf)
-                    break;  // OOM - abort logging
-                size32_t newkbufsz = klogctl(3,newkbuf,kbufmax);
-                if ((int)newkbufsz<0) {
-                    ERRLOG("klogctl error %d",errno);
-                    free(newkbuf);
-                    data = NULL;
-                    return 0;
+        if (kbufmax)
+        {
+            data = nullptr;
+            size32_t ksz = 0;
+            unsigned short lastCRC = 0;
+            // NOTE: allocated 2*kbufmax to work around kernel bug
+            // where klogctl() could sometimes return more than requested
+            size32_t sz = klogctl(3, kbuf, kbufmax);
+            if ((int)sz < 0)
+            {
+                if (kbadcnt < 5)
+                {
+                    ERRLOG("klogctl SYSLOG_ACTION_READ_ALL error %d", errno);
+                    kbadcnt++;
                 }
-                if (newkbufsz<kbufmax) {
-                    unsigned short crc = chksum16(newkbuf,newkbufsz);
-                    if (kbuf) {
-                        if (crc!=kbufcrc) {
-                            unsigned ofs = 0;
-                            if ((newkbufsz>=kbufsz)) {
-                                for (unsigned i=0;i+3<kbufsz;i++) { // not very quick!
-                                    if (memcmp(kbuf+i,newkbuf,kbufsz-i)==0) {
-                                        ofs = kbufsz-i;
-                                        break;
-                                    }
-                                }
-                            }
-                            size32_t ret = newkbufsz-ofs;
-                            if (ret>3) {
-                                kbufcrc = crc;
-                                free(kbuf);
-                                kbuf = newkbuf;
-                                kbufsz = newkbufsz;
-                                data = kbuf+ofs;
-                                return ret;
-                            }
-                        }
+                else
+                    kbufmax = 0;
+                return 0;
+            }
+#if 0
+            kbuf[sz] = '\0';
+#endif
+            if (kbufcrc)
+            {
+                data = kbuf;
+                ksz = sz;
+            }
+            // determine where new info starts ...
+            StringBuffer ln;
+            const char *p = kbuf;
+            const char *e = p+sz;
+            while (p && p!=e)
+            {
+                if (*p=='<')
+                {
+                    ln.clear();
+                    while ((p && p!=e)&&(*p!='\n'))
+                    {
+                        ln.append(*p);
+                        p++;
+                        sz--;
                     }
-                    else  { // first time {
-                        kbuf = newkbuf;
-                        newkbuf = NULL;
-                        kbufsz = newkbufsz;
+                    lastCRC = chksum16(ln.str(), ln.length());
+                    if (kbufcrc && kbufcrc == lastCRC)
+                    {
+                        ksz = sz - 1;
+                        if (ksz && sz)
+                            data = p + 1;
+                        else
+                            data = nullptr;
                     }
-                    free(newkbuf);
-                    data = NULL;
-                    return 0;
                 }
-                if (kbufmax>0x100000) {
-                    // don't believe!
-                    ERRLOG("klogctl buffer too big!");
-                    free(newkbuf);
-                    break;
+                while ((p && p!=e)&&(*p!='\n'))
+                {
+                    p++;
+                    sz--;
+                }
+                if (p && p!=e)
+                {
+                    p++;
+                    sz--;
                 }
-                kbufmax += 0x1000;
-                free(newkbuf);
             }
-            kbufmax = 0;
-            kbufsz = 0;
-            free(kbuf);
-            kbuf = NULL;
+            if (lastCRC)
+                kbufcrc = lastCRC;
+            if (!ksz)
+                data = nullptr;
+            return ksz;
         }
 #endif
-        data = NULL;
+        data = nullptr;
         return 0;
     }
 
@@ -1956,8 +1966,7 @@ public:
         oldblkio = NULL;
         first = true;
         ncpu = 0;
-        kbuf = NULL;
-        kbufsz = 0;
+        kbuf = nullptr;
         kbufcrc = 0;
         memset(&oldcpu, 0, sizeof(oldcpu));
         memset(&newcpu, 0, sizeof(newcpu));
@@ -1967,8 +1976,14 @@ public:
         memset(&oldnet, 0, sizeof(oldnet));
         memset(&newnet, 0, sizeof(newnet));
         ndisks = 0;
+        kbadcnt = 0;
         if (printklog)
+        {
             kbufmax = 0x1000;
+            kbuf = (char *)malloc(kbufmax*2);
+            if (!kbuf)
+                kbufmax = 0;
+        }
         else
             kbufmax = 0;
     }
@@ -1976,9 +1991,10 @@ public:
     ~CExtendedStats()
     {
         free(partition);
-        free(kbuf);
         free(newblkio);
         free(oldblkio);
+        if (kbuf != nullptr)
+            free(kbuf);
     }
 
     bool getLine(StringBuffer &out)
@@ -2042,23 +2058,26 @@ public:
         return true;
     }
 
-#define KERN_EMERG  "<0>"   // system is unusable
-#define KERN_ALERT  "<1>"   // action must be taken immediately
-#define KERN_CRIT   "<2>"   // critical conditions
-#define KERN_ERR    "<3>"   // error conditions
+#define KERN_EMERG   "<0>"   // system is unusable
+#define KERN_ALERT   "<1>"   // action must be taken immediately
+#define KERN_CRIT    "<2>"   // critical conditions
+#define KERN_ERR     "<3>"   // error conditions
 #define KERN_WARNING "<4>"  // warning conditions
-#define KERN_NOTICE "<5>"   // normal but significant condition
-#define KERN_INFO   "<6>"   // informational
-#define KERN_DEBUG  "<7>"   // debug-level messages
+#define KERN_NOTICE  "<5>"   // normal but significant condition
+#define KERN_INFO    "<6>"   // informational
+#define KERN_DEBUG   "<7>"   // debug-level messages
 #define KMSGTEST(S) if (memcmp(p,S,3)==0) { ln.append(#S); level = p[1]-'0'; }
 
     void printKLog(IPerfMonHook *hook)
     {
-        const char *p;
+        const char *p = nullptr;
         size32_t sz = getKLog(p);
+#if 0
+        DBGLOG("getKLog() returns: %u <%s>", sz, p);
+#endif
         StringBuffer ln;
         const char *e = p+sz;
-        while (p!=e) {
+        while (p && (p!=e)) {
             if (*p=='<') {
                 ln.clear();
                 int level = -1;
@@ -2076,16 +2095,16 @@ public:
                 }
                 p += 3;
                 ln.append(": ");
-                while ((p!=e)&&(*p!='\n'))
+                while ((p && p!=e)&&(*p!='\n'))
                     ln.append(*(p++));
                 if (hook)
                     hook->log(level, ln.str());
                 else
                     PROGLOG("%s",ln.str());
             }
-            while ((p!=e)&&(*p!='\n'))
+            while ((p && p!=e)&&(*p!='\n'))
                 p++;
-            if (p!=e)
+            if (p && p!=e)
                 p++;
         }
     }

+ 1 - 1
system/security/LdapSecurity/ldapconnection.cpp

@@ -329,7 +329,7 @@ public:
         else
             m_ldap_secure_port = atoi(portbuf.str());
 
-        int rc;
+        int rc = LDAP_OTHER;
         StringBuffer hostbuf, dcbuf;
         const char * ldapDomain = cfg->queryProp(".//@ldapDomain");
         for (int numHosts=0; numHosts < getHostCount(); numHosts++)

+ 2 - 1
system/security/shared/caching.cpp

@@ -367,8 +367,9 @@ bool CPermissionsCache::lookup(ISecUser& sec_user)
                     DBGLOG("CACHE: CPermissionsCache Found validated user %s", username);
 #endif
                     // Copy cached user to the sec_user structure, but still keep the original clear text password.
+                    StringAttr originalPW(pw);
                     user->queryUser()->copyTo(sec_user);
-                    sec_user.credentials().setPassword(pw);
+                    sec_user.credentials().setPassword(originalPW.get());
                     return true;
                 }
                 else

+ 4 - 1
system/security/shared/secloader.hpp

@@ -67,7 +67,10 @@ public:
 
         //Call ISecManager instance factory and return the new instance
         DBGLOG("Calling '%s' in pluggable security manager '%s'", instFactory.str(), libName.str());
-        return xproc(bindingName, *secMgrCfg, *bindingCfg);
+        ISecManager* pPSM = xproc(bindingName, *secMgrCfg, *bindingCfg);
+        if (pPSM == nullptr)
+            throw MakeStringException(-1, "%s Security Manager %s failed to instantiate in call to %s", lsm, libName.str(), instFactory.str());
+        return pPSM;
     }
 
     static ISecManager* loadSecManager(const char* model_name, const char* servicename, IPropertyTree* cfg)

+ 2 - 2
testing/regress/ecl/aaalibrary2.ecl

@@ -30,13 +30,13 @@ string10        forename;
 integer2        age := 25;
             END;
 
-FilterDatasetInterface(dataset(namesRecord) ds, string search, boolean onlyOldies) := interface
+FilterDatasetInterface(dataset(namesRecord) ds, dataset(namesRecord) unused, string search, boolean onlyOldies) := interface
     export dataset(namesRecord) matches;
     export dataset(namesRecord) others;
 end;
 
 
-filterDatasetLibrary(dataset(namesRecord) ds, string search, boolean onlyOldies) := module,library(FilterDatasetInterface)
+filterDatasetLibrary(dataset(namesRecord) ds, dataset(namesRecord) unused, string search, boolean onlyOldies) := module,library(FilterDatasetInterface)
     f := ds;
     shared g := if (onlyOldies, f(age >= 65), f);
     export matches := g(surname = search);

+ 8 - 1
testing/regress/ecl/httpcall_multiheader.ecl

@@ -16,5 +16,12 @@ string TargetURL := 'http://' + TargetIP + ':8010/WsSmc/HttpEcho?name=doe,joe&nu
 string constHeader := 'constHeaderValue';
 
 httpcallResult := HTTPCALL(TargetURL,'GET', 'text/xml', httpEchoServiceResponseRecord, xpath('Envelope/Body/HttpEchoResponse'),httpheader('literalHeader','literalValue'), httpheader('constHeader','constHeaderValue'), httpheader('storedHeader', storedHeader));
+output(httpcallResult, named('httpcallResult'));
 
-output(httpcallResult);
+//test proxyaddress functionality by using an invalid targetUrl, but a valid proxyaddress.  HTTP Host header will be wrong, but should still work fine as it's ignored by ESP.
+string hostURL := 'http://1.1.1.1:9999/WsSmc/HttpEcho?name=doe,joe&number=1';
+string targetProxy := 'http://' + TargetIP + ':8010';
+
+proxyResult := HTTPCALL(hostURL,'GET', 'text/xml', httpEchoServiceResponseRecord, xpath('Envelope/Body/HttpEchoResponse'), proxyaddress(targetProxy), httpheader('literalHeader','literalValue'), httpheader('constHeader','constHeaderValue'), httpheader('storedHeader', storedHeader));
+
+output(proxyResult, named('proxyResult'));

+ 4 - 1
testing/regress/ecl/key/httpcall_multiheader.xml

@@ -1,3 +1,6 @@
-<Dataset name='Result 1'>
+<Dataset name='httpcallResult'>
+ <Row><Method>GET</Method><UrlPath>/WsSmc/HttpEcho</UrlPath><UrlParameters>name=doe,joe&amp;number=1</UrlParameters><Headers><Header>Accept-Encoding: gzip, deflate</Header><Header>Accept: text/xml</Header><Header>constHeader: constHeaderValue</Header><Header>literalHeader: literalValue</Header><Header>storedHeader: StoredHeaderDefault</Header></Headers><Content></Content></Row>
+</Dataset>
+<Dataset name='proxyResult'>
  <Row><Method>GET</Method><UrlPath>/WsSmc/HttpEcho</UrlPath><UrlParameters>name=doe,joe&amp;number=1</UrlParameters><Headers><Header>Accept-Encoding: gzip, deflate</Header><Header>Accept: text/xml</Header><Header>constHeader: constHeaderValue</Header><Header>literalHeader: literalValue</Header><Header>storedHeader: StoredHeaderDefault</Header></Headers><Content></Content></Row>
 </Dataset>

+ 3 - 0
testing/regress/ecl/key/library1.xml

@@ -10,3 +10,6 @@
 <Dataset name='OldNotHalliday'>
  <Row><surname>Smith               </surname><forename>George    </forename><age>75</age></Row>
 </Dataset>
+<Dataset name='Result 4'>
+ <Row><surname>a                   </surname><forename>a         </forename><age>2</age></Row>
+</Dataset>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 7 - 1
testing/regress/ecl/key/soapcall_multihttpheader.xml


+ 6 - 3
testing/regress/ecl/library1.ecl

@@ -26,21 +26,22 @@ integer2        age := 25;
             END;
 
 
-FilterDatasetInterface(dataset(namesRecord) ds, string search, boolean onlyOldies) := interface
+FilterDatasetInterface(dataset(namesRecord) ds, dataset(namesRecord) unused, string search, boolean onlyOldies) := interface
     export dataset(namesRecord) matches;
     export dataset(namesRecord) others;
 end;
 
 
-FilterDatasetLibrary(dataset(namesRecord) ds, string search, boolean onlyOldies) := module,library(FilterDatasetInterface)
+FilterDatasetLibrary(dataset(namesRecord) ds, dataset(namesRecord) unused, string search, boolean onlyOldies) := module,library(FilterDatasetInterface)
     f := ds;
     shared g := if (onlyOldies, f(age >= 65), f);
     export matches := g(surname = search);
     export others := g(surname != search);
 end;
 
+empty := nofold(DATASET([{'a','a',2}], namesRecord));
 
-filterDataset(dataset(namesRecord) ds, string search, boolean onlyOldies) := library(internal(FilterDatasetLibrary), FilterDatasetInterface(ds, search, onlyOldies));
+filterDataset(dataset(namesRecord) ds, string search, boolean onlyOldies) := library(internal(FilterDatasetLibrary), FilterDatasetInterface(ds, empty, search, onlyOldies));
 
 
 namesTable := dataset([
@@ -58,3 +59,5 @@ output(filtered2.others,,named('NotHalliday'));
 
 filtered3 := filterDataset(namesTable, 'Halliday', true);
 output(filtered3.others,,named('OldNotHalliday'));
+
+output(empty);

+ 3 - 2
testing/regress/ecl/library2.ecl

@@ -27,13 +27,14 @@ string10        forename;
 integer2        age := 25;
             END;
 
-FilterDatasetInterface(dataset(namesRecord) ds, string search, boolean onlyOldies) := interface
+FilterDatasetInterface(dataset(namesRecord) ds, dataset(namesRecord) unused, string search, boolean onlyOldies) := interface
     export dataset(namesRecord) matches;
     export dataset(namesRecord) others;
 end;
 
+empty := DATASET([], namesRecord);
 
-filterDataset(dataset(namesRecord) ds, string search, boolean onlyOldies) := library('aaaLibrary2',FilterDatasetInterface(ds,search,onlyOldies));
+filterDataset(dataset(namesRecord) ds, string search, boolean onlyOldies) := library('aaaLibrary2',FilterDatasetInterface(ds,empty,search,onlyOldies));
 
 namesTable := dataset([
         {'Halliday','Gavin',31},

+ 4 - 2
testing/regress/ecl/library2a.ecl

@@ -27,7 +27,7 @@ string10        forename;
 integer2        age := 25;
             END;
 
-FilterDatasetInterface(dataset(namesRecord) ds, string search, boolean onlyOldies) := interface
+FilterDatasetInterface(dataset(namesRecord) ds, dataset(namesRecord) unused, string search, boolean onlyOldies) := interface
     export dataset(namesRecord) matches;
     export dataset(namesRecord) others;
 end;
@@ -35,7 +35,9 @@ end;
 
 boolean falseval := false: stored('yeahright');
 
-filterDataset(dataset(namesRecord) ds, string search, boolean onlyOldies) := library('aaaLibrary2',FilterDatasetInterface(ds,search,onlyOldies));
+empty := DATASET([], namesRecord);
+
+filterDataset(dataset(namesRecord) ds, string search, boolean onlyOldies) := library('aaaLibrary2',FilterDatasetInterface(ds,empty,search,onlyOldies));
 
 namesTable := dataset([
         {'Halliday','Gavin',31},

+ 10 - 1
testing/regress/ecl/soapcall_multihttpheader.ecl

@@ -24,4 +24,13 @@ string constHeader := 'constHeaderValue';
 
 soapcallResult := SOAPCALL(TargetURL, 'HttpEcho', httpEchoServiceRequestRecord, DATASET(httpEchoServiceResponseRecord), LITERAL, xpath('HttpEchoResponse'), httpheader('StoredHeader', storedHeader), httpheader('literalHeader', 'literalHeaderValue'), httpheader('constHeader', constHeader));
 
-output(soapcallResult);
+output(soapcallResult, named('soapcallResult'));
+
+
+//test proxyaddress functionality by using an invalid targetUrl, but a valid proxyaddress.  HTTP Host header will be wrong, but should still work fine as it's ignored by ESP.
+string HostURL := 'http://1.1.1.1:9999/WsSmc/HttpEcho?name=doe,joe&number=1';
+string TargetProxy := 'http://' + TargetIP + ':8010';
+
+proxyResult := SOAPCALL(HostURL, 'HttpEcho', httpEchoServiceRequestRecord, DATASET(httpEchoServiceResponseRecord), LITERAL, xpath('HttpEchoResponse'), proxyAddress(TargetProxy), httpheader('StoredHeader', storedHeader), httpheader('literalHeader', 'literalHeaderValue'), httpheader('constHeader', constHeader));
+
+output(proxyResult, named('proxyResult'));

+ 1 - 1
testing/unittests/jlibtests.cpp

@@ -124,7 +124,7 @@ protected:
         sem.signal();
         if (!sem.wait(1000))
         {
-            VStringBuffer errMsg("Semaphore stalled (%s:%s)", sanitizeSourceFile(__FILE__), __LINE__);
+            VStringBuffer errMsg("Semaphore stalled (%s:%d)", sanitizeSourceFile(__FILE__), __LINE__);
             CPPUNIT_FAIL(errMsg.str());
         }
         testTimedElapsed(sem, 5, 1000);