vitessio/vitess · error

unsupported qualifier for column: %v

Error message

unsupported qualifier for column: %v

What it means

When walking a CONVERT(...) USING style expression, the builder collects the single column being converted. Any column reference with a qualifier (e.g. `t.col`) is rejected because the generated plan rewrites the expression against one fixed table and qualified names would not resolve there.

Source

Thrown at go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go:458

			return nil, fmt.Errorf("expression needs an alias: %v", sqlparser.String(aliased))
		}
	}
	cexpr := &colExpr{
		colName:    as,
		references: make(map[string]bool),
	}
	if expr, ok := aliased.Expr.(*sqlparser.ConvertUsingExpr); ok {
		// Here we find the actual column name in the convert, in case
		// this is a column rename and the AS is the new column.
		// For example, in convert(c1 using utf8mb4) as c2, we want to find
		// c1, because c1 exists in the current table whereas c2 is the renamed column
		// in the desired table.
		var colName sqlparser.IdentifierCI
		err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
			switch node := node.(type) {
			case *sqlparser.ColName:
				if !node.Qualifier.IsEmpty() {
					return false, fmt.Errorf("unsupported qualifier for column: %v", sqlparser.String(node))
				}
				colName = node.Name
			}
			return true, nil
		}, aliased.Expr)
		if err != nil {
			return nil, fmt.Errorf("failed to find column name for convert using expression: %v, %v", sqlparser.String(aliased.Expr), err)
		}
		selExpr := &sqlparser.ConvertUsingExpr{
			Type: "utf8mb4",
			Expr: &sqlparser.ColName{Name: colName},
		}
		cexpr.expr = expr
		cexpr.operation = opExpr
		tpb.sendSelect.AddSelectExpr(&sqlparser.AliasedExpr{Expr: selExpr, As: as})
		cexpr.references[as.String()] = true
		return cexpr, nil
	}

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Remove the table qualifier inside CONVERT USING: use `CONVERT(name USING utf8mb4)`
  2. Ensure the CONVERT USING expression references exactly one unqualified column
  3. Regenerate the filter rule after editing

Example fix

// before
SELECT CONVERT(t.name USING utf8mb4) AS name FROM t
// after
SELECT CONVERT(name USING utf8mb4) AS name FROM t
Defensive patterns

Strategy: validation

Validate before calling

sqlparser.Walk(func(n sqlparser.SQLNode) (bool, error) {
    if cn, ok := n.(*sqlparser.ColName); ok && !cn.Qualifier.IsEmpty() {
        return false, fmt.Errorf("qualified column %v not allowed", sqlparser.String(cn))
    }
    return true, nil
}, aliased.Expr)

Type guard

func unqualifiedOnly(expr sqlparser.Expr) bool {
    err := sqlparser.Walk(func(n sqlparser.SQLNode) (bool, error) {
        if cn, ok := n.(*sqlparser.ColName); ok && !cn.Qualifier.IsEmpty() {
            return false, fmt.Errorf("qualified")
        }
        return true, nil
    }, expr)
    return err == nil
}

Prevention

When it happens

Trigger: A select expression like `CONVERT(t.name USING utf8mb4)` — the inner ColName carries a table qualifier.

Common situations: Copy-pasted queries from application SQL that qualify columns; generated plans where the source query used aliases.

Related errors


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