use of datawave.webservice.query.exception.BadRequestQueryException in project datawave by NationalSecurityAgency.
the class CachedResultsBean method getRows.
/**
* Returns a set of rows based on the given starting and end positions. The response object type is dynamic, see the listQueryLogic operation to determine
* what the response type object will be.
*
* @param queryId
* CachedResults queryId
* @param rowBegin
* first row to be returned
* @param rowEnd
* last row to be returned
* @return datawave.webservice.result.BaseQueryResponse
* @RequestHeader X-ProxiedEntitiesChain use when proxying request for user by specifying a chain of DNs of the identities to proxy
* @RequestHeader X-ProxiedIssuersChain required when using X-ProxiedEntitiesChain, specify one issuer DN per subject DN listed in X-ProxiedEntitiesChain
* @RequestHeader query-session-id session id value used for load balancing purposes. query-session-id can be placed in the request in a Cookie header or as
* a query parameter
* @ResponseHeader X-OperationTimeInMS time spent on the server performing the operation, does not account for network or result serialization
* @ResponseHeader X-Partial-Results true if the page contains less than the requested number of results
*
* @HTTP 200 success
* @HTTP 401 caller is not authorized to run the query
* @HTTP 412 if the query is not active
* @HTTP 500 internal server error
*/
@GET
@javax.ws.rs.Path("/{queryId}/getRows")
@Produces({ "application/xml", "text/xml", "application/json", "text/yaml", "text/x-yaml", "application/x-yaml", "application/x-protobuf" })
@GZIP
@Interceptors({ RequiredInterceptor.class, ResponseInterceptor.class })
@Timed(name = "dw.cachedr.getRows", absolute = true)
public BaseQueryResponse getRows(@PathParam("queryId") @Required("queryId") String queryId, @QueryParam("rowBegin") @DefaultValue("1") Integer rowBegin, @QueryParam("rowEnd") Integer rowEnd) {
BaseQueryResponse response = responseObjectFactory.getEventQueryResponse();
// Find out who/what called this method
Principal p = ctx.getCallerPrincipal();
String owner = getOwnerFromPrincipal(p);
try {
if (rowBegin < 1) {
throw new BadRequestQueryException(DatawaveErrorCode.ROW_BEGIN_LESS_THAN_1);
}
if (rowEnd != null && rowEnd < rowBegin) {
throw new BadRequestQueryException(DatawaveErrorCode.ROW_END_LESS_THAN_ROW_BEGIN);
}
// If there is a this.maxPageSize set, then we should honor it here. Otherwise, we use Integer.MAX_VALUE
int maxPageSize = cachedResultsConfiguration.getMaxPageSize();
if (rowEnd == null) {
if (maxPageSize > 0) {
rowEnd = (rowBegin + maxPageSize) - 1;
} else {
rowEnd = Integer.MAX_VALUE;
}
}
int pagesize = (rowEnd - rowBegin) + 1;
if (maxPageSize > 0 && pagesize > maxPageSize) {
throw new QueryException(DatawaveErrorCode.TOO_MANY_ROWS_REQUESTED, MessageFormat.format("Size must be less than or equal to: {0}", maxPageSize));
}
CachedRunningQuery crq = null;
try {
// Get the CachedRunningQuery object from the cache
try {
crq = retrieve(queryId, owner);
} catch (IOException e) {
throw new PreConditionFailedQueryException(DatawaveErrorCode.CACHED_RESULTS_IMPORT_ERROR, e);
}
if (null == crq)
throw new PreConditionFailedQueryException(DatawaveErrorCode.QUERY_NOT_CACHED);
response = crq.getQueryLogic().getResponseObjectFactory().getEventQueryResponse();
if (!crq.getUser().equals(owner)) {
throw new UnauthorizedQueryException(DatawaveErrorCode.QUERY_OWNER_MISMATCH, MessageFormat.format("{0} != {1}", crq.getUser(), owner));
}
synchronized (crq) {
if (crq.isActivated() == false) {
Connection connection = ds.getConnection();
String logicName = crq.getQueryLogicName();
QueryLogic<?> queryLogic = queryFactory.getQueryLogic(logicName, p);
crq.activate(connection, queryLogic);
}
try {
ResultsPage resultList = crq.getRows(rowBegin, rowEnd, cachedResultsConfiguration.getPageByteTrigger());
response = crq.getTransformer().createResponse(resultList);
Status status;
if (!resultList.getResults().isEmpty()) {
response.setHasResults(true);
status = Status.OK;
} else {
response.setHasResults(false);
status = Status.NO_CONTENT;
}
response.setLogicName(crq.getQueryLogic().getLogicName());
response.setQueryId(crq.getQueryId());
if (response instanceof TotalResultsAware) {
((TotalResultsAware) response).setTotalResults(crq.getTotalRows());
}
if (status == Status.NO_CONTENT) {
throw new NoResultsQueryException(DatawaveErrorCode.NO_CONTENT_STATUS);
}
crq.getMetric().setLifecycle(QueryMetric.Lifecycle.RESULTS);
return response;
} catch (SQLException e) {
throw new QueryException();
} catch (NoResultsQueryException e) {
throw e;
} catch (RuntimeException e) {
log.error(e.getMessage(), e);
throw e;
} finally {
crq.closeConnection(log);
}
}
} finally {
// Push metrics
try {
if (null != crq && crq.getQueryLogic().getCollectQueryMetrics() == true) {
metrics.updateMetric(crq.getMetric());
}
} catch (Exception e1) {
log.error("Error updating metrics", e1);
}
}
} catch (Exception e) {
DatawaveErrorCode dec;
if (e instanceof NoResultsQueryException) {
dec = DatawaveErrorCode.NO_CONTENT_STATUS;
} else {
dec = DatawaveErrorCode.CACHED_QUERY_TRANSACTION_ERROR;
}
QueryException qe = new QueryException(dec, e);
log.error(qe);
response.addException(qe.getBottomQueryException());
int statusCode = qe.getBottomQueryException().getStatusCode();
throw new DatawaveWebApplicationException(qe, response, statusCode);
}
}
use of datawave.webservice.query.exception.BadRequestQueryException in project datawave by NationalSecurityAgency.
the class DefaultQueryPlanner method timedTestForNonExistentFields.
protected void timedTestForNonExistentFields(QueryStopwatch timers, final ASTJexlScript script, ShardQueryConfiguration config, MetadataHelper metadataHelper, QueryModel queryModel, Query settings) throws DatawaveQueryException {
TraceStopwatch stopwatch = timers.newStartedStopwatch("DefaultQueryPlanner - Test for Non-Existent Fields");
// Verify that the query does not contain fields we've never seen
// before
Set<String> specialFields = Sets.newHashSet(QueryOptions.DEFAULT_DATATYPE_FIELDNAME, Constants.ANY_FIELD, Constants.NO_FIELD);
specialFields.addAll(config.getEvaluationOnlyFields());
Set<String> nonexistentFields = FieldMissingFromSchemaVisitor.getNonExistentFields(metadataHelper, script, config.getDatatypeFilter(), specialFields);
if (log.isDebugEnabled()) {
log.debug("Testing for non-existent fields, found: " + nonexistentFields.size());
}
// ensure that all of the fields actually exist in the data dictionary
Set<String> allFields = null;
try {
allFields = metadataHelper.getAllFields(config.getDatatypeFilter());
} catch (TableNotFoundException e) {
throw new DatawaveQueryException("Unable get get data dictionary", e);
}
// Fields in the data dictionary is always uppercase. Convert the unique fields to uppercase
// so the comparisons are case insensitive
List<String> fields = config.getUniqueFields().getFields().stream().map(String::toUpperCase).collect(Collectors.toList());
// for the unique fields we need to also look for any model aliases (forward or reverse) and fields generated post evaluation (e.g. HIT_TERM)
// this is because unique fields operate on the fields as returned to the user. We essentially leave all variants of the fields
// in the unique field list to ensure we catch everything
Set<String> uniqueFields = new HashSet<>(allFields);
if (queryModel != null) {
uniqueFields.addAll(queryModel.getForwardQueryMapping().keySet());
uniqueFields.addAll(queryModel.getReverseQueryMapping().values());
}
uniqueFields.add(JexlEvaluation.HIT_TERM_FIELD);
if (!uniqueFields.containsAll(fields)) {
Set<String> missingFields = Sets.newHashSet(config.getUniqueFields().getFields());
missingFields.removeAll(uniqueFields);
nonexistentFields.addAll(missingFields);
}
if (!nonexistentFields.isEmpty()) {
String datatypeFilterSet = (null == config.getDatatypeFilter()) ? "none" : config.getDatatypeFilter().toString();
if (log.isTraceEnabled()) {
try {
log.trace("current size of fields" + metadataHelper.getAllFields(config.getDatatypeFilter()));
log.trace("all fields: " + metadataHelper.getAllFields(config.getDatatypeFilter()));
} catch (TableNotFoundException e) {
log.error("table not found when reading metadata", e);
}
log.trace("QueryModel:" + (null == queryModel ? "null" : queryModel));
log.trace("metadataHelper " + metadataHelper);
}
log.trace("QueryModel:" + (null == queryModel ? "null" : queryModel));
log.trace("metadataHelper " + metadataHelper);
BadRequestQueryException qe = new BadRequestQueryException(DatawaveErrorCode.FIELDS_NOT_IN_DATA_DICTIONARY, MessageFormat.format("Datatype Filter: {0}, Missing Fields: {1}, Auths: {2}", datatypeFilterSet, nonexistentFields, settings.getQueryAuthorizations()));
log.error(qe);
throw new InvalidQueryException(qe);
}
stopwatch.stop();
}
use of datawave.webservice.query.exception.BadRequestQueryException in project datawave by NationalSecurityAgency.
the class DefaultQueryPlanner method parseQueryAndValidatePattern.
protected ASTJexlScript parseQueryAndValidatePattern(String query, TraceStopwatch stopwatch) {
ASTJexlScript queryTree;
try {
queryTree = JexlASTHelper.parseAndFlattenJexlQuery(query);
ValidPatternVisitor.check(queryTree);
ValidComparisonVisitor.check(queryTree);
} catch (StackOverflowError soe) {
if (log.isTraceEnabled()) {
log.trace("Stack trace for overflow " + soe);
}
stopwatch.stop();
PreConditionFailedQueryException qe = new PreConditionFailedQueryException(DatawaveErrorCode.QUERY_DEPTH_OR_TERM_THRESHOLD_EXCEEDED, soe);
log.warn(qe);
throw new DatawaveFatalQueryException(qe);
} catch (ParseException e) {
stopwatch.stop();
BadRequestQueryException qe = new BadRequestQueryException(DatawaveErrorCode.UNPARSEABLE_JEXL_QUERY, e, MessageFormat.format("Query: {0}", query));
log.warn(qe);
throw new DatawaveFatalQueryException(qe);
} catch (PatternSyntaxException e) {
stopwatch.stop();
BadRequestQueryException qe = new BadRequestQueryException(DatawaveErrorCode.INVALID_REGEX, e, MessageFormat.format("Query: {0}", query));
log.warn(qe);
throw new DatawaveFatalQueryException(qe);
}
return queryTree;
}
use of datawave.webservice.query.exception.BadRequestQueryException in project datawave by NationalSecurityAgency.
the class DefaultQueryPlanner method getQueryRanges.
/**
* Returns a Tuple2<Iterable<Range>,Boolean> whose elements represent the Ranges to use for querying the shard table and whether or not this is
* a "full-table-scan" query.
*
* @param scannerFactory
* @param metadataHelper
* @param config
* @param queryTree
* @return
* @throws DatawaveQueryException
*/
public Tuple2<CloseableIterable<QueryPlan>, Boolean> getQueryRanges(ScannerFactory scannerFactory, MetadataHelper metadataHelper, ShardQueryConfiguration config, JexlNode queryTree) throws DatawaveQueryException {
Preconditions.checkNotNull(queryTree);
boolean needsFullTable = false;
CloseableIterable<QueryPlan> ranges = null;
// if the query has already been reduced to false there is no reason to do more
if (QueryPruningVisitor.getState(queryTree) == QueryPruningVisitor.TruthState.FALSE) {
return new Tuple2<>(emptyCloseableIterator(), false);
}
// if we still have an unexecutable tree, then a full table scan is
// required
List<String> debugOutput = null;
if (log.isDebugEnabled()) {
debugOutput = new ArrayList<>(32);
}
STATE state = ExecutableDeterminationVisitor.getState(queryTree, config, metadataHelper, debugOutput);
if (log.isDebugEnabled()) {
logDebug(debugOutput, "ExecutableDeterminationVisitor at getQueryRanges:");
}
if (state != STATE.EXECUTABLE) {
if (state == STATE.ERROR) {
log.warn("After expanding the query, it is determined that the query cannot be executed due to index-only fields mixed with expressions that cannot be run against the index.");
BadRequestQueryException qe = new BadRequestQueryException(DatawaveErrorCode.INDEX_ONLY_FIELDS_MIXED_INVALID_EXPRESSIONS);
throw new InvalidQueryException(qe);
}
log.warn("After expanding the query, it is determined that the query cannot be executed against the field index and a full table scan is required");
needsFullTable = true;
}
// scan, then lets try to compute ranges
if (!needsFullTable) {
// count the terms
int termCount = TermCountingVisitor.countTerms(queryTree);
if (termCount >= pushdownThreshold) {
if (log.isTraceEnabled()) {
log.trace("pushing down query because it has " + termCount + " when our max is " + pushdownThreshold);
}
config.setCollapseUids(true);
}
TraceStopwatch stopwatch = config.getTimers().newStartedStopwatch("DefaultQueryPlanner - Begin stream of ranges from inverted index");
RangeStream stream = initializeRangeStream(config, scannerFactory, metadataHelper);
ranges = stream.streamPlans(queryTree);
if (log.isTraceEnabled()) {
log.trace("query stream is " + stream.context());
}
// if a term threshold is exceeded and we cannot handle that, then
// throw unsupported
boolean thresholdExceeded = StreamContext.EXCEEDED_TERM_THRESHOLD.equals(stream.context());
if (thresholdExceeded && !config.canHandleExceededTermThreshold()) {
throw new UnsupportedOperationException(EXCEED_TERM_EXPANSION_ERROR);
}
if (StreamContext.UNINDEXED.equals(stream.context())) {
log.debug("Needs full table scan because of unindexed fields");
needsFullTable = true;
} else if (StreamContext.DELAYED_FIELD.equals(stream.context())) {
log.debug("Needs full table scan because query consists of only delayed expressions");
needsFullTable = true;
} else // force a full table scan
if (IvaratorRequiredVisitor.isIvaratorRequired(queryTree) && !config.canHandleExceededValueThreshold()) {
log.debug("Needs full table scan because we exceeded the value threshold and config.canHandleExceededValueThreshold() is false");
needsFullTable = true;
}
stopwatch.stop();
}
if (needsFullTable) {
if (config.getFullTableScanEnabled()) {
ranges = this.getFullScanRange(config, queryTree);
} else {
if (log.isTraceEnabled())
log.trace("Full table scans are not enabled, query will not be run");
QueryException qe = new QueryException(DatawaveErrorCode.FULL_TABLE_SCAN_REQUIRED_BUT_DISABLED);
throw new FullTableScansDisallowedException(qe);
}
if (log.isTraceEnabled())
log.trace("Ranges are " + ranges);
}
return new Tuple2<>(ranges, needsFullTable);
}
use of datawave.webservice.query.exception.BadRequestQueryException in project datawave by NationalSecurityAgency.
the class QueryExecutorBean method disableTracing.
/**
* <strong>JBossAdministrator or Administrator credentials required.</strong> Disables tracing that was previously enabled using the
* {@link #enableTracing(String, String)} method.
*
* @param queryRegex
* (optional) the query regular expression defining queries to disable tracing
* @param user
* (optional) the user name for which to disable query tracing
* @return datawave.webservice.result.VoidResponse
*
* @HTTP 200 success
* @HTTP 400 if neither queryRegex nor user are specified
* @HTTP 401 if the user does not have Administrative credentials
*/
@GET
@Path("/disableTracing")
@Produces({ "application/xml", "text/xml", "application/json", "text/yaml", "text/x-yaml", "application/x-yaml", "application/x-protobuf", "application/x-protostuff" })
@RolesAllowed({ "Administrator", "JBossAdministrator" })
@Override
public VoidResponse disableTracing(@QueryParam("queryRegex") String queryRegex, @QueryParam("user") String user) {
VoidResponse response = new VoidResponse();
if (queryRegex == null && user == null) {
BadRequestQueryException qe = new BadRequestQueryException(DatawaveErrorCode.QUERY_REGEX_OR_USER_REQUIRED);
response.addException(qe);
throw new BadRequestException(qe, response);
} else if (queryRegex == null) {
traceInfos.removeAll(user);
response.addMessage("All query tracing for " + user + " is disabled. Per-query tracing is still possible.");
} else {
traceInfos.remove(user, PatternWrapper.wrap(queryRegex));
response.addMessage("Queries for user " + user + " matching " + queryRegex + " have been disabled. Per-query tracing is still possible.");
}
// Put updated map back in the cache
queryTraceCache.put("traceInfos", traceInfos);
return response;
}
Aggregations