use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperationType.AND in project ignite by apache.
the class SqlAstTraverser method lookForPartitionedJoin.
/**
* Traverse AST while join operation isn't found. Check it if found.
*
* @param ast AST item to check recursively.
* @param upWhere Where condition that applies to this ast.
*/
private void lookForPartitionedJoin(GridSqlAst ast, GridSqlAst upWhere) {
if (ast == null)
return;
GridSqlJoin join = null;
GridSqlAst where = null;
if (ast instanceof GridSqlJoin) {
join = (GridSqlJoin) ast;
where = upWhere;
} else if (ast instanceof GridSqlSelect) {
GridSqlSelect select = (GridSqlSelect) ast;
if (select.from() instanceof GridSqlJoin) {
join = (GridSqlJoin) select.from();
where = select.where();
}
} else if (ast instanceof GridSqlSubquery)
hasSubQueries = true;
else if (ast instanceof GridSqlTable)
hasPartitionedTables |= ((GridSqlTable) ast).dataTable().isPartitioned();
// No joins on this level. Traverse AST deeper.
if (join == null) {
for (int i = 0; i < ast.size(); i++) lookForPartitionedJoin(ast.child(i), null);
return;
}
// Check WHERE clause first.
lookForPartitionedJoin(where, null);
// Check left side of join.
GridSqlTable leftTable = getTable(join.leftTable());
GridH2Table left = null;
// Left side of join is a subquery.
if (leftTable == null) {
hasSubQueries = true;
// Check subquery on left side.
lookForPartitionedJoin(join.leftTable(), where);
} else {
left = leftTable.dataTable();
// Data table is NULL for views.
if (left != null && left.isPartitioned())
hasPartitionedTables = true;
}
// Check right side of join.
GridSqlTable rightTable = getTable(join.rightTable());
// Right side of join is a subquery.
if (rightTable == null) {
hasSubQueries = true;
// Check subquery and return (can't exctract more info there).
lookForPartitionedJoin(join.rightTable(), where);
return;
}
GridH2Table right = rightTable.dataTable();
if (right != null && right.isPartitioned())
hasPartitionedTables = true;
// Skip check of views.
if (left == null || right == null)
return;
if (join.isLeftOuter() && !left.isPartitioned() && right.isPartitioned())
hasOuterJoinReplicatedPartitioned = true;
// Skip check if at least one of tables isn't partitioned.
if (!(left.isPartitioned() && right.isPartitioned()))
return;
if (!distributedJoins)
checkPartitionedJoin(join, where, left, right, log);
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperationType.AND in project ignite by apache.
the class NoneOrSinglePartitionsQueryOptimizationsTest method runQuery.
/**
* Runs query and checks that given sql query returns expect rows count.
*
* @param sqlQry SQL query
* @param expResCnt Expected result rows count.
* @param expMergeTbl Flag that signals that merge table is expected to be created.
* @param explainSize Explain plan response size.
* @param expOriginalQry Flag that signals that orignial sql query is expected as map query.
* @throws Exception If failed.s
*/
@SuppressWarnings({ "ThrowableNotThrown", "unchecked" })
private void runQuery(String sqlQry, int expResCnt, boolean expMergeTbl, boolean expOriginalQry, int explainSize, Object... args) throws Exception {
TestCommunicationSpi commSpi = (TestCommunicationSpi) grid(NODES_COUNT).configuration().getCommunicationSpi();
commSpi.resetQueries();
IgniteInternalFuture res = GridTestUtils.runAsync(() -> {
QueryCursor cursor = orgCache.query(new SqlFieldsQuery(sqlQry).setArgs(args));
Iterable iter = U.field(cursor, "iterExec");
Iterator innerIter = U.field(iter.iterator(), "iter");
if (expMergeTbl)
assertTrue(innerIter instanceof H2ResultSetIterator);
else
assertTrue(innerIter instanceof ReduceIndexIterator);
List<List<?>> all = new ArrayList<>();
while (innerIter.hasNext()) all.add((List) innerIter.next());
return all;
});
List<List<?>> rows = (List<List<?>>) res.get(RES_RETRIEVAL_TIMEOUT);
assertNotNull(rows);
assertEquals(expResCnt, rows.size());
int mapQueriesCnt = commSpi.mapQueries.size();
if (expOriginalQry) {
assertEquals(1, mapQueriesCnt);
assertEquals(sqlQry, commSpi.mapQueries.get(0));
} else {
for (String mapQry : commSpi.mapQueries) assertNotEquals(sqlQry, mapQry);
}
// Test explain query.
QueryCursor explainCursor = orgCache.query(new SqlFieldsQuery("explain " + sqlQry).setArgs(args));
List<List<?>> explainRes = explainCursor.getAll();
assertEquals(explainSize, explainRes.size());
if (expMergeTbl)
assertTrue(((String) explainRes.get(explainRes.size() - 1).get(0)).contains(GridSqlQuerySplitter.mergeTableIdentifier(0)));
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperationType.AND in project ignite by apache.
the class DmlStatementsProcessor method rowToKeyValue.
/**
* Convert row presented as an array of Objects into key-value pair to be inserted to cache.
* @param cctx Cache context.
* @param row Row to process.
* @param plan Update plan.
* @throws IgniteCheckedException if failed.
*/
@SuppressWarnings({ "unchecked", "ConstantConditions", "ResultOfMethodCallIgnored" })
private IgniteBiTuple<?, ?> rowToKeyValue(GridCacheContext cctx, List<?> row, UpdatePlan plan) throws IgniteCheckedException {
GridH2RowDescriptor rowDesc = plan.tbl.rowDescriptor();
GridQueryTypeDescriptor desc = rowDesc.type();
Object key = plan.keySupplier.apply(row);
if (QueryUtils.isSqlType(desc.keyClass())) {
assert plan.keyColIdx != -1;
key = convert(key, rowDesc, desc.keyClass(), plan.colTypes[plan.keyColIdx]);
}
Object val = plan.valSupplier.apply(row);
if (QueryUtils.isSqlType(desc.valueClass())) {
assert plan.valColIdx != -1;
val = convert(val, rowDesc, desc.valueClass(), plan.colTypes[plan.valColIdx]);
}
if (key == null)
throw new IgniteSQLException("Key for INSERT or MERGE must not be null", IgniteQueryErrorCode.NULL_KEY);
if (val == null)
throw new IgniteSQLException("Value for INSERT or MERGE must not be null", IgniteQueryErrorCode.NULL_VALUE);
Map<String, Object> newColVals = new HashMap<>();
for (int i = 0; i < plan.colNames.length; i++) {
if (i == plan.keyColIdx || i == plan.valColIdx)
continue;
String colName = plan.colNames[i];
GridQueryProperty prop = desc.property(colName);
assert prop != null;
Class<?> expCls = prop.type();
newColVals.put(colName, convert(row.get(i), rowDesc, expCls, plan.colTypes[i]));
}
// We update columns in the order specified by the table for a reason - table's
// column order preserves their precedence for correct update of nested properties.
Column[] cols = plan.tbl.getColumns();
// First 3 columns are _key, _val and _ver. Skip 'em.
for (int i = DEFAULT_COLUMNS_COUNT; i < cols.length; i++) {
if (plan.tbl.rowDescriptor().isKeyValueOrVersionColumn(i))
continue;
String colName = cols[i].getName();
if (!newColVals.containsKey(colName))
continue;
Object colVal = newColVals.get(colName);
desc.setValue(colName, key, val, colVal);
}
if (cctx.binaryMarshaller()) {
if (key instanceof BinaryObjectBuilder)
key = ((BinaryObjectBuilder) key).build();
if (val instanceof BinaryObjectBuilder)
val = ((BinaryObjectBuilder) val).build();
}
return new IgniteBiTuple<>(key, val);
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperationType.AND in project ignite by apache.
the class GridH2TableSelfTest method testTable.
/**
* Simple table test.
*
* @throws Exception If failed.
*/
public void testTable() throws Exception {
// Test insert.
long x = MAX_X;
Random rnd = new Random();
while (x-- > 0) {
UUID id = UUID.randomUUID();
GridH2Row row = row(id, System.currentTimeMillis(), rnd.nextBoolean() ? id.toString() : UUID.randomUUID().toString(), rnd.nextInt(100));
tbl.doUpdate(row, false);
}
assertEquals(MAX_X, tbl.getRowCountApproximation());
assertEquals(MAX_X, tbl.getRowCount(null));
for (GridH2IndexBase idx : tbl.indexes()) {
assertEquals(MAX_X, idx.getRowCountApproximation());
assertEquals(MAX_X, idx.getRowCount(null));
}
// Check correct rows order.
checkOrdered((GridH2TreeIndex) tbl.indexes().get(0), new Comparator<SearchRow>() {
@Override
public int compare(SearchRow o1, SearchRow o2) {
UUID id1 = (UUID) o1.getValue(0).getObject();
UUID id2 = (UUID) o2.getValue(0).getObject();
return id1.compareTo(id2);
}
});
checkOrdered((GridH2TreeIndex) tbl.indexes().get(1), new Comparator<SearchRow>() {
@Override
public int compare(SearchRow o1, SearchRow o2) {
Long x1 = (Long) o1.getValue(3).getObject();
Long x2 = (Long) o2.getValue(3).getObject();
int c = x2.compareTo(x1);
if (c != 0)
return c;
Timestamp t1 = (Timestamp) o1.getValue(1).getObject();
Timestamp t2 = (Timestamp) o2.getValue(1).getObject();
return t1.compareTo(t2);
}
});
checkOrdered((GridH2TreeIndex) tbl.indexes().get(2), new Comparator<SearchRow>() {
@Override
public int compare(SearchRow o1, SearchRow o2) {
String s1 = (String) o1.getValue(2).getObject();
String s2 = (String) o2.getValue(2).getObject();
return s2.compareTo(s1);
}
});
// Indexes data consistency.
ArrayList<? extends Index> idxs = tbl.indexes();
checkIndexesConsistent((ArrayList<Index>) idxs, null);
// Check unique index.
UUID id = UUID.randomUUID();
UUID id2 = UUID.randomUUID();
assertTrue(tbl.doUpdate(row(id, System.currentTimeMillis(), id.toString(), rnd.nextInt(100)), false));
assertTrue(tbl.doUpdate(row(id2, System.currentTimeMillis(), id2.toString(), rnd.nextInt(100)), false));
// Check index selection.
checkQueryPlan(conn, "SELECT * FROM T", SCAN_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T WHERE ID IS NULL", PK_NAME);
checkQueryPlan(conn, "SELECT * FROM T WHERE ID = RANDOM_UUID()", PK_NAME);
checkQueryPlan(conn, "SELECT * FROM T WHERE ID > RANDOM_UUID()", PK_NAME);
checkQueryPlan(conn, "SELECT * FROM T ORDER BY ID", PK_NAME);
checkQueryPlan(conn, "SELECT * FROM T WHERE STR IS NULL", STR_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T WHERE STR = 'aaaa'", STR_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T WHERE STR > 'aaaa'", STR_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T ORDER BY STR DESC", STR_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T WHERE X IS NULL", NON_UNIQUE_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T WHERE X = 10000", NON_UNIQUE_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T WHERE X > 10000", NON_UNIQUE_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T ORDER BY X DESC", NON_UNIQUE_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T ORDER BY X DESC, T", NON_UNIQUE_IDX_NAME);
checkQueryPlan(conn, "SELECT * FROM T ORDER BY T, X DESC", SCAN_IDX_NAME);
// Simple queries.
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("select id from t where x between 0 and 100");
int i = 0;
while (rs.next()) i++;
assertEquals(MAX_X + 2, i);
// -----
rs = s.executeQuery("select id from t where t is not null");
i = 0;
while (rs.next()) i++;
assertEquals(MAX_X + 2, i);
// ----
int cnt = 10 + rnd.nextInt(25);
long t = System.currentTimeMillis();
for (i = 0; i < cnt; i++) {
id = UUID.randomUUID();
assertTrue(tbl.doUpdate(row(id, t, id.toString(), 51), false));
}
rs = s.executeQuery("select x, id from t where x = 51 limit " + cnt);
i = 0;
while (rs.next()) {
assertEquals(51, rs.getInt(1));
i++;
}
assertEquals(cnt, i);
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperationType.AND in project ignite by apache.
the class UpdatePlanBuilder method planForInsert.
/**
* Prepare update plan for INSERT or MERGE.
*
* @param stmt INSERT or MERGE statement.
* @return Update plan.
* @throws IgniteCheckedException if failed.
*/
@SuppressWarnings("ConstantConditions")
private static UpdatePlan planForInsert(GridSqlStatement stmt) throws IgniteCheckedException {
GridSqlQuery sel;
GridSqlElement target;
GridSqlColumn[] cols;
boolean isTwoStepSubqry;
int rowsNum;
GridSqlTable tbl;
GridH2RowDescriptor desc;
if (stmt instanceof GridSqlInsert) {
GridSqlInsert ins = (GridSqlInsert) stmt;
target = ins.into();
tbl = gridTableForElement(target);
desc = tbl.dataTable().rowDescriptor();
cols = ins.columns();
sel = DmlAstUtils.selectForInsertOrMerge(cols, ins.rows(), ins.query(), desc);
isTwoStepSubqry = (ins.query() != null);
rowsNum = isTwoStepSubqry ? 0 : ins.rows().size();
} else if (stmt instanceof GridSqlMerge) {
GridSqlMerge merge = (GridSqlMerge) stmt;
target = merge.into();
tbl = gridTableForElement(target);
desc = tbl.dataTable().rowDescriptor();
// This check also protects us from attempts to update key or its fields directly -
// when no key except cache key can be used, it will serve only for uniqueness checks,
// not for updates, and hence will allow putting new pairs only.
// We don't quote _key and _val column names on CREATE TABLE, so they are always uppercase here.
GridSqlColumn[] keys = merge.keys();
if (keys.length != 1 || !desc.isKeyColumn(tbl.dataTable().getColumn(keys[0].columnName()).getColumnId()))
throw new CacheException("SQL MERGE does not support arbitrary keys");
cols = merge.columns();
sel = DmlAstUtils.selectForInsertOrMerge(cols, merge.rows(), merge.query(), desc);
isTwoStepSubqry = (merge.query() != null);
rowsNum = isTwoStepSubqry ? 0 : merge.rows().size();
} else
throw new IgniteSQLException("Unexpected DML operation [cls=" + stmt.getClass().getName() + ']', IgniteQueryErrorCode.UNEXPECTED_OPERATION);
// Let's set the flag only for subqueries that have their FROM specified.
isTwoStepSubqry = (isTwoStepSubqry && (sel instanceof GridSqlUnion || (sel instanceof GridSqlSelect && ((GridSqlSelect) sel).from() != null)));
int keyColIdx = -1;
int valColIdx = -1;
boolean hasKeyProps = false;
boolean hasValProps = false;
if (desc == null)
throw new IgniteSQLException("Row descriptor undefined for table '" + tbl.dataTable().getName() + "'", IgniteQueryErrorCode.NULL_TABLE_DESCRIPTOR);
GridCacheContext<?, ?> cctx = desc.context();
String[] colNames = new String[cols.length];
int[] colTypes = new int[cols.length];
for (int i = 0; i < cols.length; i++) {
GridSqlColumn col = cols[i];
String colName = col.columnName();
colNames[i] = colName;
colTypes[i] = col.resultType().type();
int colId = col.column().getColumnId();
if (desc.isKeyColumn(colId)) {
keyColIdx = i;
continue;
}
if (desc.isValueColumn(colId)) {
valColIdx = i;
continue;
}
GridQueryProperty prop = desc.type().property(colName);
assert prop != null : "Property '" + colName + "' not found.";
if (prop.key())
hasKeyProps = true;
else
hasValProps = true;
}
KeyValueSupplier keySupplier = createSupplier(cctx, desc.type(), keyColIdx, hasKeyProps, true, false);
KeyValueSupplier valSupplier = createSupplier(cctx, desc.type(), valColIdx, hasValProps, false, false);
if (stmt instanceof GridSqlMerge)
return UpdatePlan.forMerge(tbl.dataTable(), colNames, colTypes, keySupplier, valSupplier, keyColIdx, valColIdx, sel.getSQL(), !isTwoStepSubqry, rowsNum);
else
return UpdatePlan.forInsert(tbl.dataTable(), colNames, colTypes, keySupplier, valSupplier, keyColIdx, valColIdx, sel.getSQL(), !isTwoStepSubqry, rowsNum);
}
Aggregations