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,88 @@
package validate
import (
"errors"
"fmt"
"github.com/sqlc-dev/sqlc/internal/metadata"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
"github.com/sqlc-dev/sqlc/internal/sql/astutils"
)
func validateCopyfrom(n ast.Node) error {
stmt, ok := n.(*ast.InsertStmt)
if !ok {
return errors.New(":copyfrom requires an INSERT INTO statement")
}
if stmt.OnConflictClause != nil {
return errors.New(":copyfrom is not compatible with ON CONFLICT")
}
if stmt.WithClause != nil {
return errors.New(":copyfrom is not compatible with WITH clauses")
}
if stmt.ReturningList != nil && len(stmt.ReturningList.Items) > 0 {
return errors.New(":copyfrom is not compatible with RETURNING")
}
sel, ok := stmt.SelectStmt.(*ast.SelectStmt)
if !ok {
return nil
}
if len(sel.FromClause.Items) > 0 {
return errors.New(":copyfrom is not compatible with INSERT INTO ... SELECT")
}
if sel.ValuesLists == nil || len(sel.ValuesLists.Items) != 1 {
return errors.New(":copyfrom requires exactly one example row to be inserted")
}
sublist, ok := sel.ValuesLists.Items[0].(*ast.List)
if !ok {
return nil
}
for _, v := range sublist.Items {
if _, ok := v.(*ast.ParamRef); !ok {
return errors.New(":copyfrom doesn't support non-parameter values")
}
}
return nil
}
func validateBatch(n ast.Node) error {
args := astutils.Search(n, func(n ast.Node) bool {
_, ok := n.(*ast.ParamRef)
return ok
})
if len(args.Items) == 0 {
return errors.New(":batch* commands require parameters")
}
return nil
}
func Cmd(n ast.Node, name, cmd string) error {
if cmd == metadata.CmdCopyFrom {
return validateCopyfrom(n)
}
if (cmd == metadata.CmdBatchExec || cmd == metadata.CmdBatchMany) || cmd == metadata.CmdBatchOne {
if err := validateBatch(n); err != nil {
return err
}
}
if !(cmd == metadata.CmdMany || cmd == metadata.CmdOne || cmd == metadata.CmdBatchMany || cmd == metadata.CmdBatchOne) {
return nil
}
var list *ast.List
switch stmt := n.(type) {
case *ast.SelectStmt:
return nil
case *ast.DeleteStmt:
list = stmt.ReturningList
case *ast.InsertStmt:
list = stmt.ReturningList
case *ast.UpdateStmt:
list = stmt.ReturningList
default:
return nil
}
if list == nil || len(list.Items) == 0 {
return fmt.Errorf("query %q specifies parameter %q without containing a RETURNING clause", name, cmd)
}
return nil
}

View File

@@ -0,0 +1,48 @@
package validate
import (
"errors"
"github.com/sqlc-dev/sqlc/internal/config"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
"github.com/sqlc-dev/sqlc/internal/sql/astutils"
"github.com/sqlc-dev/sqlc/internal/sql/catalog"
"github.com/sqlc-dev/sqlc/internal/sql/sqlerr"
)
type funcCallVisitor struct {
catalog *catalog.Catalog
settings config.CombinedSettings
err error
}
func (v *funcCallVisitor) Visit(node ast.Node) astutils.Visitor {
if v.err != nil {
return nil
}
call, ok := node.(*ast.FuncCall)
if !ok {
return v
}
fn := call.Func
if fn == nil {
return v
}
fun, err := v.catalog.ResolveFuncCall(call)
if fun != nil {
return v
}
if errors.Is(err, sqlerr.NotFound) && !v.settings.Package.StrictFunctionChecks {
return v
}
v.err = err
return nil
}
func FuncCall(c *catalog.Catalog, cs config.CombinedSettings, n ast.Node) error {
visitor := funcCallVisitor{catalog: c, settings: cs}
astutils.Walk(&visitor, n)
return visitor.err
}

View File

@@ -0,0 +1,141 @@
package validate
import (
"strings"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
"github.com/sqlc-dev/sqlc/internal/sql/catalog"
"github.com/sqlc-dev/sqlc/internal/sql/sqlerr"
)
const excludedTable = "EXCLUDED"
func InsertStmt(c *catalog.Catalog, fqn *ast.TableName, stmt *ast.InsertStmt) error {
sel, ok := stmt.SelectStmt.(*ast.SelectStmt)
if !ok {
return nil
}
if sel.ValuesLists == nil {
return nil
}
if len(sel.ValuesLists.Items) != 1 {
return nil
}
sublist, ok := sel.ValuesLists.Items[0].(*ast.List)
if !ok {
return nil
}
colsLen := len(stmt.Cols.Items)
valsLen := len(sublist.Items)
switch {
case colsLen > valsLen:
return &sqlerr.Error{
Code: "42601",
Message: "INSERT has more target columns than expressions",
}
case colsLen < valsLen:
return &sqlerr.Error{
Code: "42601",
Message: "INSERT has more expressions than target columns",
}
}
return onConflictClause(c, fqn, stmt)
}
// onConflictClause validates an ON CONFLICT DO UPDATE clause against the target
// table. It checks:
// - ON CONFLICT (col, ...) conflict target columns exist
// - DO UPDATE SET col = ... assignment target columns exist
// - EXCLUDED.col references exist
func onConflictClause(c *catalog.Catalog, fqn *ast.TableName, n *ast.InsertStmt) error {
if fqn == nil || n.OnConflictClause == nil || n.OnConflictClause.Action != ast.OnConflictActionUpdate {
return nil
}
table, err := c.GetTable(fqn)
if err != nil {
return err
}
// Build set of column names for existence checks.
colNames := make(map[string]struct{}, len(table.Columns))
for _, col := range table.Columns {
colNames[col.Name] = struct{}{}
}
// DO UPDATE requires a conflict target: ON CONFLICT (col) or ON CONFLICT ON CONSTRAINT name.
if n.OnConflictClause.Infer == nil {
return &sqlerr.Error{
Code: "42601",
Message: "ON CONFLICT DO UPDATE requires inference specification or constraint name",
}
}
// Validate ON CONFLICT (col, ...) conflict target columns.
if n.OnConflictClause.Infer.IndexElems != nil {
for _, item := range n.OnConflictClause.Infer.IndexElems.Items {
elem, ok := item.(*ast.IndexElem)
if !ok || elem.Name == nil {
continue
}
if _, exists := colNames[*elem.Name]; !exists {
e := sqlerr.ColumnNotFound(table.Rel.Name, *elem.Name)
e.Location = n.OnConflictClause.Infer.Location
return e
}
}
}
// Validate DO UPDATE SET col = ... assignment target columns and EXCLUDED.col references.
if n.OnConflictClause.TargetList == nil {
return nil
}
for _, item := range n.OnConflictClause.TargetList.Items {
target, ok := item.(*ast.ResTarget)
if !ok || target.Name == nil {
continue
}
if _, exists := colNames[*target.Name]; !exists {
e := sqlerr.ColumnNotFound(table.Rel.Name, *target.Name)
e.Location = target.Location
return e
}
if ref, ok := target.Val.(*ast.ColumnRef); ok {
if excludedCol, ok := excludedColumnRef(ref); ok {
if _, exists := colNames[excludedCol]; !exists {
e := sqlerr.ColumnNotFound(excludedTable, excludedCol)
e.Location = ref.Location
return e
}
}
}
}
return nil
}
// excludedColumnRef returns the column name if the ColumnRef is an EXCLUDED.col
// reference, and ok=true. Returns "", false otherwise.
func excludedColumnRef(ref *ast.ColumnRef) (string, bool) {
if ref.Fields == nil || len(ref.Fields.Items) != 2 {
return "", false
}
first, ok := ref.Fields.Items[0].(*ast.String)
if !ok || !strings.EqualFold(first.Str, excludedTable) {
return "", false
}
second, ok := ref.Fields.Items[1].(*ast.String)
if !ok {
return "", false
}
return second.Str, true
}

View File

@@ -0,0 +1,70 @@
package validate
import (
"fmt"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
"github.com/sqlc-dev/sqlc/internal/sql/astutils"
"github.com/sqlc-dev/sqlc/internal/sql/sqlerr"
)
type sliceVisitor struct {
// slices maps the location of a placeholder in the query text to the name
// of the sqlc.slice() parameter it was rewritten from.
slices map[int]string
err error
}
func (v *sliceVisitor) Visit(node ast.Node) astutils.Visitor {
if v.err != nil {
return nil
}
in, ok := node.(*ast.In)
if !ok {
return v
}
// A slice expands to a comma-separated list at query time, so it has to be
// the only element of the IN expression:
// id IN (sqlc.slice("ids")) -- GOOD
// id in (0, 1, sqlc.slice("ids")) -- BAD
if len(in.List) <= 1 {
return v
}
for _, n := range in.List {
ref, ok := n.(*ast.ParamRef)
if !ok {
continue
}
name, ok := v.slices[ref.Location]
if !ok {
continue
}
inExpr := "..."
if col, ok := in.Expr.(*ast.ColumnRef); ok {
inExpr = col.Name
}
v.err = &sqlerr.Error{
Message: fmt.Sprintf("expected '%s IN' expr to consist only of sqlc.slice(%s); eg ", inExpr, name),
Location: ref.Location,
}
return nil
}
return v
}
// Slice reports whether every sqlc.slice() parameter is the only element of the
// IN expression that contains it. The slices map is keyed by the location the
// preprocessor recorded for each rewritten slice placeholder.
func Slice(n ast.Node, slices map[int]string) error {
if len(slices) == 0 {
return nil
}
visitor := sliceVisitor{slices: slices}
astutils.Walk(&visitor, n)
return visitor.err
}