Procházet zdrojové kódy

Merge branch 'candidate-6.2.2' into candidate-6.4.0

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman před 8 roky
rodič
revize
cf79df169e

+ 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()
 
 

+ 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

+ 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");

+ 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>

+ 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;
 

+ 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 *= *//'`
 

+ 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

@@ -15986,7 +15986,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++)
@@ -15998,7 +15998,7 @@ public:
             ForEachItemIn(i3, extra.unusedOutputs)
             {
                 Owned<IFinalRoxieInput> output = graph->selectOutput(numInputs+extra.unusedOutputs.item(i3));
-                // output->queryStream().stop(); Is this needed??
+                output->stopall();
             }
         }
     }
@@ -16014,7 +16014,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++;
         }
     }

+ 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

+ 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);

+ 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>

+ 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},