lowka commented on code in PR #4221:
URL: https://github.com/apache/ignite-3/pull/4221#discussion_r1721259852
##########
modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/PlannerHelper.java:
##########
@@ -343,4 +360,171 @@ static boolean hasSubQuery(SqlNode node) {
return super.visit(call);
}
}
+
+
+ /**
+ * Tries to optimize a query that looks like {@code SELECT count(*)}.
+ *
+ * @param planner Planner.
+ * @param txContext Transactional context.
+ * @param node Query node.
+ * @return Plan node with list of aliases, if the optimization is
applicable.
+ */
+ public static @Nullable Pair<IgniteRel, List<String>>
tryOptimizeSelectCount(
+ IgnitePlanner planner,
+ @Nullable QueryTransactionContext txContext,
+ SqlNode node
+ ) {
+ if (txContext != null && txContext.explicitTx() != null) {
+ return null;
+ }
+
+ if (!(node instanceof SqlSelect)) {
+ return null;
+ }
+
+ SqlSelect select = (SqlSelect) node;
+
+ if (select.getGroup() != null
+ || select.getWhere() != null
+ || select.getHaving() != null
+ || select.getQualify() != null
+ || !select.getWindowList().isEmpty()
+ || select.getOffset() != null
+ || select.getFetch() != null) {
+ return null;
+ }
+
+ IgniteSqlToRelConvertor converter = planner.sqlToRelConverter();
+
+ RelOptTable targetTable;
+
+ if (select.getFrom() != null) {
+ SqlNode from = SqlUtil.stripAs(select.getFrom());
+ // Skip non-references such as VALUES ..
+ if (from.getKind() != SqlKind.IDENTIFIER) {
+ return null;
+ }
+
+ targetTable = converter.getTargetTable(select.getFrom());
+ IgniteDataSource dataSource =
targetTable.unwrap(IgniteDataSource.class);
+ if (!(dataSource instanceof IgniteTable)) {
+ return null;
+ }
+ } else {
+ // Try to optimize SELECT count(*) as well
+ targetTable = null;
+ }
+
+ IgniteTypeFactory typeFactory = planner.getTypeFactory();
+
+ // SELECT COUNT(*) ... row type
+ RelDataType countResultType =
typeFactory.createSqlType(SqlTypeName.BIGINT);
+
+ RelDataTypeFactory.Builder inputRowBuilder = new Builder(typeFactory);
+ inputRowBuilder.add("ROWCOUNT", countResultType);
+ RelDataType inputRowType = inputRowBuilder.build();
+
+ RelDataType getCountType =
inputRowType.getFieldList().get(0).getType();
+
+ // Build projection
+ // Rewrites SELECT count(*) ... as Project(exprs = [lit, $0, ... ]),
where $0 references a row that stores a count.
+ // So we can feed results of get count operation into a projection to
compute final results.
+
+ List<RexNode> expressions = new ArrayList<>();
+ List<String> expressionNames = new ArrayList<>();
+ boolean countAdded = false;
+
+ for (SqlNode selectItem : select.getSelectList()) {
+ SqlNode expr = SqlUtil.stripAs(selectItem);
+
+ if (isCountStar(planner.validator(), expr)) {
+ SqlCall call = (SqlCall) expr;
+
+ // Reject COUNT(DISTINCT id), but allow COUNT(DISTINCT 1)
Review Comment:
Thanks. Fixed.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]