Version
1.31.1
What happened?
Summary
sqlc v1.31.1 and earlier versions generate Go string constants from PostgreSQL enum values without applying Go string escaping. Enum values containing backslash characters are reinterpreted as Go escape sequences, producing constants whose runtime values silently differ from the corresponding database values. Enum values containing double-quote characters produce Go string concatenation expressions that compile successfully but evaluate to incorrect values.
Details:
The Go code generation template at internal/codegen/golang/templates/template.tmpl interpolates enum values using:
{{.Name}} {{$enumName}} = "{{.Value}}"
The .Value field comes from internal/codegen/golang/result.go, which passes the raw SQL enum string without transformation:
This creates three verified impacts:
Silent semantic corruption: PostgreSQL enum value user\nadmin (literal backslash + n) generates Go constant "user\nadmin" (newline character). The 12-byte DB value becomes a 10-byte Go constant. Comparisons silently fail.
Build disruption: Enum values containing " cause go/format.Source() to reject the generated code, breaking sqlc generate.
Constant value manipulation: Enum values like injected" + "arbitrary_go_code" + " produce valid Go string concatenation that compiles with a different value.
Both SQL file parsing and database introspection (database.uri) paths are affected.
schema.sql:
CREATE TYPE user_role AS ENUM (
'admin',
'user',
'readonly',
'user\nadmin'
);
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
role user_role NOT NULL DEFAULT 'user'
);
query.sql:
-- name: GetUser :one
SELECT id, name, role FROM users WHERE id = $1;
sqlc.yaml:
version: "2"
sql:
- engine: "postgresql"
queries: "query.sql"
schema: "schema.sql"
gen:
go:
package: "authdb"
out: "go"
Run sqlc generate. The generated go/models.go contains:
const (
UserRoleAdmin UserRole = "admin"
UserRoleUser UserRole = "user"
UserRoleReadonly UserRole = "readonly"
UserRoleUsernadmin UserRole = "user\nadmin" // \n interpreted as newline by Go
)
Verification:
package main
import "fmt"
func main() {
goConstant := "user\nadmin" // what sqlc generated (10 bytes, newline)
dbValue := "user\\nadmin" // what PostgreSQL stores (11 bytes, literal backslash)
fmt.Printf("Go: %d bytes %q\n", len(goConstant), goConstant)
fmt.Printf("DB: %d bytes %q\n", len(dbValue), dbValue)
fmt.Printf("Match: %v\n", goConstant == dbValue) // false
}
String concatenation variant. schema.sql:
CREATE TYPE injection AS ENUM (
'safe_value',
'injected" + "arbitrary_go_code" + "'
);
Generated output:
InjectionInjectedarbitraryGoCode Injection = "injected" + "arbitrary_go_code" + ""
Compiles as Go string concatenation. Constant value differs from DB value.
Impact
Silent data corruption in any Go application using sqlc with PostgreSQL enum types containing backslashes. Role checks, status comparisons, and other enum-based logic fail silently. In an authorization context, if user.Role == UserRoleUsernadmin never matches, potentially granting or denying access incorrectly.
Fix:
Replace "{{.Value}}" on template.tmpl line 95 with {{printf "%q" .Value}}. Go’s %q verb properly escapes backslashes, double quotes, and non-printable characters.
Relevant log output
Database schema
SQL queries
Configuration
Playground URL
No response
What operating system are you using?
macOS
What database engines are you using?
PostgreSQL
What type of code are you generating?
Go
Version
1.31.1
What happened?
Summary
sqlc v1.31.1 and earlier versions generate Go string constants from PostgreSQL enum values without applying Go string escaping. Enum values containing backslash characters are reinterpreted as Go escape sequences, producing constants whose runtime values silently differ from the corresponding database values. Enum values containing double-quote characters produce Go string concatenation expressions that compile successfully but evaluate to incorrect values.
Details:
The Go code generation template at internal/codegen/golang/templates/template.tmpl interpolates enum values using:
The
.Valuefield comes from internal/codegen/golang/result.go, which passes the raw SQL enum string without transformation:This creates three verified impacts:
Silent semantic corruption: PostgreSQL enum value user\nadmin (literal backslash + n) generates Go constant "user\nadmin" (newline character). The 12-byte DB value becomes a 10-byte Go constant. Comparisons silently fail.
Build disruption: Enum values containing " cause go/format.Source() to reject the generated code, breaking sqlc generate.
Constant value manipulation: Enum values like injected" + "arbitrary_go_code" + " produce valid Go string concatenation that compiles with a different value.
Both SQL file parsing and database introspection (database.uri) paths are affected.
schema.sql:
query.sql:
sqlc.yaml:
Run sqlc generate. The generated go/models.go contains:
Verification:
String concatenation variant. schema.sql:
Generated output:
Compiles as Go string concatenation. Constant value differs from DB value.
Impact
Silent data corruption in any Go application using sqlc with PostgreSQL enum types containing backslashes. Role checks, status comparisons, and other enum-based logic fail silently. In an authorization context, if user.Role == UserRoleUsernadmin never matches, potentially granting or denying access incorrectly.
Fix:
Replace "{{.Value}}" on template.tmpl line 95 with {{printf "%q" .Value}}. Go’s %q verb properly escapes backslashes, double quotes, and non-printable characters.
Relevant log output
Database schema
SQL queries
Configuration
Playground URL
No response
What operating system are you using?
macOS
What database engines are you using?
PostgreSQL
What type of code are you generating?
Go