Skip to content

Commit 3e4c623

Browse files
committed
pg-gen: add tables from pg_tables and pg_views
1 parent 8618c39 commit 3e4c623

File tree

1 file changed

+132
-4
lines changed

1 file changed

+132
-4
lines changed

internal/tools/sqlc-pg-gen/main.go

Lines changed: 132 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@ WHERE n.nspname OPERATOR(pg_catalog.~) '^(pg_catalog)$'
3232
ORDER BY 1;
3333
`
3434

35+
// Relations are the relations available in pg_tables and pg_views
36+
// such as pg_catalog.pg_timezone_names
37+
const relations = `
38+
with relations as (
39+
select schemaname, tablename as name from pg_catalog.pg_tables
40+
UNION ALL
41+
select schemaname, viewname as name from pg_catalog.pg_views
42+
)
43+
select
44+
relations.schemaname,
45+
relations.name as tablename,
46+
pg_attribute.attname as column_name,
47+
attnotnull as column_notnull,
48+
column_type.typname as column_type,
49+
nullif(column_type.typlen, -1) as column_length,
50+
column_type.typcategory = 'A' as column_isarray
51+
from relations
52+
inner join pg_catalog.pg_class on pg_class.relname = relations.name
53+
left join pg_catalog.pg_attribute on pg_attribute.attrelid = pg_class.oid
54+
inner join pg_catalog.pg_type column_type on pg_attribute.atttypid = column_type.oid
55+
where relations.schemaname = 'pg_catalog'
56+
order by relations.schemaname ASC, relations.name ASC
57+
`
58+
3559
// https://dba.stackexchange.com/questions/255412/how-to-select-functions-that-belong-in-a-given-extension-in-postgresql
3660
//
3761
// Extension functions are added to the public schema
@@ -67,6 +91,14 @@ import (
6791
"github.com/kyleconroy/sqlc/internal/sql/catalog"
6892
)
6993
94+
{{- if .Tables }}
95+
// toPointer converts an int to a pointer without a temporary
96+
// variable at the call-site
97+
func toPointer(x int) *int {
98+
return &x;
99+
}
100+
{{- end }}
101+
70102
func {{.Name}}() *catalog.Schema {
71103
s := &catalog.Schema{Name: "pg_catalog"}
72104
s.Funcs = []*catalog.Function{
@@ -89,6 +121,36 @@ func {{.Name}}() *catalog.Schema {
89121
},
90122
{{- end}}
91123
}
124+
{{- if .Tables }}
125+
s.Tables = []*catalog.Table {
126+
{{- range .Tables}}
127+
{
128+
Rel: &ast.TableName{
129+
Catalog: "{{.Rel.Catalog}}",
130+
Schema: "{{.Rel.Schema}}",
131+
Name: "{{.Rel.Name}}",
132+
},
133+
Columns: []*catalog.Column{
134+
{{- range .Columns}}
135+
{
136+
Name: "{{.Name}}",
137+
Type: ast.TypeName{Name: "{{.Type.Name}}"},
138+
{{- if .IsNotNull}}
139+
IsNotNull: true,
140+
{{- end}}
141+
{{- if .IsArray}}
142+
IsArray: true,
143+
{{- end}}
144+
{{- if .Length }}
145+
Length: toPointer({{ .Length }}),
146+
{{- end}}
147+
},
148+
{{- end}}
149+
},
150+
},
151+
{{- end}}
152+
}
153+
{{- end }}
92154
return s
93155
}
94156
`
@@ -115,9 +177,10 @@ func loadExtension(name string) *catalog.Schema {
115177
`
116178

117179
type tmplCtx struct {
118-
Pkg string
119-
Name string
120-
Funcs []catalog.Function
180+
Pkg string
181+
Name string
182+
Funcs []catalog.Function
183+
Tables []catalog.Table
121184
}
122185

123186
func main() {
@@ -173,6 +236,59 @@ func (p Proc) Args() []*catalog.Argument {
173236
return args
174237
}
175238

239+
func scanTables(rows pgx.Rows) ([]catalog.Table, error) {
240+
defer rows.Close()
241+
// Iterate through the result set
242+
var tables []catalog.Table
243+
var prevTable *catalog.Table
244+
245+
for rows.Next() {
246+
var schemaName string
247+
var tableName string
248+
var columnName string
249+
var columnNotNull bool
250+
var columnType string
251+
var columnLength *int
252+
var columnIsArray bool
253+
err := rows.Scan(
254+
&schemaName,
255+
&tableName,
256+
&columnName,
257+
&columnNotNull,
258+
&columnType,
259+
&columnLength,
260+
&columnIsArray,
261+
)
262+
if err != nil {
263+
return nil, err
264+
}
265+
266+
if prevTable == nil || tableName != prevTable.Rel.Name {
267+
// We are on the same table, just keep adding columns
268+
t := catalog.Table{
269+
Rel: &ast.TableName{
270+
Catalog: "pg_catalog",
271+
Schema: schemaName,
272+
Name: tableName,
273+
},
274+
}
275+
276+
tables = append(tables, t)
277+
prevTable = &tables[len(tables)-1]
278+
}
279+
280+
prevTable.Columns = append(prevTable.Columns, &catalog.Column{
281+
Name: columnName,
282+
Type: ast.TypeName{Name: columnType},
283+
IsNotNull: columnNotNull,
284+
IsArray: columnIsArray,
285+
Length: columnLength,
286+
})
287+
}
288+
289+
return tables, rows.Err()
290+
}
291+
176292
func scanFuncs(rows pgx.Rows) ([]catalog.Function, error) {
177293
defer rows.Close()
178294
// Iterate through the result set
@@ -238,12 +354,24 @@ func run(ctx context.Context) error {
238354
if err != nil {
239355
return err
240356
}
357+
241358
funcs, err := scanFuncs(rows)
242359
if err != nil {
243360
return err
244361
}
362+
363+
rows, err = conn.Query(ctx, relations)
364+
if err != nil {
365+
return err
366+
}
367+
368+
tables, err := scanTables(rows)
369+
if err != nil {
370+
return err
371+
}
372+
245373
out := bytes.NewBuffer([]byte{})
246-
if err := tmpl.Execute(out, tmplCtx{Pkg: "postgresql", Name: "genPGCatalog", Funcs: funcs}); err != nil {
374+
if err := tmpl.Execute(out, tmplCtx{Pkg: "postgresql", Name: "genPGCatalog", Funcs: funcs, Tables: tables}); err != nil {
247375
return err
248376
}
249377
code, err := format.Source(out.Bytes())

0 commit comments

Comments
 (0)