@@ -32,6 +32,30 @@ WHERE n.nspname OPERATOR(pg_catalog.~) '^(pg_catalog)$'
3232ORDER 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+
70102func {{.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
117179type 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
123186func 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+
176292func 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