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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Silent Data Corruption via Unescaped Enum Values in Generated Go Code

1 participant