static int compareWUs(IInterface **ll, IInterface **rr)
{
    IConstECLWorkunit *l = (IConstECLWorkunit *) *ll;
    IConstECLWorkunit *r = (IConstECLWorkunit *) *rr;
    const char* ln = l->getWuid();
    const char* rn = r->getWuid();
    return strcmp(ln, rn);
}
bool DeleteHelper::doit(FILE * fp)
{
    const char* wuid = globals->queryProp("WUID");
    StringArray wuids;
    if(wuid && *wuid)
    {
        wuids.append(wuid);
    }
    else
    {
        const char* owner = globals->queryProp("OWNER");
        if(owner == NULL || *owner=='\0')
            return false;

        Owned<IClientWUQueryRequest> req = wuclient->createWUQueryRequest();
        req->setOwner(owner);

        Owned<IClientWUQueryResponse> resp = wuclient->WUQuery(req);
        if(!resp)
            return false;
        IArrayOf<IConstECLWorkunit>& wus = resp->getWorkunits();
        ForEachItemIn(idx, wus)
        {
            IConstECLWorkunit* wu = &wus.item(idx);
            if(wu == NULL || wu->getWuid() == NULL)
                continue;
            switch (wu->getStateID())
            {
            case WUStateAborted:
            case WUStateCompleted:
            case WUStateFailed:
                wuids.append(wu->getWuid());
                break;
            }
        }
    }
bool DumpHelper::doit(FILE * fp)
{
    SCMStringBuffer xml;

    // If we were given a workunit dump that one workunit, otherwise moan
    if (globals->hasProp("WUID"))
    {
        const char* wuid = globals->queryProp("WUID");
        const char *whichPath = globals->queryProp("prop");
        if (whichPath)
        {
            if (stricmp(whichPath, "ecl")==0)
            {                   
                Owned<IClientWUInfoRequest> inforeq = wuclient->createWUInfoRequest();
                inforeq->setWuid(wuid);
                Owned<IClientWUInfoResponse> inforesp = wuclient->WUInfo(inforeq);
                if(!inforesp)
                {
                    printf("Workunit %s not found\n", wuid);
                    return false;
                }

                IConstECLWorkunit* wu = &inforesp->getWorkunit();
                IConstECLQuery* query = &wu->getQuery();
                if(query)
                    xml.set(query->getText());
            }
            else
            {
                printf("Unrecognized parameter prop=%s", whichPath);
                return false;
            }
        }
        else
        {
            Owned<IClientWULogFileRequest> req = wuclient->createWUFileRequest();
            req->setWuid(wuid);
            req->setType("XML");
            Owned<IClientWULogFileResponse> resp = wuclient->WUFile(req);
            if(!resp)
            {
                printf("Workunit %s not found\n", wuid);
                return false;
            }
            const IMultiException* excep = &resp->getExceptions();
            if(excep != NULL && excep->ordinality())
            {
                unsigned i = 0;
                while (i < excep->ordinality())
                {
                    StringBuffer msg;
                    excep->item(i).errorMessage(msg);
                    unsigned code = excep->item(i).errorCode();
                    printf("<Error><code>%d</code><message>%s</message></Error>\n", code, msg.str());
                }
                return false;
            }

            const MemoryBuffer & xmlmem = resp->getThefile();
            StringBuffer xmlbuf;
            xmlbuf.append(xmlmem.length(), xmlmem.toByteArray());
            xml.set(xmlbuf.str());
        }
        // Print the results
        if (fp != NULL)
        {
            fprintf(fp, "%s", xml.str());
        }
        return true;
    }

    return false;
}
bool ViewHelper::doit(FILE * fp)
{
    if (globals->hasProp("WUID"))
    {
        const char* wuid = globals->queryProp("WUID");

        Owned<IClientWUInfoRequest> req = wuclient->createWUInfoRequest();
        req->setWuid(wuid);
        Owned<IClientWUInfoResponse> resp = wuclient->WUInfo(req);
        if(!resp)
            return false;

        const IMultiException* excep = &resp->getExceptions();
        if(excep != NULL && excep->ordinality() > 0)
        {
            StringBuffer msg;
            excep->errorMessage(msg);
            printf("%s\n", msg.str());
            return false;
        }

        IConstECLWorkunit* w = &resp->getWorkunit();
        if (w && fp)
        {
            bool xml = true;
            const char* fmt = globals->queryProp("format");
            if(fmt && (stricmp(fmt, "bin") == 0 || stricmp(fmt, "binary") == 0))
                xml = false;
            IArrayOf<IConstECLException>& exceptions = w->getExceptions();
            ForEachItemIn(ind, exceptions)
            {
                IConstECLException* excep = &exceptions.item(ind);
                if(!excep)
                    continue;

                bool skip = false;
                const char* severity = excep->getSeverity();
                if (severity != NULL && stricmp(severity, "Warning") == 0 && globals->getPropBool("noWarnings", false))
                    skip = true;
                if (severity != NULL && stricmp(severity, "Info") == 0 && globals->getPropBool("noInfo", false))
                    skip = true;
                if (severity != NULL && stricmp(severity, "Error") == 0 && globals->getPropBool("noErrors", false))
                    skip = true;
                if (!skip)
                {
                    int lineno = excep->getLineNo();
                    const char* source = excep->getSource();
                    const char* msg = excep->getMessage();
                    unsigned code = excep->getCode();
                    if (lineno && source != NULL)
                    {
                        if (xml)
                            fprintf(fp, "<%s><source>%s</source><line>%d</line><code>%d</code><message>%s</message></%s>\n", severity, source, lineno, code, msg, severity);
                        else
                            fprintf(fp, "%s: %s(%d) %s\n", severity, source, lineno, msg);
                    }
                    else if(source != NULL)
                    {
                        if (xml)
                            fprintf(fp, "<%s><source>%s</source><code>%d</code><message>%s</message></%s>\n", severity, source, code, msg, severity);
                        else
                            fprintf(fp, "%s: %s %s\n", severity, source, msg);
                    }
                    else
                    {
                        if (xml)
                            fprintf(fp, "<%s><code>%d</code><message>%s</message></%s>\n", severity, code, msg, severity);
                        else
                            fprintf(fp, "%s: %s\n", severity, msg);
                    }
                }
            }

            if (w->getStateID() == WUStateAborted)
            {
                fprintf(fp, "Aborted\n");
                return true;
            }
            if (w->getStateID() == WUStateFailed)
                return false;

            int queryid = 0;

            IArrayOf<IConstECLResult>& results = w->getResults();
            ForEachItemIn(res_ind, results)
            {
                IConstECLResult* result = &results.item(res_ind);
                
                if(!result)
                    continue;
                
                const char* value = result->getValue();
                if(value != NULL && stricmp(value, "[undefined]") == 0)
                    continue;

                if(format)
                    format->printHeader(fp, result->getName());

                const char* rfname = result->getFileName();
                if(!(rfname && *rfname  && (globals->getPropInt("viewFileResults") ==0)))
                {
                    int pagesize = 0;
                    if(globals->hasProp("pagesize"))
                        pagesize = atoi(globals->queryProp("pagesize"));
                    if(pagesize == 0)
                        pagesize = DEFAULT_PAGESIZE;
                    int curpos = 0;
                    int count = 0;
                    int total = 0;
                    do
                    {
                        Owned<IClientWUResultBinRequest> res_req = wuclient->createWUResultBinRequest();
                        res_req->setStart(curpos);
                        res_req->setWuid(wuid);
                        res_req->setSequence(result->getSequence());
                        res_req->setCount(pagesize);
                        if (xml)
                            res_req->setFormat("xml");
                        else
                            res_req->setFormat("raw");
                        Owned<IClientWUResultBinResponse> res_resp = wuclient->WUResultBin(res_req);

                        const IMultiException* excep = &res_resp->getExceptions();
                        if(excep != NULL && excep->ordinality() > 0)
                        {
                            StringBuffer errmsg;
                            excep->errorMessage(errmsg);
                            printf("%s\n", errmsg.str());
                            continue;
                        }

                        const MemoryBuffer& resultbuf = res_resp->getResult();
                        count = res_resp->getCount();
                        total = (int)res_resp->getTotal();
                        
                        if(format)
                        {
                            format->setStartRowNumber(curpos);
                            format->printBody(fp, resultbuf.length(), (char*)resultbuf.toByteArray());
                        }
                        else
                        {
                            // This should never happen
                            fprintf(fp, "%s", resultbuf.toByteArray());
                        }
                        
                        curpos += count;
                    }
                    while (count > 0 && curpos < total - 1);
                }
                
                if(format)
                    format->printFooter(fp);
            }
bool QueryHelper::doit(FILE * fp)
{
    Owned<IClientWUCreateRequest> creq = wuclient->createWUCreateRequest();
    Owned<IClientWUCreateResponse> cresp = wuclient->WUCreate(creq);
    const IMultiException* excep = &cresp->getExceptions();
    if(excep != NULL && excep->ordinality() > 0)
    {
        StringBuffer msg;
        excep->errorMessage(msg);
        printf("%s\n", msg.str());
        return false;
    }

    IConstECLWorkunit* wu = &cresp->getWorkunit();
    if(!wu)
    {
        printf("can't create workunit\n");
        return false;
    }

    Owned<IClientWUUpdateRequest> ureq = wuclient->createWUUpdateRequest();
    ureq->setWuid(wu->getWuid());

    // Make a workUnit
    StringBuffer jobname;
    if(globals->hasProp("jobname"))
        jobname.append(globals->queryProp("jobname"));

    StringBuffer ecl;
    if (globals->getProp("ecl", ecl))
    {
        if (ecl.length() && ecl.charAt(0)=='@')
        {
            StringBuffer filename(ecl.str()+1);
            ecl.clear().loadFile(filename);
            if (jobname.length() == 0)
                splitFilename(filename, NULL, NULL, &jobname, NULL);
        }
        ureq->setQueryText(ecl.str());
    }
    else if (globals->hasProp("main"))
        ureq->setQueryMainDefinition(globals->queryProp("main"));
    else if (globals->hasProp("attr"))
        ureq->setQueryText(globals->queryProp("attr"));

    if (globals->getPropInt("compileOnly", 0)!=0)
        ureq->setAction(WUActionCompile);
    if (jobname.length())
        ureq->setJobname(jobname);

    IArrayOf<IEspDebugValue> dvals;
    IArrayOf<IEspApplicationValue> avals;
    StringBuffer xmlParams;

    Owned<IPropertyIterator> it = globals->getIterator();
    bool xmlSeen = false;
    ForEach(*it)
    {
        const char * key = it->getPropKey();
        if (key && strlen(key)>1)
        {
            if(key[0] == '-')
            {
                if (key[1] == 'f')
                {
                    Owned<IEspDebugValue> dval = createDebugValue();
                    dval->setName(&key[2]);
                    dval->setValue(globals->queryProp(key));
                    dvals.append(*dval.getLink());
                }
                //All other options are ignored.
            }
            else if(key[0] == '_')
            {
                Owned<IEspApplicationValue> aval = createApplicationValue();
                aval->setApplication("eclplus");
                aval->setName(&key[1]);
                aval->setValue(globals->queryProp(key));
                avals.append(*aval.getLink());
            }
            else if(key[0] == '/')
            {
                if (xmlSeen)
                    throw MakeStringException(0, "query option must not be used with stored or /, and cannot appear more than once");
                // The / form is expected to be used for scalars, so xmlEncode is appropriate.
                // To pass sets or datasets, use the xml= version
                xmlParams.appendf("<%s>", &key[1]);
                encodeXML(globals->queryProp(key), xmlParams);
                xmlParams.appendf("</%s>", &key[1]);
            }
            else if(stricmp(key, "stored")==0)
            {
                if (xmlSeen)
                    throw MakeStringException(0, "query option must not be used with stored or /, and cannot appear more than once");
                const char *xml = globals->queryProp(key);
                try
                {
                    Owned<IPropertyTree> checkValid = createPTreeFromXMLString(xml);
                }
                catch (IException *E)
                {
                    StringBuffer msg;
                    E->errorMessage(msg);
                    E->Release();
                    throw MakeStringException(0, "Invalid xml: %s", msg.str());
                }
                xmlParams.append(xml);
            }
            else if(stricmp(key, "query")==0)
            {
                if (xmlSeen || xmlParams.length())
                    throw MakeStringException(0, "query option must not be used with stored or /, and cannot appear more than once");
                xmlSeen = true;
                StringBuffer xml;
                if (!globals->getProp(key, xml))
                    throw MakeStringException(0, "Invalid value for query= parameter");
                if (xml.length() && xml.charAt(0)=='@')
                {
                    StringBuffer filename(xml.str()+1);
                    xml.clear().loadFile(filename);
                }
                try
                {
                    Owned<IPropertyTree> checkValid = createPTreeFromXMLString(xml);
                }
                catch (IException *E)
                {
                    StringBuffer msg;
                    E->errorMessage(msg);
                    E->Release();
                    throw MakeStringException(0, "Invalid xml: %s", msg.str());
                }
                xmlParams.append(xml);
            }
        }
    }
    if(dvals.length() > 0)
        ureq->setDebugValues(dvals);
    if(avals.length() > 0)
        ureq->setApplicationValues(avals);
    if (xmlParams.length())
    {
        if (!xmlSeen)
        {
            xmlParams.insert(0, "<Query>");
            xmlParams.append("</Query>");
        }
        ureq->setXmlParams(xmlParams);
    }

    Owned<IClientWUUpdateResponse> uresp = wuclient->WUUpdate(ureq);
    const IMultiException* uexcep = &uresp->getExceptions();
    if(uexcep != NULL && uexcep->ordinality() > 0)
    {
        StringBuffer msg;
        uexcep->errorMessage(msg);
        printf("%s\n", msg.str());
        return false;
    }

    // Execute it
    return doSubmitWorkUnit(fp, wu->getWuid(), globals->queryProp("cluster"));
}