TestProfilingSettingsArePerConnection reproduces the cluster-mode bug: DuckDB profiling settings are session-scoped (DuckDB rejects `SET GLOBAL` for `enable_profiling` etc.), so when the worker's evictConnFromPool discards a session's connection between sessions, the next fresh connection has no pro
(t *testing.T)
| 223 | // connection has no profiling configured and the profile file stays |
| 224 | // untouched. ProfilingSetupSQL applied per-connection is the fix. |
| 225 | func TestProfilingSettingsArePerConnection(t *testing.T) { |
| 226 | db, err := sql.Open("duckdb", ":memory:") |
| 227 | if err != nil { |
| 228 | t.Fatalf("open duckdb: %v", err) |
| 229 | } |
| 230 | defer func() { _ = db.Close() }() |
| 231 | // Two slots so we can pin two distinct underlying connections. |
| 232 | db.SetMaxOpenConns(2) |
| 233 | db.SetMaxIdleConns(2) |
| 234 | |
| 235 | ctx := context.Background() |
| 236 | tmpFile := t.TempDir() + "/profiling.json" |
| 237 | setup := ProfilingSetupSQL(tmpFile) |
| 238 | |
| 239 | // Connection A: full setup, simulates the warmup conn that ConfigureMainDB |
| 240 | // ran on. Apply the production setup statements directly so we're testing |
| 241 | // the same SQL the real code path uses. |
| 242 | connA, err := db.Conn(ctx) |
| 243 | if err != nil { |
| 244 | t.Fatalf("conn A: %v", err) |
| 245 | } |
| 246 | defer func() { _ = connA.Close() }() |
| 247 | if _, err := connA.ExecContext(ctx, "CREATE TABLE t (x INT)"); err != nil { |
| 248 | t.Fatalf("create table: %v", err) |
| 249 | } |
| 250 | for _, s := range setup { |
| 251 | if _, err := connA.ExecContext(ctx, s); err != nil { |
| 252 | t.Fatalf("connA %s: %v", s, err) |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | // Connection B: pretend we've evicted A and the pool handed out a fresh |
| 257 | // conn. Without per-session re-application, this conn has no profiling |
| 258 | // settings. |
| 259 | connB, err := db.Conn(ctx) |
| 260 | if err != nil { |
| 261 | t.Fatalf("conn B: %v", err) |
| 262 | } |
| 263 | defer func() { _ = connB.Close() }() |
| 264 | |
| 265 | _ = os.Remove(tmpFile) |
| 266 | if _, err := connB.ExecContext(ctx, "INSERT INTO t VALUES (1)"); err != nil { |
| 267 | t.Fatalf("connB pre-fix INSERT: %v", err) |
| 268 | } |
| 269 | if data, err := os.ReadFile(tmpFile); err == nil && len(data) > 0 { |
| 270 | t.Fatalf("pre-fix sanity: fresh conn should not produce profile JSON, got %d bytes", len(data)) |
| 271 | } |
| 272 | |
| 273 | // Now apply the same setup to connB and re-run the INSERT — this is what |
| 274 | // duckdbservice.CreateSession does via server.ApplyProfilingSettings. |
| 275 | for _, s := range setup { |
| 276 | if _, err := connB.ExecContext(ctx, s); err != nil { |
| 277 | t.Fatalf("connB re-apply %s: %v", s, err) |
| 278 | } |
| 279 | } |
| 280 | _ = os.Remove(tmpFile) |
| 281 | if _, err := connB.ExecContext(ctx, "INSERT INTO t VALUES (2)"); err != nil { |
| 282 | t.Fatalf("connB post-fix INSERT: %v", err) |
nothing calls this directly
no test coverage detected