Skip to content

Fix bugs found by end-to-end testing of v0.13.0 - #45

Merged
doron050 merged 3 commits into
mainfrom
devin/1793570850-fix-e2e-bugs
Nov 3, 2026
Merged

doron050 merged 3 commits into
mainfrom
devin/1793570850-fix-e2e-bugs

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes the 19 bugs found by end-to-end testing of the published v0.13.0 WASM against real PostgreSQL 16, MySQL 8.3 and SQLite (Ruby 3.1 – 3.4).

MySQL (mysql2)

  • A sqlc.arg used twice generated def f(term:, term:) (syntax error, the whole file failed to load): now one keyword, sent twice. Repeated ? of one column become id:, id_2:, id_3:.
  • Unaliased expressions (SELECT count(*)) were always nil: rows are now read by position (as: :array).
  • :copyfrom stored the string "NULL" as SQL NULL: values are quoted, only nil becomes \N. The CSV is built without the csv gem, so the generated Gemfile no longer needs it.

SQLite (sqlite3)

  • Types with modifiers (VARCHAR(255), DECIMAL(10,2)) aborted generation: Base#column_type strips the modifier, and its prefix check was reversed.
  • :exec / :execrows with RETURNING never ran, or only touched the first row: the result is now drained.

PostgreSQL (pg)

  • bytea containing NUL or non-UTF-8 bytes failed, both as a parameter and in COPY: now encoded with PG::TextEncoder::Bytea.
  • JSON parameters holding a Ruby Array were sent as a PG array literal: now PG::TextEncoder::JSON.
  • enum[] / uuid[] columns came back as the raw "{a,b}" string: they are decoded into arrays by a PG::TypeMapByOid built from pg_type.
  • :execlastid crashed when RETURNING produced no row: it now returns nil.
  • After PG::Connection#reset, every prepared query failed permanently: prepared state is now tracked per backend PID, so statements are prepared again.

All drivers

  • Leaving transaction with break / return / throw neither committed nor rolled back, so the pooled connection kept an open transaction. It now commits, and rolls back on an exception or a killed thread.
  • :copyfrom didn't quote identifiers (a column named order broke it): now quoted per driver.
  • A casted sqlc.narg(x)::text became a required keyword: it now defaults to nil, as the README says.
  • An expression sqlc can't type (any, e.g. coalesce(max(n), 0)) aborted generation: it is now untyped. Type errors also name the query.
  • Name collisions:
    • Parameters named like generated locals (client, sql, ...) are renamed (client_:).
    • Columns named like row methods (hash) are renamed (hash_), and columns that aren't valid identifiers are snake_cased.
    • A constant or method defined twice is now a generation error.
    • Lowercase query names now get a valid ...Row class.
  • Ruby 3.1: rows are keyword_init Structs (Row.new(name: ...) used to put the whole hash into the first field), RBS uses ::Struct[untyped] with keyword initialize / self.new, and long row constructors wrap, so the output is RuboCop-clean.
  • Nested moduleName (MyApp::Db) is emitted as nested module blocks, so the files load without MyApp being defined first.
  • rubyVersion: "3.4" is accepted. Unknown option keys, and preparedStatements with a driver other than pg, are now errors instead of being silently ignored.

Tests

  • Added a regressions table and queries to examples/authors/{postgresql,mysql,sqlite}; examples/ and the test/fixtures/*.bin captures are regenerated from them.
  • New E2E cases in tests/end2end_{pg,mysql2,sqlite3}.rb cover each runtime bug.
  • New unit tests in test/features_test.rb cover the generation bugs.
  • test/options_test.rb is updated for 3.4.
  • Goldens and steep_expectations.yml are regenerated; the new expected diagnostics are the PG:: constants used by the array decoder.

Docs (README options table and semantics, docs/Design.md, CLAUDE.md) now say Ruby 3.1–3.4 and describe the new validation and naming rules.

Local results:

  • rake test: 62 runs, 0 failures
  • RuboCop and Steep on examples/: clean
  • E2E: PostgreSQL 41/41, MySQL 36/36, SQLite 28/28
  • scripts/tests/run_codegen.rb passes on Ruby 3.1 and 3.4

Worth reviewing:

  • The pg connection setup now runs one pg_type query, to build the array decoder.
  • Generated code for MySQL rows changed from hash access to positional access.

Checklist

  • examples/ is regenerated (rake sqlc_generate_process) and committed
  • Tests added or updated (rake test, and rake end2end_* when the generated code changes)
  • The generated code stays RuboCop-clean (rake rubocop) and Steep-clean (rake steep)
  • Labelled (feature, bug, breaking, documentation) so the release notes are grouped correctly

devin-ai-integration Bot and others added 2 commits November 1, 2026 22:28
…exits

Co-Authored-By: Doron Eli Rachman <doron050@gmail.com>
- MySQL: a reused sqlc.arg is one keyword; repeated ? get id, id_2, ...; rows are read by
  position so unaliased expressions (count(*)) work; :copyfrom quotes values so "NULL" stays a string
- SQLite: types with modifiers (VARCHAR(255), DECIMAL(10,2)); :exec / :execrows with RETURNING
  run every row
- PostgreSQL: bytea with NUL / non-UTF-8 bytes (parameters and COPY), JSON array parameters,
  enum[] / uuid[] decoded to arrays, :execlastid without a row returns nil, prepared statements
  are re-prepared after PG::Connection#reset
- All drivers: transactions commit on break / return / throw instead of leaking an open
  transaction; :copyfrom quotes identifiers; casted sqlc.narg is optional; untyped (any)
  expressions generate as untyped
- Names: parameters / columns that collide with generated locals or row methods, or are not
  valid identifiers, are renamed; colliding constants / methods are reported; lowercase query
  names get a valid Row class
- Ruby 3.1: keyword_init Structs (+ RBS), RuboCop-clean output; rubyVersion 3.4 accepted;
  unknown options and preparedStatements on non-pg drivers are errors; nested moduleName
  output is self-contained

Co-Authored-By: Doron Eli Rachman <doron050@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot added the bug Something isn't working label Nov 1, 2026
…ry Ruby

Co-Authored-By: Doron Eli Rachman <doron050@gmail.com>
@doron050
doron050 merged commit de74512 into main Nov 3, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant