Files
upstream-mirror 0f4df23290
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
snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
2026-09-16 02:17:34 +05:00

145 lines
4.1 KiB
Go

package sqlite
import (
"strings"
meyer "github.com/sqlc-dev/meyer/ast"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
)
// identifier folds a name the way SQLite resolves one: an unquoted name is
// case-insensitive and normalizes to lower case, while a quoted name keeps
// the spelling that appeared between the quotes.
func identifier(n *meyer.Ident) string {
if n == nil {
return ""
}
if n.Quote == meyer.QuoteNone {
return strings.ToLower(n.Name)
}
return n.Name
}
// NewIdentifier returns the folded name of id as an ast.String, the shape
// sqlc uses for the parts of a ColumnRef or a function name.
func NewIdentifier(id *meyer.Ident) *ast.String {
return &ast.String{Str: identifier(id)}
}
func parseTableName(n *meyer.QualifiedName) *ast.TableName {
if n == nil {
return &ast.TableName{}
}
return &ast.TableName{
Schema: identifier(n.Schema),
Name: identifier(n.Name),
}
}
// parseRangeVar builds the relation reference sqlc expects for a table named
// in a FROM, INSERT, UPDATE or DELETE clause.
func parseRangeVar(n *meyer.QualifiedName, alias *meyer.Ident) *ast.RangeVar {
rv := &ast.RangeVar{}
if n == nil {
return rv
}
rv.Location = n.Pos()
name := identifier(n.Name)
rv.Relname = &name
if n.Schema != nil {
schema := identifier(n.Schema)
rv.Schemaname = &schema
}
if alias != nil {
aliasName := identifier(alias)
rv.Alias = &ast.Alias{Aliasname: &aliasName}
}
return rv
}
// typeName renders a type the way sqlc's type resolution expects to see it:
// the tokens joined without separators, matching what the ANTLR parser's
// GetText produced. "UNSIGNED BIG INT" becomes "UNSIGNEDBIGINT" and
// "DECIMAL(10, 5)" becomes "DECIMAL(10,5)".
func typeName(n *meyer.TypeName) string {
if n == nil {
return ""
}
var sb strings.Builder
sb.WriteString(strings.ReplaceAll(n.Name, " ", ""))
if len(n.Args) > 0 {
sb.WriteString("(")
sb.WriteString(strings.Join(n.Args, ","))
sb.WriteString(")")
}
return sb.String()
}
// typeSpelling returns the type as the author wrote it — identifier tokens
// space-joined, arguments as written — for the formatter to print back.
// typeName folds the spaces out for catalog matching.
func typeSpelling(n *meyer.TypeName) string {
if n == nil {
return ""
}
var sb strings.Builder
sb.WriteString(n.Name)
if len(n.Args) > 0 {
sb.WriteString("(")
sb.WriteString(strings.Join(n.Args, ","))
sb.WriteString(")")
}
return sb.String()
}
// representableColumn reports whether a column definition round-trips
// through the fields ast.ColumnDef models: a plain NOT NULL, a plain
// PRIMARY KEY, or nothing. Anything else — a named constraint, a conflict
// clause, ASC/DESC or AUTOINCREMENT, DEFAULT, UNIQUE, CHECK, COLLATE,
// REFERENCES, GENERATED — is parsed away, so a statement printing such a
// column would lose it. NOT NULL next to PRIMARY KEY is also beyond the
// node: SQLite's PRIMARY KEY does not imply NOT NULL, and the printed form
// carries only one of the pair.
func representableColumn(def *meyer.ColumnDef) bool {
var notNull, primary bool
for _, con := range def.Constraints {
switch {
case con.Name != nil:
return false
case con.Kind == meyer.ColumnNotNull && con.OnConflict == meyer.ConflictDefault:
notNull = true
case con.Kind == meyer.ColumnPrimaryKey && con.OnConflict == meyer.ConflictDefault &&
con.Order == meyer.SortDefault && !con.AutoIncrement:
primary = true
default:
return false
}
}
return !(notNull && primary)
}
// hasPrimaryKeyConstraint reports whether a column definition carries a
// PRIMARY KEY constraint.
func hasPrimaryKeyConstraint(constraints []*meyer.ColumnConstraint) bool {
for _, constraint := range constraints {
if constraint.Kind == meyer.ColumnPrimaryKey {
return true
}
}
return false
}
// hasNotNullConstraint reports whether a column definition guarantees a
// value. A PRIMARY KEY implies NOT NULL for the purposes of code
// generation, matching the behavior of the previous parser.
func hasNotNullConstraint(constraints []*meyer.ColumnConstraint) bool {
for _, constraint := range constraints {
switch constraint.Kind {
case meyer.ColumnNotNull, meyer.ColumnPrimaryKey:
return true
}
}
return false
}