/** * Test digest authentication. * * @throws Exception exception */ @Test public void digest() throws Exception { // correct credentials try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request xmlns:http='http://expath.org/ns/http-client' method='GET' " + "send-authorization='true' auth-method='Digest' username='******' password='******' " + "href='" + REST_ROOT + "'/>"), ctx)) { checkResponse(qp.value(), 2, HttpURLConnection.HTTP_OK); } // wrong credentials try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request xmlns:http='http://expath.org/ns/http-client' method='GET' " + "send-authorization='true' auth-method='Digest' username='******' password='******' " + "href='" + REST_ROOT + "?query=()'/>") + "[. instance of node()][@status = '401']", ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_UNAUTHORIZED); } }
/** * Creates query plans. * * @param comp compiled flag */ private void plan(final boolean comp) { if (comp != options.get(MainOptions.COMPPLAN)) return; // show dot plan try { if (options.get(MainOptions.DOTPLAN)) { final String path = options.get(MainOptions.QUERYPATH); final String dot = path.isEmpty() ? "plan.dot" : new IOFile(path).name().replaceAll("\\..*?$", ".dot"); try (final BufferOutput bo = new BufferOutput(dot)) { try (final DOTSerializer d = new DOTSerializer(bo, options.get(MainOptions.DOTCOMPACT))) { d.serialize(qp.plan()); } } } // show XML plan if (options.get(MainOptions.XMLPLAN)) { info(NL + QUERY_PLAN + COL); info(qp.plan().serialize().toString()); } } catch (final Exception ex) { Util.stack(ex); } }
/** * Tests an erroneous query. * * @throws Exception exception */ @Test public void error() throws Exception { try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='get'/>", RESTURL + "unknown") + "[1]/@status/data()", ctx)) { assertEquals("404", qp.value().serialize().toString()); } }
/** * Parses the query. * * @param p performance * @throws QueryException query exception */ private void parse(final Performance p) throws QueryException { qp.http(http); for (final Entry<String, String[]> entry : vars.entrySet()) { final String name = entry.getKey(); final String[] value = entry.getValue(); if (name == null) qp.context(value[0], value[1]); else qp.bind(name, value[0], value[1]); } qp.parse(); if (p != null) info.parsing += p.time(); }
/** * Test sending of HTTP PUT requests. * * @throws Exception exception */ @Test public void put() throws Exception { try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='put' status-only='true'>" + "<http:body media-type='text/xml'>" + BOOKS + "</http:body>" + "</http:request>", RESTURL), ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_CREATED); } }
/** * Returns an extended error message. * * @param err error message * @return result of check */ private boolean extError(final String err) { // will only be evaluated when an error has occurred final StringBuilder sb = new StringBuilder(); if (options.get(MainOptions.QUERYINFO)) { sb.append(info()).append(qp.info()).append(NL).append(ERROR).append(COL).append(NL); } sb.append(err); return error(sb.toString()); }
@Override public void databases(final LockResult lr) { if (qp == null) { lr.writeAll = true; } else { qp.databases(lr); info.readLocked = lr.readAll ? null : lr.read; info.writeLocked = lr.writeAll ? null : lr.write; } }
/** * Test sending of HTTP GET requests. * * @throws Exception exception */ @Test public void postGet() throws Exception { // GET1 - just send a GET request try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='get' href='" + REST_ROOT + "'/>"), ctx)) { final Value v = qp.value(); checkResponse(v, 2, HttpURLConnection.HTTP_OK); assertEquals(NodeType.DOC, v.itemAt(1).type); } // GET2 - with override-media-type='text/plain' try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='get' override-media-type='text/plain'/>", REST_ROOT), ctx)) { final Value v = qp.value(); checkResponse(v, 2, HttpURLConnection.HTTP_OK); assertEquals(AtomType.STR, v.itemAt(1).type); } // Get3 - with status-only='true' try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='get' status-only='true'/>", REST_ROOT), ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_OK); } }
/** * Test sending of HTTP DELETE requests. * * @throws Exception exception */ @Test public void postDelete() throws Exception { // add document to be deleted try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='put'>" + "<http:body media-type='text/xml'><ToBeDeleted/></http:body>" + "</http:request>", RESTURL), ctx)) { qp.value(); } // DELETE try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='delete' status-only='true'/>", RESTURL), ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_OK); } }
/** * Checks if the query possibly performs updates. * * @param ctx database context * @param query query string * @return result of check */ final boolean updates(final Context ctx, final String query) { try { final Performance p = new Performance(); qp(query, ctx); parse(p); return qp.updating; } catch (final QueryException ex) { Util.debug(ex); exception = ex; qp.close(); return false; } }
/** * Test sending of HTTP POST requests. * * @throws Exception exception */ @Test public void putPost() throws Exception { // PUT - query try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='put' status-only='true'>" + "<http:body media-type='text/xml'>" + BOOKS + "</http:body>" + "</http:request>", RESTURL), ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_CREATED); } // POST - query try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='post'>" + "<http:body media-type='application/xml'>" + "<query xmlns='" + Prop.URL + "/rest'>" + "<text><![CDATA[<x>1</x>]]></text>" + "</query>" + "</http:body>" + "</http:request>", RESTURL), ctx)) { checkResponse(qp.value(), 2, HttpURLConnection.HTTP_OK); } // Execute the same query but with content set from $bodies try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='post'>" + "<http:body media-type='application/xml'/>" + "</http:request>", RESTURL, "<query xmlns='" + Prop.URL + "/rest'>" + "<text><![CDATA[<x>1</x>]]></text>" + "</query>"), ctx)) { checkResponse(qp.value(), 2, HttpURLConnection.HTTP_OK); } }
/** * Refreshes the view after a file has been saved. * * @param root root directory * @param ctx database context * @throws InterruptedException interruption */ void parse(final IOFile root, final Context ctx) throws InterruptedException { final long id = ++parseId; final HashSet<String> parsed = new HashSet<>(); final TreeMap<String, InputInfo> errs = new TreeMap<>(); // collect files to be parsed final ProjectCache pc = cache(root); final StringList mods = new StringList(), lmods = new StringList(); for (final String path : pc) { final IOFile file = new IOFile(path); if (file.hasSuffix(IO.XQSUFFIXES)) (file.hasSuffix(IO.XQMSUFFIX) ? lmods : mods).add(path); } mods.add(lmods); // parse modules for (final String path : mods) { if (id != parseId) throw new InterruptedException(); if (parsed.contains(path)) continue; final IOFile file = new IOFile(path); try (final TextInput ti = new TextInput(file)) { // parse query try (final QueryContext qc = new QueryContext(ctx)) { final String input = ti.cache().toString(); final boolean lib = QueryProcessor.isLibrary(input); qc.parse(input, lib, path, null); // parsing was successful: remember path parsed.add(path); for (final byte[] mod : qc.modParsed) parsed.add(Token.string(mod)); } catch (final QueryException ex) { // parsing failed: remember path final InputInfo ii = ex.info(); errs.put(path, ii); parsed.add(ii.path()); } } catch (final IOException ex) { // file may not be accessible Util.debug(ex); } } errors = errs; }
/** * Evaluates the specified query. * * @param query query * @return success flag */ final boolean query(final String query) { final Performance p = new Performance(); String error; if (exception != null) { error = Util.message(exception); } else { try { long hits = 0; final boolean run = options.get(MainOptions.RUNQUERY); final boolean serial = options.get(MainOptions.SERIALIZE); final int runs = Math.max(1, options.get(MainOptions.RUNS)); for (int r = 0; r < runs; ++r) { // reuse existing processor instance if (r != 0) qp = null; qp(query, context); parse(p); if (r == 0) plan(false); qp.compile(); info.compiling += p.time(); if (r == 0) plan(true); if (!run) continue; final PrintOutput po = r == 0 && serial ? out : new NullOutput(); try (final Serializer ser = qp.getSerializer(po)) { if (maxResults >= 0) { result = qp.cache(maxResults); info.evaluating += p.time(); result.serialize(ser); hits = result.size(); } else { hits = 0; final Iter ir = qp.iter(); info.evaluating += p.time(); for (Item it; (it = ir.next()) != null; ) { ser.serialize(it); ++hits; checkStop(); } } } qp.close(); info.serializing += p.time(); } // dump some query info // out.flush(); // remove string list if global locking is used and if query is updating if (soptions.get(StaticOptions.GLOBALLOCK) && qp.updating) { info.readLocked = null; info.writeLocked = null; } return info(info.toString(qp, out.size(), hits, options.get(MainOptions.QUERYINFO))); } catch (final QueryException | IOException ex) { exception = ex; error = Util.message(ex); } catch (final ProcException ex) { error = INTERRUPTED; } catch (final StackOverflowError ex) { Util.debug(ex); error = BASX_STACKOVERFLOW.desc; } catch (final RuntimeException ex) { extError(""); Util.debug(info()); throw ex; } finally { // close processor after exceptions if (qp != null) qp.close(); } } return extError(error); }
@Override public final boolean updated(final Context ctx) { return qp != null && qp.updates() != 0; }
/** Closes the query processor. */ protected void closeQp() { if (qp != null) { qp.close(); qp = null; } }
public RowMutation mutationForKey( CFDefinition cfDef, ByteBuffer key, ColumnNameBuilder builder, boolean isRange, UpdateParameters params, ColumnGroupMap group) throws InvalidRequestException { QueryProcessor.validateKey(key); RowMutation rm = new RowMutation(cfDef.cfm.ksName, key); ColumnFamily cf = rm.addOrGet(columnFamily()); if (columns.isEmpty() && builder.componentCount() == 0) { // No columns, delete the row cf.delete(new DeletionInfo(params.timestamp, params.localDeletionTime)); } else { if (isRange) { ByteBuffer start = builder.copy().build(); ByteBuffer end = builder.buildAsEndOfRange(); QueryProcessor.validateColumnName(start); // If start is good, end is too cf.addAtom(params.makeRangeTombstone(start, end)); } else { // Delete specific columns if (cfDef.isCompact) { ByteBuffer columnName = builder.build(); QueryProcessor.validateColumnName(columnName); cf.addColumn(params.makeTombstone(columnName)); } else { Iterator<Pair<CFDefinition.Name, Term>> iter = toRemove.iterator(); while (iter.hasNext()) { Pair<CFDefinition.Name, Term> p = iter.next(); CFDefinition.Name column = p.left; if (column.type.isCollection()) { CollectionType validator = (CollectionType) column.type; Term keySelected = p.right; if (keySelected == null) { // Delete the whole collection ByteBuffer start = builder.copy().add(column.name.key).build(); QueryProcessor.validateColumnName(start); ColumnNameBuilder b = iter.hasNext() ? builder.copy() : builder; ByteBuffer end = b.add(column.name.key).buildAsEndOfRange(); cf.addAtom(params.makeRangeTombstone(start, end)); } else { builder.add(column.name.key); List<Term> args = Collections.singletonList(keySelected); Operation op; switch (validator.kind) { case LIST: op = ListOperation.DiscardKey(args); break; case SET: op = SetOperation.Discard(args); break; case MAP: op = MapOperation.DiscardKey(keySelected); break; default: throw new InvalidRequestException("Unknown collection type: " + validator.kind); } op.execute( cf, builder, validator, params, group == null ? null : group.getCollection(column.name.key)); } } else { ColumnNameBuilder b = iter.hasNext() ? builder.copy() : builder; ByteBuffer columnName = b.add(column.name.key).build(); QueryProcessor.validateColumnName(columnName); cf.addColumn(params.makeTombstone(columnName)); } } } } } return rm; }