use of org.apache.ignite.cache.query.SqlFieldsQuery in project ignite by apache.
the class IgniteH2Indexing method querySqlFields.
/**
* {@inheritDoc}
*/
@SuppressWarnings({ "StringEquality" })
@Override
public List<FieldsQueryCursor<List<?>>> querySqlFields(String schemaName, SqlFieldsQuery qry, @Nullable SqlClientContext cliCtx, boolean keepBinary, boolean failOnMultipleStmts, GridQueryCancel cancel) {
try {
List<FieldsQueryCursor<List<?>>> res = new ArrayList<>(1);
SqlFieldsQuery remainingQry = qry;
while (remainingQry != null) {
Span qrySpan = ctx.tracing().create(SQL_QRY, MTC.span()).addTag(SQL_SCHEMA, () -> schemaName);
try (TraceSurroundings ignored = MTC.supportContinual(qrySpan)) {
// Parse.
QueryParserResult parseRes = parser.parse(schemaName, remainingQry, !failOnMultipleStmts);
qrySpan.addTag(SQL_QRY_TEXT, () -> parseRes.queryDescriptor().sql());
remainingQry = parseRes.remainingQuery();
// Get next command.
QueryDescriptor newQryDesc = parseRes.queryDescriptor();
QueryParameters newQryParams = parseRes.queryParameters();
// since they pass parameters differently.
if (!newQryDesc.batched()) {
int qryParamsCnt = F.isEmpty(newQryParams.arguments()) ? 0 : newQryParams.arguments().length;
if (qryParamsCnt < parseRes.parametersCount())
throw new IgniteSQLException("Invalid number of query parameters [expected=" + parseRes.parametersCount() + ", actual=" + qryParamsCnt + ']');
}
// Check if cluster state is valid.
checkClusterState(parseRes);
// Execute.
if (parseRes.isCommand()) {
QueryParserResultCommand cmd = parseRes.command();
assert cmd != null;
FieldsQueryCursor<List<?>> cmdRes = executeCommand(newQryDesc, newQryParams, cliCtx, cmd);
res.add(cmdRes);
} else if (parseRes.isDml()) {
QueryParserResultDml dml = parseRes.dml();
assert dml != null;
List<? extends FieldsQueryCursor<List<?>>> dmlRes = executeDml(newQryDesc, newQryParams, dml, cancel);
res.addAll(dmlRes);
} else {
assert parseRes.isSelect();
QueryParserResultSelect select = parseRes.select();
assert select != null;
List<? extends FieldsQueryCursor<List<?>>> qryRes = executeSelect(newQryDesc, newQryParams, select, keepBinary, cancel);
res.addAll(qryRes);
}
} catch (Throwable th) {
qrySpan.addTag(ERROR, th::getMessage).end();
throw th;
}
}
return res;
} catch (RuntimeException | Error e) {
GridNearTxLocal tx = ctx.cache().context().tm().tx();
if (tx != null && tx.mvccSnapshot() != null && (!(e instanceof IgniteSQLException) || /* Parsing errors should not rollback Tx. */
((IgniteSQLException) e).sqlState() != SqlStateCode.PARSING_EXCEPTION))
tx.setRollbackOnly();
throw e;
}
}
use of org.apache.ignite.cache.query.SqlFieldsQuery in project ignite by apache.
the class IgniteH2Indexing method executeUpdateNonTransactional.
/**
* Execute update in non-transactional mode.
*
* @param qryId Query id.
* @param qryDesc Query descriptor.
* @param qryParams Query parameters.
* @param dml Plan.
* @param loc Local flag.
* @param filters Filters.
* @param cancel Cancel hook.
* @return Update result.
* @throws IgniteCheckedException If failed.
*/
private UpdateResult executeUpdateNonTransactional(long qryId, QueryDescriptor qryDesc, QueryParameters qryParams, QueryParserResultDml dml, boolean loc, IndexingQueryFilter filters, GridQueryCancel cancel) throws IgniteCheckedException {
UpdatePlan plan = dml.plan();
UpdateResult fastUpdateRes = plan.processFast(qryParams.arguments());
if (fastUpdateRes != null)
return fastUpdateRes;
DmlDistributedPlanInfo distributedPlan = loc ? null : plan.distributedPlan();
if (distributedPlan != null) {
if (cancel == null)
cancel = new GridQueryCancel();
UpdateResult result = rdcQryExec.update(qryDesc.schemaName(), distributedPlan.getCacheIds(), qryDesc.sql(), qryParams.arguments(), qryDesc.enforceJoinOrder(), qryParams.pageSize(), qryParams.timeout(), qryParams.partitions(), distributedPlan.isReplicatedOnly(), cancel);
// Null is returned in case not all nodes support distributed DML.
if (result != null)
return result;
}
final GridQueryCancel selectCancel = (cancel != null) ? new GridQueryCancel() : null;
if (cancel != null)
cancel.add(selectCancel::cancel);
SqlFieldsQuery selectFieldsQry = new SqlFieldsQuery(plan.selectQuery(), qryDesc.collocated()).setArgs(qryParams.arguments()).setDistributedJoins(qryDesc.distributedJoins()).setEnforceJoinOrder(qryDesc.enforceJoinOrder()).setLocal(qryDesc.local()).setPageSize(qryParams.pageSize()).setTimeout(qryParams.timeout(), TimeUnit.MILLISECONDS).setLazy(qryParams.lazy() && plan.canSelectBeLazy());
Iterable<List<?>> cur;
// sub-query and not some dummy stuff like "select 1, 2, 3;"
if (!loc && !plan.isLocalSubquery()) {
assert !F.isEmpty(plan.selectQuery());
cur = executeSelectForDml(qryId, qryDesc.schemaName(), selectFieldsQry, null, selectCancel, qryParams.timeout());
} else if (plan.hasRows())
cur = plan.createRows(qryParams.arguments());
else {
selectFieldsQry.setLocal(true);
QueryParserResult selectParseRes = parser.parse(qryDesc.schemaName(), selectFieldsQry, false);
final GridQueryFieldsResult res = executeSelectLocal(qryId, selectParseRes.queryDescriptor(), selectParseRes.queryParameters(), selectParseRes.select(), filters, null, selectCancel, false, qryParams.timeout());
cur = new QueryCursorImpl<>(new Iterable<List<?>>() {
@Override
public Iterator<List<?>> iterator() {
try {
return new GridQueryCacheObjectsIterator(res.iterator(), objectContext(), true);
} catch (IgniteCheckedException e) {
throw new IgniteException(e);
}
}
}, cancel, true, qryParams.lazy());
}
int pageSize = qryParams.updateBatchSize();
// TODO: IGNITE-11176 - Need to support cancellation
try {
return DmlUtils.processSelectResult(plan, cur, pageSize);
} finally {
if (cur instanceof AutoCloseable)
U.closeQuiet((AutoCloseable) cur);
}
}
use of org.apache.ignite.cache.query.SqlFieldsQuery in project ignite by apache.
the class QueryParser method parseH2.
/**
* Parse and split query if needed, cache either two-step query or statement.
*
* @param schemaName Schema name.
* @param qry Query.
* @param batched Batched flag.
* @param remainingAllowed Whether multiple statements are allowed.
* @return Parsing result.
*/
@SuppressWarnings("IfMayBeConditional")
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);
// 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();
Integer mvccCacheId = mvccCacheIdForSelect(parser.objectsMap());
// 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;
String forUpdateQryOutTx = null;
String forUpdateQryTx = null;
GridCacheTwoStepQuery forUpdateTwoStepQry = null;
boolean forUpdate = GridSqlQueryParser.isForUpdateQuery(prepared);
// column to be able to lock selected rows further.
if (forUpdate) {
// We have checked above that it's not an UNION query, so it's got to be SELECT.
assert selectStmt instanceof GridSqlSelect;
// Check FOR UPDATE invariants: only one table, MVCC is there.
if (cacheIds.size() != 1)
throw new IgniteSQLException("SELECT FOR UPDATE is supported only for queries " + "that involve single transactional cache.");
if (mvccCacheId == null)
throw new IgniteSQLException("SELECT FOR UPDATE query requires transactional cache " + "with MVCC enabled.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
// We need a copy because we are going to modify AST a bit. We do not want to modify original select.
GridSqlSelect selForUpdate = ((GridSqlSelect) selectStmt).copySelectForUpdate();
// Clear forUpdate flag to run it as a plain query.
selForUpdate.forUpdate(false);
((GridSqlSelect) selectStmt).forUpdate(false);
// Remember sql string without FOR UPDATE clause.
forUpdateQryOutTx = selForUpdate.getSQL();
GridSqlAlias keyCol = keyColumn(selForUpdate);
selForUpdate.addColumn(keyCol, true);
// Remember sql string without FOR UPDATE clause and with _key column.
forUpdateQryTx = selForUpdate.getSQL();
// Prepare additional two-step query for FOR UPDATE case.
if (splitNeeded) {
c.schema(newQry.getSchema());
forUpdateTwoStepQry = GridSqlQuerySplitter.split(c, selForUpdate, forUpdateQryTx, newQry.isCollocated(), newQry.isDistributedJoins(), newQry.isEnforceJoinOrder(), locSplit, idx, paramsCnt, log);
}
}
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, forUpdateTwoStepQry, meta, cacheIds, mvccCacheId, forUpdateQryOutTx, forUpdateQryTx);
return new QueryParserResult(newQryDesc, queryParameters(newQry), remainingQry, paramsMeta, select, null, null);
} catch (IgniteCheckedException | SQLException e) {
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), IgniteQueryErrorCode.PARSING, e);
} finally {
U.close(stmt, log);
}
}
}
use of org.apache.ignite.cache.query.SqlFieldsQuery in project ignite by apache.
the class IgniteSqlSkipReducerOnUpdateDmlSelfTest method testSpecificPartitionsUpdate.
/**
* @throws Exception if failed.
*/
@Test
public void testSpecificPartitionsUpdate() throws Exception {
fillCaches();
Affinity aff = grid(NODE_CLIENT).affinity(CACHE_PERSON);
int numParts = aff.partitions();
int[] parts = new int[numParts / 2];
for (int idx = 0; idx < numParts / 2; idx++) parts[idx] = idx * 2;
IgniteCache<PersonKey, Person> cache = grid(NODE_CLIENT).cache(CACHE_PERSON);
// UPDATE over even partitions
cache.query(new SqlFieldsQueryEx("UPDATE Person SET position = 0", false).setSkipReducerOnUpdate(true).setPartitions(parts));
List<List<?>> rows = cache.query(new SqlFieldsQuery("SELECT _key, position FROM Person")).getAll();
for (List<?> row : rows) {
PersonKey personKey = (PersonKey) row.get(0);
int pos = ((Number) row.get(1)).intValue();
int part = aff.partition(personKey);
assertTrue((part % 2 == 0) ^ (pos != 0));
}
}
use of org.apache.ignite.cache.query.SqlFieldsQuery in project ignite by apache.
the class KillQueryErrorOnCancelTest method testCancelAfterIteratorObtainedLazy.
/**
*/
@Test
public void testCancelAfterIteratorObtainedLazy() throws Exception {
IgniteEx node = grid(0);
FieldsQueryCursor<List<?>> cur = node.context().query().querySqlFields(new SqlFieldsQuery("select * from \"default\".Integer ORDER BY _val").setLazy(true).setPageSize(1), false);
Iterator<List<?>> it = cur.iterator();
it.next();
Long qryId = node.context().query().runningQueries(-1).iterator().next().id();
GridTestUtils.assertThrows(log, () -> node.context().query().querySqlFields(createKillQuery(node.context().localNodeId(), qryId, false), false).getAll(), IgniteException.class, "Fake network error");
List<GridRunningQueryInfo> runningQueries = (List<GridRunningQueryInfo>) node.context().query().runningQueries(-1);
assertTrue("runningQueries=" + runningQueries, runningQueries.isEmpty());
ensureMapQueriesHasFinished(grid(0));
ensureMapQueriesHasFinished(grid(1));
}
Aggregations