snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
This commit is contained in:
99
internal/goldeneye/mysql/relations.go
Normal file
99
internal/goldeneye/mysql/relations.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/sqlc-dev/sqlc/internal/goldeneye/dialect"
|
||||
)
|
||||
|
||||
// systemSchemas are the schemas whose relations are generated: the data
|
||||
// dictionary's views, which are what a query of the server's catalog
|
||||
// reads. The other schemas mysqld --initialize creates — mysql,
|
||||
// performance_schema and sys — are tables rather than views, and every
|
||||
// table a dialect seeds is one the analysis core hands codegen as a model,
|
||||
// so they wait until codegen knows a system schema when it sees one.
|
||||
var systemSchemas = []string{
|
||||
"information_schema",
|
||||
}
|
||||
|
||||
// relationQuery lists a schema's relations and their columns, in the order
|
||||
// the columns were declared, so that the output is stable.
|
||||
const relationQuery = `
|
||||
SELECT t.TABLE_NAME, t.TABLE_TYPE,
|
||||
c.COLUMN_NAME, c.DATA_TYPE, c.COLUMN_TYPE, c.IS_NULLABLE
|
||||
FROM information_schema.TABLES t
|
||||
JOIN information_schema.COLUMNS c
|
||||
ON c.TABLE_SCHEMA = t.TABLE_SCHEMA AND c.TABLE_NAME = t.TABLE_NAME
|
||||
WHERE t.TABLE_SCHEMA = ?
|
||||
ORDER BY t.TABLE_NAME, c.ORDINAL_POSITION`
|
||||
|
||||
// readRelations reads a schema's tables and views. Their names are written
|
||||
// in lower case: information_schema names its views in upper case and
|
||||
// matches them in any case, MySQL matches every column name in any case,
|
||||
// and sqlc's MySQL parser lowercases every identifier, so lower case is
|
||||
// how a query reaches them. A column's type is spelled the way a
|
||||
// declaration does, as COLUMN_TYPE reports it, arguments and UNSIGNED
|
||||
// included: varchar(64), bigint unsigned.
|
||||
func readRelations(ctx context.Context, conn *sql.Conn, schema string) ([]dialect.Relation, error) {
|
||||
rows, err := conn.QueryContext(ctx, relationQuery, schema)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", schema, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
var relations []dialect.Relation
|
||||
var cur *dialect.Relation
|
||||
for rows.Next() {
|
||||
var name, kind, colName, dataType, columnType, nullable string
|
||||
if err := rows.Scan(&name, &kind, &colName, &dataType, &columnType, &nullable); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name = strings.ToLower(name)
|
||||
if cur == nil || cur.Name != name {
|
||||
rel := dialect.Relation{Catalog: "def", Schema: schema, Name: name}
|
||||
if kind != "BASE TABLE" {
|
||||
rel.Kind = "v"
|
||||
}
|
||||
relations = append(relations, rel)
|
||||
cur = &relations[len(relations)-1]
|
||||
}
|
||||
cur.Columns = append(cur.Columns, dialect.Column{
|
||||
Name: strings.ToLower(colName),
|
||||
Type: typeName(dataType, columnType),
|
||||
NotNull: nullable == "NO",
|
||||
})
|
||||
}
|
||||
return relations, rows.Err()
|
||||
}
|
||||
|
||||
// typeName spells a column's type the way a declaration does, which is
|
||||
// COLUMN_TYPE as information_schema reports it: "varchar(64)", "bigint
|
||||
// unsigned", "enum('a','b')". The family is spelled in lower case; the
|
||||
// members of an enum or set are values and keep theirs.
|
||||
func typeName(dataType, columnType string) string {
|
||||
if columnType == "" {
|
||||
return strings.ToLower(dataType)
|
||||
}
|
||||
var out strings.Builder
|
||||
quoted := false
|
||||
for i := 0; i < len(columnType); i++ {
|
||||
c := columnType[i]
|
||||
switch {
|
||||
case quoted && c == '\\' && i+1 < len(columnType):
|
||||
out.WriteByte(c)
|
||||
i++
|
||||
out.WriteByte(columnType[i])
|
||||
continue
|
||||
case c == '\'':
|
||||
quoted = !quoted
|
||||
}
|
||||
if quoted {
|
||||
out.WriteByte(c)
|
||||
} else {
|
||||
out.WriteString(strings.ToLower(string(c)))
|
||||
}
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
Reference in New Issue
Block a user