vitessio/vitess · error
table expression is complex
Error message
table expression is complex
What it means
sqlparser.TableFromStatement extracts a single simple table name from a SQL statement. It first requires the statement to be a SELECT with exactly one FROM item; if there are multiple/joined FROM items (len(sel.From) != 1) it cannot identify one table and returns 'table expression is complex'.
Source
Thrown at go/vt/sqlparser/analyzer.go:354
return true
}
return false
}
// TableFromStatement returns the qualified table name for the query.
// This works only for select statements.
func (p *Parser) TableFromStatement(sql string) (TableName, error) {
stmt, err := p.Parse(sql)
if err != nil {
return TableName{}, err
}
sel, ok := stmt.(*Select)
if !ok {
return TableName{}, fmt.Errorf("unrecognized statement: %s", sql)
}
if len(sel.From) != 1 {
return TableName{}, errors.New("table expression is complex")
}
aliased, ok := sel.From[0].(*AliasedTableExpr)
if !ok {
return TableName{}, errors.New("table expression is complex")
}
tableName, ok := aliased.Expr.(TableName)
if !ok {
return TableName{}, errors.New("table expression is complex")
}
return tableName, nil
}
// GetTableName returns the table name from the SimpleTableExpr
// only if it's a simple expression. Otherwise, it returns "".
func GetTableName(node SimpleTableExpr) IdentifierCS {
if n, ok := node.(TableName); ok && n.Qualifier.IsEmpty() {
return n.Name
}View on GitHub (pinned to 01a25a7d17)
Solutions
- Pass a SELECT with exactly one table in FROM (no joins, no comma lists)
- Parse the statement yourself with sqlparser and handle multi-table FROM explicitly
- Simplify the query upstream (e.g. split per-table queries) before extracting the table name
Example fix
// before
tn, err := TableFromStatement("select * from a join b on a.id=b.id")
// after
tn, err := TableFromStatement("select * from a") Defensive patterns
Strategy: validation
Validate before calling
stmt, err := sqlparser.Parse(sql)
if err != nil { return err }
sel, ok := stmt.(*sqlparser.Select)
if !ok || len(sel.From) != 1 { return errors.New("query must be a single-table select") } Type guard
func isSimpleSelect(sql string) bool {
stmt, err := sqlparser.Parse(sql)
if err != nil { return false }
sel, ok := stmt.(*sqlparser.Select)
return ok && len(sel.From) == 1
} Try / catch
tn, err := sqlparser.TableFromStatement(sql)
if err != nil && strings.Contains(err.Error(), "table expression is complex") {
// fall back to full AST parsing of the query
} Prevention
- Only pass single-table SELECTs to TableFromStatement
- Pre-parse and validate query shape before extraction
- Reject joins/comma-FROM at the API boundary
When it happens
Trigger: TableFromStatement called with SQL whose SELECT has more than one FROM element — joins, comma-separated tables, or subquery-in-FROM constructs.
Common situations: VReplication/automation code assuming single-table SELECTs but given joins; users passing 'SELECT * FROM a JOIN b' where only 'SELECT * FROM a' is supported.
Related errors
- missing value for 'rate'
- missing value for 'path'
- range %d should be >= %d
- unexpected character %q in JSON
- expected ',' or '}' in object, got %q
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/678302909b392b4d.
Report an issue: GitHub.