Skip to content

Commit f758c7e

Browse files
committed
fix: human readable formatting for types
1 parent bd77a02 commit f758c7e

File tree

4 files changed

+96
-11
lines changed

4 files changed

+96
-11
lines changed

internal/compiler/compile.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Parser interface {
2424
Parse(io.Reader) ([]ast.Statement, error)
2525
CommentSyntax() source.CommentSyntax
2626
IsReservedKeyword(string) bool
27+
TypeName(ns, name string) string
2728
}
2829

2930
func (c *Compiler) parseCatalog(schemas []string) error {

internal/compiler/resolve.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,21 @@ func hasConcreteParamType(col *Column) bool {
2626
return col != nil && col.DataType != "" && col.DataType != "any"
2727
}
2828

29-
func paramTypeString(col *Column) string {
30-
if !hasConcreteParamType(col) {
31-
return "any"
32-
}
33-
return col.DataType + strings.Repeat("[]", col.ArrayDims)
29+
func (comp *Compiler) paramTypeString(col *Column) string {
30+
if !hasConcreteParamType(col) {
31+
return "any"
32+
}
33+
34+
arraySuffix := strings.Repeat("[]", col.ArrayDims)
35+
if col.Type != nil && col.Type.Name != "" {
36+
return comp.parser.TypeName(col.Type.Schema, col.Type.Name) + arraySuffix
37+
}
38+
39+
if rel, err := ParseRelationString(col.DataType); err == nil && rel.Catalog == "" {
40+
return comp.parser.TypeName(rel.Schema, rel.Name) + arraySuffix
41+
}
42+
43+
return col.DataType + arraySuffix
3444
}
3545

3646
func compatibleParamTypes(a, b *Column) bool {
@@ -81,10 +91,15 @@ func mergeResolvedParam(existing, incoming Parameter) Parameter {
8191
return base
8292
}
8393

84-
func incompatibleParamRefError(ref paramRef, existing, incoming Parameter) error {
94+
func (comp *Compiler) incompatibleParamRefError(ref paramRef, existing, incoming Parameter) error {
8595
return &sqlerr.Error{
8696
Code: "42P08",
87-
Message: fmt.Sprintf("parameter $%d has incompatible types: %s, %s", ref.ref.Number, paramTypeString(existing.Column), paramTypeString(incoming.Column)),
97+
Message: fmt.Sprintf(
98+
"parameter $%d has incompatible types: %s, %s",
99+
ref.ref.Number,
100+
comp.paramTypeString(existing.Column),
101+
comp.paramTypeString(incoming.Column),
102+
),
88103
Location: ref.ref.Location,
89104
}
90105
}
@@ -171,7 +186,7 @@ func (comp *Compiler) resolveCatalogRefs(qc *QueryCatalog, rvs []*ast.RangeVar,
171186
addParam := func(ref paramRef, p Parameter) error {
172187
if idx, ok := seen[p.Number]; ok {
173188
if !compatibleParamTypes(a[idx].Column, p.Column) {
174-
return incompatibleParamRefError(ref, a[idx], p)
189+
return comp.incompatibleParamRefError(ref, a[idx], p)
175190
}
176191
a[idx] = mergeResolvedParam(a[idx], p)
177192
return nil
@@ -381,9 +396,10 @@ func (comp *Compiler) resolveCatalogRefs(qc *QueryCatalog, rvs []*ast.RangeVar,
381396
p, isNamed := params.FetchMerge(ref.ref.Number, defaultP)
382397
var namePrefix string
383398
if !isNamed {
384-
if ref.ref == n.Left {
399+
switch ref.ref {
400+
case n.Left:
385401
namePrefix = "from_"
386-
} else if ref.ref == n.Right {
402+
case n.Right:
387403
namePrefix = "to_"
388404
}
389405
}

internal/compiler/resolve_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package compiler
2+
3+
import (
4+
"testing"
5+
6+
"github.com/sqlc-dev/sqlc/internal/engine/postgresql"
7+
"github.com/sqlc-dev/sqlc/internal/engine/sqlite"
8+
"github.com/sqlc-dev/sqlc/internal/sql/ast"
9+
"github.com/sqlc-dev/sqlc/internal/sql/sqlerr"
10+
)
11+
12+
func TestParamTypeString(t *testing.T) {
13+
t.Parallel()
14+
15+
t.Run("postgresql type aliases", func(t *testing.T) {
16+
t.Parallel()
17+
comp := &Compiler{parser: postgresql.NewParser()}
18+
19+
got := comp.paramTypeString(&Column{DataType: "pg_catalog.int4", ArrayDims: 2})
20+
if got != "integer[][]" {
21+
t.Fatalf("expected integer[][], got %q", got)
22+
}
23+
})
24+
25+
t.Run("structured type metadata is preferred", func(t *testing.T) {
26+
t.Parallel()
27+
comp := &Compiler{parser: postgresql.NewParser()}
28+
29+
got := comp.paramTypeString(&Column{
30+
DataType: "catalog.pg_catalog.int4",
31+
Type: &ast.TypeName{Schema: "pg_catalog", Name: "bpchar"},
32+
})
33+
if got != "character" {
34+
t.Fatalf("expected character, got %q", got)
35+
}
36+
})
37+
38+
t.Run("sqlite keeps names unchanged", func(t *testing.T) {
39+
t.Parallel()
40+
comp := &Compiler{parser: sqlite.NewParser()}
41+
42+
got := comp.paramTypeString(&Column{DataType: "custom_type", ArrayDims: 1})
43+
if got != "custom_type[]" {
44+
t.Fatalf("expected custom_type[], got %q", got)
45+
}
46+
})
47+
}
48+
49+
func TestIncompatibleParamRefErrorFormatsTypeNames(t *testing.T) {
50+
t.Parallel()
51+
52+
comp := &Compiler{parser: postgresql.NewParser()}
53+
err := comp.incompatibleParamRefError(paramRef{ref: &ast.ParamRef{Number: 1}}, Parameter{
54+
Number: 1,
55+
Column: &Column{DataType: "text"},
56+
}, Parameter{
57+
Number: 1,
58+
Column: &Column{DataType: "pg_catalog.int4"},
59+
})
60+
61+
sqlErr, ok := err.(*sqlerr.Error)
62+
if !ok {
63+
t.Fatalf("expected *sqlerr.Error, got %T", err)
64+
}
65+
if sqlErr.Message != "parameter $1 has incompatible types: text, integer" {
66+
t.Fatalf("unexpected message: %q", sqlErr.Message)
67+
}
68+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# package querytest
2-
query.sql:5:10: parameter $1 has incompatible types: text, integer
2+
query.sql:5:10: parameter $1 has incompatible types: text, integer

0 commit comments

Comments
 (0)