use of org.apache.ignite.internal.sql.optimizer.affinity.PartitionSingleNode in project ignite by apache.
the class PartitionExtractor method extractFromEqual.
/**
* Extract partition information from equality.
*
* @param op Operation.
* @param tblModel Table model.
* @param disjunct Disjunction flag. When set possible join expression will not be processed.
* @return Partition.
*/
private PartitionNode extractFromEqual(GridSqlOperation op, PartitionTableModel tblModel, boolean disjunct) throws IgniteCheckedException {
assert op.operationType() == GridSqlOperationType.EQUAL;
GridSqlElement left = op.child(0);
GridSqlElement right = op.child(1);
GridSqlColumn leftCol = unwrapColumn(left);
if (leftCol == null)
return PartitionAllNode.INSTANCE;
if (!(leftCol.column().getTable() instanceof GridH2Table))
return PartitionAllNode.INSTANCE;
GridSqlConst rightConst;
GridSqlParameter rightParam;
if (right instanceof GridSqlConst) {
rightConst = (GridSqlConst) right;
rightParam = null;
} else if (right instanceof GridSqlParameter) {
rightConst = null;
rightParam = (GridSqlParameter) right;
} else {
if (right instanceof GridSqlColumn) {
if (!disjunct) {
PartitionJoinCondition cond = parseJoinCondition(op);
if (cond != null && !cond.cross())
tblModel.addJoin(cond);
}
}
return PartitionAllNode.INSTANCE;
}
PartitionSingleNode part = extractSingle(leftCol, rightConst, rightParam, tblModel);
return part != null ? part : PartitionAllNode.INSTANCE;
}
use of org.apache.ignite.internal.sql.optimizer.affinity.PartitionSingleNode in project ignite by apache.
the class PartitionExtractor method tryExtractBetween.
/**
* Try to extract partitions from {@code op} assuming that it's between operation or simple range.
*
* @param op Sql operation.
* @param tblModel Table model.
* @return {@code PartitionSingleNode} if operation reduced to one partition,
* {@code PartitionGroupNode} if operation reduced to multiple partitions or null if operation is neither
* between nor simple range. Null also returns if it's not possible to extract partitions from given operation.
* @throws IgniteCheckedException If failed.
*/
private PartitionNode tryExtractBetween(GridSqlOperation op, PartitionTableModel tblModel) throws IgniteCheckedException {
// Between operation (or similar range) should contain exact two children.
assert op.size() == 2;
GridSqlAst left = op.child();
GridSqlAst right = op.child(1);
GridSqlOperationType leftOpType = retrieveOperationType(left);
GridSqlOperationType rightOpType = retrieveOperationType(right);
if ((GridSqlOperationType.BIGGER == rightOpType || GridSqlOperationType.BIGGER_EQUAL == rightOpType) && (GridSqlOperationType.SMALLER == leftOpType || GridSqlOperationType.SMALLER_EQUAL == leftOpType)) {
GridSqlAst tmp = left;
left = right;
right = tmp;
} else if (!((GridSqlOperationType.BIGGER == leftOpType || GridSqlOperationType.BIGGER_EQUAL == leftOpType) && (GridSqlOperationType.SMALLER == rightOpType || GridSqlOperationType.SMALLER_EQUAL == rightOpType)))
return null;
// Try parse left AST.
GridSqlColumn leftCol;
if (left instanceof GridSqlOperation && left.child() instanceof GridSqlColumn && (((GridSqlColumn) left.child()).column().getTable() instanceof GridH2Table))
leftCol = left.child();
else
return null;
// Try parse right AST.
GridSqlColumn rightCol;
if (right instanceof GridSqlOperation && right.child() instanceof GridSqlColumn)
rightCol = right.child();
else
return null;
GridH2Table tbl = (GridH2Table) leftCol.column().getTable();
// Check that columns might be used for partition pruning.
if (!tbl.isColumnForPartitionPruning(leftCol.column()))
return null;
// Check that both left and right AST use same column.
if (!F.eq(leftCol.schema(), rightCol.schema()) || !F.eq(leftCol.columnName(), rightCol.columnName()) || !F.eq(leftCol.tableAlias(), rightCol.tableAlias()))
return null;
// Check columns type
if (!(leftCol.column().getType() == Value.BYTE || leftCol.column().getType() == Value.SHORT || leftCol.column().getType() == Value.INT || leftCol.column().getType() == Value.LONG))
return null;
// Try parse left AST right value (value to the right of '>' or '>=').
GridSqlConst leftConst;
if (left.child(1) instanceof GridSqlConst)
leftConst = left.child(1);
else
return null;
// Try parse right AST right value (value to the right of '<' or '<=').
GridSqlConst rightConst;
if (right.child(1) instanceof GridSqlConst)
rightConst = right.child(1);
else
return null;
long leftLongVal;
long rightLongVal;
try {
leftLongVal = leftConst.value().getLong();
rightLongVal = rightConst.value().getLong();
} catch (Exception e) {
return null;
}
// Increment left long value if '>' is used.
if (((GridSqlOperation) left).operationType() == GridSqlOperationType.BIGGER)
leftLongVal++;
// Decrement right long value if '<' is used.
if (((GridSqlOperation) right).operationType() == GridSqlOperationType.SMALLER)
rightLongVal--;
Set<PartitionSingleNode> parts = new HashSet<>();
PartitionTable tbl0 = tblModel.table(leftCol.tableAlias());
// If table is in ignored set, then we cannot use it for partition extraction.
if (tbl0 == null)
return null;
for (long i = leftLongVal; i <= rightLongVal; i++) {
int part = partResolver.partition(i, leftCol.column().getType(), tbl0.cacheName());
parts.add(new PartitionConstantNode(tbl0, part));
if (parts.size() > maxPartsCntBetween)
return null;
}
return parts.isEmpty() ? PartitionNoneNode.INSTANCE : parts.size() == 1 ? parts.iterator().next() : new PartitionGroupNode(parts);
}
use of org.apache.ignite.internal.sql.optimizer.affinity.PartitionSingleNode in project ignite by apache.
the class JdbcThinPartitionAwarenessReconnectionAndFailoverSelfTest method testQueryFailover.
/**
* Check that failover occurs if the result of sending first iteration of sql request is an Exception but not an
* SQLException.
*
* <ol>
* <li>Create {@code JdbcThinConnection} to all existing nodes.</li>
* <li>Create a cache and populate it with some data.</li>
* <li>Submit some failover-applicable sql query with specific condition within where clause,
* that assumes partition awareness. Submit same query one more time. It's necessary in order to warm up affinity
* awareness cache.</li>
* <li>From within affinity cache calculate node that was used to process query. Stop it.</li>
* <li>Submit sql query, that is equal to initial one, one more time.
* Because of partition awareness, given query will be routed to previously stopped node, so an Exception will be
* received. Here query failover goes and resents query to an alive node using another {@code JdbcThinTcpIo}</li>
* <li>Because of failover, no exceptions are expected on Jdbc thin client side.
* However within the {@code JdbcThinConnection}, in case of {@code Level.FINE} log level, corresponding log record
* is expected.</li>
* </ol>
*
* @throws Exception If failed.
*/
@Test
public void testQueryFailover() throws Exception {
try (Connection conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1:10800..10802?partitionAwareness=true")) {
final String cacheName = UUID.randomUUID().toString().substring(0, 6);
final String sql = "select * from \"" + cacheName + "\".Person where _key = 1";
CacheConfiguration<Object, Object> cache = prepareCacheConfig(cacheName);
ignite(0).createCache(cache);
fillCache(cacheName);
Statement stmt = conn.createStatement();
stmt.execute(sql);
stmt.execute(sql);
AffinityCache affinityCache = GridTestUtils.getFieldValue(conn, "affinityCache");
Integer part = ((PartitionSingleNode) affinityCache.partitionResult(new QualifiedSQLQuery("PUBLIC", sql)).partitionResult().tree()).value();
UUID nodeId = affinityCache.cacheDistribution(GridCacheUtils.cacheId(cacheName))[part];
int gridIdx = new Integer(Ignition.ignite(nodeId).name().substring(getTestIgniteInstanceName().length()));
stopGrid(gridIdx);
logHnd.records.clear();
conn.createStatement().execute(sql);
startGrid(gridIdx);
}
assertEquals("Unexpected log records count.", 1, logHnd.records.size());
LogRecord record = logHnd.records.get(0);
assertEquals("Unexpected log record text.", "Exception during sending an sql request.", record.getMessage());
assertEquals("Unexpected log level", Level.FINE, record.getLevel());
}
use of org.apache.ignite.internal.sql.optimizer.affinity.PartitionSingleNode in project ignite by apache.
the class PartitionExtractor method extractFromIn.
/**
* Extract partition information from IN.
*
* @param op Operation.
* @param tblModel Table model.
* @return Partition.
*/
private PartitionNode extractFromIn(GridSqlOperation op, PartitionTableModel tblModel) throws IgniteCheckedException {
// Operation should contain at least two children: left (column) and right (const or column).
if (op.size() < 2)
return PartitionAllNode.INSTANCE;
// Left operand should be column.
GridSqlAst left = op.child();
GridSqlColumn leftCol = unwrapColumn(left);
if (leftCol == null)
return PartitionAllNode.INSTANCE;
// Can work only with Ignite tables.
if (!(leftCol.column().getTable() instanceof GridH2Table))
return PartitionAllNode.INSTANCE;
Set<PartitionSingleNode> parts = new HashSet<>();
for (int i = 1; i < op.size(); i++) {
GridSqlAst right = op.child(i);
GridSqlConst rightConst;
GridSqlParameter rightParam;
if (right instanceof GridSqlConst) {
rightConst = (GridSqlConst) right;
rightParam = null;
} else if (right instanceof GridSqlParameter) {
rightConst = null;
rightParam = (GridSqlParameter) right;
} else
// set globally. Hence, returning null.
return PartitionAllNode.INSTANCE;
// Extract.
PartitionSingleNode part = extractSingle(leftCol, rightConst, rightParam, tblModel);
// Same thing as above: single unknown partition in disjunction defeats optimization.
if (part == null)
return PartitionAllNode.INSTANCE;
parts.add(part);
}
return parts.size() == 1 ? parts.iterator().next() : new PartitionGroupNode(parts);
}
Aggregations