Skip to content

Fix interrupted PostgreSQL PREPAREs, SQLite JSON/UUID read as numbers, Has/Is query names; MySQL :copyfrom takes any Enumerable - #56

Merged
devin-ai-integration[bot] merged 1 commit into
mainfrom
devin/1793757233-sweep4-fixes
Nov 4, 2026
Merged

devin-ai-integration[bot] merged 1 commit into
mainfrom
devin/1793757233-sweep4-fixes

Conversation

@devin-ai-integration

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

Copy link
Copy Markdown
Contributor

Summary

Fixes three bugs found in a pre-release sweep. Each one has a test that fails on main.

PostgreSQL: an interrupted PREPARE broke a query on that connection for good. If a Timeout, Thread#raise or a stopped Async task hit after the server had prepared the statement but before run_prepared recorded it, every later call on that pooled connection raised PG::DuplicatePstatement.

  • Fix (drivers/pg.rb): a new private prepare helper prepares and records the statement inside Thread.handle_interrupt(::Object => :never). It also rescues PG::DuplicatePstatement and records the statement. Outside a transaction the call then continues; inside one the error has already aborted the transaction, so it is raised, the same rule as InvalidSqlStatementName.
  • Tests (tests/end2end_pg.rb): test_an_interrupt_during_prepare_leaves_the_statement_usable sends Thread#raise while a hooked PREPARE is still running after the server prepared the statement. test_a_statement_left_prepared_by_a_failed_prepare_is_used makes PREPARE raise after the server ran it, both outside and inside a transaction. Both are deterministic: they hook PG::Connection#prepare.

SQLite: JSON / UUID columns did not always come back as Strings. These columns have NUMERIC affinity, so SQLite stores numeric-looking text ('42', '1.5') as a number and the row held an Integer or Float.

  • Fix: a new driver hook, decode_value (default: unchanged). drivers/sqlite3.rb reads json / jsonb / uuid columns as row[i]&.to_s.
  • Test: test_json_and_uuid_columns_return_strings_that_look_numeric (tests/end2end_sqlite3.rb), which includes the RBS runtime type check.

Has… / Is… query names were not RuboCop-clean. Naming/PredicatePrefix flagged has_authors / has_authors!.

  • Fix (method_gen.rb): methods whose names start with is_ / has_ / have_ get # rubocop:disable Naming/PredicatePrefix, the bang method too. The names are not changed.
  • Tests: a new HasAuthors :one example query for every engine, so rake rubocop on examples/ catches a regression. Also test_predicate_like_query_names_are_kept (each engine's E2E suite) and the unit test test_predicate_like_query_names_are_rubocop_clean.

MySQL :copyfrom now takes any Enumerable (lazy enumerators, Enumerator), like PostgreSQL and SQLite. Before, it called rows.empty?. Now the rows are written to the temporary CSV and LOAD DATA is skipped when the file is empty (file.pos.positive?). Test: test_copyfrom_takes_any_enumerable on all three engines.

Docs

  • README: :copyfrom takes any Enumerable; SQLite JSON/UUID are Strings; predicate-like query names.
  • README Limitations: a known sqlc bug (seen with 1.27.0 and 1.31.1). A non-ASCII character anywhere in a SQLite query file (name, literal or comment) cuts characters off the end of that query and the following ones, e.g. FROM user instead of FROM users. The README's naïve naming example now points to this limitation.
  • docs/Coverage.md and docs/Testing.md: new rows and test names.
  • Prepare was added to the reserved query names test, because the new helper is a generated method.

Steep: the new prepare helper adds two expected PG unknown-constant diagnostics and one handle_interrupt block diagnostic, the same kinds already in steep_expectations.yml. The fixtures in test/fixtures/*.bin were re-captured with sqlc 1.27.0.

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 (bug, enhancement, documentation, or breaking) so the release notes are grouped correctly

…, Has/Is query names; :copyfrom takes any Enumerable on MySQL

- pg: prepare and record a statement with interrupts deferred, and use a statement the server already has
  (PG::DuplicatePstatement) instead of failing on every later call
- sqlite3: JSON / UUID columns (NUMERIC affinity) are always read as Strings
- query names starting with has_ / is_ / have_ get Naming/PredicatePrefix disabled
- mysql2: :copyfrom no longer calls rows.empty?, so lazy enumerators work like on PostgreSQL / SQLite
- README: document the sqlc bug that cuts SQLite query text after a non-ASCII character

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 4, 2026
@devin-ai-integration
devin-ai-integration Bot merged commit 65c6a45 into main Nov 4, 2026
41 checks passed
@devin-ai-integration
devin-ai-integration Bot deleted the devin/1793757233-sweep4-fixes branch November 4, 2026 02:08
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