{"record":{"id":"b8fb7ed98f324dfb","repo":"vitessio/vitess","slug":"unsupported-mix-of-and-columns","errorCode":null,"errorMessage":"unsupported mix of '*' and columns","messagePattern":"unsupported mix of '\\*' and columns","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go","lineNumber":242,"sourceCode":"\t\tbuf := sqlparser.NewTrackedBuffer(nil)\n\t\tbuf.Myprintf(\"select * from %v where in_keyrange(%v)\", sqlparser.NewIdentifierCS(tableName), sqlparser.NewStrLiteral(filter))\n\t\tquery = buf.String()\n\tcase filter == ExcludeStr:\n\t\treturn nil, nil\n\t}\n\tsel, fromTable, err := analyzeSelectFrom(query, parser)\n\tif err != nil {\n\t\treturn nil, planError(err, query)\n\t}\n\tsendRule := &binlogdatapb.Rule{\n\t\tMatch: fromTable,\n\t}\n\n\tif expr, ok := sel.SelectExprs.Exprs[0].(*sqlparser.StarExpr); ok {\n\t\t// If it's a \"select *\", we return a partial plan, and complete\n\t\t// it when we get back field info from the stream.\n\t\tif len(sel.SelectExprs.Exprs) != 1 {\n\t\t\treturn nil, planError(errors.New(\"unsupported mix of '*' and columns\"), sqlparser.String(sel))\n\t\t}\n\t\tif !expr.TableName.IsEmpty() {\n\t\t\treturn nil, planError(errors.New(\"unsupported qualifier for '*' expression\"), sqlparser.String(expr))\n\t\t}\n\t\tsendRule.Filter = query\n\t\ttablePlan := &TablePlan{\n\t\t\tTargetName:       tableName,\n\t\t\tSendRule:         sendRule,\n\t\t\tLastpk:           lastpk,\n\t\t\tStats:            stats,\n\t\t\tConvertCharset:   rule.ConvertCharset,\n\t\t\tConvertIntToEnum: rule.ConvertIntToEnum,\n\t\t\tCollationEnv:     collationEnv,\n\t\t\tWorkflowConfig:   workflowConfig,\n\t\t}\n\n\t\treturn tablePlan, nil\n\t}","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go#L224-L260","documentation":"buildReplicatorPlan/buildTablePlan parses the filter rule's 'select *' query. A '*' is only supported as the sole select expression (the plan is completed later from stream field info); mixing '*' with named columns is not representable in the replication plan and is rejected.","triggerScenarios":"Creating a vreplication stream (MoveTables/Reshard/filter rule) whose filter query is like 'select *, col from t' or 'select col, * from t'.","commonSituations":"Hand-written filter rules combining explicit columns with '*'; generated rules edited by hand during MoveTables customization.","solutions":["Use either plain 'select * from t' or an explicit column list — never both","If you need extra computed columns, list all columns explicitly instead of '*'","Fix the filter rule in the MoveTables/Reshard create command and re-run"],"exampleFix":"// before\n\"filter\": \"select *, id from t\"\n// after\n\"filter\": \"select * from t\"  // or list all columns explicitly","handlingStrategy":"validation","validationCode":"stmt, err := parser.Parse(filterQuery)\nif sel, ok := stmt.(*sqlparser.Select); ok {\n    stars := 0\n    for _, e := range sel.SelectExprs.Exprs {\n        if _, ok := e.(*sqlparser.StarExpr); ok { stars++ }\n    }\n    if stars > 0 && len(sel.SelectExprs.Exprs) > 1 {\n        return errors.New(\"filter cannot mix '*' with columns\")\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Review filter rules before MoveTables/Reshard create","Use either '*' alone or an explicit column list","Lint filter SQL with the vitess sqlparser in CI"],"tags":["vreplication","filter","sql-parsing"],"backgroundTag":"invalid-filter-rule","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}