GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat(golang): add emit_read_only_prepared to generate read-only queries by jarri-abidi · Pull Request #4669 · sqlc-dev/sqlc

Conversation

@jarri-abidi

@jarri-abidi jarri-abidi commented Oct 29, 2026

Copy link
Copy Markdown

Closes #3187. Supersedes #3291, which was closed automatically for merge conflicts; this is the same feature rebased onto the current main, with the fixes from running it since.

Problem

With emit_prepared_queries, Prepare prepares every query on one connection. A database user that can only read, such as one connecting to a read replica, can't prepare the INSERT, UPDATE and DELETE statements, so you either prepare everything with a read-write user or generate a second package and duplicate all the models (#3187).

Solution

A new emit_read_only_prepared option (Go, database/sql). When set, sqlc also generates read.go with a ReadQueries type, created with PrepareReadOnly, that prepares only the read-only queries. Prepare is unchanged, and the models are shared.

version: "2"
sql:
  - engine: "postgresql"
    queries: "query.sql"
    schema: "schema.sql"
    gen:
      go:
        package: "db"
        out: "db"
        emit_prepared_queries: true
        emit_read_only_prepared: true
writes, err := db.Prepare(ctx, primary)        // every query
reads, err := db.PrepareReadOnly(ctx, replica) // read-only queries only
user, err := reads.GetUserByID(ctx, id)

A query is read-only if it SELECTs and doesn't INSERT, UPDATE, DELETE or SELECT ... FOR UPDATE, so a DELETE ... WHERE id IN (SELECT ...) stays out of read.go, as asked in the #3291 review. Keywords are matched when followed by any whitespace, so queries written as SELECT\n col1, ... are recognised.

read.go gets its imports from the read-only queries' own argument and result types, including github.com/lib/pq when they bind or scan slices with pq.Array.

pgx isn't supported (no read.go is generated), because emit_prepared_queries doesn't apply to it.

Changes

  • emit_read_only_prepared in the Go options, the v1 config, both config JSON schemas and docs/reference/config.md
  • readQueriesFile template (stdlib/readonlyCode.tmpl) and the read-only query selection in gen.go
  • endtoend fixtures under read_write_segregation: MySQL, PostgreSQL, and PostgreSQL with slice arguments and results

Testing

  • go vet ./... and go test --tags=examples ./... pass locally
  • This feature has been running in production services generating read.go, which is where the pq import and bare-SELECT fixes came from

🤖 Generated with Claude Code

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@jarri-abidi @claude
feat(golang): add emit_read_only_prepared to generate read-only queries
7dc4b32
Add an emit_read_only_prepared option for database/sql. When set, sqlc
also generates read.go with a ReadQueries type, created with
PrepareReadOnly, that prepares only the read-only queries: those that
SELECT and do not INSERT, UPDATE, DELETE or SELECT ... FOR UPDATE.

This lets read queries be prepared on a connection whose database user
can only read, such as a read replica, without preparing write
statements that user isn't allowed to prepare. Prepare is unchanged and
keeps every query, and the models are shared, so nothing is duplicated.

read.go gets its imports from the read-only queries' own argument and
result types, including lib/pq when they bind or scan slices with
pq.Array. Keywords are matched when followed by any whitespace, so
queries written as "SELECT\n    col1, ..." are recognised. pgx is not
supported; no read.go is generated for it.

Adds the option to the docs and both config schemas, and endtoend
fixtures for MySQL, PostgreSQL, and PostgreSQL with slice arguments and
results.

Closes sqlc-dev#3187. Supersedes sqlc-dev#3291, which was closed for merge conflicts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@jarri-abidi
jarri-abidi marked this pull request as ready for review October 29, 2026 17:41
@jarri-abidi

jarri-abidi commented Nov 1, 2026

Copy link
Copy Markdown
Author

@kyleconroy this supersedes #3291 please approve

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Option to Segregate Read and Write queries to have separate db users with each type of query.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@jarri-abidi
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.