{"record":{"id":"ae97e32f61ac7259","repo":"vitessio/vitess","slug":"unsupported-aggregation-function-v","errorCode":null,"errorMessage":"unsupported aggregation function: %v","messagePattern":"unsupported aggregation function: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go","lineNumber":530,"sourceCode":"\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})\n}\n","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go#L512-L548","documentation":"Aggregate functions found in unexpected positions (outside the handled count/sum analysis paths) are rejected by the sqlparser.Walk in the non-aggregate expression branch. Only top-level count(*) and single-column sum are supported; e.g. an aggregate nested inside a scalar expression like ABS(sum(x)) triggers this.","triggerScenarios":"Materialize/vreplication SELECT where an aggregate appears inside a larger expression, e.g. SELECT abs(sum(x)) AS a FROM t; the walk visits the sqlparser.AggrFunc node and errors.","commonSituations":"Users wrapping aggregates in functions or arithmetic (sum(x)+1) assuming expression support; porting general SQL into a materialize workflow.","solutions":["Use the aggregate bare at the top level of a select-list item: SELECT sum(x) AS sum_x FROM t.","Apply post-processing (abs, +1, etc.) after materialization, in the consumer query.","Stick to the supported set: count(*) and sum(single unqualified column)."],"exampleFix":"// before\nselect abs(sum(x)) as a from t\n// after\nselect sum(x) as sum_x from t","handlingStrategy":"validation","validationCode":"// Ensure each select item is either a plain column or a bare top-level count(*)/sum(col)\nfunc supportedSelectItem(e sqlparser.Expr) bool {\n    ag, ok := e.(*sqlparser.AliasedExpr)\n    if !ok { return false }\n    switch x := ag.Expr.(type) {\n    case *sqlparser.ColName, *sqlparser.CountStar:\n        return true\n    case *sqlparser.Sum:\n        col, ok := x.Args[0].(*sqlparser.ColName)\n        return ok && col.Qualifier.IsEmpty()\n    }\n    return false\n}","typeGuard":"func isBareAggr(n sqlparser.SQLNode) bool { switch n.(type) { case *sqlparser.CountStar, *sqlparser.Sum: return true }; return false }","tryCatchPattern":null,"preventionTips":["Never wrap aggregates in other functions or arithmetic in workflow queries.","Restrict select lists to plain columns plus bare count(*)/sum(col) items."],"tags":["vreplication","sql","aggregation","vttablet"],"backgroundTag":"unsupported-aggregate-expression","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}