Skip to content

Detect slice/array element kinds in Eq/Neq via reflection - #7872

Open
januththedev wants to merge 1 commit into
go-gorm:masterfrom
januththedev:fix/eq-neq-slice-element-kinds
Open

januththedev wants to merge 1 commit into
go-gorm:masterfrom
januththedev:fix/eq-neq-slice-element-kinds

Conversation

@januththedev

Copy link
Copy Markdown

Eq/Neq only recognise 8 slice types, so others emit an invalid row-value comparison

Description

clause/expression.go, in Eq.Build and Neq.Build:

switch eq.Value.(type) {
case []string, []int, []int32, []int64, []uint, []uint32, []uint64, []interface{}:
    ... render IN (...) / NOT IN (...)
default:
    ... render = ? / <> ?
}

That is an incomplete enumeration of slice types. Any other slice or array falls to default, where AddVar expands it into a parenthesised placeholder list, producing `col` = (?,?) — a row-value comparison, which is invalid SQL against a scalar column and errors at execution.

Why it's wrong

The intent is clearly "slice ⇒ IN list" — eight types got it — but the mechanism only recognises eight spellings. So []float64, []float32, []int8, []int16, []uint16, []bool, [N]T arrays, and any named slice type (e.g. type Money []float64) silently produce broken SQL.

The codebase already has the correct discriminator twice: processValue in the same file (clause/expression.go:161-182) and Statement.AddVar (statement.go:250, rv.Type().Elem() == reflect.TypeOf(uint8(0))). Neither is used here.

Reachable from the plain public API with no clause import, since BuildCondition (statement.go:315-317) wraps a single non-string argument in clause.Eq.

Reproduction (real output, before the fix)

Where id []int64        => ... WHERE `id` IN (?,?)          vars=[1 2]
Where score []float64   => ... WHERE `score` = (?,?)       vars=[1 2]
Where id []int8         => ... WHERE `id` = (?,?)         vars=[1 2]
Where id []bool         => ... WHERE `id` = (?,?)         vars=[true false]
Where name []byte       => ... WHERE `name` = ?           vars=[[97 98]]   (correctly unchanged)
Not score []float64     => ... WHERE `score` <> (?,?)     vars=[1 2]
Where score []float64{} => ... WHERE `score` = (NULL)      vars=[]

The fix

Both switches are replaced by one shared helper:

func isValueList(value interface{}) bool {
	if _, ok := value.(driver.Valuer); ok {
		return false
	}
	rv := reflect.ValueOf(value)
	switch rv.Kind() {
	case reflect.Slice, reflect.Array:
		return rv.Type().Elem().Kind() != reflect.Uint8
	default:
		return false
	}
}

The driver.Valuer and uint8-element guards keep []byte, named byte slices, and types like uuid.UUID as single values, matching the existing AddVar semantics.

Tests

Seven cases added to TestExpression in clause/expression_test.go, covering []float64, []int8, []bool, a named slice type, the X-to-end-to-end db.Where/db.Not path via DryRun, an empty slice, and a control asserting []byte is still a single value.

  • Before: expects column-nameIN (?,?), but gotcolumn-name = (?,?) (and the NOT IN / empty-slice equivalents). After: pass.
  • clause: 18 top-level / 128 total (incl. subtests), 0 failures. utils, schema, logger all ok, 0 failures. go vet ./clause/... and go build ./... clean. No existing test changed behaviour.

Two environment limitations, both pre-existing and unrelated:

  • The root gorm package does not build here — generics_withresult_test.go imports gorm.io/driver/sqlite, which needs cgo, and there is no working C compiler (gcc: fatal error: cannot execute 'cc1'). I skipped tests/ entirely since it needs MySQL/Postgres/SQLite servers, and verified the fix through the clause unit tests plus the DryRun path above.

Not a duplicate of the open PRs

#7830 fixes Neq with an empty slice (NOT IN () → IS NOT NULL); #7848 fixes BuildCondition treating []byte/uuid.UUID as lists. Neither touches Eq/Neq element-type dispatch, and the driver.Valuer guard here keeps them working.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@januththedev
januththedev force-pushed the fix/eq-neq-slice-element-kinds branch from a66b992 to 2f04590 Compare October 3, 2026 10:11

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant