{"record":{"id":"7bec0210f1261867","repo":"vitessio/vitess","slug":"unsupported-constraint-v","errorCode":null,"errorMessage":"unsupported constraint: %v","messagePattern":"unsupported constraint: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/vttablet/tabletserver/vstreamer/planbuilder.go","lineNumber":687,"sourceCode":"\t\t\t\tplan.whereExprsToPushDown = append(plan.whereExprsToPushDown, expr)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresolved, err := plan.getEvalResultForLiteral(expr.Right)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tplan.Filters = append(plan.Filters, Filter{\n\t\t\t\tOpcode: opcode,\n\t\t\t\tColNum: colnum,\n\t\t\t\tValue:  resolved.Value(plan.env.CollationEnv().DefaultConnectionCharset()),\n\t\t\t})\n\t\t\t// Add it to the expressions that get pushed down to mysqld.\n\t\t\tplan.whereExprsToPushDown = append(plan.whereExprsToPushDown, expr)\n\t\tcase *sqlparser.FuncExpr:\n\t\t\t// We cannot filter binlog events in VStreamer using MySQL functions so\n\t\t\t// we only allow the in_keyrange() function, which is VStreamer specific.\n\t\t\tif !expr.Name.EqualString(\"in_keyrange\") {\n\t\t\t\treturn fmt.Errorf(\"unsupported constraint: %v\", sqlparser.String(expr))\n\t\t\t}\n\t\t\tif err := plan.analyzeInKeyRange(vschema, expr.Exprs); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\tcase *sqlparser.IsExpr:\n\t\t\tqualifiedName, ok := expr.Left.(*sqlparser.ColName)\n\t\t\tif !ok {\n\t\t\t\treturn fmt.Errorf(\"unexpected: %v\", sqlparser.String(expr))\n\t\t\t}\n\t\t\tif !qualifiedName.Qualifier.IsEmpty() {\n\t\t\t\treturn fmt.Errorf(\"unsupported qualifier for column: %v\", sqlparser.String(qualifiedName))\n\t\t\t}\n\t\t\tcolnum, err := findColumn(plan.Table, qualifiedName.Name)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tswitch expr.Right {\n\t\t\tcase sqlparser.IsNullOp:","sourceCodeStart":669,"sourceCodeEnd":705,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/vttablet/tabletserver/vstreamer/planbuilder.go#L669-L705","documentation":"VStreamer cannot evaluate arbitrary MySQL functions when filtering binlog events, since event filtering happens in Go on rows from the binlog stream. Only the VStreamer-specific in_keyrange() function is allowed as a function constraint in a WHERE clause; anything else is rejected at plan-build time.","triggerScenarios":"Calling Stream/StreamRows with a filter whose WHERE condition contains a MySQL function other than in_keyrange(), e.g. WHERE DATE(ts) = '2024-01-01' or UPPER(name) = 'X'.","commonSituations":"Users copy a query with SQL functions into a vstream Filter rules' filter field, or an ORM-generated filter includes function calls; also happens after upgrading filters that previously ran client-side.","solutions":["Remove the function call and filter on a bare column, e.g. ts >= '2024-01-01' instead of DATE(ts) = '2024-01-01'","Use in_keyrange() if the goal is keyspace-range based filtering, which is the only supported function","Filter unconditionally (no WHERE) in the Filter and apply function-based filtering in your own event callback","If pushdown to MySQL is acceptable, verify the expression is a simple comparison so it lands in whereExprsToPushDown instead"],"exampleFix":"// before\nfilter := \"DATE(ts) = '2024-01-01'\"\n// after\nfilter := \"ts >= '2024-01-01'\"","handlingStrategy":"validation","validationCode":"func validateFilter(expr string) error {\n\tparsed, err := sqlparser.Parse(\"select * from t where \" + expr)\n\tif err != nil { return err }\n\twhere := parsed.(*sqlparser.Select).Where.Expr\n\tfor _, c := range splitAndExpression(nil, where) {\n\t\tif fn, ok := c.(*sqlparser.FuncExpr); ok && !fn.Name.EqualString(\"in_keyrange\") {\n\t\t\treturn fmt.Errorf(\"function not allowed in vstream filter: %v\", sqlparser.String(fn))\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"err := buildPlan(filter)\nif err != nil && strings.Contains(err.Error(), \"unsupported constraint\") {\n\t// fall back to client-side filtering of unfiltered stream\n}","preventionTips":["Keep vstream filter WHERE clauses to simple column comparisons","Use in_keyrange() for keyspace-range filtering needs","Apply function-based transformations in your event callback, not the filter","Review the vstreamer planbuilder docs for supported operators"],"tags":["vstreamer","binlog","sql","unsupported-feature"],"backgroundTag":"unsupported-sql-feature","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}