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

This commit is contained in:
upstream-mirror
2026-09-16 02:17:34 +05:00
commit 0f4df23290
7340 changed files with 238743 additions and 0 deletions

View File

@@ -0,0 +1,233 @@
package analyzer
import (
"context"
"fmt"
"strings"
"sync"
"github.com/ncruces/go-sqlite3"
core "github.com/sqlc-dev/sqlc/internal/analysis"
"github.com/sqlc-dev/sqlc/internal/config"
"github.com/sqlc-dev/sqlc/internal/shfmt"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
"github.com/sqlc-dev/sqlc/internal/sql/named"
"github.com/sqlc-dev/sqlc/internal/sql/sqlerr"
"github.com/sqlc-dev/sqlc/internal/sqlcdebug"
_ "github.com/sqlc-dev/sqlc/internal/sqlite3ext"
)
var debugDatabases = sqlcdebug.New("databases")
type Analyzer struct {
db config.Database
conn *sqlite3.Conn
replacer *shfmt.Replacer
mu sync.Mutex
}
func New(db config.Database) *Analyzer {
return &Analyzer{
db: db,
replacer: shfmt.NewReplacer(nil),
}
}
func (a *Analyzer) Analyze(ctx context.Context, n ast.Node, query string, migrations []string, ps *named.ParamSet) (*core.Analysis, error) {
a.mu.Lock()
defer a.mu.Unlock()
if a.conn == nil {
var uri string
applyMigrations := a.db.Managed
if a.db.Managed {
// For managed databases, create an in-memory database
uri = ":memory:"
} else if debugDatabases.Value() == "managed" {
return nil, fmt.Errorf("database: connections disabled via SQLCDEBUG=databases=managed")
} else {
uri = a.replacer.Replace(a.db.URI)
// For in-memory databases, we need to apply migrations since the database starts empty
if isInMemoryDatabase(uri) {
applyMigrations = true
}
}
conn, err := sqlite3.Open(uri)
if err != nil {
return nil, fmt.Errorf("failed to open sqlite database: %w", err)
}
a.conn = conn
// Apply migrations for managed or in-memory databases
if applyMigrations {
for _, m := range migrations {
if len(strings.TrimSpace(m)) == 0 {
continue
}
if err := a.conn.Exec(m); err != nil {
a.conn.Close()
a.conn = nil
return nil, fmt.Errorf("migration failed: %s: %w", m, err)
}
}
}
}
// Prepare the statement to get column and parameter information
stmt, _, err := a.conn.Prepare(query)
if err != nil {
return nil, a.extractSqlErr(n, err)
}
defer stmt.Close()
var result core.Analysis
// Get column information
colCount := stmt.ColumnCount()
for i := range colCount {
name := stmt.ColumnName(i)
declType := stmt.ColumnDeclType(i)
dbName := stmt.ColumnDatabaseName(i)
tableName := stmt.ColumnTableName(i)
originName := stmt.ColumnOriginName(i)
// Determine if column is NOT NULL
var notNull bool
var dataType string
if originName != "" {
declType, _, notNull, _, _, _ = a.conn.TableColumnMetadata(
dbName, tableName, originName)
}
// Normalize the data type
dataType = normalizeType(declType)
col := &core.Column{
Name: name,
OriginalName: originName,
DataType: dataType,
NotNull: notNull,
}
if tableName != "" {
col.Table = &core.Identifier{
Schema: dbName,
Name: tableName,
}
}
result.Columns = append(result.Columns, col)
}
// Get parameter information
bindCount := stmt.BindCount()
for i := 1; i <= bindCount; i++ {
paramName := stmt.BindName(i)
// SQLite doesn't provide parameter types from prepared statements
// We use "any" as the default type
name := ""
if paramName != "" {
// Remove the prefix (?, :, @, $) from parameter names
name = strings.TrimLeft(paramName, "?:@$")
}
if ps != nil {
if n, ok := ps.NameFor(i); ok {
name = n
}
}
result.Params = append(result.Params, &core.Parameter{
Number: int32(i),
Column: &core.Column{
Name: name,
DataType: "any",
NotNull: false,
},
})
}
return &result, nil
}
func (a *Analyzer) extractSqlErr(n ast.Node, err error) error {
if err == nil {
return nil
}
// Try to extract SQLite error details
var sqliteErr *sqlite3.Error
if e, ok := err.(*sqlite3.Error); ok {
sqliteErr = e
}
if sqliteErr != nil {
return &sqlerr.Error{
Code: fmt.Sprintf("%d", sqliteErr.Code()),
Message: sqliteErr.Error(),
Location: n.Pos(),
}
}
return &sqlerr.Error{
Message: err.Error(),
Location: n.Pos(),
}
}
func (a *Analyzer) Close(_ context.Context) error {
a.mu.Lock()
defer a.mu.Unlock()
if a.conn != nil {
err := a.conn.Close()
a.conn = nil
return err
}
return nil
}
// isInMemoryDatabase checks if a SQLite URI refers to an in-memory database
func isInMemoryDatabase(uri string) bool {
if uri == ":memory:" || uri == "" {
return true
}
// Check for file URI with mode=memory parameter
// e.g., "file:test?mode=memory&cache=shared"
if strings.Contains(uri, "mode=memory") {
return true
}
return false
}
// normalizeType converts SQLite type declarations to standard type names
func normalizeType(declType string) string {
if declType == "" {
return "any"
}
// Convert to lowercase for comparison
lower := strings.ToLower(declType)
// SQLite type affinity rules (https://www.sqlite.org/datatype3.html)
switch {
case strings.Contains(lower, "int"):
return "integer"
case strings.Contains(lower, "char"),
strings.Contains(lower, "clob"),
strings.Contains(lower, "text"):
return "text"
case strings.Contains(lower, "blob"):
return "blob"
case strings.Contains(lower, "real"),
strings.Contains(lower, "floa"),
strings.Contains(lower, "doub"):
return "real"
case strings.Contains(lower, "bool"):
return "boolean"
case strings.Contains(lower, "date"),
strings.Contains(lower, "time"):
return "datetime"
default:
// Return as-is for numeric or other types
return lower
}
}

View File

@@ -0,0 +1,15 @@
package sqlite
import "github.com/sqlc-dev/sqlc/internal/sql/catalog"
func NewCatalog() *catalog.Catalog {
def := "main"
return &catalog.Catalog{
DefaultSchema: def,
Schemas: []*catalog.Schema{
defaultSchema(def),
},
LoadExtension: loadExtension,
Extensions: map[string]struct{}{},
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
{
"dialect": "sqlite",
"alias": "base",
"const": {
"integer": "integer",
"float": "real",
"string": "text",
"bool": "boolean"
},
"bool": "boolean",
"comparison": ["=", "==", "<>", "!=", "<", "<=", ">", ">=", "IS", "IS NOT", "LIKE", "NOT LIKE", "GLOB", "NOT GLOB", "REGEXP", "NOT REGEXP", "MATCH", "NOT MATCH"],
"comparison_categories": "BNSDU",
"arithmetic": ["+", "-", "*", "/", "%"],
"arithmetic_categories": "N",
"cast_categories": "*",
"modules": {
"fts3": "enable_fts3",
"fts4": "enable_fts3",
"fts5": "enable_fts5",
"geopoly": "enable_geopoly",
"rtree": "enable_rtree",
"rtree_i32": "enable_rtree"
},
"affinity": [
{
"contains": ["INT"],
"type": "integer"
},
{
"contains": ["CHAR", "CLOB", "TEXT"],
"type": "text"
},
{
"contains": ["BLOB"],
"type": "blob"
},
{
"contains": ["REAL", "FLOA", "DOUB"],
"type": "real"
},
{
"type": "numeric"
}
]
}

View File

@@ -0,0 +1,5 @@
{"name":"matchinfo","args":[{"type":"any"}],"returns":"blob"}
{"name":"matchinfo","args":[{"type":"any"},{"type":"text"}],"returns":"blob"}
{"name":"offsets","args":[{"type":"any"}],"returns":"text"}
{"name":"optimize","args":[{"type":"any"}],"returns":"text"}
{"name":"snippet","args":[{"type":"any","has_default":true},{"type":"any","has_default":true},{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"integer","has_default":true},{"type":"integer","has_default":true},{"type":"any","mode":"v"}],"returns":"text"}

View File

@@ -0,0 +1,7 @@
{"name":"bm25","args":[{"type":"any","has_default":true},{"type":"real","mode":"v"}],"returns":"real"}
{"name":"fts5_get_locale","args":[{"type":"any","has_default":true},{"type":"integer","has_default":true},{"type":"any","mode":"v"}],"returns":"text","nullable":true}
{"name":"fts5_insttoken","args":[{"type":"any"}],"returns":"any"}
{"name":"fts5_locale","args":[{"type":"text"},{"type":"text"}],"returns":"text"}
{"name":"fts5_source_id","returns":"text"}
{"name":"highlight","args":[{"type":"any","has_default":true},{"type":"integer","has_default":true},{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"}
{"name":"snippet","args":[{"type":"any","has_default":true},{"type":"any","has_default":true},{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"integer","has_default":true},{"type":"integer","has_default":true},{"type":"any","mode":"v"}],"returns":"text"}

View File

@@ -0,0 +1,15 @@
{"name":"geopoly_area","args":[{"type":"any"}],"returns":"real","nullable":true}
{"name":"geopoly_bbox","args":[{"type":"any"}],"returns":"blob","nullable":true}
{"name":"geopoly_blob","args":[{"type":"any"}],"returns":"blob","nullable":true}
{"name":"geopoly_ccw","args":[{"type":"any"}],"returns":"blob","nullable":true}
{"name":"geopoly_contains_point","args":[{"type":"any"},{"type":"real"},{"type":"real"}],"returns":"integer","nullable":true}
{"name":"geopoly_group_bbox","kind":"a","args":[{"type":"any"}],"returns":"blob","nullable":true}
{"name":"geopoly_json","args":[{"type":"any"}],"returns":"text","nullable":true}
{"name":"geopoly_overlap","args":[{"type":"any"},{"type":"any"}],"returns":"integer","nullable":true}
{"name":"geopoly_regular","args":[{"type":"real"},{"type":"real"},{"type":"real"},{"type":"integer"}],"returns":"blob"}
{"name":"geopoly_svg","args":[{"type":"text","mode":"v"}],"returns":"text","nullable":true}
{"name":"geopoly_within","args":[{"type":"any"},{"type":"any"}],"returns":"integer","nullable":true}
{"name":"geopoly_xform","args":[{"type":"any"},{"type":"real"},{"type":"real"},{"type":"real"},{"type":"real"},{"type":"real"},{"type":"real"}],"returns":"blob","nullable":true}
{"name":"rtreecheck","args":[{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"}
{"name":"rtreedepth","args":[{"type":"blob"}],"returns":"integer"}
{"name":"rtreenode","args":[{"type":"integer"},{"type":"blob"}],"returns":"text"}

View File

@@ -0,0 +1 @@
{"name":"sqlite_offset","args":[{"type":"any"}],"returns":"integer","nullable":true}

View File

@@ -0,0 +1,4 @@
{"name":"median","kind":"a","args":[{"type":"real"}],"returns":"real","nullable":true}
{"name":"percentile","kind":"a","args":[{"type":"real"},{"type":"real"}],"returns":"real","nullable":true}
{"name":"percentile_cont","kind":"a","args":[{"type":"real"},{"type":"real"}],"returns":"real","nullable":true}
{"name":"percentile_disc","kind":"a","args":[{"type":"real"},{"type":"real"}],"returns":"real","nullable":true}

View File

@@ -0,0 +1,3 @@
{"name":"rtreecheck","args":[{"type":"text","has_default":true},{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"}
{"name":"rtreedepth","args":[{"type":"blob"}],"returns":"integer"}
{"name":"rtreenode","args":[{"type":"integer"},{"type":"blob"}],"returns":"text"}

View File

@@ -0,0 +1 @@
{"name":"soundex","args":[{"type":"text"}],"returns":"text"}

View File

@@ -0,0 +1,236 @@
{"name":"-\u003e","args":[{"type":"any"},{"type":"any"}],"returns":"text","nullable":true}
{"name":"-\u003e\u003e","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true}
{"name":"abs","args":[{"type":"any"}],"returns":"real"}
{"name":"abs","args":[{"type":"integer"}],"returns":"integer"}
{"name":"abs","args":[{"type":"int"}],"returns":"integer"}
{"name":"abs","args":[{"type":"tinyint"}],"returns":"integer"}
{"name":"abs","args":[{"type":"smallint"}],"returns":"integer"}
{"name":"abs","args":[{"type":"mediumint"}],"returns":"integer"}
{"name":"abs","args":[{"type":"bigint"}],"returns":"integer"}
{"name":"abs","args":[{"type":"unsigned big int"}],"returns":"integer"}
{"name":"abs","args":[{"type":"int2"}],"returns":"integer"}
{"name":"abs","args":[{"type":"int8"}],"returns":"integer"}
{"name":"abs","args":[{"type":"real"}],"returns":"real"}
{"name":"abs","args":[{"type":"double"}],"returns":"real"}
{"name":"abs","args":[{"type":"double precision"}],"returns":"real"}
{"name":"abs","args":[{"type":"float"}],"returns":"real"}
{"name":"acos","args":[{"type":"real"}],"returns":"real"}
{"name":"acosh","args":[{"type":"real"}],"returns":"real"}
{"name":"asin","args":[{"type":"real"}],"returns":"real"}
{"name":"asinh","args":[{"type":"real"}],"returns":"real"}
{"name":"atan","args":[{"type":"real"}],"returns":"real"}
{"name":"atan2","args":[{"type":"real"},{"type":"real"}],"returns":"real"}
{"name":"atanh","args":[{"type":"real"}],"returns":"real"}
{"name":"avg","kind":"a","args":[{"type":"any"}],"returns":"real","nullable":true}
{"name":"ceil","args":[{"type":"any"}],"returns":"real"}
{"name":"ceil","args":[{"type":"integer"}],"returns":"integer"}
{"name":"ceil","args":[{"type":"int"}],"returns":"integer"}
{"name":"ceil","args":[{"type":"tinyint"}],"returns":"integer"}
{"name":"ceil","args":[{"type":"smallint"}],"returns":"integer"}
{"name":"ceil","args":[{"type":"mediumint"}],"returns":"integer"}
{"name":"ceil","args":[{"type":"bigint"}],"returns":"integer"}
{"name":"ceil","args":[{"type":"unsigned big int"}],"returns":"integer"}
{"name":"ceil","args":[{"type":"int2"}],"returns":"integer"}
{"name":"ceil","args":[{"type":"int8"}],"returns":"integer"}
{"name":"ceil","args":[{"type":"real"}],"returns":"real"}
{"name":"ceil","args":[{"type":"double"}],"returns":"real"}
{"name":"ceil","args":[{"type":"double precision"}],"returns":"real"}
{"name":"ceil","args":[{"type":"float"}],"returns":"real"}
{"name":"ceiling","args":[{"type":"any"}],"returns":"real"}
{"name":"ceiling","args":[{"type":"integer"}],"returns":"integer"}
{"name":"ceiling","args":[{"type":"int"}],"returns":"integer"}
{"name":"ceiling","args":[{"type":"tinyint"}],"returns":"integer"}
{"name":"ceiling","args":[{"type":"smallint"}],"returns":"integer"}
{"name":"ceiling","args":[{"type":"mediumint"}],"returns":"integer"}
{"name":"ceiling","args":[{"type":"bigint"}],"returns":"integer"}
{"name":"ceiling","args":[{"type":"unsigned big int"}],"returns":"integer"}
{"name":"ceiling","args":[{"type":"int2"}],"returns":"integer"}
{"name":"ceiling","args":[{"type":"int8"}],"returns":"integer"}
{"name":"ceiling","args":[{"type":"real"}],"returns":"real"}
{"name":"ceiling","args":[{"type":"double"}],"returns":"real"}
{"name":"ceiling","args":[{"type":"double precision"}],"returns":"real"}
{"name":"ceiling","args":[{"type":"float"}],"returns":"real"}
{"name":"changes","returns":"integer"}
{"name":"char","args":[{"type":"integer","mode":"v"}],"returns":"text"}
{"name":"coalesce","args":[{"type":"any"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"}
{"name":"concat","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"text"}
{"name":"concat_ws","args":[{"type":"text"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"text"}
{"name":"cos","args":[{"type":"real"}],"returns":"real"}
{"name":"cosh","args":[{"type":"real"}],"returns":"real"}
{"name":"count","kind":"a","returns":"integer"}
{"name":"count","kind":"a","args":[{"type":"any"}],"returns":"integer"}
{"name":"cume_dist","kind":"w","returns":"real"}
{"name":"current_date","returns":"text"}
{"name":"current_time","returns":"text"}
{"name":"current_timestamp","returns":"text"}
{"name":"date","args":[{"type":"any","mode":"v"}],"returns":"text","nullable":true}
{"name":"datetime","args":[{"type":"any","mode":"v"}],"returns":"text","nullable":true}
{"name":"degrees","args":[{"type":"real"}],"returns":"real"}
{"name":"dense_rank","kind":"w","returns":"integer"}
{"name":"exp","args":[{"type":"real"}],"returns":"real"}
{"name":"first_value","kind":"w","args":[{"type":"any"}],"returns":"any","nullable":true}
{"name":"floor","args":[{"type":"any"}],"returns":"real"}
{"name":"floor","args":[{"type":"integer"}],"returns":"integer"}
{"name":"floor","args":[{"type":"int"}],"returns":"integer"}
{"name":"floor","args":[{"type":"tinyint"}],"returns":"integer"}
{"name":"floor","args":[{"type":"smallint"}],"returns":"integer"}
{"name":"floor","args":[{"type":"mediumint"}],"returns":"integer"}
{"name":"floor","args":[{"type":"bigint"}],"returns":"integer"}
{"name":"floor","args":[{"type":"unsigned big int"}],"returns":"integer"}
{"name":"floor","args":[{"type":"int2"}],"returns":"integer"}
{"name":"floor","args":[{"type":"int8"}],"returns":"integer"}
{"name":"floor","args":[{"type":"real"}],"returns":"real"}
{"name":"floor","args":[{"type":"double"}],"returns":"real"}
{"name":"floor","args":[{"type":"double precision"}],"returns":"real"}
{"name":"floor","args":[{"type":"float"}],"returns":"real"}
{"name":"format","args":[{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"}
{"name":"glob","args":[{"type":"text"},{"type":"text"}],"returns":"integer"}
{"name":"group_concat","kind":"a","args":[{"type":"text"}],"returns":"text","nullable":true}
{"name":"group_concat","kind":"a","args":[{"type":"text"},{"type":"text"}],"returns":"text","nullable":true}
{"name":"hex","args":[{"type":"blob"}],"returns":"text"}
{"name":"if","args":[{"type":"any"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"}
{"name":"ifnull","args":[{"type":"any"},{"type":"any"}],"returns":"any"}
{"name":"iif","args":[{"type":"any"},{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"}
{"name":"instr","args":[{"type":"any"},{"type":"any"}],"returns":"integer"}
{"name":"json","args":[{"type":"any"}],"returns":"text"}
{"name":"json_array","args":[{"type":"any","mode":"v"}],"returns":"text"}
{"name":"json_array_insert","args":[{"type":"any","mode":"v"}],"returns":"text"}
{"name":"json_array_length","args":[{"type":"any"}],"returns":"integer","nullable":true}
{"name":"json_array_length","args":[{"type":"any"},{"type":"text"}],"returns":"integer","nullable":true}
{"name":"json_error_position","args":[{"type":"text"}],"returns":"integer"}
{"name":"json_extract","args":[{"type":"text","mode":"v"}],"returns":"any","nullable":true}
{"name":"json_group_array","kind":"a","args":[{"type":"any"}],"returns":"text"}
{"name":"json_group_object","kind":"a","args":[{"type":"text"},{"type":"any"}],"returns":"text"}
{"name":"json_insert","args":[{"type":"any","mode":"v"}],"returns":"text"}
{"name":"json_object","args":[{"type":"text","mode":"v"}],"returns":"text"}
{"name":"json_patch","args":[{"type":"any"},{"type":"any"}],"returns":"text"}
{"name":"json_pretty","args":[{"type":"any"}],"returns":"text"}
{"name":"json_pretty","args":[{"type":"any"},{"type":"text"}],"returns":"text"}
{"name":"json_quote","args":[{"type":"any"}],"returns":"text"}
{"name":"json_remove","args":[{"type":"text","mode":"v"}],"returns":"text"}
{"name":"json_replace","args":[{"type":"any","mode":"v"}],"returns":"text"}
{"name":"json_set","args":[{"type":"any","mode":"v"}],"returns":"text"}
{"name":"json_type","args":[{"type":"any"}],"returns":"text","nullable":true}
{"name":"json_type","args":[{"type":"any"},{"type":"text"}],"returns":"text","nullable":true}
{"name":"json_valid","args":[{"type":"any"}],"returns":"integer"}
{"name":"json_valid","args":[{"type":"any"},{"type":"integer"}],"returns":"integer"}
{"name":"jsonb","args":[{"type":"any"}],"returns":"blob"}
{"name":"jsonb_array","args":[{"type":"any","mode":"v"}],"returns":"blob"}
{"name":"jsonb_array_insert","args":[{"type":"any","mode":"v"}],"returns":"blob"}
{"name":"jsonb_extract","args":[{"type":"text","mode":"v"}],"returns":"any","nullable":true}
{"name":"jsonb_group_array","kind":"a","args":[{"type":"any"}],"returns":"blob"}
{"name":"jsonb_group_object","kind":"a","args":[{"type":"text"},{"type":"any"}],"returns":"blob"}
{"name":"jsonb_insert","args":[{"type":"any","mode":"v"}],"returns":"blob"}
{"name":"jsonb_object","args":[{"type":"text","mode":"v"}],"returns":"blob"}
{"name":"jsonb_patch","args":[{"type":"any"},{"type":"any"}],"returns":"blob"}
{"name":"jsonb_remove","args":[{"type":"text","mode":"v"}],"returns":"blob"}
{"name":"jsonb_replace","args":[{"type":"any","mode":"v"}],"returns":"blob"}
{"name":"jsonb_set","args":[{"type":"any","mode":"v"}],"returns":"blob"}
{"name":"julianday","args":[{"type":"any","mode":"v"}],"returns":"real","nullable":true}
{"name":"lag","kind":"w","args":[{"type":"any"}],"returns":"any","nullable":true}
{"name":"lag","kind":"w","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true}
{"name":"lag","kind":"w","args":[{"type":"any"},{"type":"any"},{"type":"any"}],"returns":"any","nullable":true}
{"name":"last_insert_rowid","returns":"integer"}
{"name":"last_value","kind":"w","args":[{"type":"any"}],"returns":"any","nullable":true}
{"name":"lead","kind":"w","args":[{"type":"any"}],"returns":"any","nullable":true}
{"name":"lead","kind":"w","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true}
{"name":"lead","kind":"w","args":[{"type":"any"},{"type":"any"},{"type":"any"}],"returns":"any","nullable":true}
{"name":"length","args":[{"type":"text"}],"returns":"integer"}
{"name":"like","args":[{"type":"text"},{"type":"text"}],"returns":"integer"}
{"name":"like","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"integer"}
{"name":"likelihood","args":[{"type":"any"},{"type":"any"}],"returns":"any"}
{"name":"likely","args":[{"type":"any"}],"returns":"any"}
{"name":"ln","args":[{"type":"real"}],"returns":"real"}
{"name":"log","args":[{"type":"real"}],"returns":"real"}
{"name":"log","args":[{"type":"real"},{"type":"real"}],"returns":"real"}
{"name":"log10","args":[{"type":"real"}],"returns":"real"}
{"name":"log2","args":[{"type":"real"}],"returns":"real"}
{"name":"lower","args":[{"type":"text"}],"returns":"text"}
{"name":"ltrim","args":[{"type":"text"}],"returns":"text"}
{"name":"ltrim","args":[{"type":"text"},{"type":"text"}],"returns":"text"}
{"name":"max","kind":"a","args":[{"type":"any"}],"returns":"any","nullable":true}
{"name":"max","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"}
{"name":"min","kind":"a","args":[{"type":"any"}],"returns":"any","nullable":true}
{"name":"min","args":[{"type":"any"},{"type":"any","mode":"v"}],"returns":"any"}
{"name":"mod","args":[{"type":"real"},{"type":"real"}],"returns":"real"}
{"name":"nth_value","kind":"w","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true}
{"name":"ntile","kind":"w","args":[{"type":"integer"}],"returns":"integer"}
{"name":"nullif","args":[{"type":"any"},{"type":"any"}],"returns":"any","nullable":true}
{"name":"octet_length","args":[{"type":"any"}],"returns":"integer"}
{"name":"percent_rank","kind":"w","returns":"real"}
{"name":"pi","returns":"real"}
{"name":"pow","args":[{"type":"real"},{"type":"real"}],"returns":"real"}
{"name":"power","args":[{"type":"real"},{"type":"real"}],"returns":"real"}
{"name":"printf","args":[{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text"}
{"name":"quote","args":[{"type":"any"}],"returns":"text"}
{"name":"radians","args":[{"type":"real"}],"returns":"real"}
{"name":"random","returns":"integer"}
{"name":"randomblob","args":[{"type":"integer"}],"returns":"blob"}
{"name":"rank","kind":"w","returns":"integer"}
{"name":"replace","args":[{"type":"text"},{"type":"text"},{"type":"text"}],"returns":"text"}
{"name":"round","args":[{"type":"real"}],"returns":"real"}
{"name":"round","args":[{"type":"real"},{"type":"integer"}],"returns":"real"}
{"name":"row_number","kind":"w","returns":"integer"}
{"name":"rtrim","args":[{"type":"text"}],"returns":"text"}
{"name":"rtrim","args":[{"type":"text"},{"type":"text"}],"returns":"text"}
{"name":"sign","args":[{"type":"real"}],"returns":"integer","nullable":true}
{"name":"sin","args":[{"type":"real"}],"returns":"real"}
{"name":"sinh","args":[{"type":"real"}],"returns":"real"}
{"name":"sqlite_compileoption_get","args":[{"type":"integer"}],"returns":"text","nullable":true}
{"name":"sqlite_compileoption_used","args":[{"type":"text"}],"returns":"integer"}
{"name":"sqlite_source_id","returns":"text"}
{"name":"sqlite_version","returns":"text"}
{"name":"sqrt","args":[{"type":"real"}],"returns":"real"}
{"name":"strftime","args":[{"type":"text","has_default":true},{"type":"any","mode":"v"}],"returns":"text","nullable":true}
{"name":"string_agg","kind":"a","args":[{"type":"text"},{"type":"text"}],"returns":"text","nullable":true}
{"name":"substr","args":[{"type":"any"},{"type":"integer"}],"returns":"text"}
{"name":"substr","args":[{"type":"any"},{"type":"integer"},{"type":"integer"}],"returns":"text"}
{"name":"substring","args":[{"type":"any"},{"type":"integer"}],"returns":"text"}
{"name":"substring","args":[{"type":"any"},{"type":"integer"},{"type":"integer"}],"returns":"text"}
{"name":"subtype","args":[{"type":"any"}],"returns":"integer"}
{"name":"sum","kind":"a","args":[{"type":"any"}],"returns":"real","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"integer"}],"returns":"integer","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"int"}],"returns":"integer","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"tinyint"}],"returns":"integer","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"smallint"}],"returns":"integer","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"mediumint"}],"returns":"integer","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"bigint"}],"returns":"integer","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"unsigned big int"}],"returns":"integer","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"int2"}],"returns":"integer","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"int8"}],"returns":"integer","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"real"}],"returns":"real","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"double"}],"returns":"real","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"double precision"}],"returns":"real","nullable":true}
{"name":"sum","kind":"a","args":[{"type":"float"}],"returns":"real","nullable":true}
{"name":"tan","args":[{"type":"real"}],"returns":"real"}
{"name":"tanh","args":[{"type":"real"}],"returns":"real"}
{"name":"time","args":[{"type":"any","mode":"v"}],"returns":"text","nullable":true}
{"name":"timediff","args":[{"type":"any"},{"type":"any"}],"returns":"text","nullable":true}
{"name":"total","kind":"a","args":[{"type":"any"}],"returns":"real"}
{"name":"total_changes","returns":"integer"}
{"name":"trim","args":[{"type":"text"}],"returns":"text"}
{"name":"trim","args":[{"type":"text"},{"type":"text"}],"returns":"text"}
{"name":"trunc","args":[{"type":"any"}],"returns":"real"}
{"name":"trunc","args":[{"type":"integer"}],"returns":"integer"}
{"name":"trunc","args":[{"type":"int"}],"returns":"integer"}
{"name":"trunc","args":[{"type":"tinyint"}],"returns":"integer"}
{"name":"trunc","args":[{"type":"smallint"}],"returns":"integer"}
{"name":"trunc","args":[{"type":"mediumint"}],"returns":"integer"}
{"name":"trunc","args":[{"type":"bigint"}],"returns":"integer"}
{"name":"trunc","args":[{"type":"unsigned big int"}],"returns":"integer"}
{"name":"trunc","args":[{"type":"int2"}],"returns":"integer"}
{"name":"trunc","args":[{"type":"int8"}],"returns":"integer"}
{"name":"trunc","args":[{"type":"real"}],"returns":"real"}
{"name":"trunc","args":[{"type":"double"}],"returns":"real"}
{"name":"trunc","args":[{"type":"double precision"}],"returns":"real"}
{"name":"trunc","args":[{"type":"float"}],"returns":"real"}
{"name":"typeof","args":[{"type":"any"}],"returns":"text"}
{"name":"unhex","args":[{"type":"text"}],"returns":"blob","nullable":true}
{"name":"unhex","args":[{"type":"text"},{"type":"text"}],"returns":"blob","nullable":true}
{"name":"unicode","args":[{"type":"text"}],"returns":"integer"}
{"name":"unistr","args":[{"type":"text"}],"returns":"text"}
{"name":"unistr_quote","args":[{"type":"any"}],"returns":"text"}
{"name":"unixepoch","args":[{"type":"any","mode":"v"}],"returns":"real","nullable":true}
{"name":"unlikely","args":[{"type":"any"}],"returns":"any"}
{"name":"upper","args":[{"type":"text"}],"returns":"text"}
{"name":"zeroblob","args":[{"type":"integer"}],"returns":"blob"}

View File

@@ -0,0 +1 @@
{"name": "||", "left": "text", "right": "text", "result": "text"}

View File

@@ -0,0 +1,10 @@
{"name": "integer", "category": "N", "aliases": ["int", "tinyint", "smallint", "mediumint", "bigint", "unsigned big int", "int2", "int8"]}
{"name": "real", "category": "N", "aliases": ["double", "double precision", "float"]}
{"name": "numeric", "category": "N", "aliases": ["decimal"]}
{"name": "boolean", "category": "B", "aliases": ["bool"]}
{"name": "text", "category": "S", "aliases": ["character", "varchar", "varying character", "nchar", "native character", "nvarchar", "clob"]}
{"name": "blob", "category": "U"}
{"name": "any", "category": "U"}
{"name": "date", "category": "D"}
{"name": "datetime", "category": "D"}
{"name": "timestamp", "category": "D"}

View File

@@ -0,0 +1,26 @@
package sqlite
import (
"github.com/sqlc-dev/sqlc/internal/core/seed"
"github.com/sqlc-dev/sqlc/internal/sql/catalog"
)
// loadExtension returns the functions a compile option adds, read from the
// option's directory under the dialect's extensions/. The name is either the
// directory's — enable_fts5 — or a virtual table module the dialect maps to
// one, since a schema that says CREATE VIRTUAL TABLE ... USING fts5 has said
// which build of SQLite it runs on. An option the dialect has no data for
// adds nothing.
func loadExtension(name string) *catalog.Schema {
dir, ok := seed.ExtensionDir(dialectFS, "dialect", name)
if !ok {
return nil
}
funcs, err := seed.Functions(dialectFS, dir)
if err != nil {
// The list is embedded in the binary: a failure here means sqlc was
// built from a broken tree, which no caller can do anything about.
panic(err)
}
return &catalog.Schema{Name: "main", Funcs: funcs}
}

View File

@@ -0,0 +1,59 @@
package sqlite
import (
"strconv"
"strings"
)
// QuoteIdent quotes an identifier when printing it bare would change what it
// names: the parser folds unquoted identifiers to lower case, so any name
// that is not already a plain lower-case identifier — or that collides with
// a keyword — only survives a parse round-trip inside double quotes.
func (p *Parser) QuoteIdent(s string) string {
if s == "" || p.IsReservedKeyword(s) || !plainIdent(s) {
return `"` + strings.ReplaceAll(s, `"`, `""`) + `"`
}
return s
}
// plainIdent reports whether s parses back as itself unquoted: ASCII
// lower-case letters, digits and underscores, not starting with a digit.
func plainIdent(s string) bool {
for i, r := range s {
switch {
case r >= 'a' && r <= 'z', r == '_':
case r >= '0' && r <= '9':
if i == 0 {
return false
}
default:
return false
}
}
return true
}
// TypeName returns the SQL type name for the given namespace and name.
func (p *Parser) TypeName(ns, name string) string {
if ns != "" {
return ns + "." + name
}
return name
}
// Param returns the parameter placeholder for the given number. SQLite
// takes both a bare ? (the next index) and an explicit ?N, and they are
// not interchangeable — reordered ?N parameters bind by their numbers —
// so the one the author wrote is the one printed.
func (p *Parser) Param(n int, numbered bool) string {
if numbered {
return "?" + strconv.Itoa(n)
}
return "?"
}
// Cast returns a type cast expression.
// SQLite uses CAST(expr AS type) syntax.
func (p *Parser) Cast(arg, typeName string) string {
return "CAST(" + arg + " AS " + typeName + ")"
}

View File

@@ -0,0 +1,158 @@
package sqlite
import (
"errors"
"io"
"strings"
meyer "github.com/sqlc-dev/meyer/ast"
"github.com/sqlc-dev/meyer/parser"
mtoken "github.com/sqlc-dev/meyer/token"
"github.com/sqlc-dev/sqlc/internal/source"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
"github.com/sqlc-dev/sqlc/internal/sql/sqlerr"
)
func NewParser() *Parser {
return &Parser{}
}
type Parser struct {
}
// parseOptions accepts ORDER BY and LIMIT on UPDATE and DELETE. SQLite has
// them only when built with SQLITE_ENABLE_UPDATE_DELETE_LIMIT, which meyer
// cannot tell from the SQL, so the caller has to ask. sqlc has always
// accepted them.
var parseOptions = parser.Options{UpdateDeleteLimit: true}
func (p *Parser) Parse(r io.Reader) ([]ast.Statement, error) {
f, err := p.ParseFile(r)
if err != nil {
return nil, err
}
// The compiler skips statements sqlc has no node for (PRAGMA and
// friends); the formatter must see them, so the filter lives here,
// not in ParseFile.
var stmts []ast.Statement
for _, stmt := range f.Stmts {
if _, ok := stmt.Raw.Stmt.(*ast.TODO); ok {
continue
}
stmts = append(stmts, stmt)
}
return stmts, nil
}
// ParseFile parses like Parse and also carries the file's comments, taken
// from the trivia meyer's single lexer pass produces alongside the tokens.
func (p *Parser) ParseFile(r io.Reader) (*ast.File, error) {
blob, err := io.ReadAll(r)
if err != nil {
return nil, err
}
src := string(blob)
parsed, err := parseOptions.ParseFile(src)
if err != nil {
return nil, normalizeErr(err)
}
var stmts []ast.Statement
// loc tracks the first byte after the previous statement's terminator, so
// that a statement's extent covers the comments written above it. sqlc
// reads the "-- name:" annotation out of that range.
loc := 0
for _, raw := range parsed.Stmts {
converter := &cc{src: src}
// A statement sqlc has no node for converts to a TODO and stays in
// the list: the formatter needs its extent to keep it as written,
// and Parse filters it out for the compiler.
stmts = append(stmts, ast.Statement{
Raw: &ast.RawStmt{
Stmt: converter.convert(raw),
StmtLocation: loc,
StmtLen: trimTerminator(src, raw) - loc,
},
})
loc = raw.End()
}
var comments []ast.Comment
for _, tr := range parsed.Trivia {
if tr.Kind != mtoken.COMMENT {
continue
}
comments = append(comments, ast.Comment{
Text: strings.TrimRight(tr.Text(src), " \t\r\n"),
Start: tr.Pos,
End: tr.End,
OwnLine: ownLine(src, tr.Pos),
})
}
return &ast.File{Stmts: stmts, Comments: comments}, nil
}
// ownLine reports that only blank space sits between the preceding line
// break and pos.
func ownLine(src string, pos int) bool {
for j := pos - 1; j >= 0; j-- {
switch src[j] {
case '\n':
return true
case ' ', '\t', '\r':
continue
default:
return false
}
}
return true
}
// trimTerminator returns the end of stmt with its terminating semicolon, and
// any space before it, removed. A statement's span runs through the
// semicolon, but sqlc's statement text does not include it.
func trimTerminator(src string, stmt meyer.Stmt) int {
end := stmt.End()
if end > stmt.Pos() && end <= len(src) && src[end-1] == ';' {
end--
}
for end > stmt.Pos() && isSpace(src[end-1]) {
end--
}
return end
}
func isSpace(b byte) bool {
switch b {
case ' ', '\t', '\n', '\r', '\f':
return true
}
return false
}
// normalizeErr turns a meyer parse failure into the positioned error sqlc
// reports to the user. meyer's message and byte offset match SQLite's own.
func normalizeErr(err error) error {
var perr *parser.Error
if !errors.As(err, &perr) {
return err
}
line, column := parser.LineCol(perr.SQL, perr.Offset)
if line == 0 {
return errors.New(perr.Message)
}
return &sqlerr.Error{
Message: perr.Message,
Line: line,
Column: column,
}
}
func (p *Parser) CommentSyntax() source.CommentSyntax {
return source.CommentSyntax{
Dash: true,
Hash: false,
SlashStar: true,
}
}

View File

@@ -0,0 +1,10 @@
package sqlite
import "github.com/sqlc-dev/meyer/token"
// IsReservedKeyword reports whether s is a keyword in SQLite; see
// https://sqlite.org/lang_keywords.html. The table lives in meyer, which
// transcribes it from SQLite's own aKeywordTable.
func (p *Parser) IsReservedKeyword(s string) bool {
return token.Lookup(s) != token.ID
}

View File

@@ -0,0 +1,34 @@
package sqlite
import (
"embed"
"sync"
"github.com/sqlc-dev/sqlc/internal/core"
"github.com/sqlc-dev/sqlc/internal/core/seed"
"github.com/sqlc-dev/sqlc/internal/sql/catalog"
)
// The dialect directory describes SQLite's type system, and functions.jsonl is
// its standard library. Both the analysis core and the catalog the legacy
// compiler builds read them.
//
//go:embed dialect
var dialectFS embed.FS
// Dialect returns the catalog option that seeds SQLite's type system.
func Dialect() core.Option {
return seed.Dialect(dialectFS, "dialect")
}
// stdlib is SQLite's functions in the form the catalog uses. They are embedded
// in the binary and never change within a run, so they are read once.
var stdlib = sync.OnceValue(func() []*catalog.Function {
funcs, err := seed.Functions(dialectFS, "dialect")
if err != nil {
// A failure here means sqlc was built from a broken tree, which no
// caller can do anything about.
panic(err)
}
return funcs
})

View File

@@ -0,0 +1,13 @@
package sqlite
import (
"github.com/sqlc-dev/sqlc/internal/sql/catalog"
)
// defaultSchema is SQLite's standard library, read from the dialect
// directory's functions.jsonl, which internal/goldeneye generates from a
// default build of SQLite. The functions further compile options add live
// under the dialect's extensions/, one directory per option.
func defaultSchema(name string) *catalog.Schema {
return &catalog.Schema{Name: name, Funcs: stdlib()}
}

View File

@@ -0,0 +1,144 @@
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
}