use of org.apache.ignite.internal.processors.query.GridQueryFieldMetadata in project ignite by apache.
the class IgniteCacheAbstractFieldsQuerySelfTest method testExecuteWithMetaData.
/**
* @throws Exception If failed.
*/
@Test
public void testExecuteWithMetaData() throws Exception {
QueryCursorImpl<List<?>> cursor = (QueryCursorImpl<List<?>>) personCache.query(sqlFieldsQuery(String.format("select p._KEY, p.name, p.age, o.name " + "from \"%s\".Person p, \"%s\".Organization o where p.orgId = o.id", personCache.getName(), orgCache.getName())));
Collection<GridQueryFieldMetadata> meta = cursor.fieldsMeta();
assertNotNull(meta);
assertEquals(4, meta.size());
Iterator<GridQueryFieldMetadata> metaIt = meta.iterator();
assertNotNull(metaIt);
assert metaIt.hasNext();
GridQueryFieldMetadata field = metaIt.next();
assertNotNull(field);
assertEquals(personCache.getName(), field.schemaName());
assertEquals("PERSON", field.typeName());
assertEquals("_KEY", field.fieldName());
assertEquals(Object.class.getName(), field.fieldTypeName());
assert metaIt.hasNext();
field = metaIt.next();
assertNotNull(field);
assertEquals(personCache.getName(), field.schemaName());
assertEquals("PERSON", field.typeName());
assertEquals("NAME", field.fieldName());
assertEquals(String.class.getName(), field.fieldTypeName());
assert metaIt.hasNext();
field = metaIt.next();
assertNotNull(field);
assertEquals(personCache.getName(), field.schemaName());
assertEquals("PERSON", field.typeName());
assertEquals("AGE", field.fieldName());
assertEquals(Integer.class.getName(), field.fieldTypeName());
assert metaIt.hasNext();
field = metaIt.next();
assert field != null;
assertNotNull(field);
assertEquals(orgCache.getName(), field.schemaName());
assertEquals("ORGANIZATION", field.typeName());
assertEquals("NAME", field.fieldName());
assertEquals(String.class.getName(), field.fieldTypeName());
assert !metaIt.hasNext();
List<List<?>> res = cursor.getAll();
dedup(res);
assertEquals(3, res.size());
Collections.sort(res, new Comparator<List<?>>() {
@Override
public int compare(List<?> row1, List<?> row2) {
return ((Integer) row1.get(2)).compareTo((Integer) row2.get(2));
}
});
int cnt = 0;
for (List<?> row : res) {
assert row.size() == 4;
if (cnt == 0) {
assertEquals(new AffinityKey<>("p1", "o1"), row.get(0));
assertEquals("John White", row.get(1));
assertEquals(25, row.get(2));
assertEquals("A", row.get(3));
} else if (cnt == 1) {
assertEquals(new AffinityKey<>("p2", "o1"), row.get(0));
assertEquals("Joe Black", row.get(1));
assertEquals(35, row.get(2));
assertEquals("A", row.get(3));
}
if (cnt == 2) {
assertEquals(new AffinityKey<>("p3", "o2"), row.get(0));
assertEquals("Mike Green", row.get(1));
assertEquals(40, row.get(2));
assertEquals("B", row.get(3));
}
cnt++;
}
assertEquals(3, cnt);
}
use of org.apache.ignite.internal.processors.query.GridQueryFieldMetadata in project ignite by apache.
the class IgniteCacheAbstractFieldsQuerySelfTest method testDecimalColumnScaleAndPrecision.
/**
* Test that scale and precision returned correctly for Decimal column in result set:
*
* 1. Start node;
* 2. Create table with Decimal(3,0) column;
* 3. Insert a new row into the table;
* 4. Execute select with decimal row;
* 5. Check that selected decimal column has precision 3 and scale 0.
*
* @throws Exception If failed.
*/
@Test
public void testDecimalColumnScaleAndPrecision() throws Exception {
QueryEntity qeWithPrecision = new QueryEntity().setKeyType("java.lang.Long").setValueType("TestType").addQueryField("age", "java.math.BigDecimal", "age").setFieldsPrecision(ImmutableMap.of("age", 3)).setFieldsScale(ImmutableMap.of("age", 0));
grid(0).getOrCreateCache(cacheConfiguration().setName("cacheWithDecimalPrecisionAndScale").setQueryEntities(Collections.singleton(qeWithPrecision)));
GridQueryProcessor qryProc = grid(0).context().query();
qryProc.querySqlFields(new SqlFieldsQuery("INSERT INTO TestType(_key, age) VALUES(?, ?)").setSchema("cacheWithDecimalPrecisionAndScale").setArgs(1, new BigDecimal(160)), true);
QueryCursorImpl<List<?>> cursor = (QueryCursorImpl<List<?>>) qryProc.querySqlFields(new SqlFieldsQuery("SELECT age FROM TestType").setSchema("cacheWithDecimalPrecisionAndScale"), true);
List<GridQueryFieldMetadata> fieldsMeta = cursor.fieldsMeta();
assertEquals(1, fieldsMeta.size());
GridQueryFieldMetadata meta = fieldsMeta.get(0);
assertEquals(3, meta.precision());
assertEquals(0, meta.scale());
}
use of org.apache.ignite.internal.processors.query.GridQueryFieldMetadata 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.internal.processors.query.GridQueryFieldMetadata in project ignite by apache.
the class GridSubqueryJoinOptimizerSelfTest method check.
/**
* @param sql Sql.
* @param expSelectClauses Expected select clauses.
*/
private void check(String sql, int expSelectClauses) {
optimizationEnabled(false);
FieldsQueryCursor<List<?>> qry = cache.query(new SqlFieldsQuery(sql));
List<GridQueryFieldMetadata> expMetaList = ((QueryCursorEx<List<?>>) qry).fieldsMeta();
List<List<?>> exp = qry.getAll();
exp.sort(ROW_COMPARATOR);
optimizationEnabled(true);
FieldsQueryCursor<List<?>> optQry = cache.query(new SqlFieldsQuery(sql).setEnforceJoinOrder(true));
List<GridQueryFieldMetadata> actMetaList = ((QueryCursorEx<List<?>>) optQry).fieldsMeta();
List<List<?>> act = optQry.getAll();
act.sort(ROW_COMPARATOR);
Assert.assertEquals("Result set mismatch", exp, act);
List<String> expFieldTypes = new ArrayList<>();
List<String> actualFieldTypes = new ArrayList<>();
for (int i = 0; i < expMetaList.size(); i++) {
GridQueryFieldMetadata expMeta = expMetaList.get(i);
GridQueryFieldMetadata actMeta = actMetaList.get(i);
expFieldTypes.add(expMeta.fieldName() + ":" + expMeta.fieldTypeName());
actualFieldTypes.add(actMeta.fieldName() + ":" + actMeta.fieldTypeName());
}
Assert.assertEquals("Result set field names or field types mismatch", expFieldTypes, actualFieldTypes);
String plan = cache.query(new SqlFieldsQuery("explain " + sql)).getAll().get(0).get(0).toString();
System.out.println(plan);
int actCnt = countEntries(plan, "SELECT");
Assert.assertEquals(String.format("SELECT-clause count mismatch: exp=%d, act=%d, plan=[%s]", expSelectClauses, actCnt, plan), expSelectClauses, actCnt);
}
use of org.apache.ignite.internal.processors.query.GridQueryFieldMetadata in project ignite by apache.
the class OdbcRequestHandler method getResultMeta.
/**
* {@link OdbcQueryGetQueryMetaRequest} command handler.
* Returns metadata for a columns of the result set.
*
* @param req Get resultset metadata request.
* @return Response.
*/
private ClientListenerResponse getResultMeta(OdbcQueryGetResultsetMetaRequest req) {
try {
String sql = OdbcEscapeUtils.parse(req.query());
String schema = OdbcUtils.prepareSchema(req.schema());
SqlFieldsQueryEx qry = makeQuery(schema, sql);
List<GridQueryFieldMetadata> columns = ctx.query().getIndexing().resultMetaData(schema, qry);
Collection<OdbcColumnMeta> meta = OdbcUtils.convertMetadata(columns);
OdbcQueryGetResultsetMetaResult res = new OdbcQueryGetResultsetMetaResult(meta);
return new OdbcResponse(res);
} catch (Exception e) {
U.error(log, "Failed to get resultset metadata [reqId=" + req.requestId() + ", req=" + req + ']', e);
return exceptionToResult(e);
}
}
Aggregations