{"record":{"id":"cbb8944cd130825a","repo":"vitessio/vitess","slug":"vt09015-cbb894","errorCode":"VT09015","errorMessage":"VT09015","messagePattern":"VT09015","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vtgate/planbuilder/operators/horizon_expanding.go","lineNumber":366,"sourceCode":"\t\t\tproj.addUnexploredExpr(org, expr)\n\t\t} else {\n\t\t\tproj.addSubqueryExpr(ctx, org, newExpr, subqs...)\n\t\t}\n\t}\n\tproj.Source = sqc.getRootOperator(src, nil)\n\treturn proj\n}\n\nfunc newStarProjection(src Operator, qp *QueryProjection) *Projection {\n\tcols := make([]sqlparser.SelectExpr, 0, len(qp.SelectExprs))\n\n\tfor _, expr := range qp.SelectExprs {\n\t\t_ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {\n\t\t\t_, isSubQ := node.(*sqlparser.Subquery)\n\t\t\tif !isSubQ {\n\t\t\t\treturn true, nil\n\t\t\t}\n\t\t\tpanic(vterrors.VT09015())\n\t\t}, expr.Col)\n\t\tcols = append(cols, expr.Col)\n\t}\n\n\treturn &Projection{\n\t\tunaryOperator: newUnaryOp(src),\n\t\tColumns:       StarProjections(cols),\n\t}\n}\n","sourceCodeStart":348,"sourceCodeEnd":376,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vtgate/planbuilder/operators/horizon_expanding.go#L348-L376","documentation":"VT09015: unsupported subquery in this projection context. During projection building (after a route/aggregation has been collapsed), the planner walks each projected column and panics with VT09015 if it finds a *sqlparser.Subquery, because subqueries cannot be evaluated inside this operator's projection on the chosen route.","triggerScenarios":"A SELECT list (of a collapsed/merged query, e.g. inside an aggregation or post-processing projection) contains a scalar subquery expression, e.g. `SELECT (SELECT MAX(x) FROM t2) FROM t GROUP BY a`.","commonSituations":"Queries ported from application code that relies on scalar subqueries in the SELECT list combined with GROUP BY or other constructs that force them into the internal projection operator.","solutions":["Rewrite the subquery as a JOIN against a derived table: `SELECT d.m FROM t JOIN (SELECT MAX(x) AS m FROM t2) d`","Move the subquery result into a derived table and reference its column in the projection","Split into two queries executed by the application","Check Vitess release notes — subquery support expands over time; upgrade may help"],"exampleFix":"// before\nSELECT a, (SELECT MAX(x) FROM t2) AS m FROM t GROUP BY a;\n// after\nSELECT t.a, d.m FROM t JOIN (SELECT MAX(x) AS m FROM t2) AS d ON TRUE GROUP BY t.a, d.m;","handlingStrategy":"validation","validationCode":"// Reject scalar subqueries in SELECT list before sending to Vitess\nfunc selectContainsSubquery(stmt sqlparser.Statement) bool {\n  found := false\n  _ = sqlparser.Walk(func(n sqlparser.SQLNode) (bool, error) {\n    if _, ok := n.(*sqlparser.Subquery); ok { found = true; return false, nil }\n    return true, nil\n  }, stmt)\n  return found\n}","typeGuard":"_, isSubquery := node.(*sqlparser.Subquery) // isSubquery true => unsupported here","tryCatchPattern":"err := exec(q)\nif err != nil && strings.Contains(err.Error(), \"VT09015\") {\n  // rewrite query to use JOIN against derived table instead\n}","preventionTips":["Rewrite scalar subqueries in SELECT lists as JOINs with derived tables","Keep subqueries in WHERE/FROM clauses where Vitess support is broader","Consult Vitess subquery support docs for your version before adopting patterns","Add pre-deployment SQL linting to flag SELECT-list subqueries"],"tags":["go","subquery","unsupported-query","query-planning"],"backgroundTag":"unsupported-subquery","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}