Browse Source

HPCC-9682 Add WsWorkunits method to return paged QuerySet Queries

This fix adds new WsWorkunits method 'WUListQueries' to return
QuerySet Queries with paging/sorting options.

Signed-off-by: Kevin Wang <kevin.wang@lexisnexis.com>
Kevin Wang 12 years ago
parent
commit
ec3504ef9d

+ 224 - 5
common/workunit/workunit.cpp

@@ -1855,7 +1855,7 @@ public:
     virtual IStringVal & str(IStringVal &s) { s.clear(); return s; }
 };
 
-mapEnums sortFields[] = 
+mapEnums workunitSortFields[] =
 {
    { WUSFuser, "@submitID" },
    { WUSFcluster, "@clusterName" },
@@ -1879,6 +1879,24 @@ mapEnums sortFields[] =
    { WUSFterm, NULL }
 };
 
+mapEnums querySortFields[] =
+{
+   { WUQSFId, "@id" },
+   { WUQSFwuid, "@wuid" },
+   { WUQSFname, "@name" },
+   { WUQSFdll, "@dll" },
+   { WUQSFmemoryLimit, "@memoryLimit" },
+   { WUQSFmemoryLimitHi, "@memoryLimit" },
+   { WUQSFtimeLimit, "@timeLimit" },
+   { WUQSFtimeLimitHi, "@timeLimit" },
+   { WUQSFwarnTimeLimit, "@warnTimeLimit" },
+   { WUQSFwarnTimeLimitHi, "@warnTimeLimit" },
+   { WUQSFpriority, "@priority" },
+   { WUQSFpriorityHi, "@priority" },
+   { WUQSFQuerySet, "../@id" },
+   { WUQSFterm, NULL }
+};
+
 class asyncRemoveDllWorkItem: public CInterface, implements IWorkQueueItem // class only used in asyncRemoveDll
 {
     StringAttr name;
@@ -1919,6 +1937,47 @@ public:
     }
 };
 
+//==========================================================================================
+
+class CConstQuerySetQueryIterator : public CInterface, implements IConstQuerySetQueryIterator
+{
+    IArrayOf<IPropertyTree> trees;
+    unsigned index;
+public:
+    IMPLEMENT_IINTERFACE;
+    CConstQuerySetQueryIterator(IArrayOf<IPropertyTree> &_trees)
+    {
+        ForEachItemIn(t, _trees)
+            trees.append(*LINK(&_trees.item(t)));
+        index = 0;
+    }
+    ~CConstQuerySetQueryIterator()
+    {
+        trees.kill();
+    }
+    bool first()
+    {
+        index = 0;
+        return (trees.ordinality()!=0);
+    }
+
+    bool next()
+    {
+        index++;
+        return (index<trees.ordinality());
+    }
+
+    bool isValid()
+    {
+        return (index<trees.ordinality());
+    }
+
+    IPropertyTree &query()
+    {
+        return trees.item(index);
+    }
+};
+
 #define WUID_VERSION 2 // recorded in each wuid created, useful for bkwd compat. checks
 
 class CWorkUnitFactory : public CInterface, implements IWorkUnitFactory, implements IDaliClientShutdown
@@ -2211,6 +2270,32 @@ public:
                                                 ISecUser *secuser,
                                                 unsigned *total)
     {
+        class CWorkUnitsPager : public CSimpleInterface, implements IElementsPager
+        {
+            StringAttr xPath;
+            StringAttr sortOrder;
+            StringAttr nameFilterLo;
+            StringAttr nameFilterHi;
+
+        public:
+            IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
+
+            CWorkUnitsPager(const char* _xPath, const char *_sortOrder, const char* _nameFilterLo, const char* _nameFilterHi)
+                : xPath(_xPath), sortOrder(_sortOrder), nameFilterLo(_nameFilterLo), nameFilterHi(_nameFilterHi)
+            {
+            }
+            virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
+            {
+                Owned<IRemoteConnection> conn = querySDS().connect("WorkUnits", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
+                if (!conn)
+                    return NULL;
+                Owned<IPropertyTreeIterator> iter = conn->getElements(xPath);
+                if (!iter)
+                    return NULL;
+                sortElements(iter, sortOrder.get(), nameFilterLo.get(), nameFilterHi.get(), elements);
+                return conn.getClear();
+            }
+        };
         class CScopeChecker : public CSimpleInterface, implements ISortedElementsTreeFilter
         {
             UniqueScopes done;
@@ -2261,7 +2346,7 @@ public:
                 else if (subfmt==WUSFwuidhigh) 
                     namefilterhi.set(fv);
                 else {
-                    query.append('[').append(getEnumText(subfmt,sortFields)).append('=');
+                    query.append('[').append(getEnumText(subfmt,workunitSortFields)).append('=');
                     if (fmt&WUSFnocase)
                         query.append('?');
                     if (fmt&WUSFwild)
@@ -2282,12 +2367,12 @@ public:
                     so.append('?');
                 if (fmt&WUSFnumeric) 
                     so.append('#');
-                so.append(getEnumText(fmt&0xff,sortFields));
+                so.append(getEnumText(fmt&0xff,workunitSortFields));
             }
         }
         IArrayOf<IPropertyTree> results;
-        Owned<IRemoteConnection> conn=getElementsPaged("WorkUnits", query.str(), so.length()?so.str():NULL,startoffset,maxnum,
-            secmgr?sc:NULL,queryowner,cachehint,namefilterlo.get(),namefilterhi.get(),results,total);
+        Owned<IElementsPager> elementsPager = new CWorkUnitsPager(query.str(), so.length()?so.str():NULL, namefilterlo.get(), namefilterhi.get());
+        Owned<IRemoteConnection> conn=getElementsPaged(elementsPager,startoffset,maxnum,secmgr?sc:NULL,queryowner,cachehint,results,total);
         return new CConstWUArrayIterator(conn, results, secmgr, secuser);
     }
 
@@ -2304,6 +2389,129 @@ public:
         return getWorkUnitsSorted(sortorder,filters,filterbuf,startoffset,maxnum,queryowner,cachehint, NULL, NULL, total);
     }
 
+    IConstQuerySetQueryIterator* getQuerySetQueriesSorted( WUQuerySortField *sortorder, // list of fields to sort by (terminated by WUSFterm)
+                                                WUQuerySortField *filters,   // NULL or list of fields to folteron (terminated by WUSFterm)
+                                                const void *filterbuf,  // (appended) string values for filters
+                                                unsigned startoffset,
+                                                unsigned maxnum,
+                                                __int64 *cachehint,
+                                                unsigned *total)
+    {
+        class CQuerySetQueriesPager : public CSimpleInterface, implements IElementsPager
+        {
+            StringAttr querySet;
+            StringAttr xPath;
+            StringAttr sortOrder;
+
+            void getQuerySetQueries(const char* querySetId, IPropertyTree* querySetTree, const char *xPath, IPropertyTree* queryTreeRoot)
+            {
+                Owned<IPropertyTreeIterator> iter = querySetTree->getElements(xPath);
+                ForEach(*iter)
+                {
+                    IPropertyTree &query = iter->query();
+                    IPropertyTree *queryWithSetId = queryTreeRoot->addPropTree("Query", LINK(&query));
+                    queryWithSetId->addProp("@querySetId", querySetId);
+                }
+            }
+
+            IPropertyTree* getAllQuerySetQueries(IRemoteConnection* conn, const char *querySet, const char *xPath)
+            {
+                Owned<IPropertyTree> queryTreeRoot = createPTree("Queries");
+                IPropertyTree* root = conn->queryRoot();
+                if (querySet && *querySet)
+                {
+                    VStringBuffer path("QuerySet[@id='%s']/Query%s", querySet, xPath);
+                    getQuerySetQueries(querySet, root, path.str(), queryTreeRoot);
+                }
+                else
+                {
+                    Owned<IPropertyTreeIterator> iter = root->getElements("QuerySet");
+                    ForEach(*iter)
+                    {
+                        IPropertyTree &querySet = iter->query();
+                        const char* id = querySet.queryProp("@id");
+                        if (id && *id)
+                        {
+                            VStringBuffer path("Query%s", xPath);
+                            getQuerySetQueries(id, &querySet, path.str(), queryTreeRoot);
+                        }
+                    }
+                }
+                return queryTreeRoot.getClear();
+            }
+
+        public:
+            IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
+
+            CQuerySetQueriesPager(const char* _querySet, const char* _xPath, const char *_sortOrder)
+                : querySet(_querySet), xPath(_xPath), sortOrder(_sortOrder)
+            {
+            }
+            virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
+            {
+                Owned<IRemoteConnection> conn = querySDS().connect("QuerySets", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
+                if (!conn)
+                    return NULL;
+                Owned<IPropertyTree> elementTree = getAllQuerySetQueries(conn, querySet.get(), xPath.get());
+                if (!elementTree)
+                    return NULL;
+                Owned<IPropertyTreeIterator> iter = elementTree->getElements("*");
+                if (!iter)
+                    return NULL;
+                sortElements(iter, sortOrder.get(), NULL, NULL, elements);
+                return conn.getClear();
+            }
+        };
+        StringAttr querySet;
+        StringBuffer xPath;
+        StringBuffer so;
+        if (filters)
+        {
+            const char *fv = (const char *)filterbuf;
+            for (unsigned i=0;filters[i]!=WUQSFterm;i++) {
+                int fmt = filters[i];
+                int subfmt = (fmt&0xff);
+                if (subfmt==WUQSFQuerySet)
+                    querySet.set(fv);
+                else if ((subfmt==WUQSFmemoryLimit) || (subfmt==WUQSFtimeLimit) || (subfmt==WUQSFwarnTimeLimit) || (subfmt==WUQSFpriority))
+                    xPath.append('[').append(getEnumText(subfmt,querySortFields)).append(">=").append(fv).append("]");
+                else if ((subfmt==WUQSFmemoryLimitHi) || (subfmt==WUQSFtimeLimitHi) || (subfmt==WUQSFwarnTimeLimitHi) || (subfmt==WUQSFpriorityHi))
+                    xPath.append('[').append(getEnumText(subfmt,querySortFields)).append("<=").append(fv).append("]");
+                else {
+                    xPath.append('[').append(getEnumText(subfmt,querySortFields)).append('=');
+                    if (fmt&WUQSFnocase)
+                        xPath.append('?');
+                    if (fmt&WUQSFnumeric)
+                        xPath.append('#');
+                    if (fmt&WUQSFwild)
+                        xPath.append('~');
+                    xPath.append('"').append(fv).append("\"]");
+                }
+                fv = fv + strlen(fv)+1;
+            }
+        }
+        if (xPath.length() < 1)
+            xPath.set("*");
+        if (sortorder) {
+            for (unsigned i=0;sortorder[i]!=WUQSFterm;i++) {
+                if (so.length())
+                    so.append(',');
+                int fmt = sortorder[i];
+                if (fmt&WUQSFreverse)
+                    so.append('-');
+                if (fmt&WUQSFnocase)
+                    so.append('?');
+                if (fmt&WUQSFnumeric)
+                    so.append('#');
+                so.append(getEnumText(fmt&0xff,querySortFields));
+            }
+        }
+        IArrayOf<IPropertyTree> results;
+        Owned<IElementsPager> elementsPager = new CQuerySetQueriesPager(querySet.get(), xPath.str(), so.length()?so.str():NULL);
+        Owned<IRemoteConnection> conn=getElementsPaged(elementsPager,startoffset,maxnum,NULL,"",cachehint,results,total);
+        return new CConstQuerySetQueryIterator(results);
+    }
+
     virtual unsigned numWorkUnits()
     {
         Owned<IRemoteConnection> conn = sdsManager->connect("/WorkUnits", session, 0, SDS_LOCK_TIMEOUT);
@@ -2570,6 +2778,17 @@ public:
         return factory->getWorkUnitsSorted(sortorder,filters,filterbuf,startoffset,maxnum,queryowner,cachehint, secMgr.get(), secUser.get(), total);
     }
 
+    virtual IConstQuerySetQueryIterator* getQuerySetQueriesSorted( WUQuerySortField *sortorder,
+                                                WUQuerySortField *filters,
+                                                const void *filterbuf,
+                                                unsigned startoffset,
+                                                unsigned maxnum,
+                                                __int64 *cachehint,
+                                                unsigned *total)
+    {
+        return factory->getQuerySetQueriesSorted(sortorder,filters,filterbuf,startoffset,maxnum,cachehint,total);
+    }
+
     virtual unsigned numWorkUnits()
     {
         return factory->numWorkUnits();

+ 24 - 1
common/workunit/workunit.hpp

@@ -1027,7 +1027,6 @@ interface IConstWorkUnitIterator : extends IScmIterator
     virtual IConstWorkUnit & query() = 0;
 };
 
-
 //! IWUTimers
 
 interface IWUTimers : extends IInterface
@@ -1085,6 +1084,29 @@ enum WUSortField
     WUSFwild = 2048
 };
 
+enum WUQuerySortField
+{
+    WUQSFId = 1,
+    WUQSFname = 2,
+    WUQSFwuid = 3,
+    WUQSFdll = 4,
+    WUQSFmemoryLimit = 5,
+    WUQSFmemoryLimitHi = 6,
+    WUQSFtimeLimit = 7,
+    WUQSFtimeLimitHi = 8,
+    WUQSFwarnTimeLimit = 9,
+    WUQSFwarnTimeLimitHi = 10,
+    WUQSFpriority = 11,
+    WUQSFpriorityHi = 12,
+    WUQSFQuerySet = 13,
+    WUQSFterm = 0,
+    WUQSFreverse = 256,
+    WUQSFnocase = 512,
+    WUQSFnumeric = 1024,
+    WUQSFwild = 2048
+};
+
+typedef IIteratorOf<IPropertyTree> IConstQuerySetQueryIterator;
 
 
 interface IWorkUnitFactory : extends IInterface
@@ -1105,6 +1127,7 @@ interface IWorkUnitFactory : extends IInterface
     virtual unsigned numWorkUnitsFiltered(WUSortField * filters, const void * filterbuf) = 0;
     virtual void descheduleAllWorkUnits() = 0;
     virtual bool deleteWorkUnitEx(const char * wuid) = 0;
+    virtual IConstQuerySetQueryIterator * getQuerySetQueriesSorted(WUQuerySortField *sortorder, WUQuerySortField *filters, const void *filterbuf, unsigned startoffset, unsigned maxnum, __int64 *cachehint, unsigned *total) = 0;
 };
 
 

+ 21 - 7
dali/base/dautils.cpp

@@ -1826,20 +1826,34 @@ public:
     Owned<IBitSet> passesFilter;
 };
 
-IRemoteConnection *getElementsPaged( const char *basexpath,
-                                     const char *xpath,
-                                     const char *sortorder,
+void sortElements(IPropertyTreeIterator* elementsIter,
+                    const char *sortOrder,
+                    const char *nameFilterLo,
+                    const char *nameFilterHi,
+                    IArrayOf<IPropertyTree> &sortedElements)
+{
+    if (nameFilterLo&&!*nameFilterLo)
+        nameFilterLo = NULL;
+    if (nameFilterHi&&!*nameFilterHi)
+        nameFilterHi = NULL;
+    cSort sort;
+    if (sortOrder && *sortOrder)
+        sort.dosort(*elementsIter,sortOrder,nameFilterLo,nameFilterHi,sortedElements);
+    else
+        ForEach(*elementsIter)
+            filteredAdd(sortedElements,nameFilterLo,nameFilterHi,&elementsIter->query());
+};
+
+IRemoteConnection *getElementsPaged( IElementsPager *elementsPager,
                                      unsigned startoffset,
                                      unsigned pagesize,
                                      ISortedElementsTreeFilter *postfilter, // filters before adding to page
                                      const char *owner,
                                      __int64 *hint,
-                                     const char *namefilterlo,
-                                     const char *namefilterhi,
                                      IArrayOf<IPropertyTree> &results,
                                      unsigned *total)
 {
-    if (pagesize==0)
+    if ((pagesize==0) || !elementsPager)
         return NULL;
     {
         CriticalBlock block(pagedElementsCacheSect);
@@ -1857,7 +1871,7 @@ IRemoteConnection *getElementsPaged( const char *basexpath,
     if (!elem)
         elem.setown(new CPECacheElem(owner, postfilter));
     if (!elem->conn)
-        elem->conn.setown(getSortedElements(basexpath,xpath,sortorder,namefilterlo,namefilterhi,elem->totalres));
+        elem->conn.setown(elementsPager->getElements(elem->totalres));
     if (!elem->conn)
         return NULL;
     unsigned n;

+ 10 - 5
dali/base/dautils.hpp

@@ -263,17 +263,22 @@ interface ISortedElementsTreeFilter : extends IInterface
 {
     virtual bool isOK(IPropertyTree &tree) = 0;
 };
-
-extern da_decl IRemoteConnection *getElementsPaged( const char *basexpath, 
-                                     const char *xpath, 
+interface IElementsPager : extends IInterface
+{
+    virtual IRemoteConnection *getElements(IArrayOf<IPropertyTree> &elements) = 0;
+};
+extern da_decl void sortElements( IPropertyTreeIterator* elementsIter,
                                      const char *sortorder, 
+                                     const char *namefilterlo, // if non null filter less than this value
+                                     const char *namefilterhi, // if non null filter greater than this value
+                                     IArrayOf<IPropertyTree> &sortedElements);
+
+extern da_decl IRemoteConnection *getElementsPaged(IElementsPager *elementsPager,
                                      unsigned startoffset, 
                                      unsigned pagesize, 
                                      ISortedElementsTreeFilter *postfilter, // if non-NULL filters before adding to page
                                      const char *owner,
                                      __int64 *hint,                         // if non null points to in/out cache hint
-                                     const char *namefilterlo, // if non null filter less than this value
-                                     const char *namefilterhi, // if non null filter greater than this value
                                      IArrayOf<IPropertyTree> &results,
                                      unsigned *total); // total possible filtered matches, i.e. irrespective of startoffset and pagesize
 

+ 29 - 2
dali/dfu/dfuwu.cpp

@@ -2975,6 +2975,33 @@ public:
                                                     __int64 *cachehint,
                                                     unsigned *total)
     {
+        class CWorkUnitsPager : public CSimpleInterface, implements IElementsPager
+        {
+            StringAttr xPath;
+            StringAttr sortOrder;
+            StringAttr nameFilterLo;
+            StringAttr nameFilterHi;
+
+        public:
+            IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
+
+            CWorkUnitsPager(const char* _xPath, const char *_sortOrder, const char* _nameFilterLo, const char* _nameFilterHi)
+                : xPath(_xPath), sortOrder(_sortOrder), nameFilterLo(_nameFilterLo), nameFilterHi(_nameFilterHi)
+            {
+            }
+            virtual IRemoteConnection* getElements(IArrayOf<IPropertyTree> &elements)
+            {
+                Owned<IRemoteConnection> conn = querySDS().connect("DFU/WorkUnits", myProcessSession(), 0, SDS_LOCK_TIMEOUT);
+                if (!conn)
+                    return NULL;
+                Owned<IPropertyTreeIterator> iter = conn->getElements(xPath);
+                if (!iter)
+                    return NULL;
+                sortElements(iter, sortOrder.get(), nameFilterLo.get(), nameFilterHi.get(), elements);
+                return conn.getClear();
+            }
+        };
+
         StringBuffer query("*");
         StringBuffer so;
         const char *field;
@@ -3010,8 +3037,8 @@ public:
             }
         }
         IArrayOf<IPropertyTree> results;
-        Owned<IRemoteConnection> conn=getElementsPaged( "DFU/WorkUnits", query.str(), so.length()?so.str():NULL,startoffset,maxnum,
-            NULL,queryowner,cachehint,namefilterlo.get(),namefilterhi.get(),results,total);
+        Owned<IElementsPager> elementsPager = new CWorkUnitsPager(query.str(), so.length()?so.str():NULL, namefilterlo.get(), namefilterhi.get());
+        Owned<IRemoteConnection> conn=getElementsPaged(elementsPager,startoffset,maxnum,NULL,queryowner,cachehint,results,total);
         return new CConstDFUWUArrayIterator(this,conn,results);
     }
 

+ 30 - 1
esp/scm/ws_workunits.ecm

@@ -1169,6 +1169,7 @@ ESPStruct [nil_remove] QuerySetQuery
     nonNegativeInteger warnTimeLimit;
     string priority;
     string Comment;
+    [min_ver("1.45")] string QuerySetId;
 };
 
 ESPStruct QuerySetAlias
@@ -1205,6 +1206,33 @@ ESPresponse [exceptions_inline] WUQuerySetDetailsResponse
     [min_ver("1.37")] ESParray<string> ClusterNames;
 };
 
+ESPrequest [nil_remove] WUListQueriesRequest
+{
+    string  QuerySetName;
+    string  ClusterName;
+    int64 MemoryLimitLow;
+    int64 MemoryLimitHigh;
+    nonNegativeInteger TimeLimitLow;
+    nonNegativeInteger TimeLimitHigh;
+    nonNegativeInteger WarnTimeLimitLow;
+    nonNegativeInteger WarnTimeLimitHigh;
+    nonNegativeInteger PriorityLow;
+    nonNegativeInteger PriorityHigh;
+
+    nonNegativeInteger PageSize(0);
+    nonNegativeInteger PageStartFrom(0);
+    string Sortby;
+    bool Descending(false);
+    int64 CacheHint;
+};
+
+ESPresponse [exceptions_inline] WUListQueriesResponse
+{
+    int   NumberOfQueries;
+    int64 CacheHint;
+    ESParray<ESPstruct QuerySetQuery> QuerysetQueries;
+};
+
 ESPrequest WUQueryDetailsRequest
 {
     string QueryId;
@@ -1362,7 +1390,7 @@ ESPresponse [exceptions_inline] WUQuerySetCopyQueryResponse
 };
 
 ESPservice [
-    version("1.44"), default_client_version("1.44"),
+    version("1.45"), default_client_version("1.45"),
     noforms,exceptions_inline("./smc_xslt/exceptions.xslt"),use_method_name] WsWorkunits
 {
     ESPmethod [resp_xsl_default("/esp/xslt/workunits.xslt")]     WUQuery(WUQueryRequest, WUQueryResponse);
@@ -1429,6 +1457,7 @@ ESPservice [
     ESPmethod WUQuerysetCopyQuery(WUQuerySetCopyQueryRequest, WUQuerySetCopyQueryResponse);
     ESPmethod [resp_xsl_default("/esp/xslt/WUCopyLogicalFiles.xslt")] WUCopyLogicalFiles(WUCopyLogicalFilesRequest, WUCopyLogicalFilesResponse);
     ESPmethod WUQueryConfig(WUQueryConfigRequest, WUQueryConfigResponse);
+    ESPmethod WUListQueries(WUListQueriesRequest, WUListQueriesResponse);
 };
 
 

+ 144 - 2
esp/services/ws_workunits/ws_workunitsQuerySets.cpp

@@ -833,8 +833,6 @@ void retrieveAllQuerysetDetails(IArrayOf<IEspWUQuerySetDetail> &details, const c
     if (!root)
         throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "QuerySet Registry not found");
     Owned<IPropertyTreeIterator> querysets = root->getElements("QuerySet");
-    if (!root)
-        throw MakeStringException(ECLWATCH_QUERYSET_NOT_FOUND, "QuerySet Registry not found");
     ForEach(*querysets)
         retrieveQuerysetDetails(details, &querysets->query(), type, value);
 }
@@ -901,6 +899,150 @@ bool CWsWorkunitsEx::onWUMultiQuerysetDetails(IEspContext &context, IEspWUMultiQ
     return true;
 }
 
+bool addWUQSQueryFilter(WUQuerySortField *filters, unsigned short &count, MemoryBuffer &buff, const char* value, WUQuerySortField name)
+{
+    if (isEmpty(value))
+        return false;
+    filters[count++] = name;
+    buff.append(value);
+    return true;
+}
+
+bool addWUQSQueryFilterInt(WUQuerySortField *filters, unsigned short &count, MemoryBuffer &buff, int value, WUQuerySortField name)
+{
+    VStringBuffer vBuf("%d", value);
+    filters[count++] = name;
+    buff.append(vBuf.str());
+    return true;
+}
+
+bool addWUQSQueryFilterInt64(WUQuerySortField *filters, unsigned short &count, MemoryBuffer &buff, __int64 value, WUQuerySortField name)
+{
+    VStringBuffer vBuf("%ld", value);
+    filters[count++] = name;
+    buff.append(vBuf.str());
+    return true;
+}
+
+bool CWsWorkunitsEx::onWUListQueries(IEspContext &context, IEspWUListQueriesRequest & req, IEspWUListQueriesResponse & resp)
+{
+    bool descending = req.getDescending();
+    const char *sortBy =  req.getSortby();
+    WUQuerySortField sortOrder[2] = {WUQSFId, WUQSFterm};
+    if(notEmpty(sortBy))
+    {
+        if (strieq(sortBy, "Name"))
+            sortOrder[0] = WUQSFname;
+        else if (strieq(sortBy, "WUID"))
+            sortOrder[0] = WUQSFwuid;
+        else if (strieq(sortBy, "DLL"))
+            sortOrder[0] = WUQSFdll;
+        else if (strieq(sortBy, "MemoryLimit"))
+            sortOrder[0] = (WUQuerySortField) (WUQSFmemoryLimit | WUQSFnumeric);
+        else if (strieq(sortBy, "TimeLimit"))
+            sortOrder[0] = (WUQuerySortField) (WUQSFtimeLimit | WUQSFnumeric);
+        else if (strieq(sortBy, "WarnTimeLimit"))
+            sortOrder[0] = (WUQuerySortField) (WUQSFwarnTimeLimit | WUQSFnumeric);
+        else if (strieq(sortBy, "Priority"))
+            sortOrder[0] = (WUQuerySortField) (WUQSFpriority | WUQSFnumeric);
+        else
+            sortOrder[0] = WUQSFId;
+
+        sortOrder[0] = (WUQuerySortField) (sortOrder[0] | WUQSFnocase);
+        if (descending)
+            sortOrder[0] = (WUQuerySortField) (sortOrder[0] | WUQSFreverse);
+    }
+
+    WUQuerySortField filters[16];
+    unsigned short filterCount = 0;
+    MemoryBuffer filterBuf;
+    const char* clusterReq = req.getClusterName();
+    addWUQSQueryFilter(filters, filterCount, filterBuf, req.getQuerySetName(), WUQSFQuerySet);
+    if (!req.getMemoryLimitLow_isNull())
+        addWUQSQueryFilterInt64(filters, filterCount, filterBuf, req.getMemoryLimitLow(), (WUQuerySortField) (WUQSFmemoryLimit | WUQSFnumeric));
+    if (!req.getMemoryLimitHigh_isNull())
+        addWUQSQueryFilterInt64(filters, filterCount, filterBuf, req.getMemoryLimitHigh(), (WUQuerySortField) (WUQSFmemoryLimitHi | WUQSFnumeric));
+    if (!req.getTimeLimitLow_isNull())
+        addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getTimeLimitLow(), (WUQuerySortField) (WUQSFtimeLimit | WUQSFnumeric));
+    if (!req.getTimeLimitHigh_isNull())
+        addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getTimeLimitHigh(), (WUQuerySortField) (WUQSFtimeLimitHi | WUQSFnumeric));
+    if (!req.getWarnTimeLimitLow_isNull())
+        addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getWarnTimeLimitLow(), (WUQuerySortField) (WUQSFwarnTimeLimit | WUQSFnumeric));
+    if (!req.getWarnTimeLimitHigh_isNull())
+        addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getWarnTimeLimitHigh(), (WUQuerySortField) (WUQSFwarnTimeLimitHi | WUQSFnumeric));
+    if (!req.getPriorityLow_isNull())
+        addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getPriorityLow(), (WUQuerySortField) (WUQSFpriority | WUQSFnumeric));
+    if (!req.getPriorityHigh_isNull())
+        addWUQSQueryFilterInt(filters, filterCount, filterBuf, req.getPriorityHigh(), (WUQuerySortField) (WUQSFpriorityHi | WUQSFnumeric));
+    filters[filterCount] = WUQSFterm;
+
+    unsigned numberOfQueries = 0;
+    unsigned pageSize = req.getPageSize();
+    unsigned pageStartFrom = req.getPageStartFrom();
+    if(pageSize < 1)
+        pageSize = 100;
+    __int64 cacheHint = 0;
+    if (!req.getCacheHint_isNull())
+        cacheHint = req.getCacheHint();
+
+    Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
+    Owned<IConstQuerySetQueryIterator> it = factory->getQuerySetQueriesSorted(sortOrder, filters, filterBuf.bufferBase(), pageStartFrom, pageSize, &cacheHint, &numberOfQueries);
+    resp.setCacheHint(cacheHint);
+
+    IArrayOf<IEspQuerySetQuery> queries;
+    ForEach(*it)
+    {
+        IPropertyTree &query=it->query();
+        Owned<IEspQuerySetQuery> q = createQuerySetQuery();
+        q->setId(query.queryProp("@id"));
+        q->setName(query.queryProp("@name"));
+        q->setQuerySetId(query.queryProp("@querySetId"));
+        q->setDll(query.queryProp("@dll"));
+        q->setWuid(query.queryProp("@wuid"));
+        q->setSuspended(query.getPropBool("@suspended", false));
+        if (query.hasProp("@memoryLimit"))
+        {
+            StringBuffer s;
+            memoryLimitStringFromUInt64(s, query.getPropInt64("@memoryLimit"));
+            q->setMemoryLimit(s);
+        }
+        if (query.hasProp("@timeLimit"))
+            q->setTimeLimit(query.getPropInt("@timeLimit"));
+        if (query.hasProp("@warnTimeLimit"))
+            q->setWarnTimeLimit(query.getPropInt("@warnTimeLimit"));
+        if (query.hasProp("@priority"))
+            q->setPriority(getQueryPriorityName(query.getPropInt("@priority")));
+        if (query.hasProp("@comment"))
+            q->setComment(query.queryProp("@comment"));
+
+        try
+        {
+            const char* cluster = clusterReq;
+            const char* querySetId = query.queryProp("@querySetId");
+            if (isEmpty(cluster))
+                cluster = querySetId;
+            Owned<IPropertyTree> queriesOnCluster = getQueriesOnCluster(cluster, querySetId);
+            if (queriesOnCluster)
+            {
+                IArrayOf<IEspClusterQueryState> clusters;
+                addClusterQueryStates(queriesOnCluster, cluster, query.queryProp("@id"), clusters);
+                q->setClusters(clusters);
+            }
+        }
+        catch(IException *e)
+        {
+            StringBuffer err;
+            DBGLOG("Get exception in WUListQueries: %s", e->errorMessage(err.append(e->errorCode()).append(' ')).str());
+            e->Release();
+        }
+        queries.append(*q.getClear());
+    }
+    resp.setQuerysetQueries(queries);
+    resp.setNumberOfQueries(numberOfQueries);
+
+    return true;
+}
+
 bool CWsWorkunitsEx::onWUQueryDetails(IEspContext &context, IEspWUQueryDetailsRequest & req, IEspWUQueryDetailsResponse & resp)
 {
     const char* querySet = req.getQuerySet();

+ 1 - 0
esp/services/ws_workunits/ws_workunitsService.hpp

@@ -108,6 +108,7 @@ public:
     void setPort(unsigned short _port){port=_port;}
 
     bool isQuerySuspended(const char* query, IConstWUClusterInfo *clusterInfo, unsigned wait, StringBuffer& errorMessage);
+    bool onWUListQueries(IEspContext &context, IEspWUListQueriesRequest &req, IEspWUListQueriesResponse &resp);
 
 private:
     unsigned awusCacheMinutes;