I ran into a few separate issues. Since they concentrate on the same piece of code, I address them simultaneously. In my program I have the following method:
private void processEventTriggers() { try { ByteArrayOutputStream stream = new ByteArrayOutputStream(); String inQuery = "collection()/event/@in/string()"; XQuery inputQuery = new XQuery(inQuery); inputQuery.execute(_context,stream); String input = stream.toString();
String processQuery = "collection()/trigger_set/trigger[@name='"+_currentTrigger+"']/matches"; System.out.println("Process Event: "+processQuery); QueryProcessor processor = new QueryProcessor(processQuery, _context); Iter iterator = processor.iter(); Item item; while ((item=iterator.next())!=null) { BXNode node = (BXNode)item.toJava();
String pattern = node.getAttributes().getNamedItem("pattern").getNodeValue(); // Pattern regexp = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); // Matcher regexpMatcher = regexp.matcher(input); // System.out.print("'"+input+"' matches '"+pattern+"'"); // if (regexpMatcher.matches()) // System.out.println(" = true"); // else // System.out.println(" = false"); String matchQueryString = "matches('"+input+"','"+pattern+"','i')"; System.out.print("Match Query: "+matchQueryString); XQuery matchQuery = new XQuery(matchQueryString); stream.reset(); matchQuery.execute(_context,stream); if (stream.toString().equals("true")) { System.out.println(" = true"); if (executeCommands(node)) break; } else System.out.println(" = false"); } } catch (BaseXException exception) { exception.printStackTrace(); } catch (QueryException exception) { exception.printStackTrace(); } }
What this does is it queries the database for an input item and then matches this input to a set of 'matches' nodes. When a node matches it starts executing a series of commands, which are mostly XQuery commands themselves.
The first issue I have is that it seemed a bit inefficient to use an XQuery to match a regular expression. The section commented out matches the same regular expression. Unfortunately, I bumped into a few cases where the Java implementation mistakenly returns 'false' whereas the BaseX implementation returns 'true'. I can't complain really about BaseX here. Actually, kudos for providing a proper implementation, because I had assumed it would simply delegate this functionality to the Java regexp API. But I was a bit surprised to find that the Java regular expressions implementation seems to be broken. My question now is, can I call the BaseX 'matches()' function directly? Because I think that would be much more efficient.
A more serious issue I have is that the XQueries that are executed in the 'executeCommand()' call occasionally insert and delete nodes into collection()/memory sub-elements. And it also can recursively call processEventTriggers() again. Most of the time this works fine, but occasionally I get the following error:
Exception in thread "main" java.lang.RuntimeException: Possible bug? Feedback is welcome: basex-talk@mailman.uni-konstanz.de BaseX 6.3.2: Data Access out of bounds [pre:403, indexSize:4, access:4 > 3]
at org.basex.util.Util.notexpected(Util.java:46) at org.basex.io.TableDiskAccess.cursor(TableDiskAccess.java:323) at org.basex.io.TableDiskAccess.read1(TableDiskAccess.java:92) at org.basex.data.Data.kind(Data.java:324) at org.basex.query.item.DBNode$4.next(DBNode.java:272) at org.basex.query.path.IterStep$1.next(IterStep.java:45) at org.basex.query.iter.NodeIter.next(NodeIter.java:1) at org.basex.query.path.IterPath$1.next(IterPath.java:66) at org.basex.query.path.IterPath$1.next(IterPath.java:1) at BotCommandProcessor.processEventTriggers(BotCommandProcessor.java:285) at BotCommandProcessor.processEvent(BotCommandProcessor.java:262) at BotCommandProcessor.executeCommands(BotCommandProcessor.java:364) at BotCommandProcessor.processEventTriggers(BotCommandProcessor.java:305) at BotCommandProcessor.processEvent(BotCommandProcessor.java:262) at BotCommandProcessor.main(BotCommandProcessor.java:442)
Now I'm not entirely sure, but I suspect that the iterator is affected either by the insert/delete operations or by the nesting of the iterator process. Or a combination of the two. I could somehow understand this if the queries that are being executed would affect the set of triggers it's looping over, but that is not the case.
I did find an ugly way around this problem but I'm afraid it could get me into trouble later. So any feed-back about what might be the best way to fix this would be appreciated.
Mark Boon
Hi Mark,
ByteArrayOutputStream stream = new ByteArrayOutputStream(); String inQuery = "collection()/event/@in/string()"; XQuery inputQuery = new XQuery(inQuery); inputQuery.execute(_context,stream); String input = stream.toString();
Just a hint.. The following code might do the same:
String inQuery = "/event/@in/string()"; XQuery inputQuery = new XQuery(inQuery); String input = inputQuery.execute(_context);
QueryProcessor processor = new QueryProcessor(processQuery, _context); Iter iterator = processor.iter(); Item item; while ((item=iterator.next())!=null) { [...] } [...] Exception in thread "main" java.lang.RuntimeException: Possible bug? Feedback is welcome: basex-talk@mailman.uni-konstanz.de
You should be very careful when executing nested queries incl. update operations, as the inner update operation might change parts of the database, which you are addressing by the outer QueryProcessor instance. I would recommend to...
a) do it all in just one XQuery expression, or b) sequentially run all query operations (nested read-only operations won't cause any troubles)
If the exception still occurs after rewriting your code, it would be great if you could create a little example that allows us to reproduce the issue.
The first issue I have is that it seemed a bit inefficient to use an XQuery to match a regular expression. [...] My question now is, can I call the BaseX 'matches()' function directly? Because I think that would be much more efficient.
Our XQuery functions are not designated to be run stand-alone; next, we're internally working with byte arrays instead of strings. I'd recommend to first benchmark the evaluation of your regular XQuery expressions, as I don't believe they are the major bottleneck here (instead, I believe that you might save execution time by avoiding the use of DOM (BXNode) instances).
Christian
basex-talk@mailman.uni-konstanz.de