Repository: sqlc-dev/sqlc
Pull request #2844 (2023-10-12 23:40:34)

fix(compiler): Account for parameters without parents
Before, these parameters would be dropped. Instead, add them to the list but mark their type as `any`.

Fixes https://github.com/sqlc-dev/sqlc/issues/2748
Fixes https://github.com/sqlc-dev/sqlc/issues/2786


Patch:
diff --git a/internal/compiler/resolve.go b/internal/compiler/resolve.go
index 2cb93fabc..4624c5a45 100644
--- a/internal/compiler/resolve.go
+++ b/internal/compiler/resolve.go
@@ -600,6 +600,16 @@ func (comp *Compiler) resolveCatalogRefs(qc *QueryCatalog, rvs []*ast.RangeVar,
 
 		default:
 			slog.Debug("unsupported reference type", "type", fmt.Sprintf("%T", n))
+			defaultP := named.NewInferredParam(ref.name, false)
+			p, isNamed := params.FetchMerge(ref.ref.Number, defaultP)
+			a = append(a, Parameter{
+				Number: ref.ref.Number,
+				Column: &Column{
+					Name:         p.Name(),
+					DataType:     "any",
+					IsNamedParam: isNamed,
+				},
+			})
 		}
 	}
 	return a, nil


Test patch:
diff --git a/internal/endtoend/testdata/coalesce_params/issue.md b/internal/endtoend/testdata/coalesce_params/issue.md
new file mode 100644
index 000000000..ad6db4167
--- /dev/null
+++ b/internal/endtoend/testdata/coalesce_params/issue.md
@@ -0,0 +1,2 @@
+https://github.com/sqlc-dev/sqlc/issues/2748
+https://github.com/sqlc-dev/sqlc/issues/2786
diff --git a/internal/endtoend/testdata/coalesce_params/mysql/go/db.go b/internal/endtoend/testdata/coalesce_params/mysql/go/db.go
new file mode 100644
index 000000000..a457fb76b
--- /dev/null
+++ b/internal/endtoend/testdata/coalesce_params/mysql/go/db.go
@@ -0,0 +1,31 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.22.0
+
+package querytest
+
+import (
+	"context"
+	"database/sql"
+)
+
+type DBTX interface {
+	ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
+	PrepareContext(context.Context, string) (*sql.Stmt, error)
+	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
+	QueryRowContext(context.Context, string, ...interface{}) *sql.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx *sql.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/coalesce_params/mysql/go/models.go b/internal/endtoend/testdata/coalesce_params/mysql/go/models.go
new file mode 100644
index 000000000..b2fc5363f
--- /dev/null
+++ b/internal/endtoend/testdata/coalesce_params/mysql/go/models.go
@@ -0,0 +1,87 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.22.0
+
+package querytest
+
+import (
+	"database/sql"
+	"database/sql/driver"
+	"fmt"
+	"time"
+)
+
+type CalendarMaincalendar string
+
+const (
+	CalendarMaincalendarTrue  CalendarMaincalendar = "true"
+	CalendarMaincalendarFalse CalendarMaincalendar = "false"
+)
+
+func (e *CalendarMaincalendar) Scan(src interface{}) error {
+	switch s := src.(type) {
+	case []byte:
+		*e = CalendarMaincalendar(s)
+	case string:
+		*e = CalendarMaincalendar(s)
+	default:
+		return fmt.Errorf("unsupported scan type for CalendarMaincalendar: %T", src)
+	}
+	return nil
+}
+
+type NullCalendarMaincalendar struct {
+	CalendarMaincalendar CalendarMaincalendar
+	Valid                bool // Valid is true if CalendarMaincalendar is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (ns *NullCalendarMaincalendar) Scan(value interface{}) error {
+	if value == nil {
+		ns.CalendarMaincalendar, ns.Valid = "", false
+		return nil
+	}
+	ns.Valid = true
+	return ns.CalendarMaincalendar.Scan(value)
+}
+
+// Value implements the driver Valuer interface.
+func (ns NullCalendarMaincalendar) Value() (driver.Value, error) {
+	if !ns.Valid {
+		return nil, nil
+	}
+	return string(ns.CalendarMaincalendar), nil
+}
+
+type Author struct {
+	ID      int64
+	Address string
+	Name    string
+	Bio     string
+}
+
+type Calendar struct {
+	ID           uint64
+	Relation     uint64
+	Calendarname []byte
+	Title        []byte
+	Description  []byte
+	Timezone     string
+	Uniquekey    string
+	Idkey        string
+	Maincalendar CalendarMaincalendar
+	Createdate   time.Time
+	Modifydate   time.Time
+}
+
+type Event struct {
+	ID                uint64
+	Relation          uint64
+	Calendarreference uint64
+	Uniquekey         string
+	Eventname         []byte
+	Description       []byte
+	Location          string
+	Timezone          string
+	Idkey             sql.NullString
+}
diff --git a/internal/endtoend/testdata/coalesce_params/mysql/go/query.sql.go b/internal/endtoend/testdata/coalesce_params/mysql/go/query.sql.go
new file mode 100644
index 000000000..833f917be
--- /dev/null
+++ b/internal/endtoend/testdata/coalesce_params/mysql/go/query.sql.go
@@ -0,0 +1,57 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.22.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+)
+
+const addAuthor = `-- name: AddAuthor :execlastid
+INSERT INTO authors (
+    address,
+    name,
+    bio
+) VALUES (
+    ?,
+    COALESCE(?, ""),
+    COALESCE(?, "")
+)
+`
+
+type AddAuthorParams struct {
+	Address        string
+	CalName        interface{}
+	CalDescription interface{}
+}
+
+func (q *Queries) AddAuthor(ctx context.Context, arg AddAuthorParams) (int64, error) {
+	result, err := q.db.ExecContext(ctx, addAuthor, arg.Address, arg.CalName, arg.CalDescription)
+	if err != nil {
+		return 0, err
+	}
+	return result.LastInsertId()
+}
+
+const addEvent = `-- name: AddEvent :execlastid
+INSERT INTO ` + "`" + `Event` + "`" + ` (
+    Timezone
+) VALUES (
+    (CASE WHEN ? = "calendar" THEN (SELECT cal.Timezone FROM Calendar cal WHERE cal.IdKey = ?) ELSE ? END)
+)
+`
+
+type AddEventParams struct {
+	Timezone      interface{}
+	CalendarIdKey string
+}
+
+func (q *Queries) AddEvent(ctx context.Context, arg AddEventParams) (int64, error) {
+	result, err := q.db.ExecContext(ctx, addEvent, arg.Timezone, arg.CalendarIdKey, arg.Timezone)
+	if err != nil {
+		return 0, err
+	}
+	return result.LastInsertId()
+}
diff --git a/internal/endtoend/testdata/coalesce_params/mysql/query.sql b/internal/endtoend/testdata/coalesce_params/mysql/query.sql
new file mode 100644
index 000000000..f6df77d55
--- /dev/null
+++ b/internal/endtoend/testdata/coalesce_params/mysql/query.sql
@@ -0,0 +1,17 @@
+-- name: AddEvent :execlastid
+INSERT INTO `Event` (
+    Timezone
+) VALUES (
+    (CASE WHEN sqlc.arg("Timezone") = "calendar" THEN (SELECT cal.Timezone FROM Calendar cal WHERE cal.IdKey = sqlc.arg("calendarIdKey")) ELSE sqlc.arg("Timezone") END)
+);
+
+-- name: AddAuthor :execlastid
+INSERT INTO authors (
+    address,
+    name,
+    bio
+) VALUES (
+    ?,
+    COALESCE(sqlc.narg("calName"), ""),
+    COALESCE(sqlc.narg("calDescription"), "")
+);
diff --git a/internal/endtoend/testdata/coalesce_params/mysql/schema.sql b/internal/endtoend/testdata/coalesce_params/mysql/schema.sql
new file mode 100644
index 000000000..a0d41cbe7
--- /dev/null
+++ b/internal/endtoend/testdata/coalesce_params/mysql/schema.sql
@@ -0,0 +1,43 @@
+CREATE TABLE `Calendar` (
+  `Id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+  `Relation` bigint(20) unsigned NOT NULL,
+  `CalendarName` longblob NOT NULL,
+  `Title` longblob NOT NULL,
+  `Description` longblob NOT NULL,
+  `Timezone` varchar(50) NOT NULL,
+  `UniqueKey` varchar(50) NOT NULL,
+  `IdKey` varchar(50) NOT NULL,
+  `MainCalendar` enum('true','false') NOT NULL DEFAULT 'false',
+  `CreateDate` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `ModifyDate` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`Id`),
+  KEY `Relation` (`Relation`),
+  KEY `UniqueKey` (`UniqueKey`),
+  KEY `IdKey` (`IdKey`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
+
+
+CREATE TABLE `Event` (
+  `Id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+  `Relation` bigint(20) unsigned NOT NULL,
+  `CalendarReference` bigint(20) unsigned NOT NULL,
+  `UniqueKey` varchar(50) NOT NULL,
+  `EventName` longblob NOT NULL,
+  `Description` longblob NOT NULL,
+  `Location` varchar(500) NOT NULL,
+  `Timezone` varchar(50) NOT NULL,
+  `IdKey` varchar(48) DEFAULT NULL,
+  PRIMARY KEY (`Id`),
+  KEY `Relation` (`Relation`),
+  KEY `CalendarReference` (`CalendarReference`),
+  KEY `UniqueKey` (`UniqueKey`),
+  KEY `IdKey` (`IdKey`)
+) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
+
+
+CREATE TABLE authors (
+  id   BIGINT AUTO_INCREMENT NOT NULL,
+  address VARCHAR(200) NOT NULL,
+  name VARCHAR(20) NOT NULL,
+  bio  LONGTEXT NOT NULL
+);
diff --git a/internal/endtoend/testdata/coalesce_params/mysql/sqlc.yaml b/internal/endtoend/testdata/coalesce_params/mysql/sqlc.yaml
new file mode 100644
index 000000000..b843ef55e
--- /dev/null
+++ b/internal/endtoend/testdata/coalesce_params/mysql/sqlc.yaml
@@ -0,0 +1,9 @@
+version: "2"
+sql:
+  - engine: "mysql"
+    schema: "schema.sql"
+    queries: "query.sql"
+    gen:
+      go:
+        package: "querytest"
+        out: "go"