{"record":{"id":"1210b5a749d7fff5","repo":"prestodb/presto","slug":"pinot-unsupported-expression-1210b5","errorCode":"PINOT_UNSUPPORTED_EXPRESSION","errorMessage":"Don't know how to handle plan node of type ","messagePattern":"Don't know how to handle plan node of type ","errorType":"error_code","errorClass":"PinotException","httpStatus":null,"severity":"error","filePath":"presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotQueryGenerator.java","lineNumber":232,"sourceCode":"\n    class PinotQueryPlanVisitor\n            extends PlanVisitor<PinotQueryGeneratorContext, PinotQueryGeneratorContext>\n    {\n        private final ConnectorSession session;\n        private final boolean forbidBrokerQueries;\n        private final boolean pushdownTopnBrokerQueries;\n\n        protected PinotQueryPlanVisitor(ConnectorSession session)\n        {\n            this.session = session;\n            this.forbidBrokerQueries = PinotSessionProperties.isForbidBrokerQueries(session);\n            this.pushdownTopnBrokerQueries = PinotSessionProperties.getPushdownTopnBrokerQueries(session);\n        }\n\n        @Override\n        public PinotQueryGeneratorContext visitPlan(PlanNode node, PinotQueryGeneratorContext context)\n        {\n            throw new PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), \"Don't know how to handle 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 PinotException(PINOT_UNSUPPORTED_EXPRESSION, Optional.empty(), \"Expected a variable reference but got \" + expression);\n        }\n\n        @Override\n        public PinotQueryGeneratorContext visitMarkDistinct(MarkDistinctNode node, PinotQueryGeneratorContext context)\n        {\n            requireNonNull(context, \"context is null\");\n            return node.getSource().accept(this, context);\n        }\n\n        @Override","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-pinot-toolkit/src/main/java/com/facebook/presto/pinot/query/PinotQueryGenerator.java#L214-L250","documentation":"The default branch of the plan visitor (visitPlan) in PinotQueryGenerator throws PINOT_UNSUPPORTED_EXPRESSION 'Don't know how to handle plan node of type <node>' for any PlanNode type it does not explicitly override. The connector only knows how to translate a fixed set of plan nodes (scan, filter, project, aggregate, top-n, etc.); anything else means it cannot generate a Pinot query for that subtree.","triggerScenarios":"The Presto planner produces a plan node the Pinot connector lacks a visit method for — e.g. JoinNode, WindowNode, RowNumberNode, UnionNode, UnnestNode, MarkDistinctNode (partially supported) or other exotic nodes — directly in the part of the plan the connector attempts to convert.","commonSituations":"Queries with joins/windows/CTEs/unions over Pinot tables that the planner did not isolate from the Pinot scan; new engine features emitting newer node types the connector predates; version mismatch between Presto core and the Pinot plugin.","solutions":["Restructure the query so unsupported operations happen above the Pinot subquery: keep pushed-down parts to filters/aggregations/limits on a single table, join or window in an outer query.","Upgrade the Pinot connector plugin to match your Presto engine version so more plan node types are handled.","Check which node type the message names and rewrite that specific operation (e.g. replace a WINDOW with LIMIT/GROUP BY the connector supports).","If the node should be supported, add a visitXxx override in the visitor that translates it or explicitly delegates to Presto execution."],"exampleFix":"// before (join inside the Pinot-subplan triggers the error)\nSELECT a.x, b.y FROM pinot_a a JOIN pinot_b b ON a.id = b.id WHERE a.dt = '2026-01-01';\n\n// after (isolate Pinot scans; connector pushes simple filters/aggregations)\nWITH s1 AS (SELECT id, x FROM pinot_a WHERE dt = '2026-01-01'),\n     s2 AS (SELECT id, y FROM pinot_b)\nSELECT s1.x, s2.y FROM s1 JOIN s2 ON s1.id = s2.id;","handlingStrategy":"fallback","validationCode":"-- Inspect the plan before execution and check for node types the pinot connector cannot visit:\nEXPLAIN ANALYZE? or EXPLAIN <sql>;\n-- look for Join/Window/RowNumber/Unnest/Union nodes adjacent to the PinotTableScan;\n-- if present, restructure the query","typeGuard":null,"tryCatchPattern":"try {\n    run(sql);\n} catch (PinotException e) {\n    if (String.valueOf(e.getMessage()).startsWith(\"Don't know how to handle plan node\")) {\n        // retry with the unsupported operation isolated outside the pinot subplan\n        run(rewriteToIsolatePinotScan(sql));\n    } else throw e;\n}","preventionTips":["Keep single-table filters/aggregations/limits in the Pinot subplan; do joins and windows outside","Run EXPLAIN on new query shapes to see the plan before production","Keep the pinot plugin version in lockstep with the Presto engine"],"tags":["pinot","query-planning","unsupported-plan-node","pushdown"],"backgroundTag":"unsupported-plan-node","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"}