use of org.apache.calcite.rex.RexSlot in project druid by druid-io.
the class DruidJoinRule method analyzeCondition.
/**
* If this condition is an AND of some combination of (1) literals; (2) equality conditions of the form
* {@code f(LeftRel) = RightColumn}, then return a {@link ConditionAnalysis}.
*/
private Optional<ConditionAnalysis> analyzeCondition(final RexNode condition, final RelDataType leftRowType, DruidRel<?> right) {
final List<RexNode> subConditions = decomposeAnd(condition);
final List<Pair<RexNode, RexInputRef>> equalitySubConditions = new ArrayList<>();
final List<RexLiteral> literalSubConditions = new ArrayList<>();
final int numLeftFields = leftRowType.getFieldCount();
final Set<RexInputRef> rightColumns = new HashSet<>();
for (RexNode subCondition : subConditions) {
if (RexUtil.isLiteral(subCondition, true)) {
if (subCondition.isA(SqlKind.CAST)) {
// This is CAST(literal) which is always OK.
// We know that this is CAST(literal) as it passed the check from RexUtil.isLiteral
RexCall call = (RexCall) subCondition;
// are different, then skipping the cast might change the meaning of the subcondition.
if (call.getType().getSqlTypeName().equals(call.getOperands().get(0).getType().getSqlTypeName())) {
// If the types are the same, unwrap the cast and use the underlying literal.
literalSubConditions.add((RexLiteral) call.getOperands().get(0));
} else {
// If the types are not the same, return Optional.empty() indicating the condition is not supported.
return Optional.empty();
}
} else {
// Literals are always OK.
literalSubConditions.add((RexLiteral) subCondition);
}
continue;
}
if (!subCondition.isA(SqlKind.EQUALS)) {
// If it's not EQUALS, it's not supported.
plannerContext.setPlanningError("SQL requires a join with '%s' condition that is not supported.", subCondition.getKind());
return Optional.empty();
}
final List<RexNode> operands = ((RexCall) subCondition).getOperands();
Preconditions.checkState(operands.size() == 2, "Expected 2 operands, got[%,d]", operands.size());
if (isLeftExpression(operands.get(0), numLeftFields) && isRightInputRef(operands.get(1), numLeftFields)) {
equalitySubConditions.add(Pair.of(operands.get(0), (RexInputRef) operands.get(1)));
rightColumns.add((RexInputRef) operands.get(1));
} else if (isRightInputRef(operands.get(0), numLeftFields) && isLeftExpression(operands.get(1), numLeftFields)) {
equalitySubConditions.add(Pair.of(operands.get(1), (RexInputRef) operands.get(0)));
rightColumns.add((RexInputRef) operands.get(0));
} else {
// Cannot handle this condition.
plannerContext.setPlanningError("SQL is resulting in a join that has unsupported operand types.");
return Optional.empty();
}
}
// thereby allowing join conditions on both k and v columns of the lookup
if (right != null && !DruidJoinQueryRel.computeRightRequiresSubquery(DruidJoinQueryRel.getSomeDruidChild(right)) && right instanceof DruidQueryRel) {
DruidQueryRel druidQueryRel = (DruidQueryRel) right;
if (druidQueryRel.getDruidTable().getDataSource() instanceof LookupDataSource) {
long distinctRightColumns = rightColumns.stream().map(RexSlot::getIndex).distinct().count();
if (distinctRightColumns > 1) {
// it means that the join's right side is lookup and the join condition contains both key and value columns of lookup.
// currently, the lookup datasource in the native engine doesn't support using value column in the join condition.
plannerContext.setPlanningError("SQL is resulting in a join involving lookup where value column is used in the condition.");
return Optional.empty();
}
}
}
return Optional.of(new ConditionAnalysis(numLeftFields, equalitySubConditions, literalSubConditions));
}
use of org.apache.calcite.rex.RexSlot in project calcite by apache.
the class SplunkPushDownRule method appendSearchString.
/**
* Appends a search string.
*
* @param toAppend Search string to append
* @param splunkRel Relational expression
* @param topProj Top projection
* @param bottomProj Bottom projection
*/
protected RelNode appendSearchString(String toAppend, SplunkTableScan splunkRel, LogicalProject topProj, LogicalProject bottomProj, RelDataType topRow, RelDataType bottomRow) {
final RelOptCluster cluster = splunkRel.getCluster();
StringBuilder updateSearchStr = new StringBuilder(splunkRel.search);
if (!toAppend.isEmpty()) {
updateSearchStr.append(" ").append(toAppend);
}
List<RelDataTypeField> bottomFields = bottomRow == null ? null : bottomRow.getFieldList();
List<RelDataTypeField> topFields = topRow == null ? null : topRow.getFieldList();
if (bottomFields == null) {
bottomFields = splunkRel.getRowType().getFieldList();
}
// handle bottom projection (ie choose a subset of the table fields)
if (bottomProj != null) {
List<RelDataTypeField> tmp = new ArrayList<RelDataTypeField>();
List<RelDataTypeField> dRow = bottomProj.getRowType().getFieldList();
for (RexNode rn : bottomProj.getProjects()) {
RelDataTypeField rdtf;
if (rn instanceof RexSlot) {
RexSlot rs = (RexSlot) rn;
rdtf = bottomFields.get(rs.getIndex());
} else {
rdtf = dRow.get(tmp.size());
}
tmp.add(rdtf);
}
bottomFields = tmp;
}
// field renaming: to -> from
List<Pair<String, String>> renames = new LinkedList<Pair<String, String>>();
// handle top projection (ie reordering and renaming)
List<RelDataTypeField> newFields = bottomFields;
if (topProj != null) {
LOGGER.debug("topProj: {}", String.valueOf(topProj.getPermutation()));
newFields = new ArrayList<RelDataTypeField>();
int i = 0;
for (RexNode rn : topProj.getProjects()) {
RexInputRef rif = (RexInputRef) rn;
RelDataTypeField field = bottomFields.get(rif.getIndex());
if (!bottomFields.get(rif.getIndex()).getName().equals(topFields.get(i).getName())) {
renames.add(Pair.of(bottomFields.get(rif.getIndex()).getName(), topFields.get(i).getName()));
field = topFields.get(i);
}
newFields.add(field);
}
}
if (!renames.isEmpty()) {
updateSearchStr.append("| rename ");
for (Pair<String, String> p : renames) {
updateSearchStr.append(p.left).append(" AS ").append(p.right).append(" ");
}
}
RelDataType resultType = cluster.getTypeFactory().createStructType(newFields);
String searchWithFilter = updateSearchStr.toString();
RelNode rel = new SplunkTableScan(cluster, splunkRel.getTable(), splunkRel.splunkTable, searchWithFilter, splunkRel.earliest, splunkRel.latest, resultType.getFieldNames());
LOGGER.debug("end of appendSearchString fieldNames: {}", rel.getRowType().getFieldNames());
return rel;
}
Aggregations