Преглед изворни кода

Merge branch 'candidate-6.2.8' into candidate-6.4.0

Signed-off-by: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman пре 8 година
родитељ
комит
278590d829

+ 3 - 1
cmake_modules/commonSetup.cmake

@@ -983,10 +983,11 @@ IF ("${COMMONSETUP_DONE}" STREQUAL "")
       if("${GPG_VERSION}" VERSION_GREATER "2.1")
       if("${GPG_VERSION}" VERSION_GREATER "2.1")
           set(GPG_COMMAND_STR "${GPG_COMMAND_STR} --pinentry-mode loopback")
           set(GPG_COMMAND_STR "${GPG_COMMAND_STR} --pinentry-mode loopback")
       endif()
       endif()
-      set(GPG_COMMAND_STR "${GPG_COMMAND_STR} --batch --no-tty --output ${CMAKE_CURRENT_BINARY_DIR}/${module} --clearsign ${module}")
+      set(GPG_COMMAND_STR "${GPG_COMMAND_STR} --batch --yes --no-tty --output ${CMAKE_CURRENT_BINARY_DIR}/${module} --clearsign ${module}")
       add_custom_command(
       add_custom_command(
         OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${module}
         OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${module}
         COMMAND bash "-c" "${GPG_COMMAND_STR}"
         COMMAND bash "-c" "${GPG_COMMAND_STR}"
+        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${module}
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
         COMMENT "Adding signed ${module} to project"
         COMMENT "Adding signed ${module} to project"
         )
         )
@@ -994,6 +995,7 @@ IF ("${COMMONSETUP_DONE}" STREQUAL "")
       add_custom_command(
       add_custom_command(
         OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${module}
         OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${module}
         COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${module} ${CMAKE_CURRENT_BINARY_DIR}/${module}
         COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${module} ${CMAKE_CURRENT_BINARY_DIR}/${module}
+        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${module}
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
         COMMENT "Adding unsigned ${module} to project"
         COMMENT "Adding unsigned ${module} to project"
         VERBATIM
         VERBATIM

+ 2 - 2
esp/src/eclwatch/ECLPlaygroundWidget.js

@@ -92,10 +92,10 @@ define([
             this.stackController = registry.byId(this.id + "StackController");
             this.stackController = registry.byId(this.id + "StackController");
             this.stackContainer = registry.byId(this.id + "StackContainer");
             this.stackContainer = registry.byId(this.id + "StackContainer");
             this.errWarnWidget = registry.byId(this.id + "_ErrWarn");
             this.errWarnWidget = registry.byId(this.id + "_ErrWarn");
-            this.resultsWidget = registry.byId(this.id + "_Results");
-            this.resultsWidget.onErrorClick = function (line, col) {
+            this.errWarnWidget.onErrorClick = function (line, col) {
                 context.editorControl.setCursor(line, col);
                 context.editorControl.setCursor(line, col);
             };
             };
+            this.resultsWidget = registry.byId(this.id + "_Results");
             this.visualizeWidget = registry.byId(this.id + "_Visualize");
             this.visualizeWidget = registry.byId(this.id + "_Visualize");
         },
         },
 
 

+ 21 - 6
esp/src/eclwatch/ECLSourceWidget.js

@@ -128,16 +128,23 @@ define([
 
 
             clearErrors: function (errWarnings) {
             clearErrors: function (errWarnings) {
                 for (var i = 0; i < this.markers.length; ++i) {
                 for (var i = 0; i < this.markers.length; ++i) {
-                    this.editor.clearMarker(this.markers[i]);
+                    this.markers[i].clear();
                 }
                 }
                 this.markers = [];
                 this.markers = [];
             },
             },
 
 
             setErrors: function (errWarnings) {
             setErrors: function (errWarnings) {
                 for (var i = 0; i < errWarnings.length; ++i) {
                 for (var i = 0; i < errWarnings.length; ++i) {
-                    this.markers.push(this.editor.setMarker(parseInt(
-                            errWarnings[i].LineNo, 10) - 1, "",
-                            errWarnings[i].Severity + "Line"));
+                    var line = parseInt(errWarnings[i].LineNo, 10);
+                    this.markers.push(this.editor.doc.markText({
+                        line: line - 1,
+                        ch: 0
+                    },{
+                        line: line, 
+                        ch: 0
+                    },{
+                        className: errWarnings[i].Severity + "Line"
+                    }));
                 }
                 }
             },
             },
 
 
@@ -148,12 +155,20 @@ define([
 
 
             clearHighlightLines: function () {
             clearHighlightLines: function () {
                 for (var i = 0; i < this.highlightLines.length; ++i) {
                 for (var i = 0; i < this.highlightLines.length; ++i) {
-                    this.editor.setLineClass(this.highlightLines[i], null, null);
+                    this.highlightLines[i].clear();
                 }
                 }
             },
             },
 
 
             highlightLine: function (line) {
             highlightLine: function (line) {
-                this.highlightLines.push(this.editor.setLineClass(line - 1, "highlightline"));
+                this.highlightLines.push(this.editor.doc.markText({
+                    line: line - 1, 
+                    ch: 0
+                },{
+                    line: line, 
+                    ch: 0
+                },{
+                    className: "highlightline"
+                }));
             },
             },
 
 
             setText: function (text) {
             setText: function (text) {

+ 1 - 1
esp/src/eclwatch/templates/UserQueryWidget.html

@@ -52,7 +52,7 @@
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <div id="${id}Filter" data-dojo-type="FilterDropDownWidget">
                     <div id="${id}Filter" data-dojo-type="FilterDropDownWidget">
                         <p id="${id}LDAPWarning" style="display:none">${i18n.LDAPWarning}</p>
                         <p id="${id}LDAPWarning" style="display:none">${i18n.LDAPWarning}</p>
-                        <input id="${id}SearchInput" title="${i18n.User}:" name="searchinput" colspan="2" data-dojo-props="trim: true" data-dojo-type="dijit.form.TextBox" />
+                        <input id="${id}SearchInput" title="${i18n.User}:" name="Name" colspan="2" data-dojo-props="trim: true" data-dojo-type="dijit.form.TextBox" />
                     </div>
                     </div>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <span data-dojo-type="dijit.ToolbarSeparator"></span>
                     <div class="right" data-dojo-attach-event="onClick:_onNewPage" data-dojo-props="iconClass:'iconNewPage', showLabel:false" data-dojo-type="dijit.form.Button">${i18n.OpenInNewPage}</div>
                     <div class="right" data-dojo-attach-event="onClick:_onNewPage" data-dojo-props="iconClass:'iconNewPage', showLabel:false" data-dojo-type="dijit.form.Button">${i18n.OpenInNewPage}</div>

+ 3 - 5
roxie/ccd/ccdlistener.cpp

@@ -1342,7 +1342,7 @@ public:
         }
         }
         return *logctx;
         return *logctx;
     }
     }
-    virtual bool initQuery(StringBuffer &target, const char *name)
+    virtual void initQuery(StringBuffer &target, const char *name)
     {
     {
         queryName.set(name);
         queryName.set(name);
         queryFactory.setown(globalPackageSetManager->getQuery(name, &target, NULL, *logctx));
         queryFactory.setown(globalPackageSetManager->getQuery(name, &target, NULL, *logctx));
@@ -1356,12 +1356,10 @@ public:
                     targetMsg.append(", in target ").append(target);
                     targetMsg.append(", in target ").append(target);
                 throw MakeStringException(ROXIE_UNKNOWN_QUERY, "Unknown query %s%s", queryName.get(), targetMsg.str());
                 throw MakeStringException(ROXIE_UNKNOWN_QUERY, "Unknown query %s%s", queryName.get(), targetMsg.str());
             }
             }
-            else
-                throw MakeStringException(ROXIE_NO_PACKAGES_ACTIVE, "Unknown query %s (no packages active)", queryName.get());
-            return false;
+
+            throw MakeStringException(ROXIE_NO_PACKAGES_ACTIVE, "Unknown query %s (no packages active)", queryName.get());
         }
         }
         queryFactory->checkSuspended();
         queryFactory->checkSuspended();
-        return true;
     }
     }
     virtual void noteQueryActive()
     virtual void noteQueryActive()
     {
     {

+ 145 - 127
roxie/ccd/ccdprotocol.cpp

@@ -1336,9 +1336,13 @@ public:
     }
     }
 };
 };
 
 
-//ADF - Haven't changed it yet, but this should eliminate the need to parse the query twice below
-//I can load the query and lookup the parse flags before doing a full parse
-//if it turns out I need more info I may delete this.
+enum class WhiteSpaceHandling
+{
+    Default,
+    Strip,
+    Preserve
+};
+
 class QueryNameExtractor : implements IPTreeNotifyEvent, public CInterface
 class QueryNameExtractor : implements IPTreeNotifyEvent, public CInterface
 {
 {
 public:
 public:
@@ -1348,17 +1352,29 @@ public:
     unsigned headerDepth;
     unsigned headerDepth;
     bool isSoap;
     bool isSoap;
     bool isRequestArray;
     bool isRequestArray;
-    bool stripWhitespace;
+    bool isRequest = false;
+    WhiteSpaceHandling whitespace=WhiteSpaceHandling::Default;
     bool more;
     bool more;
 
 
 public:
 public:
     IMPLEMENT_IINTERFACE;
     IMPLEMENT_IINTERFACE;
 
 
-    QueryNameExtractor(TextMarkupFormat _mlFmt, bool _stripWhitespace) : mlFmt(_mlFmt), headerDepth(0), isSoap(false), isRequestArray(false), stripWhitespace(_stripWhitespace), more(true)
+    QueryNameExtractor(TextMarkupFormat _mlFmt) : mlFmt(_mlFmt), headerDepth(0), isSoap(false), isRequestArray(false), more(true)
     {
     {
     }
     }
-    void extractName(const char *msg, const IContextLogger &logctx, const char *peer, unsigned port)
+    void extractName(HttpHelper &httpHelper, const char *msg, const IContextLogger &logctx, const char *peer, unsigned port)
     {
     {
+        StringAttr urlName;
+        if (httpHelper.queryQueryName()) //"Adaptive REST" query name and attrs can come from URL
+        {
+            urlName.set(httpHelper.queryQueryName());
+            if (httpHelper.isMappedToInputParameter()) //this type of content can't have roxie level attrs in
+            {
+                name.set(urlName);
+                return;
+            }
+        }
+
         Owned<IPullPTreeReader> parser;
         Owned<IPullPTreeReader> parser;
         if (mlFmt==MarkupFmt_JSON)
         if (mlFmt==MarkupFmt_JSON)
             parser.setown(createPullJSONStringReader(msg, *this));
             parser.setown(createPullJSONStringReader(msg, *this));
@@ -1367,6 +1383,11 @@ public:
         if (!parser)
         if (!parser)
             return;
             return;
         while (more && parser->next());
         while (more && parser->next());
+        if (urlName.length())
+        {
+            name.set(urlName);
+            return;
+        }
         if (name.isEmpty())
         if (name.isEmpty())
         {
         {
             const char *fmt = mlFmt==MarkupFmt_XML ? "XML" : "JSON";
             const char *fmt = mlFmt==MarkupFmt_XML ? "XML" : "JSON";
@@ -1382,6 +1403,7 @@ public:
         }
         }
         else if (nameStr.endsWith("Request"))
         else if (nameStr.endsWith("Request"))
         {
         {
+            isRequest = true;
             name.set(nameStr.str(), nameStr.length() - strlen("Request"));
             name.set(nameStr.str(), nameStr.length() - strlen("Request"));
         }
         }
     }
     }
@@ -1418,9 +1440,9 @@ public:
     }
     }
     virtual void newAttribute(const char *attr, const char *value)
     virtual void newAttribute(const char *attr, const char *value)
     {
     {
-        if (!name.isEmpty() && streq(attr, "@_stripWhitespaceFromStoredDataset"))
+        if (!name.isEmpty() && strieq(attr, "@stripWhitespaceFromStoredDataset"))
         {
         {
-            stripWhitespace = strToBool(value);
+            whitespace = strToBool(value) ? WhiteSpaceHandling::Strip : WhiteSpaceHandling::Preserve;
             more = false;
             more = false;
         }
         }
     }
     }
@@ -1515,68 +1537,45 @@ private:
         }
         }
     }
     }
 
 
-    void skipProtocolRoot(Owned<IPropertyTree> &queryPT, HttpHelper &httpHelper, StringAttr &queryName, bool &isRequest, bool &isRequestArray)
+    void skipProtocolRoot(Owned<IPropertyTree> &queryPT, HttpHelper &httpHelper, const char *queryName)
     {
     {
         if (queryPT)
         if (queryPT)
         {
         {
-            queryName.set(queryPT->queryName());
-            isRequest = false;
-            isRequestArray = false;
+            const char *tagName = queryPT->queryName();
             if (httpHelper.isHttp())
             if (httpHelper.isHttp())
             {
             {
                 if (httpHelper.queryRequestMlFormat()==MarkupFmt_JSON)
                 if (httpHelper.queryRequestMlFormat()==MarkupFmt_JSON)
                 {
                 {
-                    if (strieq(queryName, "__array__"))
+                    if (strieq(tagName, "__array__"))
                         throw MakeStringException(ROXIE_DATA_ERROR, "JSON request array not implemented");
                         throw MakeStringException(ROXIE_DATA_ERROR, "JSON request array not implemented");
-                    isRequest=true;
-                    if (strieq(queryName, "__object__"))
+                    if (strieq(tagName, "__object__"))
                     {
                     {
                         queryPT.setown(queryPT->getPropTree("*[1]"));
                         queryPT.setown(queryPT->getPropTree("*[1]"));
-                        queryName.set(queryPT->queryName());
                         if (!queryPT)
                         if (!queryPT)
                             throw MakeStringException(ROXIE_DATA_ERROR, "Malformed JSON request (missing Body)");
                             throw MakeStringException(ROXIE_DATA_ERROR, "Malformed JSON request (missing Body)");
                     }
                     }
                 }
                 }
                 else
                 else
                 {
                 {
-                    if (strieq(queryName, "envelope"))
+                    if (strieq(tagName, "envelope"))
                         queryPT.setown(queryPT->getPropTree("Body/*"));
                         queryPT.setown(queryPT->getPropTree("Body/*"));
                     else if (!strnicmp(httpHelper.queryContentType(), "application/soap", strlen("application/soap")))
                     else if (!strnicmp(httpHelper.queryContentType(), "application/soap", strlen("application/soap")))
                         throw MakeStringException(ROXIE_DATA_ERROR, "Malformed SOAP request");
                         throw MakeStringException(ROXIE_DATA_ERROR, "Malformed SOAP request");
                     if (!queryPT)
                     if (!queryPT)
                         throw MakeStringException(ROXIE_DATA_ERROR, "Malformed SOAP request (missing Body)");
                         throw MakeStringException(ROXIE_DATA_ERROR, "Malformed SOAP request (missing Body)");
-                    String reqName(queryPT->queryName());
                     queryPT->removeProp("@xmlns:m");
                     queryPT->removeProp("@xmlns:m");
-
-                    // following code is moved from main() - should be no performance hit
-                    String requestString("Request");
-                    String requestArrayString("RequestArray");
-
-                    if (reqName.endsWith(requestArrayString))
-                    {
-                        isRequestArray = true;
-                        queryName.set(reqName.str(), reqName.length() - requestArrayString.length());
-                    }
-                    else if (reqName.endsWith(requestString))
-                    {
-                        isRequest = true;
-                        queryName.set(reqName.str(), reqName.length() - requestString.length());
-                    }
-                    else
-                        queryName.set(reqName.str());
-
-                    queryPT->renameProp("/", queryName.get());  // reset the name of the tree
+                    queryPT->renameProp("/", queryName);  // reset the name of the tree
                 }
                 }
             }
             }
         }
         }
+        else
+            throw MakeStringException(ROXIE_DATA_ERROR, "Malformed request");
     }
     }
 
 
-    void sanitizeQuery(Owned<IPropertyTree> &queryPT, StringAttr &queryName, StringBuffer &saniText, HttpHelper &httpHelper, const char *&uid, bool &isRequest, bool &isRequestArray, bool &isBlind, bool &isDebug)
+    void sanitizeQuery(Owned<IPropertyTree> &queryPT, StringAttr &queryName, StringBuffer &saniText, HttpHelper &httpHelper, const char *&uid, bool &isBlind, bool &isDebug)
     {
     {
         if (queryPT)
         if (queryPT)
         {
         {
-            skipProtocolRoot(queryPT, httpHelper, queryName, isRequest, isRequestArray);
-
             // convert to XML with attribute values in single quotes - makes replaying queries easier
             // convert to XML with attribute values in single quotes - makes replaying queries easier
             uid = queryPT->queryProp("@uid");
             uid = queryPT->queryProp("@uid");
             if (!uid)
             if (!uid)
@@ -1585,10 +1584,8 @@ private:
             isDebug = queryPT->getPropBool("@debug") || queryPT->getPropBool("_Probe", false);
             isDebug = queryPT->getPropBool("@debug") || queryPT->getPropBool("_Probe", false);
             toXML(queryPT, saniText, 0, isBlind ? (XML_SingleQuoteAttributeValues | XML_Sanitize) : XML_SingleQuoteAttributeValues);
             toXML(queryPT, saniText, 0, isBlind ? (XML_SingleQuoteAttributeValues | XML_Sanitize) : XML_SingleQuoteAttributeValues);
         }
         }
-        else
-            throw MakeStringException(ROXIE_DATA_ERROR, "Malformed request");
     }
     }
-    void createQueryPTree(Owned<IPropertyTree> &queryPT, HttpHelper &httpHelper, const char *text, byte flags, PTreeReaderOptions options)
+    void createQueryPTree(Owned<IPropertyTree> &queryPT, HttpHelper &httpHelper, const char *text, byte flags, byte options, const char *queryName)
     {
     {
         StringBuffer logxml;
         StringBuffer logxml;
         if (httpHelper.queryRequestMlFormat()==MarkupFmt_URL)
         if (httpHelper.queryRequestMlFormat()==MarkupFmt_URL)
@@ -1599,10 +1596,27 @@ private:
             return;
             return;
         }
         }
         if (httpHelper.queryRequestMlFormat()==MarkupFmt_JSON)
         if (httpHelper.queryRequestMlFormat()==MarkupFmt_JSON)
-            queryPT.setown(createPTreeFromJSONString(text, flags, options));
+            queryPT.setown(createPTreeFromJSONString(text, flags, (PTreeReaderOptions) options));
         else
         else
-            queryPT.setown(createPTreeFromXMLString(text, flags, options));
+            queryPT.setown(createPTreeFromXMLString(text, flags, (PTreeReaderOptions) options));
         queryPT.setown(httpHelper.checkAddWrapperForAdaptiveInput(queryPT.getClear(), flags));
         queryPT.setown(httpHelper.checkAddWrapperForAdaptiveInput(queryPT.getClear(), flags));
+        skipProtocolRoot(queryPT, httpHelper, queryName);
+        if (queryPT->hasProp("_stripWhitespaceFromStoredDataset"))
+        {
+            bool stripTag = queryPT->getPropBool("_stripWhitespaceFromStoredDataset");
+            bool stripFlag = (options & ptr_ignoreWhiteSpace) != 0;
+            if (stripTag != stripFlag)
+            {
+                if (stripTag)
+                    options |= ptr_ignoreWhiteSpace;
+                else
+                    options &= ~ptr_ignoreWhiteSpace;
+                //The tag _stripWhitespaceFromStoredDataset can appear anywhere at the same level as query inputs
+                //it can't be checked until after parsing the full request, so if it changes the parse flags
+                //we have to parse the request again now
+                createQueryPTree(queryPT, httpHelper, text, flags, options, queryName);
+            }
+        }
     }
     }
 
 
     void doMain(const char *runQuery)
     void doMain(const char *runQuery)
@@ -1685,7 +1699,7 @@ readAnother:
 
 
         StringAttr queryName;
         StringAttr queryName;
         StringAttr queryPrefix;
         StringAttr queryPrefix;
-        bool stripWhitespace = msgctx->getStripWhitespace();
+        WhiteSpaceHandling whitespace = WhiteSpaceHandling::Default;
         try
         try
         {
         {
             if (httpHelper.isHttpGet() || httpHelper.isFormPost())
             if (httpHelper.isHttpGet() || httpHelper.isFormPost())
@@ -1696,11 +1710,13 @@ readAnother:
             }
             }
             else if (mlRequestFmt==MarkupFmt_XML || mlRequestFmt==MarkupFmt_JSON)
             else if (mlRequestFmt==MarkupFmt_XML || mlRequestFmt==MarkupFmt_JSON)
             {
             {
-                QueryNameExtractor extractor(mlRequestFmt, stripWhitespace);
-                extractor.extractName(rawText.str(), logctx, peerStr, ep.port);
+                QueryNameExtractor extractor(mlRequestFmt);
+                extractor.extractName(httpHelper, rawText.str(), logctx, peerStr, ep.port);
                 queryName.set(extractor.name);
                 queryName.set(extractor.name);
                 queryPrefix.set(extractor.prefix);
                 queryPrefix.set(extractor.prefix);
-                stripWhitespace = extractor.stripWhitespace;
+                whitespace = extractor.whitespace;
+                isRequest = extractor.isRequest;
+                isRequestArray = extractor.isRequestArray;
                 if (httpHelper.isHttp())
                 if (httpHelper.isHttp())
                     httpHelper.setUseEnvelope(extractor.isSoap);
                     httpHelper.setUseEnvelope(extractor.isSoap);
             }
             }
@@ -1712,10 +1728,9 @@ readAnother:
                 bool aclupdate = strieq(queryName, "aclupdate"); //ugly
                 bool aclupdate = strieq(queryName, "aclupdate"); //ugly
                 byte iptFlags = aclupdate ? ipt_caseInsensitive : 0;
                 byte iptFlags = aclupdate ? ipt_caseInsensitive : 0;
 
 
-                createQueryPTree(queryPT, httpHelper, rawText, iptFlags, (PTreeReaderOptions)(ptr_ignoreWhiteSpace|ptr_ignoreNameSpaces));
+                createQueryPTree(queryPT, httpHelper, rawText, iptFlags, (PTreeReaderOptions)(ptr_ignoreWhiteSpace|ptr_ignoreNameSpaces), queryName);
 
 
-                IPropertyTree *root = queryPT;
-                skipProtocolRoot(queryPT, httpHelper, queryName, isRequest, isRequestArray);
+                //IPropertyTree *root = queryPT;
                 if (!strchr(queryName, ':'))
                 if (!strchr(queryName, ':'))
                 {
                 {
                     VStringBuffer fullname("control:%s", queryName.str()); //just easier to keep for debugging and internal checking
                     VStringBuffer fullname("control:%s", queryName.str()); //just easier to keep for debugging and internal checking
@@ -1733,12 +1748,30 @@ readAnother:
             }
             }
             else
             else
             {
             {
+                StringBuffer querySetName;
+                if (isHTTP)
+                {
+                    client->setHttpMode(queryName, isRequestArray, httpHelper);
+                    querySetName.set(httpHelper.queryTarget());
+                    if (querySetName.length())
+                    {
+                        const char *target = global->targetAliases->queryProp(querySetName.str());
+                        if (target)
+                            querySetName.set(target);
+                    }
+                }
+
+                msgctx->initQuery(querySetName, queryName); //needed here to allow checking hash options
+
+                if (whitespace == WhiteSpaceHandling::Default) //value in the request wins
+                    whitespace = msgctx->getStripWhitespace() ? WhiteSpaceHandling::Strip : WhiteSpaceHandling::Preserve; //might be changed by hash option, returns default otherwise
+
                 unsigned readFlags = (unsigned) global->defaultXmlReadFlags | ptr_ignoreNameSpaces;
                 unsigned readFlags = (unsigned) global->defaultXmlReadFlags | ptr_ignoreNameSpaces;
                 readFlags &= ~ptr_ignoreWhiteSpace;
                 readFlags &= ~ptr_ignoreWhiteSpace;
-                readFlags |= (stripWhitespace ? ptr_ignoreWhiteSpace : ptr_none);
+                readFlags |= (whitespace == WhiteSpaceHandling::Strip ? ptr_ignoreWhiteSpace : ptr_none);
                 try
                 try
                 {
                 {
-                    createQueryPTree(queryPT, httpHelper, rawText.str(), ipt_caseInsensitive, (PTreeReaderOptions)readFlags);
+                    createQueryPTree(queryPT, httpHelper, rawText.str(), ipt_caseInsensitive, (PTreeReaderOptions)readFlags, queryName);
                 }
                 }
                 catch (IException *E)
                 catch (IException *E)
                 {
                 {
@@ -1748,7 +1781,7 @@ readAnother:
                 }
                 }
 
 
                 uid = NULL;
                 uid = NULL;
-                sanitizeQuery(queryPT, queryName, sanitizedText, httpHelper, uid, isRequest, isRequestArray, isBlind, isDebug);
+                sanitizeQuery(queryPT, queryName, sanitizedText, httpHelper, uid, isBlind, isDebug);
                 if (uid)
                 if (uid)
                     msgctx->setTransactionId(uid);
                     msgctx->setTransactionId(uid);
                 else
                 else
@@ -1796,99 +1829,84 @@ readAnother:
                 }
                 }
                 else
                 else
                 {
                 {
-                    StringBuffer querySetName;
+                    int bindCores = queryPT->getPropInt("@bindCores", msgctx->getBindCores());
+                    if (bindCores > 0)
+                        listener->setThreadAffinity(bindCores);
+                    IArrayOf<IPropertyTree> requestArray;
                     if (isHTTP)
                     if (isHTTP)
                     {
                     {
-                        client->setHttpMode(queryName, isRequestArray, httpHelper);
-                        querySetName.set(httpHelper.queryTarget());
-                        if (querySetName.length())
-                        {
-                            const char *target = global->targetAliases->queryProp(querySetName.str());
-                            if (target)
-                                querySetName.set(target);
-                        }
-                    }
-                    if (msgctx->initQuery(querySetName, queryName))
-                    {
-                        int bindCores = queryPT->getPropInt("@bindCores", msgctx->getBindCores());
-                        if (bindCores > 0)
-                            listener->setThreadAffinity(bindCores);
-                        IArrayOf<IPropertyTree> requestArray;
-                        if (isHTTP)
+                        if (isRequestArray)
                         {
                         {
-                            if (isRequestArray)
-                            {
-                                StringBuffer reqIterString;
-                                reqIterString.append(queryName).append("Request");
+                            StringBuffer reqIterString;
+                            reqIterString.append(queryName).append("Request");
 
 
-                                Owned<IPropertyTreeIterator> reqIter = queryPT->getElements(reqIterString.str());
-                                ForEach(*reqIter)
-                                {
-                                    IPropertyTree *fixedreq = createPTree(queryName, ipt_caseInsensitive);
-                                    Owned<IPropertyTreeIterator> iter = reqIter->query().getElements("*");
-                                    ForEach(*iter)
-                                    {
-                                        fixedreq->addPropTree(iter->query().queryName(), LINK(&iter->query()));
-                                    }
-                                    requestArray.append(*fixedreq);
-                                }
-                            }
-                            else
+                            Owned<IPropertyTreeIterator> reqIter = queryPT->getElements(reqIterString.str());
+                            ForEach(*reqIter)
                             {
                             {
                                 IPropertyTree *fixedreq = createPTree(queryName, ipt_caseInsensitive);
                                 IPropertyTree *fixedreq = createPTree(queryName, ipt_caseInsensitive);
-                                Owned<IPropertyTreeIterator> iter = queryPT->getElements("*");
+                                Owned<IPropertyTreeIterator> iter = reqIter->query().getElements("*");
                                 ForEach(*iter)
                                 ForEach(*iter)
                                 {
                                 {
                                     fixedreq->addPropTree(iter->query().queryName(), LINK(&iter->query()));
                                     fixedreq->addPropTree(iter->query().queryName(), LINK(&iter->query()));
                                 }
                                 }
                                 requestArray.append(*fixedreq);
                                 requestArray.append(*fixedreq);
                             }
                             }
-                            if (httpHelper.getTrim())
-                                protocolFlags |= HPCC_PROTOCOL_TRIM;
                         }
                         }
                         else
                         else
                         {
                         {
-                            const char *format = queryPT->queryProp("@format");
-                            if (format)
+                            IPropertyTree *fixedreq = createPTree(queryName, ipt_caseInsensitive);
+                            Owned<IPropertyTreeIterator> iter = queryPT->getElements("*");
+                            ForEach(*iter)
                             {
                             {
-                                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)
-                                {
+                                fixedreq->addPropTree(iter->query().queryName(), LINK(&iter->query()));
+                            }
+                            requestArray.append(*fixedreq);
+                        }
+                        if (httpHelper.getTrim())
+                            protocolFlags |= HPCC_PROTOCOL_TRIM;
+                    }
+                    else
+                    {
+                        const char *format = queryPT->queryProp("@format");
+                        if (format)
+                        {
+                            if (stricmp(format, "raw") == 0)
+                            {
+                                protocolFlags |= HPCC_PROTOCOL_NATIVE_RAW;
+                                if (client) //not stand alone roxie exe
                                     protocolFlags |= HPCC_PROTOCOL_BLOCKED;
                                     protocolFlags |= HPCC_PROTOCOL_BLOCKED;
-                                    mlResponseFmt = MarkupFmt_XML;
-                                }
-                                else if (stricmp(format, "ascii") == 0)
-                                {
-                                    protocolFlags |= HPCC_PROTOCOL_NATIVE_ASCII;
-                                    mlResponseFmt = MarkupFmt_Unknown;
-                                }
-                                else if (stricmp(format, "xml") != 0) // xml is the default
-                                    throw MakeStringException(ROXIE_INVALID_INPUT, "Unsupported format specified: %s", format);
+                                mlResponseFmt = MarkupFmt_Unknown;
+                            }
+                            else if (stricmp(format, "bxml") == 0)
+                            {
+                                protocolFlags |= HPCC_PROTOCOL_BLOCKED;
+                                mlResponseFmt = MarkupFmt_XML;
                             }
                             }
-                            if (queryPT->getPropBool("@trim", false))
-                                protocolFlags |= HPCC_PROTOCOL_TRIM;
-                            msgctx->setIntercept(queryPT->getPropBool("@log", false));
-                            msgctx->setTraceLevel(queryPT->getPropInt("@traceLevel", logctx.queryTraceLevel()));
+                            else if (stricmp(format, "ascii") == 0)
+                            {
+                                protocolFlags |= HPCC_PROTOCOL_NATIVE_ASCII;
+                                mlResponseFmt = MarkupFmt_Unknown;
+                            }
+                            else if (stricmp(format, "xml") != 0) // xml is the default
+                                throw MakeStringException(ROXIE_INVALID_INPUT, "Unsupported format specified: %s", format);
                         }
                         }
+                        if (queryPT->getPropBool("@trim", false))
+                            protocolFlags |= HPCC_PROTOCOL_TRIM;
+                        msgctx->setIntercept(queryPT->getPropBool("@log", false));
+                        msgctx->setTraceLevel(queryPT->getPropInt("@traceLevel", logctx.queryTraceLevel()));
+                    }
 
 
-                        msgctx->noteQueryActive();
+                    msgctx->noteQueryActive();
 
 
-                        if (isHTTP)
-                        {
-                            CHttpRequestAsyncFor af(queryName, sink, msgctx, requestArray, *client, httpHelper, protocolFlags, memused, slavesReplyLen, sanitizedText, logctx, (PTreeReaderOptions)readFlags, querySetName);
-                            af.For(requestArray.length(), global->numRequestArrayThreads);
-                        }
-                        else
-                        {
-                            Owned<IHpccProtocolResponse> protocol = createProtocolResponse(queryPT->queryName(), client, httpHelper, logctx, protocolFlags, (PTreeReaderOptions)readFlags);
-                            sink->onQueryMsg(msgctx, queryPT, protocol, protocolFlags, (PTreeReaderOptions)readFlags, querySetName, 0, memused, slavesReplyLen);
-                        }
+                    if (isHTTP)
+                    {
+                        CHttpRequestAsyncFor af(queryName, sink, msgctx, requestArray, *client, httpHelper, protocolFlags, memused, slavesReplyLen, sanitizedText, logctx, (PTreeReaderOptions)readFlags, querySetName);
+                        af.For(requestArray.length(), global->numRequestArrayThreads);
+                    }
+                    else
+                    {
+                        Owned<IHpccProtocolResponse> protocol = createProtocolResponse(queryPT->queryName(), client, httpHelper, logctx, protocolFlags, (PTreeReaderOptions)readFlags);
+                        sink->onQueryMsg(msgctx, queryPT, protocol, protocolFlags, (PTreeReaderOptions)readFlags, querySetName, 0, memused, slavesReplyLen);
                     }
                     }
                 }
                 }
             }
             }

+ 1 - 1
roxie/ccd/hpccprotocol.hpp

@@ -26,7 +26,7 @@
 
 
 interface IHpccProtocolMsgContext : extends IInterface
 interface IHpccProtocolMsgContext : extends IInterface
 {
 {
-    virtual bool initQuery(StringBuffer &target, const char *queryname) = 0;
+    virtual void initQuery(StringBuffer &target, const char *queryname) = 0;
     virtual void noteQueryActive() = 0;
     virtual void noteQueryActive() = 0;
     virtual unsigned getQueryPriority() = 0;
     virtual unsigned getQueryPriority() = 0;
     virtual IContextLogger *queryLogContext() = 0;
     virtual IContextLogger *queryLogContext() = 0;

+ 6 - 0
testing/regress/ecl/key/roxiewhitespace.xml

@@ -0,0 +1,6 @@
+<Dataset name='keepResult'>
+ <Row><Dataset><Row><name><first>  Joe</first><last>  Doe</last></name><address><city>Fresno</city><state>CA</state><zipcode>11111</zipcode></address></Row></Dataset><Exception><Source></Source><Code>0</Code><Message></Message></Exception></Row>
+</Dataset>
+<Dataset name='stripResult'>
+ <Row><Dataset><Row><name><first>Joe</first><last>Doe</last></name><address><city>Fresno</city><state>CA</state><zipcode>11111</zipcode></address></Row></Dataset><Exception><Source></Source><Code>0</Code><Message></Message></Exception></Row>
+</Dataset>

+ 68 - 0
testing/regress/ecl/roxiewhitespace.ecl

@@ -0,0 +1,68 @@
+//nothor
+//nohthor
+
+NameRec := RECORD
+  string First;
+  string Last;
+END;
+
+AddressRec := RECORD
+  string City;
+  string State;
+  integer ZipCode;
+END;
+
+PersonRec := RECORD
+  NameRec Name;
+  AddressRec Address;
+END;
+
+peeps_send := DATASET([{{'  Joe  ', '  Doe  '}, {'Fresno', 'CA', 11111}}], PersonRec);
+
+roxieEchoTestRequestRecord := RECORD
+  DATASET(PersonRec) Peeps {XPATH('Peeps/Row')} := peeps_send;
+END;
+
+exceptionRec := RECORD
+  string Source {xpath('Source')};
+  integer Code {xpath('Code')};
+  string Message {xpath('Message')};
+END;
+
+roxieEchoTestResponseRecord := RECORD
+  DATASET(PersonRec) Peeps {XPATH('Dataset/Row')} := DATASET([], PersonRec);
+  exceptionRec Exception {XPATH('Exception')};
+END;
+
+roxieEchoTestResponseRecord doFail() := TRANSFORM
+  self.Exception.CODE := IF (FAILCODE=0, 0, ERROR(FAILCODE, FAILMESSAGE));
+  self.Exception.Message := FAILMESSAGE;
+  self.Exception.Source := 'Test';
+END;
+
+string TargetIP := '.' : stored('TargetIP');
+string TargetURL := 'http://' + TargetIP + ':9876';
+
+soapcallResult := SOAPCALL(TargetURL, 'roxie_keepwhitespace', roxieEchoTestRequestRecord,
+    DATASET(roxieEchoTestResponseRecord),
+    LITERAL,
+    XPATH('*/Results/Result'),
+    RESPONSE(NOTRIM),
+    ONFAIL(doFail()));
+
+OUTPUT(soapcallResult, NAMED('keepResult'));
+
+roxieEchoTestStripRequest := RECORD
+  roxieEchoTestRequestRecord;
+  boolean _stripWhitespaceFromStoredDataset := true;
+END;
+
+stripResult := SOAPCALL(TargetURL, 'roxie_keepwhitespace', roxieEchoTestStripRequest,
+    DATASET(roxieEchoTestResponseRecord),
+    LITERAL,
+    XPATH('*/Results/Result'),
+    RESPONSE(NOTRIM),
+    ONFAIL(doFail()));
+
+OUTPUT(stripResult, NAMED('stripResult'));
+

+ 26 - 0
testing/regress/ecl/setup/roxie_keepwhitespace.ecl

@@ -0,0 +1,26 @@
+//nothor
+//nohthor
+//publish
+
+#OPTION('stripwhitespacefromstoreddataset', false);
+
+NameRec := RECORD
+  string10 First;
+  string15 Last;
+END;
+
+AddressRec := RECORD
+  string10 City;
+  string2 State;
+  integer4 ZipCode;
+END;
+
+PersonRec := RECORD
+  NameRec Name;
+  AddressRec Address;
+END;
+
+peeps := DATASET([], PersonRec) : STORED('peeps', FEW);
+
+OUTPUT(peeps, NAMED('Peeps'));
+