vitessio/vitess · error

invalid comparison operator

Error message

invalid comparison operator

What it means

The tuple-comparison compiler (compileAsTuple) switches over the ComparisonExpr's operator and only supports EQ/NE/LT/LE/GT/GE-style tuple comparisons it knows about. An operator enum value outside the handled set reaches the default branch and panics. This is an internal exhaustive-switch guard: sqlparser/IR should never produce a comparison operator that lacks a tuple compilation strategy.

Source

Thrown at go/vt/vtgate/evalengine/expr_compare.go:350

		c.asm.CmpTuple(c.env.CollationEnv(), true)
		c.asm.Cmp_eq_n()
	case compareNE:
		c.asm.CmpTuple(c.env.CollationEnv(), true)
		c.asm.Cmp_ne_n()
	case compareLT:
		c.asm.CmpTuple(c.env.CollationEnv(), false)
		c.asm.Cmp_lt_n()
	case compareLE:
		c.asm.CmpTuple(c.env.CollationEnv(), false)
		c.asm.Cmp_le_n()
	case compareGT:
		c.asm.CmpTuple(c.env.CollationEnv(), false)
		c.asm.Cmp_gt_n()
	case compareGE:
		c.asm.CmpTuple(c.env.CollationEnv(), false)
		c.asm.Cmp_ge_n()
	default:
		panic("invalid comparison operator")
	}
	return ctype{Type: sqltypes.Int64, Flag: flagNullable | flagIsBoolean, Col: collationNumeric}, nil
}

func (expr *ComparisonExpr) compile(c *compiler) (ctype, error) {
	lt, err := expr.Left.compile(c)
	if err != nil {
		return ctype{}, err
	}

	var skip1 *jump
	switch expr.Op.(type) {
	case compareNullSafeEQ:
	default:
		skip1 = c.compileNullCheck1(lt)
	}

	rt, err := expr.Right.compile(c)

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Check which operator value hit the default branch and confirm it is valid for tuple comparison
  2. Add a case for the missing operator in compileAsTuple with the appropriate CmpTuple asm sequence
  3. Reject non-tuple-comparable operators earlier during typecheck so they fail with a proper error
  4. Rebuild generated IR code to ensure parser and compiler agree on operator values

Example fix

// before
case compareGE:
	c.asm.CmpTuple(c.env.CollationEnv(), false)
	c.asm.Cmp_ge_n()
default:
	panic("invalid comparison operator")
// after
case compareGE:
	c.asm.CmpTuple(c.env.CollationEnv(), false)
	c.asm.Cmp_ge_n()
case compareNewOp:
	c.asm.CmpTuple(c.env.CollationEnv(), false)
	c.asm.Cmp_newop_n()
default:
	panic("invalid comparison operator")
Defensive patterns

Strategy: validation

Validate before calling

// Validate the comparison operator is one supported for tuples
func tupleComparable(op evalengine.ComparisonOp) bool {
	switch op {
	case evalengine.Equal, evalengine.NotEqual, evalengine.LessThan,
		evalengine.LessEqual, evalengine.GreaterThan, evalengine.GreaterEqual:
		return true
	}
	return false
}

Type guard

func isTupleComparison(expr *evalengine.ComparisonExpr) (supported bool) {
	_, lTuple := expr.Left.(evalengine.TupleExpr)
	_, rTuple := expr.Right.(evalengine.TupleExpr)
	return lTuple && rTuple && tupleComparable(expr.Operator)
}

Try / catch

func safeCompileCompare(expr *evalengine.ComparisonExpr, c *compiler) (ct ctype, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("compare compile panic: %v", r)
		}
	}()
	return expr.compile(c)
}

Prevention

When it happens

Trigger: Compiling a ComparisonExpr with a comparison operator value not in the switch's cases while the compiler has chosen the tuple-comparison path (both operands are tuples). Typically only possible with a corrupted/extended operator enum or a new operator added without tuple support.

Common situations: Adding a new comparison operator to the IR without implementing compileAsTuple support; tests constructing ComparisonExpr with invalid operator constants; inconsistent generated code between parser and evalengine.

Related errors


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