vitessio/vitess · error
unsupported construct: %v
Error message
unsupported construct: %v
What it means
vexec (the wrangler's generic SQL executor for running admin DML against shards) only supports simple single-table DELETE statements. buildDeletePlan rejects DELETE statements using multi-table delete Targets, because the plan builder has no way to rewrite them for sharded execution.
Source
Thrown at go/vt/wrangler/vexec_plan.go:292
if !match {
return nil, fmt.Errorf("Query must match one of these templates: %s", strings.Join(templates, "; "))
}
}
upd.Where = vx.addDefaultWheres(planner, upd.Where)
buf := sqlparser.NewTrackedBuffer(nil)
buf.Myprintf("%v", upd)
return &vexecPlan{
opcode: updateQuery,
parsedQuery: buf.ParsedQuery(),
}, nil
}
// buildDeletePlan builds a plan for a DELETE query
func (vx *vexec) buildDeletePlan(ctx context.Context, planner vexecPlanner, del *sqlparser.Delete) (*vexecPlan, error) {
if del.Targets != nil {
return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(del))
}
if del.Partitions != nil {
return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(del))
}
if del.OrderBy != nil || del.Limit != nil {
return nil, fmt.Errorf("unsupported construct: %v", sqlparser.String(del))
}
del.Where = vx.addDefaultWheres(planner, del.Where)
buf := sqlparser.NewTrackedBuffer(nil)
buf.Myprintf("%v", del)
return &vexecPlan{
opcode: deleteQuery,
parsedQuery: buf.ParsedQuery(),
}, nil
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Rewrite the query as separate single-table DELETE statements, one per table
- Use a subquery (e.g. `DELETE FROM t1 WHERE id IN (SELECT ...)`), keeping a single delete target
- Execute the multi-table DELETE directly on the shard's MySQL via mysqlctl/queryservice instead of vexec
Example fix
// before DELETE t1, t2 FROM t1 JOIN t2 ON t1.id = t2.id WHERE t1.x = 1; // after DELETE FROM t1 WHERE x = 1; DELETE FROM t2 WHERE t1_id IN (SELECT id FROM t1 WHERE x = 1);
Defensive patterns
Strategy: validation
Validate before calling
del, err := sqlparser.Parse(query)
if err != nil { return err }
d, ok := del.(*sqlparser.Delete)
if !ok || d.Targets != nil {
return fmt.Errorf("vexec DELETE supports single-table deletes only")
} Prevention
- Avoid MySQL multi-table DELETE syntax in admin scripts
- Split cleanup logic into per-table statements
- Prefer subquery-based deletes over join-based deletes
When it happens
Trigger: Calling vexec (e.g. via wrangler query execution helpers) with a DELETE statement that contains multiple delete targets, i.e. `DELETE t1, t2 FROM t1 JOIN t2 ...` — sqlparser.Delete.Targets is non-nil.
Common situations: Operators writing cleanup SQL adapted from MySQL multi-table delete syntax; automation scripts porting OLTP queries to vtctld/vexec admin paths.
Related errors
- ErrUnsupportedQueryConstruct
- ${objError.Message}
- --batch-size only allowed when all queries are CREATE TABLE|
- query not supported by vexec
- Invalid JSON path expression.
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/cf4b9b8800e775fe.
Report an issue: GitHub.