diff --git a/internal/compiler/resolve.go b/internal/compiler/resolve.go
index b1fbb1990e..dba2e7cecc 100644
--- a/internal/compiler/resolve.go
+++ b/internal/compiler/resolve.go
@@ -67,7 +67,38 @@ func (comp *Compiler) resolveCatalogRefs(qc *QueryCatalog, rvs []*ast.RangeVar,
 				continue
 			}
 			// If the table name doesn't exist, first check if it's a CTE
-			if _, qcerr := qc.GetTable(fqn); qcerr != nil {
+			catTable, qcerr := qc.GetTable(fqn)
+			if qcerr != nil {
+				return nil, err
+			}
+
+			// If it's a CTE, add it to the alias map and add its columns to
+			// the type map. This is to allow us to resolve references to the
+			// CTE's columns in a query.
+			aliasMap[fqn.Name] = fqn
+			if rv.Alias != nil {
+				aliasMap[*rv.Alias.Aliasname] = fqn
+			}
+
+			catCols := make([]*catalog.Column, 0, len(catTable.Columns))
+			for _, col := range catTable.Columns {
+				catCols = append(catCols, &catalog.Column{
+					Name:       col.Name,
+					Type:       ast.TypeName{Name: col.DataType},
+					IsNotNull:  col.NotNull,
+					IsUnsigned: col.Unsigned,
+					IsArray:    col.IsArray,
+					ArrayDims:  col.ArrayDims,
+					Comment:    col.Comment,
+					Length:     col.Length,
+				})
+			}
+
+			err = indexTable(catalog.Table{
+				Rel:     catTable.Rel,
+				Columns: catCols,
+			})
+			if err != nil {
 				return nil, err
 			}
 			continue
diff --git a/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/query.sql.go
index 271ac35651..24f9ce475b 100644
--- a/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/query.sql.go
+++ b/internal/endtoend/testdata/cte_left_join/postgresql/pgx/go/query.sql.go
@@ -7,8 +7,6 @@ package querytest
 
 import (
 	"context"
-
-	"github.com/jackc/pgx/v5/pgtype"
 )
 
 const badQuery = `-- name: BadQuery :exec
@@ -28,7 +26,7 @@ FROM
 WHERE c1.name = $1
 `
 
-func (q *Queries) BadQuery(ctx context.Context, dollar_1 pgtype.Text) error {
-	_, err := q.db.Exec(ctx, badQuery, dollar_1)
+func (q *Queries) BadQuery(ctx context.Context, name string) error {
+	_, err := q.db.Exec(ctx, badQuery, name)
 	return err
 }
diff --git a/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/query.sql.go
index aa74cb5221..9b3b44647a 100644
--- a/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/query.sql.go
+++ b/internal/endtoend/testdata/cte_recursive_union/postgresql/pgx/go/query.sql.go
@@ -7,8 +7,6 @@ package querytest
 
 import (
 	"context"
-
-	"github.com/jackc/pgx/v5/pgtype"
 )
 
 const listCaseIntentHistory = `-- name: ListCaseIntentHistory :many
@@ -36,7 +34,7 @@ type ListCaseIntentHistoryRow struct {
 	Group string
 }
 
-func (q *Queries) ListCaseIntentHistory(ctx context.Context, caseIntentID pgtype.Int8) ([]ListCaseIntentHistoryRow, error) {
+func (q *Queries) ListCaseIntentHistory(ctx context.Context, caseIntentID int64) ([]ListCaseIntentHistoryRow, error) {
 	rows, err := q.db.Query(ctx, listCaseIntentHistory, caseIntentID)
 	if err != nil {
 		return nil, err
diff --git a/internal/endtoend/testdata/cte_resolve_ref/issue.md b/internal/endtoend/testdata/cte_resolve_ref/issue.md
new file mode 100644
index 0000000000..9268a7d1f8
--- /dev/null
+++ b/internal/endtoend/testdata/cte_resolve_ref/issue.md
@@ -0,0 +1,2 @@
+https://github.com/sqlc-dev/sqlc/issues/3219
+
diff --git a/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/go/db.go b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/go/db.go
new file mode 100644
index 0000000000..7c111fd4e7
--- /dev/null
+++ b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/go/db.go
@@ -0,0 +1,32 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.26.0
+
+package querytest
+
+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/cte_resolve_ref/postgresql/pgx/go/models.go b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/go/models.go
new file mode 100644
index 0000000000..9099b926b3
--- /dev/null
+++ b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/go/models.go
@@ -0,0 +1,13 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.26.0
+
+package querytest
+
+type T1 struct {
+	ID int32
+}
+
+type T2 struct {
+	ID int32
+}
diff --git a/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/go/query.sql.go
new file mode 100644
index 0000000000..d4fb8b9c5f
--- /dev/null
+++ b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/go/query.sql.go
@@ -0,0 +1,44 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.26.0
+// source: query.sql
+
+package querytest
+
+import (
+	"context"
+)
+
+const cTEMultipleRefs = `-- name: CTEMultipleRefs :one
+WITH t1_ids AS (
+    SELECT id FROM t1 WHERE t1.id = $1
+),
+t2_ids AS (
+    SELECT id FROM t2 WHERE t2.id = $1
+),
+all_ids AS (
+    SELECT id FROM t1_ids
+    UNION
+    SELECT id FROM t2_ids
+)
+SELECT id FROM all_ids AS ids WHERE ids.id = $1
+`
+
+func (q *Queries) CTEMultipleRefs(ctx context.Context, id int32) (int32, error) {
+	row := q.db.QueryRow(ctx, cTEMultipleRefs, id)
+	err := row.Scan(&id)
+	return id, err
+}
+
+const cTERef = `-- name: CTERef :one
+WITH t1_ids AS (
+    SELECT id FROM t1
+)
+SELECT id FROM t1_ids WHERE t1_ids.id = $1
+`
+
+func (q *Queries) CTERef(ctx context.Context, id int32) (int32, error) {
+	row := q.db.QueryRow(ctx, cTERef, id)
+	err := row.Scan(&id)
+	return id, err
+}
diff --git a/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/query.sql b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/query.sql
new file mode 100644
index 0000000000..39c87dfc31
--- /dev/null
+++ b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/query.sql
@@ -0,0 +1,21 @@
+-- name: CTERef :one
+WITH t1_ids AS (
+    SELECT id FROM t1
+)
+SELECT * FROM t1_ids WHERE t1_ids.id = sqlc.arg('id');
+
+-- name: CTEMultipleRefs :one
+WITH t1_ids AS (
+    SELECT id FROM t1 WHERE t1.id = sqlc.arg('id')
+),
+t2_ids AS (
+    SELECT id FROM t2 WHERE t2.id = sqlc.arg('id')
+),
+all_ids AS (
+    SELECT * FROM t1_ids
+    UNION
+    SELECT * FROM t2_ids
+)
+SELECT * FROM all_ids AS ids WHERE ids.id = sqlc.arg('id');
+
+
diff --git a/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/schema.sql b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/schema.sql
new file mode 100644
index 0000000000..3029ac89be
--- /dev/null
+++ b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/schema.sql
@@ -0,0 +1,9 @@
+CREATE TABLE t1
+(
+    id SERIAL NOT NULL PRIMARY KEY
+);
+
+CREATE TABLE t2
+(
+    id SERIAL NOT NULL PRIMARY KEY
+);
diff --git a/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/sqlc.yaml b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/sqlc.yaml
new file mode 100644
index 0000000000..01489e0ffc
--- /dev/null
+++ b/internal/endtoend/testdata/cte_resolve_ref/postgresql/pgx/sqlc.yaml
@@ -0,0 +1,10 @@
+version: "2"
+sql:
+  - engine: "postgresql"
+    schema: "schema.sql"
+    queries: "query.sql"
+    gen:
+      go:
+        package: "querytest"
+        out: "go"
+        sql_package: "pgx/v5"
\ No newline at end of file
diff --git a/internal/endtoend/testdata/cte_update/postgresql/pgx/go/query.sql.go b/internal/endtoend/testdata/cte_update/postgresql/pgx/go/query.sql.go
index 1176c852ae..fe4b0e3b94 100644
--- a/internal/endtoend/testdata/cte_update/postgresql/pgx/go/query.sql.go
+++ b/internal/endtoend/testdata/cte_update/postgresql/pgx/go/query.sql.go
@@ -23,9 +23,9 @@ from updated_attribute
 `
 
 type UpdateAttributeParams struct {
-	FilterValue pgtype.Bool
-	Value       pgtype.Text
-	ID          pgtype.Int8
+	FilterValue bool
+	Value       string
+	ID          int64
 }
 
 type UpdateAttributeRow struct {