Skip to content

Commit afea9bc

Browse files
kyleconroyclaude
andcommitted
core: migrate all catalog queries to sqlc-generated code
Sweep the remaining hand-written SQL against the sql_* catalog tables onto the generated catalogdb layer, completing the conversion started in the types.go/FindProcs slice. Namespace, dialect, type, class, attribute, constraint, proc, operator, and cast queries now all run through catalogdb.Queries. Notable rewrites: - FindOperators: the conditionally-appended type filters become a single static query using (@arg = 0 OR col = @arg) sentinels. - Nullable OID columns round-trip through sql.NullInt64 (orZero maps NULL to the 0 sentinel the Go API uses). - New typed catalog accessors back the cross-package call sites that previously reached into the raw handle: DropClass (ClickHouse DROP TABLE), ClassColumns (analyzer scope), and Namespaces / TablesInNamespace / ClassCodegenColumns (codegen catalog projection). Only the schema bootstrap (db.Exec(ddl)) and the DB()/Close() handles remain as raw database/sql; every catalog query is now sqlc-generated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XTGxNHW6v1S1YyC9FDSgrK
1 parent 1241e59 commit afea9bc

14 files changed

Lines changed: 1296 additions & 294 deletions

File tree

internal/cmd/shim.go

Lines changed: 21 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -244,67 +244,41 @@ func codeGenRequest(r *compiler.Result, settings config.CombinedSettings) *plugi
244244

245245
// pluginCatalogFromCore projects a core.Catalog (the xqlc SQLite-backed
246246
// catalog) into the plugin.Catalog that codegen consumes to emit models
247-
// and enums. It reads the namespace / class / attribute / type tables
248-
// directly. Projection is best-effort: an unexpected query error against
249-
// the in-memory catalog yields a partial catalog rather than aborting
250-
// generation.
247+
// and enums. It reads through the catalog's typed accessors, which are
248+
// backed by sqlc-generated queries. Projection is best-effort: an
249+
// unexpected error against the in-memory catalog yields a partial catalog
250+
// rather than aborting generation.
251251
func pluginCatalogFromCore(cc *core.Catalog) *plugin.Catalog {
252-
db := cc.DB()
253252
var schemas []*plugin.Schema
254253

255-
type row struct {
256-
oid int64
257-
name string
254+
namespaces, err := cc.Namespaces()
255+
if err != nil {
256+
return &plugin.Catalog{DefaultSchema: "public"}
258257
}
259-
readRows := func(query string, args ...any) []row {
260-
rows, err := db.Query(query, args...)
258+
for _, ns := range namespaces {
259+
tables, err := cc.TablesInNamespace(ns.OID)
261260
if err != nil {
262-
return nil
263-
}
264-
defer rows.Close()
265-
var out []row
266-
for rows.Next() {
267-
var r row
268-
if err := rows.Scan(&r.oid, &r.name); err != nil {
269-
return out
270-
}
271-
out = append(out, r)
261+
continue
272262
}
273-
return out
274-
}
275-
276-
for _, ns := range readRows(`SELECT oid, name FROM sql_namespace ORDER BY oid`) {
277-
var tables []*plugin.Table
278-
for _, cl := range readRows(
279-
`SELECT oid, name FROM sql_class WHERE namespace_oid = ? AND kind = 'r' ORDER BY oid`, ns.oid,
280-
) {
281-
rel := &plugin.Identifier{Schema: ns.name, Name: cl.name}
282-
var columns []*plugin.Column
283-
crows, err := db.Query(
284-
`SELECT a.name, t.name, a.not_null
285-
FROM sql_attribute a JOIN sql_type t ON t.oid = a.type_oid
286-
WHERE a.class_oid = ? ORDER BY a.num`, cl.oid,
287-
)
263+
var ptables []*plugin.Table
264+
for _, cl := range tables {
265+
rel := &plugin.Identifier{Schema: ns.Name, Name: cl.Name}
266+
cols, err := cc.ClassCodegenColumns(cl.OID)
288267
if err != nil {
289268
continue
290269
}
291-
for crows.Next() {
292-
var name, typeName string
293-
var notNull int
294-
if err := crows.Scan(&name, &typeName, &notNull); err != nil {
295-
break
296-
}
270+
var columns []*plugin.Column
271+
for _, col := range cols {
297272
columns = append(columns, &plugin.Column{
298-
Name: name,
299-
Type: &plugin.Identifier{Name: typeName},
300-
NotNull: notNull != 0,
273+
Name: col.Name,
274+
Type: &plugin.Identifier{Name: col.TypeName},
275+
NotNull: col.NotNull,
301276
Table: rel,
302277
})
303278
}
304-
crows.Close()
305-
tables = append(tables, &plugin.Table{Rel: rel, Columns: columns})
279+
ptables = append(ptables, &plugin.Table{Rel: rel, Columns: columns})
306280
}
307-
schemas = append(schemas, &plugin.Schema{Name: ns.name, Tables: tables})
281+
schemas = append(schemas, &plugin.Schema{Name: ns.Name, Tables: ptables})
308282
}
309283

310284
return &plugin.Catalog{

internal/core/analyzer/scope.go

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -102,30 +102,25 @@ func (a *analyzer) bindRangeVar(rv *ast.RangeVar) (scopeRel, error) {
102102
return rel, nil
103103
}
104104

105-
// classColumns reads the column layout of a relation directly from
106-
// sql_attribute. We can't go through TableColumns because that resolves
107-
// by name and doesn't return attribute OIDs.
105+
// classColumns reads the column layout of a relation by class OID. It
106+
// goes through the catalog's ClassColumns accessor (backed by a
107+
// sqlc-generated query) rather than TableColumns, because it needs the
108+
// attribute OIDs and resolves by OID rather than by name.
108109
func (a *analyzer) classColumns(classOID int64) ([]scopeCol, error) {
109-
rows, err := a.cat.DB().Query(
110-
`SELECT a.oid, a.name, a.type_oid, a.not_null
111-
FROM sql_attribute a WHERE a.class_oid = ? ORDER BY a.num`,
112-
classOID,
113-
)
110+
cols, err := a.cat.ClassColumns(classOID)
114111
if err != nil {
115112
return nil, err
116113
}
117-
defer rows.Close()
118-
var out []scopeCol
119-
for rows.Next() {
120-
var c scopeCol
121-
var nn int
122-
if err := rows.Scan(&c.attOID, &c.name, &c.typeOID, &nn); err != nil {
123-
return nil, err
124-
}
125-
c.notNull = nn != 0
126-
out = append(out, c)
114+
out := make([]scopeCol, 0, len(cols))
115+
for _, c := range cols {
116+
out = append(out, scopeCol{
117+
name: c.Name,
118+
attOID: c.AttOID,
119+
typeOID: c.TypeOID,
120+
notNull: c.NotNull,
121+
})
127122
}
128-
return out, rows.Err()
123+
return out, nil
129124
}
130125

131126
// resolveColumn locates a (relation, column) pair in the scope.

0 commit comments

Comments
 (0)