use of org.apache.calcite.util.Pair in project calcite by apache.
the class RexImplicationChecker method checkSupport.
/**
* Looks at the usage of variables in first and second conjunction to decide
* whether this kind of expression is currently supported for proving first
* implies second.
*
* <ol>
* <li>Variables should be used only once in both the conjunction against
* given set of operations only: >, <, ≤, ≥, =; ≠.
*
* <li>All the variables used in second condition should be used even in the
* first.
*
* <li>If operator used for variable in first is op1 and op2 for second, then
* we support these combination for conjunction (op1, op2) then op1, op2
* belongs to one of the following sets:
*
* <ul>
* <li>(<, ≤) X (<, ≤) <i>note: X represents cartesian product</i>
* <li>(> / ≥) X (>, ≥)
* <li>(=) X (>, ≥, <, ≤, =, ≠)
* <li>(≠, =)
* </ul>
*
* <li>We support at most 2 operators to be be used for a variable in first
* and second usages.
*
* </ol>
*
* @return whether input usage pattern is supported
*/
private boolean checkSupport(InputUsageFinder firstUsageFinder, InputUsageFinder secondUsageFinder) {
final Map<RexInputRef, InputRefUsage<SqlOperator, RexNode>> firstUsageMap = firstUsageFinder.usageMap;
final Map<RexInputRef, InputRefUsage<SqlOperator, RexNode>> secondUsageMap = secondUsageFinder.usageMap;
for (Map.Entry<RexInputRef, InputRefUsage<SqlOperator, RexNode>> entry : secondUsageMap.entrySet()) {
final InputRefUsage<SqlOperator, RexNode> secondUsage = entry.getValue();
final List<Pair<SqlOperator, RexNode>> secondUsageList = secondUsage.usageList;
final int secondLen = secondUsageList.size();
if (secondUsage.usageCount != secondLen || secondLen > 2) {
return false;
}
final InputRefUsage<SqlOperator, RexNode> firstUsage = firstUsageMap.get(entry.getKey());
if (firstUsage == null || firstUsage.usageList.size() != firstUsage.usageCount || firstUsage.usageCount > 2) {
return false;
}
final List<Pair<SqlOperator, RexNode>> firstUsageList = firstUsage.usageList;
final int firstLen = firstUsageList.size();
final SqlKind fKind = firstUsageList.get(0).getKey().getKind();
final SqlKind sKind = secondUsageList.get(0).getKey().getKind();
final SqlKind fKind2 = (firstUsageList.size() == 2) ? firstUsageList.get(1).getKey().getKind() : null;
final SqlKind sKind2 = (secondUsageList.size() == 2) ? secondUsageList.get(1).getKey().getKind() : null;
if (firstLen == 2 && secondLen == 2 && !(isEquivalentOp(fKind, sKind) && isEquivalentOp(fKind2, sKind2)) && !(isEquivalentOp(fKind, sKind2) && isEquivalentOp(fKind2, sKind))) {
return false;
} else if (firstLen == 1 && secondLen == 1 && fKind != SqlKind.EQUALS && !isSupportedUnaryOperators(sKind) && !isEquivalentOp(fKind, sKind)) {
return false;
} else if (firstLen == 1 && secondLen == 2 && fKind != SqlKind.EQUALS) {
return false;
} else if (firstLen == 2 && secondLen == 1) {
// x > 30 and x > 40 implies x < 70
if (!isOppositeOp(fKind, fKind2) && !isSupportedUnaryOperators(sKind) && !(isEquivalentOp(fKind, fKind2) && isEquivalentOp(fKind, sKind))) {
return false;
}
}
}
return true;
}
use of org.apache.calcite.util.Pair in project calcite by apache.
the class JdbcTest method testCloneQueries.
/**
* A selection of queries generated by Mondrian.
*/
@Ignore
@Test
public void testCloneQueries() {
CalciteAssert.AssertThat with = CalciteAssert.that().with(CalciteAssert.Config.FOODMART_CLONE);
for (Ord<Pair<String, String>> query : Ord.zip(FOODMART_QUERIES)) {
try {
// uncomment to run specific queries:
// if (query.i != FOODMART_QUERIES.size() - 1) continue;
final String sql = query.e.left;
if (sql.startsWith("ignore:")) {
continue;
}
final String expected = query.e.right;
final CalciteAssert.AssertQuery query1 = with.query(sql);
if (expected != null) {
if (sql.contains("order by")) {
query1.returns(expected);
} else {
query1.returnsUnordered(expected.split("\n"));
}
} else {
query1.runs();
}
} catch (Throwable e) {
throw new RuntimeException("while running query #" + query.i, e);
}
}
}
use of org.apache.calcite.util.Pair in project calcite by apache.
the class SqlTesterImpl method buildQuery2.
/**
* Builds a query that extracts all literals as columns in an underlying
* select.
*
* <p>For example,</p>
*
* <blockquote>{@code 1 < 5}</blockquote>
*
* <p>becomes</p>
*
* <blockquote>{@code SELECT p0 < p1
* FROM (VALUES (1, 5)) AS t(p0, p1)}</blockquote>
*
* <p>Null literals don't have enough type information to be extracted.
* We push down {@code CAST(NULL AS type)} but raw nulls such as
* {@code CASE 1 WHEN 2 THEN 'a' ELSE NULL END} are left as is.</p>
*
* @param expression Scalar expression
* @return Query that evaluates a scalar expression
*/
private String buildQuery2(String expression) {
// "values (1 < 5)"
// becomes
// "select p0 < p1 from (values (1, 5)) as t(p0, p1)"
SqlNode x;
final String sql = "values (" + expression + ")";
try {
x = parseQuery(sql);
} catch (SqlParseException e) {
throw new RuntimeException(e);
}
final Collection<SqlNode> literalSet = new LinkedHashSet<>();
x.accept(new SqlShuttle() {
private final List<SqlOperator> ops = ImmutableList.of(SqlStdOperatorTable.LITERAL_CHAIN, SqlStdOperatorTable.LOCALTIME, SqlStdOperatorTable.LOCALTIMESTAMP, SqlStdOperatorTable.CURRENT_TIME, SqlStdOperatorTable.CURRENT_TIMESTAMP);
@Override
public SqlNode visit(SqlLiteral literal) {
if (!isNull(literal) && literal.getTypeName() != SqlTypeName.SYMBOL) {
literalSet.add(literal);
}
return literal;
}
@Override
public SqlNode visit(SqlCall call) {
final SqlOperator operator = call.getOperator();
if (operator == SqlStdOperatorTable.CAST && isNull(call.operand(0))) {
literalSet.add(call);
return call;
} else if (ops.contains(operator)) {
// literal"
return call;
} else {
return super.visit(call);
}
}
private boolean isNull(SqlNode sqlNode) {
return sqlNode instanceof SqlLiteral && ((SqlLiteral) sqlNode).getTypeName() == SqlTypeName.NULL;
}
});
final List<SqlNode> nodes = new ArrayList<>(literalSet);
Collections.sort(nodes, new Comparator<SqlNode>() {
public int compare(SqlNode o1, SqlNode o2) {
final SqlParserPos pos0 = o1.getParserPosition();
final SqlParserPos pos1 = o2.getParserPosition();
int c = -Utilities.compare(pos0.getLineNum(), pos1.getLineNum());
if (c != 0) {
return c;
}
return -Utilities.compare(pos0.getColumnNum(), pos1.getColumnNum());
}
});
String sql2 = sql;
final List<Pair<String, String>> values = new ArrayList<>();
int p = 0;
for (SqlNode literal : nodes) {
final SqlParserPos pos = literal.getParserPosition();
final int start = SqlParserUtil.lineColToIndex(sql, pos.getLineNum(), pos.getColumnNum());
final int end = SqlParserUtil.lineColToIndex(sql, pos.getEndLineNum(), pos.getEndColumnNum()) + 1;
String param = "p" + (p++);
values.add(Pair.of(sql2.substring(start, end), param));
sql2 = sql2.substring(0, start) + param + sql2.substring(end);
}
if (values.isEmpty()) {
values.add(Pair.of("1", "p0"));
}
return "select " + sql2.substring("values (".length(), sql2.length() - 1) + " from (values (" + Util.commaList(Pair.left(values)) + ")) as t(" + Util.commaList(Pair.right(values)) + ")";
}
use of org.apache.calcite.util.Pair in project calcite by apache.
the class DiffRepository method update.
/**
* Creates a new document with a given resource.
*
* <p>This method is synchronized, in case two threads are running test
* cases of this test at the same time.
*
* @param testCaseName Test case name
* @param resourceName Resource name
* @param value New value of resource
*/
private synchronized void update(String testCaseName, String resourceName, String value) {
final List<Pair<String, Element>> map = new ArrayList<>();
Element testCaseElement = getTestCaseElement(testCaseName, true, map);
if (testCaseElement == null) {
testCaseElement = doc.createElement(TEST_CASE_TAG);
testCaseElement.setAttribute(TEST_CASE_NAME_ATTR, testCaseName);
Node refElement = ref(testCaseName, map);
root.insertBefore(testCaseElement, refElement);
}
Element resourceElement = getResourceElement(testCaseElement, resourceName, true);
if (resourceElement == null) {
resourceElement = doc.createElement(RESOURCE_TAG);
resourceElement.setAttribute(RESOURCE_NAME_ATTR, resourceName);
testCaseElement.appendChild(resourceElement);
} else {
removeAllChildren(resourceElement);
}
if (!value.equals("")) {
resourceElement.appendChild(doc.createCDATASection(value));
}
// Write out the document.
flushDoc();
}
use of org.apache.calcite.util.Pair in project calcite by apache.
the class AggregateExpandDistinctAggregatesRule method createSelectDistinct.
/**
* Given an {@link org.apache.calcite.rel.core.Aggregate}
* and the ordinals of the arguments to a
* particular call to an aggregate function, creates a 'select distinct'
* relational expression which projects the group columns and those
* arguments but nothing else.
*
* <p>For example, given
*
* <blockquote>
* <pre>select f0, count(distinct f1), count(distinct f2)
* from t group by f0</pre>
* </blockquote>
*
* <p>and the argument list
*
* <blockquote>{2}</blockquote>
*
* <p>returns
*
* <blockquote>
* <pre>select distinct f0, f2 from t</pre>
* </blockquote>
*
* <p>The <code>sourceOf</code> map is populated with the source of each
* column; in this case sourceOf.get(0) = 0, and sourceOf.get(1) = 2.
*
* @param relBuilder Relational expression builder
* @param aggregate Aggregate relational expression
* @param argList Ordinals of columns to make distinct
* @param filterArg Ordinal of column to filter on, or -1
* @param sourceOf Out parameter, is populated with a map of where each
* output field came from
* @return Aggregate relational expression which projects the required
* columns
*/
private RelBuilder createSelectDistinct(RelBuilder relBuilder, Aggregate aggregate, List<Integer> argList, int filterArg, Map<Integer, Integer> sourceOf) {
relBuilder.push(aggregate.getInput());
final List<Pair<RexNode, String>> projects = new ArrayList<>();
final List<RelDataTypeField> childFields = relBuilder.peek().getRowType().getFieldList();
for (int i : aggregate.getGroupSet()) {
sourceOf.put(i, projects.size());
projects.add(RexInputRef.of2(i, childFields));
}
for (Integer arg : argList) {
if (filterArg >= 0) {
// Implement
// agg(DISTINCT arg) FILTER $f
// by generating
// SELECT DISTINCT ... CASE WHEN $f THEN arg ELSE NULL END AS arg
// and then applying
// agg(arg)
// as usual.
//
// It works except for (rare) agg functions that need to see null
// values.
final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
final RexInputRef filterRef = RexInputRef.of(filterArg, childFields);
final Pair<RexNode, String> argRef = RexInputRef.of2(arg, childFields);
RexNode condition = rexBuilder.makeCall(SqlStdOperatorTable.CASE, filterRef, argRef.left, rexBuilder.ensureType(argRef.left.getType(), rexBuilder.makeCast(argRef.left.getType(), rexBuilder.constantNull()), true));
sourceOf.put(arg, projects.size());
projects.add(Pair.of(condition, "i$" + argRef.right));
continue;
}
if (sourceOf.get(arg) != null) {
continue;
}
sourceOf.put(arg, projects.size());
projects.add(RexInputRef.of2(arg, childFields));
}
relBuilder.project(Pair.left(projects), Pair.right(projects));
// Get the distinct values of the GROUP BY fields and the arguments
// to the agg functions.
relBuilder.push(aggregate.copy(aggregate.getTraitSet(), relBuilder.build(), false, ImmutableBitSet.range(projects.size()), null, ImmutableList.<AggregateCall>of()));
return relBuilder;
}
Aggregations