|
70 | 70 | import org.exist.security.Subject; |
71 | 71 | import org.exist.security.internal.RealmImpl; |
72 | 72 | import org.exist.source.DBSource; |
| 73 | +import org.exist.source.DbStoreSource; |
73 | 74 | import org.exist.source.Source; |
74 | 75 | import org.exist.source.StringSource; |
75 | 76 | import org.exist.source.URLSource; |
@@ -578,7 +579,7 @@ public void doGet(final DBBroker broker, final Txn transaction, final HttpServle |
578 | 579 | try { |
579 | 580 | if (xquery_mime_type.equals(resource.getMediaType())) { |
580 | 581 | // Execute the XQuery |
581 | | - executeXQuery(broker, transaction, resource, request, response, |
| 582 | + executeXQuery(broker, transaction, lockedDocument, request, response, |
582 | 583 | outputProperties, servletPath.toString(), pathInfo); |
583 | 584 | } else if (xproc_mime_type.equals(resource.getMediaType())) { |
584 | 585 | // Execute the XProc |
@@ -745,7 +746,7 @@ public void doPost(final DBBroker broker, final Txn transaction, final HttpServl |
745 | 746 | try { |
746 | 747 | if (xquery_mime_type.equals(resource.getMediaType())) { |
747 | 748 | // Execute the XQuery |
748 | | - executeXQuery(broker, transaction, resource, request, response, |
| 749 | + executeXQuery(broker, transaction, lockedDocument, request, response, |
749 | 750 | outputProperties, servletPath.toString(), pathInfo); |
750 | 751 | } else { |
751 | 752 | // Execute the XProc |
@@ -1267,7 +1268,7 @@ private boolean checkForXQueryTarget(final DBBroker broker, final Txn transactio |
1267 | 1268 | final Properties outputProperties = new Properties(defaultOutputKeysProperties); |
1268 | 1269 | try { |
1269 | 1270 | // Execute the XQuery |
1270 | | - executeXQuery(broker, transaction, resource, request, response, |
| 1271 | + executeXQuery(broker, transaction, lockedDocument, request, response, |
1271 | 1272 | outputProperties, servletPath.toString(), pathInfo); |
1272 | 1273 | } catch (final XPathException e) { |
1273 | 1274 | writeXPathExceptionHtml(response, HttpServletResponse.SC_BAD_REQUEST, UTF_8.name(), null, path.toString(), e); |
@@ -1575,41 +1576,64 @@ private void declareExternalAndXQJVariables(final XQueryContext context, |
1575 | 1576 | /** |
1576 | 1577 | * Directly execute an XQuery stored as a binary document in the database. |
1577 | 1578 | * |
1578 | | - * @throws PermissionDeniedException |
| 1579 | + * NOTE The document will be unlocked after query compilation (only if compilation succeeds). |
| 1580 | + * |
| 1581 | + * @param broker the database broker. |
| 1582 | + * @param transaction the database transaction. |
| 1583 | + * @param lockedQueryDocument the locked document holding the query to be executed. |
| 1584 | + * @param request the HTTP request. |
| 1585 | + * @param response the HTTP response. |
| 1586 | + * @param outputProperties any serialization properties. |
| 1587 | + * @param servletPath the path to the servlet. |
| 1588 | + * @param pathInfo the path. |
| 1589 | + * |
| 1590 | + * @throws XPathException if an error occurs during query compilation or execution. |
| 1591 | + * @throws BadRequestException if the request had a problem. |
| 1592 | + * @throws PermissionDeniedException if the calling user does not have sufficient permissions. |
1579 | 1593 | */ |
1580 | | - private void executeXQuery(final DBBroker broker, final Txn transaction, final DocumentImpl resource, |
| 1594 | + private void executeXQuery(final DBBroker broker, final Txn transaction, final LockedDocument lockedQueryDocument, |
1581 | 1595 | final HttpServletRequest request, final HttpServletResponse response, |
1582 | 1596 | final Properties outputProperties, final String servletPath, final String pathInfo) |
1583 | 1597 | throws XPathException, BadRequestException, PermissionDeniedException { |
1584 | 1598 |
|
1585 | | - final Source source = new DBSource(broker.getBrokerPool(), (BinaryDocument) resource, true); |
| 1599 | + final DocumentImpl resource = lockedQueryDocument.getDocument(); |
| 1600 | + final DbStoreSource source = new DBSource(broker.getBrokerPool(), (BinaryDocument) resource, true); |
1586 | 1601 |
|
1587 | 1602 | final ConsumerE<XQueryContext, XPathException> setupXqueryContextPreCompilation = xqueryContext -> { |
1588 | 1603 | xqueryContext.setModuleLoadPath(XmldbURI.EMBEDDED_SERVER_URI.append(resource.getCollection().getURI()).toString()); |
1589 | 1604 | xqueryContext.setStaticallyKnownDocuments(new XmldbURI[]{ resource.getCollection().getURI() }); |
1590 | 1605 | }; |
1591 | 1606 |
|
1592 | | - final ConsumerE<XQueryContext, XPathException> setupXqueryContextPreExecution = xqueryContext -> { |
1593 | | - final HttpRequestWrapper reqw = declareVariables(xqueryContext, null, request, response); |
1594 | | - reqw.setServletPath(servletPath); |
1595 | | - reqw.setPathInfo(pathInfo); |
1596 | | - DebuggeeFactory.checkForDebugRequest(request, xqueryContext); |
1597 | | - }; |
| 1607 | + try { |
| 1608 | + // NOTE(AR) compilationResult will be cleaned up by the try-with-resources wrapped XQueryUtil.execute(...); at present between here and there no exceptions can occur |
| 1609 | + final XQueryUtil.CompilationResult compilationResult = XQueryUtil.compile(broker, source, false, true, setupXqueryContextPreCompilation); |
1598 | 1610 |
|
1599 | | - final BiConsumerE<XQueryContext, XQueryUtil.QueryResult, XPathException> setupXqueryContextPostExecution = (xqueryContext, queryResult) -> { |
1600 | | - // Pass last modified date to the HTTP response |
1601 | | - HTTPUtils.addLastModifiedHeader(queryResult.result, xqueryContext); |
1602 | | - }; |
| 1611 | + // NOTE(AR) query is now compiled so we can release the LockedDocument eagerly |
| 1612 | + lockedQueryDocument.close(); |
1603 | 1613 |
|
1604 | | - try (final XQueryUtil.QueryResult queryResult = XQueryUtil.query(broker, source, true, null, outputProperties, setupXqueryContextPreCompilation, setupXqueryContextPreExecution, setupXqueryContextPostExecution)) { |
1605 | 1614 |
|
1606 | | - // Special header to indicate whether the compiled query is returned from the cache |
1607 | | - response.setHeader(XQUERY_CACHED_RESPONSE_HEADER, queryResult.compilationTime == XQueryUtil.CompilationResult.RETRIEVED_CACHED_COMPILED_QUERY ? "true" : "false"); |
| 1615 | + final ConsumerE<XQueryContext, XPathException> setupXqueryContextPreExecution = xqueryContext -> { |
| 1616 | + final HttpRequestWrapper reqw = declareVariables(xqueryContext, null, request, response); |
| 1617 | + reqw.setServletPath(servletPath); |
| 1618 | + reqw.setPathInfo(pathInfo); |
| 1619 | + DebuggeeFactory.checkForDebugRequest(request, xqueryContext); |
| 1620 | + }; |
| 1621 | + |
| 1622 | + final BiConsumerE<XQueryContext, XQueryUtil.QueryResult, XPathException> setupXqueryContextPostExecution = (xqueryContext, queryResult) -> { |
| 1623 | + // Pass last modified date to the HTTP response |
| 1624 | + HTTPUtils.addLastModifiedHeader(queryResult.result, xqueryContext); |
| 1625 | + }; |
| 1626 | + |
| 1627 | + try (final XQueryUtil.QueryResult queryResult = XQueryUtil.execute(broker, compilationResult, null, outputProperties, setupXqueryContextPreExecution, setupXqueryContextPostExecution)) { |
| 1628 | + // Special header to indicate whether the compiled query is returned from the cache |
| 1629 | + response.setHeader(XQUERY_CACHED_RESPONSE_HEADER, queryResult.compilationTime == XQueryUtil.CompilationResult.RETRIEVED_CACHED_COMPILED_QUERY ? "true" : "false"); |
| 1630 | + |
| 1631 | + final boolean wrap = "yes".equals(outputProperties.getProperty("_wrap")); |
| 1632 | + writeResults(response, broker, transaction, queryResult, -1, 1, false, outputProperties, wrap); |
| 1633 | + } |
1608 | 1634 |
|
1609 | | - final boolean wrap = "yes".equals(outputProperties.getProperty("_wrap")); |
1610 | | - writeResults(response, broker, transaction, queryResult, -1, 1, false, outputProperties, wrap); |
1611 | 1635 | } catch (final IOException e) { |
1612 | | - throw new BadRequestException("Failed to read query from " + resource.getURI(), e); |
| 1636 | + throw new BadRequestException("Failed to read query from: " + source.getDocumentPath(), e); |
1613 | 1637 | } |
1614 | 1638 | } |
1615 | 1639 |
|
|
0 commit comments