Repository: sqlc-dev/sqlc
Pull request #2777 (2023-09-26 08:23:18)

feat(compiler): Support DO statements
Fixes https://github.com/sqlc-dev/sqlc/issues/1617

The output is a bit wonky for `:many` and `:one`, but works fine for `:exec`.


Patch:
diff --git a/go.mod b/go.mod
index 6200e08ef..f159367c7 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ require (
 	github.com/cubicdaiya/gonp v1.0.4
 	github.com/davecgh/go-spew v1.1.1
 	github.com/go-sql-driver/mysql v1.7.1
-	github.com/google/cel-go v0.18.0
+	github.com/google/cel-go v0.18.1
 	github.com/google/go-cmp v0.5.9
 	github.com/jackc/pgconn v1.14.1
 	github.com/jackc/pgx/v4 v4.18.1
diff --git a/go.sum b/go.sum
index bd1b67b2d..5c7434d1c 100644
--- a/go.sum
+++ b/go.sum
@@ -38,8 +38,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
 github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/google/cel-go v0.18.0 h1:u74MPiEC8mejBrkXqrTWT102g5IFEUjxOngzQIijMzU=
-github.com/google/cel-go v0.18.0/go.mod h1:PVAybmSnWkNMUZR/tEWFUiJ1Np4Hz0MHsZJcgC4zln4=
+github.com/google/cel-go v0.18.1 h1:V/lAXKq4C3BYLDy/ARzMtpkEEYfHQpZzVyzy69nEUjs=
+github.com/google/cel-go v0.18.1/go.mod h1:PVAybmSnWkNMUZR/tEWFUiJ1Np4Hz0MHsZJcgC4zln4=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
diff --git a/internal/compiler/output_columns.go b/internal/compiler/output_columns.go
index 545869cf6..75ff457d6 100644
--- a/internal/compiler/output_columns.go
+++ b/internal/compiler/output_columns.go
@@ -115,6 +115,8 @@ func (c *Compiler) outputColumns(qc *QueryCatalog, node ast.Node) ([]*Column, er
 		if isUnion {
 			return c.outputColumns(qc, n.Larg)
 		}
+	case *ast.DoStmt:
+		targets = &ast.List{}
 	case *ast.CallStmt:
 		targets = &ast.List{}
 	case *ast.TruncateStmt, *ast.RefreshMatViewStmt, *ast.NotifyStmt, *ast.ListenStmt:
@@ -509,6 +511,8 @@ func (c *Compiler) sourceTables(qc *QueryCatalog, node ast.Node) ([]*Table, erro
 		list = &ast.List{
 			Items: append(n.FromClause.Items, n.Relations.Items...),
 		}
+	case *ast.DoStmt:
+		list = &ast.List{}
 	case *ast.CallStmt:
 		list = &ast.List{}
 	case *ast.NotifyStmt, *ast.ListenStmt:
diff --git a/internal/compiler/parse.go b/internal/compiler/parse.go
index 8354bd340..c660ef4fb 100644
--- a/internal/compiler/parse.go
+++ b/internal/compiler/parse.go
@@ -39,6 +39,7 @@ func (c *Compiler) parseQuery(stmt ast.Node, src string, o opts.Parser) (*Query,
 	case *ast.CallStmt:
 	case *ast.SelectStmt:
 	case *ast.DeleteStmt:
+	case *ast.DoStmt:
 	case *ast.InsertStmt:
 		if err := validate.InsertStmt(n); err != nil {
 			return nil, err


Test patch:
diff --git a/internal/endtoend/testdata/do/postgresql/pgx/db/db.go b/internal/endtoend/testdata/do/postgresql/pgx/db/db.go
new file mode 100644
index 000000000..0975c670b
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pgx/db/db.go
@@ -0,0 +1,32 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.21.0
+
+package db
+
+import (
+	"context"
+
+	"github.com/jackc/pgx/v5"
+	"github.com/jackc/pgx/v5/pgconn"
+)
+
+type DBTX interface {
+	Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
+	Query(context.Context, string, ...interface{}) (pgx.Rows, error)
+	QueryRow(context.Context, string, ...interface{}) pgx.Row
+}
+
+func New(db DBTX) *Queries {
+	return &Queries{db: db}
+}
+
+type Queries struct {
+	db DBTX
+}
+
+func (q *Queries) WithTx(tx pgx.Tx) *Queries {
+	return &Queries{
+		db: tx,
+	}
+}
diff --git a/internal/endtoend/testdata/do/postgresql/pgx/db/models.go b/internal/endtoend/testdata/do/postgresql/pgx/db/models.go
new file mode 100644
index 000000000..9d556e518
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pgx/db/models.go
@@ -0,0 +1,15 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.21.0
+
+package db
+
+import (
+	"github.com/jackc/pgx/v5/pgtype"
+)
+
+type Author struct {
+	ID   int64
+	Name string
+	Bio  pgtype.Text
+}
diff --git a/internal/endtoend/testdata/do/postgresql/pgx/db/query.sql.go b/internal/endtoend/testdata/do/postgresql/pgx/db/query.sql.go
new file mode 100644
index 000000000..b56dac6fc
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pgx/db/query.sql.go
@@ -0,0 +1,24 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.21.0
+// source: query.sql
+
+package db
+
+import (
+	"context"
+)
+
+const doStuff = `-- name: DoStuff :exec
+DO $$
+    BEGIN
+        ALTER TABLE authors
+        ADD COLUMN marked_for_processing bool;
+    END
+$$
+`
+
+func (q *Queries) DoStuff(ctx context.Context) error {
+	_, err := q.db.Exec(ctx, doStuff)
+	return err
+}
diff --git a/internal/endtoend/testdata/do/postgresql/pgx/query.sql b/internal/endtoend/testdata/do/postgresql/pgx/query.sql
new file mode 100644
index 000000000..26a790d34
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pgx/query.sql
@@ -0,0 +1,7 @@
+-- name: DoStuff :exec
+DO $$
+    BEGIN
+        ALTER TABLE authors
+        ADD COLUMN marked_for_processing bool;
+    END
+$$;
diff --git a/internal/endtoend/testdata/do/postgresql/pgx/schema.sql b/internal/endtoend/testdata/do/postgresql/pgx/schema.sql
new file mode 100644
index 000000000..69b607d90
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pgx/schema.sql
@@ -0,0 +1,5 @@
+CREATE TABLE authors (
+  id   BIGSERIAL PRIMARY KEY,
+  name text      NOT NULL,
+  bio  text
+);
diff --git a/internal/endtoend/testdata/do/postgresql/pgx/sqlc.json b/internal/endtoend/testdata/do/postgresql/pgx/sqlc.json
new file mode 100644
index 000000000..b74a2efca
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pgx/sqlc.json
@@ -0,0 +1,12 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "path": "db",
+      "engine": "postgresql",
+      "schema": "schema.sql",
+      "queries": "query.sql",
+      "sql_package": "pgx/v5"
+    }
+  ]
+}
diff --git a/internal/endtoend/testdata/do/postgresql/pq/db/db.go b/internal/endtoend/testdata/do/postgresql/pq/db/db.go
new file mode 100644
index 000000000..46fda5440
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pq/db/db.go
@@ -0,0 +1,31 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.21.0
+
+package db
+
+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/do/postgresql/pq/db/models.go b/internal/endtoend/testdata/do/postgresql/pq/db/models.go
new file mode 100644
index 000000000..b73fc43b0
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pq/db/models.go
@@ -0,0 +1,15 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.21.0
+
+package db
+
+import (
+	"database/sql"
+)
+
+type Author struct {
+	ID   int64
+	Name string
+	Bio  sql.NullString
+}
diff --git a/internal/endtoend/testdata/do/postgresql/pq/db/query.sql.go b/internal/endtoend/testdata/do/postgresql/pq/db/query.sql.go
new file mode 100644
index 000000000..3da76a3e7
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pq/db/query.sql.go
@@ -0,0 +1,24 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.21.0
+// source: query.sql
+
+package db
+
+import (
+	"context"
+)
+
+const doStuff = `-- name: DoStuff :exec
+DO $$
+    BEGIN
+        ALTER TABLE authors
+        ADD COLUMN marked_for_processing bool;
+    END
+$$
+`
+
+func (q *Queries) DoStuff(ctx context.Context) error {
+	_, err := q.db.ExecContext(ctx, doStuff)
+	return err
+}
diff --git a/internal/endtoend/testdata/do/postgresql/pq/query.sql b/internal/endtoend/testdata/do/postgresql/pq/query.sql
new file mode 100644
index 000000000..26a790d34
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pq/query.sql
@@ -0,0 +1,7 @@
+-- name: DoStuff :exec
+DO $$
+    BEGIN
+        ALTER TABLE authors
+        ADD COLUMN marked_for_processing bool;
+    END
+$$;
diff --git a/internal/endtoend/testdata/do/postgresql/pq/schema.sql b/internal/endtoend/testdata/do/postgresql/pq/schema.sql
new file mode 100644
index 000000000..69b607d90
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pq/schema.sql
@@ -0,0 +1,5 @@
+CREATE TABLE authors (
+  id   BIGSERIAL PRIMARY KEY,
+  name text      NOT NULL,
+  bio  text
+);
diff --git a/internal/endtoend/testdata/do/postgresql/pq/sqlc.json b/internal/endtoend/testdata/do/postgresql/pq/sqlc.json
new file mode 100644
index 000000000..2a4610089
--- /dev/null
+++ b/internal/endtoend/testdata/do/postgresql/pq/sqlc.json
@@ -0,0 +1,11 @@
+{
+  "version": "1",
+  "packages": [
+    {
+      "path": "db",
+      "engine": "postgresql",
+      "schema": "schema.sql",
+      "queries": "query.sql"
+    }
+  ]
+}