{"record":{"id":"6e3dcf7bf21f4122","repo":"prestodb/presto","slug":"druid-pushdown-unsupported-expression-6e3dcf","errorCode":"DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION","errorMessage":"Unsupported pushdown for Druid connector with plan node of type ${node}","messagePattern":"Unsupported pushdown for Druid connector with plan node of type (.+?)","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-druid/src/main/java/com/facebook/presto/druid/DruidQueryGenerator.java","lineNumber":186,"sourceCode":"                    .add(\"pushdown\", pushdown)\n                    .toString();\n        }\n    }\n\n    private class DruidQueryPlanVisitor\n            extends PlanVisitor<DruidQueryGeneratorContext, DruidQueryGeneratorContext>\n    {\n        private final ConnectorSession session;\n\n        protected DruidQueryPlanVisitor(ConnectorSession session)\n        {\n            this.session = session;\n        }\n\n        @Override\n        public DruidQueryGeneratorContext visitPlan(PlanNode node, DruidQueryGeneratorContext context)\n        {\n            throw new PrestoException(DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION, \"Unsupported pushdown for Druid connector with plan node of type \" + node);\n        }\n\n        protected VariableReferenceExpression getVariableReference(RowExpression expression)\n        {\n            if (expression instanceof VariableReferenceExpression) {\n                return ((VariableReferenceExpression) expression);\n            }\n            throw new PrestoException(DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION, \"Unsupported pushdown for Druid connector. Expect variable reference, but get: \" + expression);\n        }\n\n        @Override\n        public DruidQueryGeneratorContext visitMarkDistinct(MarkDistinctNode node, DruidQueryGeneratorContext context)\n        {\n            requireNonNull(context, \"context is null\");\n            return node.getSource().accept(this, context);\n        }\n\n        @Override","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-druid/src/main/java/com/facebook/presto/druid/DruidQueryGenerator.java#L168-L204","documentation":"DruidQueryGenerator's Visitor.visitPlan is the default fallback for any PlanNode type the Druid query generator does not implement. Hitting it means the plan subtree contains a node type the connector cannot translate into a Druid query, so pushdown is refused with DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION.","triggerScenarios":"node.getSource().accept(this, ...) reaches a PlanNode subclass without a visit override (e.g. WindowNode, TopNNode, UnnestNode, SortNode, JoinNode, etc.) during Druid query generation.","commonSituations":"Queries with window functions, DISTINCT-beyond-MarkDistinct shapes, unnest, sorts, or joins over a Druid table that the planner attempted to push down; plans changed by new optimizer rules in a Presto upgrade.","solutions":["Identify the unsupported node via EXPLAIN and restructure the query to avoid it above the Druid scan (e.g. avoid window functions/joins in the pushed-down portion).","Force partial (non-whole-plan) pushdown or disable pushdown for the query so unsupported nodes execute in Presto.","Split the query into a pushdown-friendly inner query over Druid plus outer processing in Presto.","Upgrade or patch the connector to add a visit override for the node type."],"exampleFix":"// before\nSELECT lag(cnt) OVER (ORDER BY day) FROM druid_agg;\n// after\nSELECT day, cnt FROM druid_agg; -- compute lag in Presto/client outside pushed-down scan","handlingStrategy":"fallback","validationCode":"// Restrict plan shape before pushdown: only scan/project/filter/aggregation\nboolean pushablePlan(PlanNode n) {\n    return n instanceof ScanFilterProjectNode || n instanceof ProjectNode\n        || n instanceof FilterNode || n instanceof AggregationNode;\n}","typeGuard":"boolean isUnsupportedNode(PlanNode n) {\n    return n instanceof WindowNode || n instanceof TopNNode || n instanceof SortNode\n        || n instanceof UnnestNode || n instanceof JoinNode;\n}","tryCatchPattern":"try { druidQuery = new DruidQueryGenerator(plan, session).generate(); }\ncatch (PrestoException e) {\n    if (e.getErrorCode().getName().equals(\"DRUID_PUSHDOWN_UNSUPPORTED_EXPRESSION\")) { executePartialPushdown(plan); }\n    else throw e;\n}","preventionTips":["Avoid window functions, unnest, sorts, and joins inside the pushed-down portion over Druid.","Run EXPLAIN to spot unsupported node types above the Druid scan.","Structure queries as simple scan/project/filter/aggregate over Druid.","Recheck plan shapes after Presto upgrades (new optimizer rules)."],"tags":["presto","druid","pushdown","plan-node"],"backgroundTag":"druid-pushdown-unsupported-expression","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}