{"record":{"id":"b523e9ee3f0ba74a","repo":"vitessio/vitess","slug":"unsupported-subquery-v","errorCode":null,"errorMessage":"unsupported subquery: %v","messagePattern":"unsupported subquery: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go","lineNumber":528,"sourceCode":"\t\t\t\treturn nil, fmt.Errorf(\"unsupported qualifier for column: %v\", sqlparser.String(innerCol))\n\t\t\t}\n\t\t\tcexpr.operation = opSum\n\t\t\tcexpr.expr = innerCol\n\t\t\ttpb.addCol(innerCol.Name)\n\t\t\tcexpr.references[innerCol.Name.String()] = true\n\t\t\treturn cexpr, nil\n\t\t}\n\t}\n\terr := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {\n\t\tswitch node := node.(type) {\n\t\tcase *sqlparser.ColName:\n\t\t\tif !node.Qualifier.IsEmpty() {\n\t\t\t\treturn false, fmt.Errorf(\"unsupported qualifier for column: %v\", sqlparser.String(node))\n\t\t\t}\n\t\t\ttpb.addCol(node.Name)\n\t\t\tcexpr.references[node.Name.String()] = true\n\t\tcase *sqlparser.Subquery:\n\t\t\treturn false, fmt.Errorf(\"unsupported subquery: %v\", sqlparser.String(node))\n\t\tcase sqlparser.AggrFunc:\n\t\t\treturn false, fmt.Errorf(\"unsupported aggregation function: %v\", sqlparser.String(node))\n\t\t}\n\t\treturn true, nil\n\t}, aliased.Expr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcexpr.expr = aliased.Expr\n\treturn cexpr, nil\n}\n\n// addCol adds the specified column to the send query\n// if it's not already present.\nfunc (tpb *tablePlanBuilder) addCol(ident sqlparser.IdentifierCI) {\n\ttpb.sendSelect.AddSelectExpr(&sqlparser.AliasedExpr{\n\t\tExpr: &sqlparser.ColName{Name: ident},\n\t})","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go#L510-L546","documentation":"Subqueries anywhere in a select-list expression are unsupported in vreplication table plans. The sqlparser.Walk rejects *sqlparser.Subquery nodes because the materialization logic cannot evaluate a nested query per row.","triggerScenarios":"Materialize/vreplication SELECT containing a subquery, e.g. SELECT (SELECT max(x) FROM t2) AS m FROM t; the walk over aliased.Expr encounters the Subquery node.","commonSituations":"Porting complex reporting SQL into a materialization workflow; generated queries that embed lookups as scalar subqueries.","solutions":["Remove the subquery from the SELECT list.","Precompute the subquery result into a column (e.g. via a trigger or application logic) and select that column.","Run the subquery separately against VTGate instead of embedding it in the workflow query."],"exampleFix":"// before\nselect id, (select max(v) from t2) as maxv from t\n// after\nselect id, maxv from t  -- maxv maintained as a stored column","handlingStrategy":"validation","validationCode":"// Reject subqueries in the workflow SELECT before submitting\nfunc noSubqueries(sel *sqlparser.Select) 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    }, sel)\n    return !found\n}","typeGuard":"func isSubquery(n sqlparser.SQLNode) bool { _, ok := n.(*sqlparser.Subquery); return ok }","tryCatchPattern":null,"preventionTips":["Keep workflow select lists free of nested SELECTs.","Precompute subquery results into columns or fetch them via separate VTGate queries."],"tags":["vreplication","sql","subquery","vttablet"],"backgroundTag":"unsupported-subquery-in-select","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}