Skip to content

Commit f60c07b

Browse files
getevoclaude
andcommitted
Fix Map.Scan nil panic and Date zero-value rejection on MySQL strict mode
- Map.Scan: auto-initialize shards when loading into a zero-value Map (e.g. via GORM); prevents nil pointer panic on MSet - Date.GormValue: return NULL for zero dates on all databases, not just PostgreSQL; MySQL 5.7+ STRICT_TRANS_TABLES rejects '0000-00-00' Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent dc71dad commit f60c07b

File tree

2 files changed

+19
-7
lines changed

2 files changed

+19
-7
lines changed

lib/db/types/date.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,11 @@ func (t Date) Value() (driver.Value, error) {
7777
}
7878

7979
// GormValue implements GormValuerInterface for dialect-aware date handling.
80-
// PostgreSQL rejects "0000-00-00" as an invalid date, so we return NULL instead.
80+
// Zero dates (year < 1000) are stored as NULL to avoid invalid date errors in
81+
// strict-mode databases (PostgreSQL, MySQL 5.7+ with STRICT_TRANS_TABLES).
8182
func (t Date) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
8283
if t.Year() < 1000 {
83-
switch db.Dialector.Name() {
84-
case "postgres":
85-
return gorm.Expr("NULL")
86-
default:
87-
return gorm.Expr("?", "0000-00-00")
88-
}
84+
return gorm.Expr("NULL")
8985
}
9086
return gorm.Expr("?", fmt.Sprintf("%d-%02d-%02d", t.Year(), t.Month(), t.Day()))
9187
}

lib/db/types/map.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,22 @@ func (m *Map[K, V]) Scan(src any) error {
219219
if err := json.Unmarshal(bytes, &all); err != nil {
220220
return err
221221
}
222+
// Initialize shards if the map was created as a zero value (e.g. loaded by GORM).
223+
if m.shards == nil {
224+
m.shards = make([]*ConcurrentMapShared[K, V], SHARD_COUNT)
225+
for i := range m.shards {
226+
m.shards[i] = &ConcurrentMapShared[K, V]{items: make(map[K]V)}
227+
}
228+
// Default sharding: fmt.Sprintf hash (safe for any comparable K).
229+
m.sharding = func(key K) uint32 {
230+
h := uint32(2166136261)
231+
for _, c := range fmt.Sprintf("%v", key) {
232+
h ^= uint32(c)
233+
h *= 16777619
234+
}
235+
return h
236+
}
237+
}
222238
m.MSet(all)
223239
return nil
224240
}

0 commit comments

Comments
 (0)