예제 #1
0
 /**
  * Import an XQuery library module from the given document. The namespace and preferred prefix of
  * the module are extracted from the module itself. The MIME type of the document is set to
  * "application/xquery" as a side-effect.
  *
  * @param module the non-XML document that holds the library module's source
  * @return this service, to chain calls
  * @throws DatabaseException if the module is an XML document, or the module declaration cannot be
  *     found at the top of the document
  */
 public QueryService importModule(Document module) {
   if (module instanceof XMLDocument)
     throw new DatabaseException("module cannot be an XML document: " + module);
   Matcher matcher = MODULE_DECLARATION_DQUOTE.matcher(module.contentsAsString());
   if (!matcher.find()) {
     matcher = MODULE_DECLARATION_SQUOTE.matcher(module.contentsAsString());
     if (!matcher.find())
       throw new DatabaseException("couldn't find a module declaration at the top of " + module);
   }
   module.metadata().setMimeType("application/xquery");
   String moduleNamespace = matcher.group(1);
   // TODO: should do URILiteral processing here to replace entity and character references and
   // normalize
   // whitespace, but since it seems that eXist doesn't do it either (bug?) there's no reason to
   // rush.
   Document prevModule = moduleMap.get(moduleNamespace);
   if (prevModule != null && !prevModule.equals(module))
     throw new DatabaseException(
         "module "
             + moduleNamespace
             + " already bound to "
             + prevModule
             + ", can't rebind to "
             + module);
   moduleMap.put(moduleNamespace, module);
   return this;
 }
예제 #2
0
 private void buildXQueryStaticContext(XQueryContext context, boolean importModules)
     throws XPathException {
   context.declareNamespaces(namespaceBindings.getCombinedMap());
   for (Map.Entry<String, Document> entry : moduleMap.entrySet()) {
     context.importModule(entry.getKey(), null, "xmldb:exist:///db" + entry.getValue().path());
   }
 }
예제 #3
0
 private void buildXQueryDynamicContext(
     XQueryContext context, Object[] params, MutableDocumentSet docsToLock, boolean bindVariables)
     throws XPathException {
   context.setBackwardsCompatibility(false);
   context.setStaticallyKnownDocuments(docs);
   context.setBaseURI(baseUri == null ? new AnyURIValue("/db") : baseUri);
   if (bindVariables) {
     for (Map.Entry<QName, Object> entry : bindings.entrySet()) {
       context.declareVariable(
           new org.exist.dom.QName(
               entry.getKey().getLocalPart(),
               entry.getKey().getNamespaceURI(),
               entry.getKey().getPrefix()),
           convertValue(entry.getValue()));
     }
     if (params != null)
       for (int i = 0; i < params.length; i++) {
         Object convertedValue = convertValue(params[i]);
         if (docsToLock != null && convertedValue instanceof Sequence) {
           docsToLock.addAll(((Sequence) convertedValue).getDocumentSet());
         }
         context.declareVariable("_" + (i + 1), convertedValue);
       }
   }
 }
예제 #4
0
  /**
   * Statically analyze a query for various properties.
   *
   * @param query the query to analyze
   * @param params parameters for the query; if necessary parameters are left out they will be
   *     listed as required variables in the analysis
   * @return a query analysis facet
   */
  public QueryAnalysis analyze(String query, Object... params) {
    if (presub) query = presub(query, params);

    long t1 = System.currentTimeMillis(), t2 = 0, t3 = 0;
    DBBroker broker = null;
    try {
      broker = db.acquireBroker();
      prepareContext(broker);
      final org.exist.source.Source source = buildQuerySource(query, params, "analyze");
      final XQuery xquery = broker.getXQueryService();
      final XQueryPool pool = xquery.getXQueryPool();
      CompiledXQuery compiledQuery = pool.borrowCompiledXQuery(broker, source);
      try {
        AnalysisXQueryContext context;
        if (compiledQuery == null) {
          context = new AnalysisXQueryContext(broker, AccessContext.INTERNAL_PREFIX_LOOKUP);
          buildXQueryStaticContext(context, false);
          buildXQueryDynamicContext(context, params, null, false);
          t2 = System.currentTimeMillis();
          compiledQuery = xquery.compile(context, source);
          t3 = System.currentTimeMillis();
        } else {
          context = (AnalysisXQueryContext) compiledQuery.getContext();
          t2 = System.currentTimeMillis();
        }
        return new QueryAnalysis(
            compiledQuery,
            Collections.unmodifiableSet(context.requiredVariables),
            Collections.unmodifiableSet(context.requiredFunctions));
      } finally {
        if (compiledQuery != null) pool.returnCompiledXQuery(source, compiledQuery);
      }
    } catch (XPathException e) {
      LOG.warn(
          "query compilation failed --  "
              + query
              + "  -- "
              + (params == null ? "" : " with params " + Arrays.asList(params))
              + (bindings.isEmpty() ? "" : " and bindings " + bindings));
      throw new DatabaseException("failed to compile query", e);
    } catch (IOException e) {
      throw new DatabaseException("unexpected exception", e);
    } catch (PermissionDeniedException e) {
      throw new DatabaseException("permission denied", e);
    } finally {
      db.releaseBroker(broker);
      STATS.update(query, t1, t2, t3, 0, System.currentTimeMillis());
    }
  }
예제 #5
0
 private org.exist.source.Source buildQuerySource(String query, Object[] params, String cookie) {
   Map<String, String> combinedMap = namespaceBindings.getCombinedMap();
   for (Map.Entry<String, Document> entry : moduleMap.entrySet()) {
     combinedMap.put("<module> " + entry.getKey(), entry.getValue().path());
   }
   for (Map.Entry<QName, Object> entry : bindings.entrySet()) {
     combinedMap.put(
         "<var> " + entry.getKey(),
         null); // don't care about values, as long as the same vars are bound
   }
   combinedMap.put("<posvars> " + params.length, null);
   combinedMap.put("<cookie>", cookie);
   // TODO: should include statically known documents and baseURI too?
   return new StringSourceWithMapKey(query, combinedMap);
 }
예제 #6
0
 /**
  * Clone this query service, optionally overriding the clone's namespace and variable bindings. If
  * the namespace bindings override or variable bindings override is specified, then that object is
  * cloned and used for its respective purpose. If an override is not specified, the bindings are
  * cloned from the original query service.
  *
  * @param nsBindingsOverride the namespace bindings to clone, or <code>null</code> to clone from
  *     the original
  * @param varBindingsOverride the variable bindings to clone, or <code>null</code> to clone from
  *     the original
  * @return a clone of this query service with bindings optionally overridden
  */
 public QueryService clone(NamespaceMap nsBindingsOverride, Map<QName, ?> varBindingsOverride) {
   try {
     QueryService that = (QueryService) super.clone();
     that.namespaceBindings =
         nsBindingsOverride != null ? nsBindingsOverride.clone() : that.namespaceBindings.clone();
     if (varBindingsOverride == null) {
       that.bindings = new HashMap<QName, Object>(that.bindings);
     } else {
       that.bindings = new HashMap<QName, Object>();
       for (Map.Entry<QName, ?> entry : varBindingsOverride.entrySet()) {
         that.let(entry.getKey(), entry.getValue());
       }
     }
     that.moduleMap = new TreeMap<String, Document>(moduleMap);
     return that;
   } catch (CloneNotSupportedException e) {
     throw new RuntimeException("unexpected exception", e);
   }
 }
예제 #7
0
 /**
  * Return a string that describes the statistics gathered for all the entries.
  *
  * @return a string describing the statistics gathered so far
  */
 public synchronized String toString() {
   return toStringTop(entries.size());
 }
예제 #8
0
 /** Reset all gathered statistics back to zero. */
 public synchronized void reset() {
   entries.clear();
 }
예제 #9
0
 /**
  * Get a list of all statistics entries for which data has been gathered. The list is a copy and
  * can be further manipulating without affecting the service.
  *
  * @return a list of all statistics entries
  */
 public synchronized List<Entry> entries() {
   return new ArrayList<Entry>(entries.values());
 }
예제 #10
0
 synchronized Entry get(String query) {
   Entry entry = entries.get(query);
   if (entry == null) entries.put(query, entry = new Entry(query));
   return entry;
 }
예제 #11
0
 boolean isFreshFrom(Resource origin) {
   return !presub
       && bindings.isEmpty()
       && moduleMap.isEmpty()
       && (namespaceBindings == null || namespaceBindings.isFreshFrom(origin.namespaceBindings()));
 }
예제 #12
0
 ItemList executeQuery(String query, WrapperFactory wrapperFactory, Object[] params) {
   long t1 = System.currentTimeMillis(), t2 = 0, t3 = 0, t4 = 0;
   if (presub) query = presub(query, params);
   DBBroker broker = null;
   try {
     broker = db.acquireBroker();
     prepareContext(broker);
     if (overrideDocs != null) docs = overrideDocs;
     final org.exist.source.Source source = buildQuerySource(query, params, "execute");
     final XQuery xquery = broker.getXQueryService();
     final XQueryPool pool = xquery.getXQueryPool();
     CompiledXQuery compiledQuery = pool.borrowCompiledXQuery(broker, source);
     MutableDocumentSet docsToLock = new DefaultDocumentSet();
     if (docs != null) docsToLock.addAll(docs);
     if (base != null) docsToLock.addAll(base.getDocumentSet());
     try {
       XQueryContext context;
       if (compiledQuery == null) {
         context = xquery.newContext(AccessContext.INTERNAL_PREFIX_LOOKUP);
         buildXQueryStaticContext(context, true);
       } else {
         context = compiledQuery.getContext();
         // static context already set
       }
       buildXQueryDynamicContext(context, params, docsToLock, true);
       t2 = System.currentTimeMillis();
       if (compiledQuery == null) {
         compiledQuery = xquery.compile(context, source);
         t3 = System.currentTimeMillis();
       }
       docsToLock.lock(broker, false, false);
       try {
         return new ItemList(
             xquery.execute(wrap(compiledQuery, wrapperFactory, context), base),
             namespaceBindings.extend(),
             db);
       } finally {
         docsToLock.unlock(false);
         t4 = System.currentTimeMillis();
       }
     } finally {
       if (compiledQuery != null) pool.returnCompiledXQuery(source, compiledQuery);
     }
   } catch (XPathException e) {
     LOG.debug(
         "query execution failed --  "
             + query
             + "  -- "
             + (params == null ? "" : " with params " + Arrays.asList(params))
             + (bindings.isEmpty() ? "" : " and bindings " + bindings));
     throw new DatabaseException("failed to execute query", e);
   } catch (IOException e) {
     throw new DatabaseException("unexpected exception", e);
   } catch (LockException e) {
     throw new DatabaseException("deadlock", e);
   } catch (PermissionDeniedException e) {
     throw new DatabaseException("permission denied", e);
   } finally {
     db.releaseBroker(broker);
     STATS.update(query, t1, t2, t3, t4, System.currentTimeMillis());
   }
 }
예제 #13
0
 /**
  * Import the same modules into this query service as imported by the given query service. This is
  * a one-time copy; further imports into either query service won't affect the other one.
  *
  * @param that the query service to copy module imports from
  * @return this service, to chain calls
  */
 public QueryService importSameModulesAs(QueryService that) {
   moduleMap.putAll(that.moduleMap);
   return this;
 }
예제 #14
0
 /**
  * Bind a variable to the given value within all query expression evaluated subsequently.
  *
  * @param variableName the qualified name of the variable to bind
  * @param value the value the variable should take
  * @return this service, to chain calls
  */
 public QueryService let(QName variableName, Object value) {
   bindings.put(variableName, value);
   return this;
 }