Skip to content

fix: escape enum values as Go string literals in generated code (#4448) - #4481

Open
ArdyJunata wants to merge 1 commit into
sqlc-dev:mainfrom
ArdyJunata:fix/enum-value-go-string-escaping
Open

fix: escape enum values as Go string literals in generated code (#4448)#4481
ArdyJunata wants to merge 1 commit into
sqlc-dev:mainfrom
ArdyJunata:fix/enum-value-go-string-escaping

Conversation

@ArdyJunata

Copy link
Copy Markdown

Summary

Fixes #4448

Problem

Enum values were interpolated raw into the Go code generation template:

{{.Name}} {{.Type}} = "{{.Value}}"

This causes silent data corruption for any PostgreSQL enum value containing special characters:

DB Enum Value Generated Go Constant Bug
user\nadmin (backslash + n, 11 bytes) "user\nadmin" (newline, 10 bytes) Silent mismatch — comparisons always fail
say "hello" "say "hello"" Breaks go/format.Source() entirely
injected" + "arbitrary" "injected" + "arbitrary" Compiles as Go string concatenation with wrong value

Fix

Replace "{{.Value}}" with {{printf "%q" .Value}} on line 95 of template.tmpl.

Go's %q verb produces a properly double-quoted, fully-escaped string literal — backslashes are doubled, double quotes are escaped, control characters use named sequences. The outer quotes are included by %q, so no surrounding quotes are needed in the template.

Before:

UserRoleUsernadmin UserRole = "user\nadmin"  // \n = newline! (10 bytes)

After:

UserRoleUsernadmin UserRole = "user\\nadmin"  // correct (11 bytes, matches DB)

Testing

Regression tests added in internal/codegen/golang/enum_test.go covering:

  • Plain values (unchanged)
  • Literal backslash sequences (\n, \t, \\)
  • Embedded control characters (actual newline, tab)
  • Double quotes embedded in values
  • String concatenation injection pattern

All 13 new sub-tests pass.

Fixes sqlc-dev#4448

Enum values containing backslashes, double quotes, or other special
characters were interpolated raw into the Go template:

    {{.Name}} {{.Type}} = "{{.Value}}"

This caused silent data corruption: a PostgreSQL enum value like
'user\nadmin' (literal backslash + n, 11 bytes) became the Go constant
"user\nadmin" (newline character, 10 bytes). Comparisons against the
database value silently fail at runtime.

Values containing double quotes broke go/format.Source() entirely.
Values like 'injected" + "code" + "' generated valid-but-wrong Go
string concatenation expressions.

Fix: replace "{{.Value}}" with {{printf "%q" .Value}}.

Go's %q verb produces a properly double-quoted, fully-escaped string
literal — backslashes are doubled, double quotes are escaped, control
characters use named sequences. The outer quotes are included by %q,
so no surrounding quotes are needed in the template.

Before: UserRoleUsernadmin UserRole = "user\nadmin"  // newline!
After:  UserRoleUsernadmin UserRole = "user\\nadmin" // correct

Regression tests added in internal/codegen/golang/enum_test.go covering:
- plain values (unchanged)
- literal backslash sequences (\n, \t, \\)
- embedded control characters
- double quotes in values
- string concatenation injection pattern
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant