Let me start off by explaining the cause of this bug by including a bit of code from dojo/_base/query.js:
root = root||getDoc();
var od = root.ownerDocument||root.documentElement;
// throw the big case sensitivity switch
// NOTE:
// Opera in XHTML mode doesn't detect case-sensitivity correctly
// and it's not clear that there's any way to test for it
caseSensitive = (root.contentType && root.contentType=="application/xml") ||
(d.isOpera && (root.doctype || od.toString() == "[object XMLDocument]")) ||
(!!od) &&
(d.isIE ? od.xml : (root.xmlVersion||od.xmlVersion));
"root" is the root of the search or Document if none is provided.
The issues start with the second line of this extract, however: it would appear that "od" is meant to contain the ownerDocument, however, in the case that the root is a Document (as it will be if no node is provided as the root for the search), then ownerDocument will always be null. Currently this leads to root.documentElement being used as od in the case of root being Document or a DOCTYPE not yet added to a document (though you can special case as no query on that will ever match anything, if it isn't already).
In the case of od being the Document everything works fine in Opera currently (though relying upon a specific stringification of od seems risky), but when it is not, it always concludes that it is case sensitive (this is the case in the changeContentTable test, and the reason for the error).
It would seem best to fix this by checking whether root is a Document (this cannot be done in a cross-browser way through instanceof, as Opera will return false in some cases, as the behaviour is different in the undefined manner in which DOM interfaces map to ECMAScript), probably by checking for some property like documentURI (which only exists on Document) and using document.ownerDocument otherwise (and special case DocumentType? nodes somehow so they fail, as it makes no sense to run a query on something that cannot have children), and then just check whether od.createElement("div").tagName === "div" (it will always return "DIV" in the case of HTML documents, which is effectively what it is testing).
Simple example:
That will fail as "p" (from the query) != "P" (from tagName). If you make the p in the query uppercase it will succeed.