in modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/QueryParser.java [313:535]
private QueryParserResult parseH2(String schemaName, SqlFieldsQuery qry, boolean batched,
boolean remainingAllowed) {
try (H2PooledConnection c = connMgr.connection(schemaName)) {
// For queries that are explicitly local, we rely on the flag specified in the query
// because this parsing result will be cached and used for queries directly.
// For other queries, we enforce join order at this stage to avoid premature optimizations
// (and therefore longer parsing) as long as there'll be more parsing at split stage.
boolean enforceJoinOrderOnParsing = (!qry.isLocal() || qry.isEnforceJoinOrder());
QueryContext qctx = QueryContext.parseContext(idx.backupFilter(null, null), qry.isLocal());
H2Utils.setupConnection(
c,
qctx,
false,
enforceJoinOrderOnParsing,
false);
PreparedStatement stmt = null;
try {
stmt = c.prepareStatementNoCache(qry.getSql());
if (qry.isLocal() && GridSqlQueryParser.checkMultipleStatements(stmt))
throw new IgniteSQLException("Multiple statements queries are not supported for local queries.",
IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
GridSqlQueryParser.PreparedWithRemaining prep = GridSqlQueryParser.preparedWithRemaining(stmt);
Prepared prepared = prep.prepared();
if (GridSqlQueryParser.isExplainUpdate(prepared))
throw new IgniteSQLException("Explains of update queries are not supported.",
IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
GridSqlQueryParser.failIfSelectForUpdateQuery(prepared);
// Get remaining query and check if it is allowed.
SqlFieldsQuery remainingQry = null;
if (!F.isEmpty(prep.remainingSql())) {
checkRemainingAllowed(remainingAllowed);
remainingQry = cloneFieldsQuery(qry).setSql(prep.remainingSql());
}
// Prepare new query.
SqlFieldsQuery newQry = cloneFieldsQuery(qry).setSql(prepared.getSQL());
final int paramsCnt = prepared.getParameters().size();
Object[] argsOrig = qry.getArgs();
Object[] args = null;
Object[] remainingArgs = null;
if (!batched && paramsCnt > 0) {
if (argsOrig == null || argsOrig.length < paramsCnt)
// Not enough parameters, but we will handle this later on execution phase.
args = argsOrig;
else {
args = Arrays.copyOfRange(argsOrig, 0, paramsCnt);
if (paramsCnt != argsOrig.length)
remainingArgs = Arrays.copyOfRange(argsOrig, paramsCnt, argsOrig.length);
}
}
else
remainingArgs = argsOrig;
newQry.setArgs(args);
QueryDescriptor newQryDesc = queryDescriptor(schemaName, newQry);
if (remainingQry != null)
remainingQry.setArgs(remainingArgs);
final List<JdbcParameterMeta> paramsMeta;
try {
paramsMeta = H2Utils.parametersMeta(stmt.getParameterMetaData());
assert prepared.getParameters().size() == paramsMeta.size();
}
catch (IgniteCheckedException | SQLException e) {
throw new IgniteSQLException("Failed to get parameters metadata", IgniteQueryErrorCode.UNKNOWN, e);
}
// Do actual parsing.
if (CommandProcessor.isCommand(prepared)) {
GridSqlStatement cmdH2 = new GridSqlQueryParser(false, log).parse(prepared);
QueryParserResultCommand cmd = new QueryParserResultCommand(null, cmdH2, false);
return new QueryParserResult(
newQryDesc,
queryParameters(newQry),
remainingQry,
paramsMeta,
null,
null,
cmd
);
}
else if (CommandProcessor.isCommandNoOp(prepared)) {
QueryParserResultCommand cmd = new QueryParserResultCommand(null, null, true);
return new QueryParserResult(
newQryDesc,
queryParameters(newQry),
remainingQry,
paramsMeta,
null,
null,
cmd
);
}
else if (GridSqlQueryParser.isDml(prepared)) {
QueryParserResultDml dml = prepareDmlStatement(newQryDesc, prepared);
return new QueryParserResult(
newQryDesc,
queryParameters(newQry),
remainingQry,
paramsMeta,
null,
dml,
null
);
}
else if (!prepared.isQuery()) {
throw new IgniteSQLException("Unsupported statement: " + newQry.getSql(),
IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
}
// Parse SELECT.
GridSqlQueryParser parser = new GridSqlQueryParser(false, log);
GridSqlQuery selectStmt = (GridSqlQuery)parser.parse(prepared);
List<Integer> cacheIds = parser.cacheIds();
// Calculate if query is in fact can be executed locally.
boolean loc = qry.isLocal();
if (!loc) {
if (parser.isLocalQuery())
loc = true;
}
// If this is a local query, check if it must be split.
boolean locSplit = false;
if (loc) {
GridCacheContext cctx = parser.getFirstPartitionedCache();
if (cctx != null && cctx.config().getQueryParallelism() > 1)
locSplit = true;
}
// Split is required either if query is distributed, or when it is local, but executed
// over segmented PARTITIONED case. In this case multiple map queries will be executed against local
// node stripes in parallel and then merged through reduce process.
boolean splitNeeded = !loc || locSplit;
GridCacheTwoStepQuery twoStepQry = null;
if (splitNeeded) {
GridSubqueryJoinOptimizer.pullOutSubQueries(selectStmt);
c.schema(newQry.getSchema());
twoStepQry = GridSqlQuerySplitter.split(
c,
selectStmt,
newQry.getSql(),
newQry.isCollocated(),
newQry.isDistributedJoins(),
newQry.isEnforceJoinOrder(),
locSplit,
idx,
paramsCnt,
log
);
}
List<GridQueryFieldMetadata> meta = H2Utils.meta(stmt.getMetaData());
QueryParserResultSelect select = new QueryParserResultSelect(
selectStmt,
twoStepQry,
meta,
cacheIds
);
return new QueryParserResult(
newQryDesc,
queryParameters(newQry),
remainingQry,
paramsMeta,
select,
null,
null
);
}
catch (SQLException e) {
if (e.getErrorCode() == ErrorCode.DATABASE_IS_CLOSED) {
idx.kernalContext().failure().process(new FailureContext(CRITICAL_ERROR, e));
throw new IgniteSQLException("Critical database error. " + e.getMessage(),
IgniteQueryErrorCode.DB_UNRECOVERABLE_ERROR, e);
}
else
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), IgniteQueryErrorCode.PARSING, e);
}
catch (IgniteCheckedException e) {
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), IgniteQueryErrorCode.PARSING, e);
}
finally {
U.close(stmt, log);
}
}
}