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

  1. Pass a SELECT with exactly one table in FROM (no joins, no comma lists)
  2. Parse the statement yourself with sqlparser and handle multi-table FROM explicitly
  3. 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

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


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/678302909b392b4d. Report an issue: GitHub.