Skip to content

Commit d73e9c9

Browse files
akoclaude
andcommitted
fix(#471): SET format = json now takes effect for subsequent statements
execSet stored the format value in ctx.Settings but never applied it to ctx.Format, and syncBack intentionally excluded Format from being written back to e.format — so the output format never changed. Fix: execSet applies the 'format' key to ctx.Format immediately; syncBack now persists e.format = ctx.Format so subsequent statements in the same session inherit the new setting. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 96cecc3 commit d73e9c9

3 files changed

Lines changed: 49 additions & 1 deletion

File tree

mdl/executor/cmd_misc.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ func execSet(ctx *ExecContext, s *ast.SetStmt) error {
4343
ctx.Settings = make(map[string]any)
4444
}
4545
ctx.Settings[s.Key] = s.Value
46+
47+
// Apply recognized session keys to the live context immediately.
48+
// syncBack will persist ctx.Format back to e.format so subsequent
49+
// statements in the same session also pick up the change.
50+
switch strings.ToLower(s.Key) {
51+
case "format":
52+
if v, ok := s.Value.(string); ok {
53+
ctx.Format = OutputFormat(strings.ToLower(v))
54+
}
55+
}
56+
4657
fmt.Fprintf(ctx.Output, "Set %s = %v\n", s.Key, s.Value)
4758
return nil
4859
}

mdl/executor/cmd_misc_mock_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,39 @@ func TestHelp_Mock(t *testing.T) {
7272
assertContainsStr(t, out, "connect local")
7373
}
7474

75+
// ---------------------------------------------------------------------------
76+
// SET — format key updates ctx.Format
77+
// ---------------------------------------------------------------------------
78+
79+
func TestExecSet_FormatKey_UpdatesCtxFormat(t *testing.T) {
80+
ctx, buf := newMockCtx(t) // starts as FormatTable (default)
81+
if ctx.Format != FormatTable {
82+
t.Fatalf("expected default FormatTable, got %q", ctx.Format)
83+
}
84+
err := execSet(ctx, &ast.SetStmt{Key: "format", Value: "json"})
85+
assertNoError(t, err)
86+
if ctx.Format != FormatJSON {
87+
t.Errorf("expected ctx.Format = %q after SET format=json, got %q", FormatJSON, ctx.Format)
88+
}
89+
assertContainsStr(t, buf.String(), "Set format = json")
90+
}
91+
92+
func TestExecSet_FormatKey_BareIdentifier(t *testing.T) {
93+
ctx, _ := newMockCtx(t)
94+
assertNoError(t, execSet(ctx, &ast.SetStmt{Key: "format", Value: "table"}))
95+
if ctx.Format != FormatTable {
96+
t.Errorf("expected FormatTable, got %q", ctx.Format)
97+
}
98+
}
99+
100+
func TestExecSet_UnknownKey_StoredOnly(t *testing.T) {
101+
ctx, _ := newMockCtx(t)
102+
assertNoError(t, execSet(ctx, &ast.SetStmt{Key: "mykey", Value: "myval"}))
103+
if ctx.Settings["mykey"] != "myval" {
104+
t.Errorf("expected Settings[mykey]=myval, got %v", ctx.Settings["mykey"])
105+
}
106+
}
107+
75108
// ---------------------------------------------------------------------------
76109
// EXECUTE SCRIPT — depth limit
77110
// ---------------------------------------------------------------------------

mdl/executor/executor_dispatch.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,18 @@ func (e *Executor) executeInner(ctx context.Context, stmt ast.Statement) error {
2929
// the next newExecContext call picks up handler-side state changes.
3030
//
3131
// Fields intentionally NOT synced back (read-only from handler perspective):
32-
// - Output, Format, Quiet, Logger — set once at Executor construction
32+
// - Output, Quiet, Logger — set once at Executor construction
3333
// - BackendFactory — set once at Executor construction
3434
// - OutputGuard — removed; writeDescribeJSON captures via Output swap only
3535
// - ExecuteFn, ExecuteProgramFn, FinalizeFn — bound to Executor methods, immutable
36+
//
37+
// Format IS synced back so that `SET format = json` takes effect for all
38+
// subsequent statements in the same session.
3639
func (e *Executor) syncBack(ctx *ExecContext) {
3740
e.backend = ctx.Backend
3841
e.mprPath = ctx.MprPath
3942
e.cache = ctx.Cache
43+
e.format = ctx.Format
4044
e.catalogMu.Lock()
4145
old := e.catalog
4246
e.catalog = ctx.Catalog

0 commit comments

Comments
 (0)