@POST @Path("data/explore/queries/{id}/next") public void getQueryNextResults( HttpRequest request, HttpResponder responder, @PathParam("id") String id) { // NOTE: this call is a POST because it is not idempotent: cursor of results is moved try { QueryHandle handle = QueryHandle.fromId(id); List<QueryResult> results; if (handle.equals(QueryHandle.NO_OP)) { results = Lists.newArrayList(); } else { Map<String, String> args = decodeArguments(request); int size = args.containsKey("size") ? Integer.valueOf(args.get("size")) : 100; results = exploreService.nextResults(handle, size); } responder.sendJson(HttpResponseStatus.OK, results); } catch (IllegalArgumentException e) { LOG.debug("Got exception:", e); responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage()); } catch (SQLException e) { LOG.debug("Got exception:", e); responder.sendString( HttpResponseStatus.BAD_REQUEST, String.format("[SQLState %s] %s", e.getSQLState(), e.getMessage())); } catch (HandleNotFoundException e) { responder.sendStatus(HttpResponseStatus.NOT_FOUND); } catch (Throwable e) { LOG.error("Got exception:", e); responder.sendStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR); } }
@POST @Path("data/explore/queries/{id}/download") public void downloadQueryResults( HttpRequest request, HttpResponder responder, @PathParam("id") final String id) { // NOTE: this call is a POST because it is not idempotent: cursor of results is moved boolean responseStarted = false; try { QueryHandle handle = QueryHandle.fromId(id); if (handle.equals(QueryHandle.NO_OP) || !exploreService.getStatus(handle).getStatus().equals(QueryStatus.OpStatus.FINISHED)) { responder.sendStatus(HttpResponseStatus.CONFLICT); return; } StringBuffer sb = new StringBuffer(); sb.append(getCSVHeaders(exploreService.getResultSchema(handle))); sb.append('\n'); List<QueryResult> results; results = exploreService.previewResults(handle); if (results.isEmpty()) { results = exploreService.nextResults(handle, DOWNLOAD_FETCH_CHUNK_SIZE); } ChunkResponder chunkResponder = responder.sendChunkStart(HttpResponseStatus.OK, null); responseStarted = true; while (!results.isEmpty()) { for (QueryResult result : results) { appendCSVRow(sb, result); sb.append('\n'); } // If failed to send to client, just propagate the IOException and let netty-http to handle chunkResponder.sendChunk(ChannelBuffers.wrappedBuffer(sb.toString().getBytes("UTF-8"))); sb.delete(0, sb.length()); results = exploreService.nextResults(handle, DOWNLOAD_FETCH_CHUNK_SIZE); } Closeables.closeQuietly(chunkResponder); } catch (IllegalArgumentException e) { LOG.debug("Got exception:", e); // We can't send another response if sendChunkStart has been called if (!responseStarted) { responder.sendString(HttpResponseStatus.BAD_REQUEST, e.getMessage()); } } catch (SQLException e) { LOG.debug("Got exception:", e); if (!responseStarted) { responder.sendString( HttpResponseStatus.BAD_REQUEST, String.format("[SQLState %s] %s", e.getSQLState(), e.getMessage())); } } catch (HandleNotFoundException e) { if (!responseStarted) { if (e.isInactive()) { responder.sendString(HttpResponseStatus.CONFLICT, "Query is inactive"); } else { responder.sendStatus(HttpResponseStatus.NOT_FOUND); } } } catch (Throwable e) { LOG.error("Got exception:", e); if (!responseStarted) { responder.sendStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR); } } }