• Codex
  • Claude Code
  • VS Code
  • GitHub Copilot
  • Cursor
  • Cline
  • Windsurf
  • Google Anti-gravity
  • OpenCode
  • Pi
  • Gemini CLI
  • Hermes Agent
  • Zed
  • Junie
  • Qwen Code
  • Kiro
  • Kilo Code
  • Factory Droid

Set up GitHits for your agents

Run this command:

<> bash
npx githits@latest init

What happens next:

  1. Opens your browser to authorize GitHits
  2. Asks whether to set up GitHits at the user or project level
  3. Detects your supported AI coding tools
  4. Lets you choose which tools to configure
  5. Configures the selected tools
Back to blogWireframe database tables with a checkmark, in the GitHits brand style

June 3, 2026 · 3 min read

Migrating dynamic SQL safely in SQLx 0.9

How Codex migrated dynamic SQL to SQLx 0.9 without turning user input into query text.

We gave Codex a Rust fixture with stale dynamic SQL and asked it to migrate the code to sqlx 0.9.0 without weakening SQL injection protection.

Both runs used Codex GPT-5.5 and the same prompt:

Fix this Rust fixture so `cargo test` succeeds against `sqlx 0.9.0`, preserving SQL injection safety.

SQLx 0.9 introduced SqlSafeStr, so an owned dynamic String can no longer be passed to query_as by default. AssertSqlSafe makes dynamic SQL compile again, but it would not fix this fixture: the string contained user input.

Case study replayReal agent replays

SQLx 0.9 SQL safety migration

modelCodex GPT-5.5

Fix this Rust fixture so `cargo test` succeeds against `sqlx 0.9.0`, preserving SQL injection safety.

Without GitHits

Costly
tokens
0
time
0s / 597s
  1. Ready. Click "Watch Replay" to start.

With GitHits

Efficient
tokens
0
time
0s / 425s
  1. Ready. Click "Watch Replay" to start.

Result

RunTimeTokensTools
With GitHits425s1.22M44
Without GitHits597s3.36M75

Both runs produced a passing patch. The GitHits run finished 29% faster, used 64% fewer processed tokens, and made 41% fewer tool calls.

The unsafe query

The fixture put the search term directly into a LIKE clause:

let sql = format!(
    "SELECT id, title FROM articles WHERE lower(title) LIKE lower('%{term}%') ORDER BY id"
);

sqlx::query_as::<_, (i64, String)>(&sql)

The tests covered normal substring search, apostrophes such as O'Reilly, and input such as ' OR 1=1 --. The last case must stay data instead of becoming part of the query.

The fix

The patch used QueryBuilder<Sqlite> and bound the search pattern:

let mut query = sqlx::QueryBuilder::<sqlx::Sqlite>::new(
    "SELECT id, title FROM articles WHERE lower(title) LIKE lower("
);
query.push_bind(format!("%{term}%"));
query.push(") ORDER BY id");

QueryBuilder is not safe on its own. Untrusted text still becomes SQL when passed to .push(). The important part is push_bind, which keeps the search term as a value.

What GitHits changed

Both runs produced a safe, passing patch. The GitHits run finished 172 seconds sooner, used 2.14 million fewer processed tokens, and needed 31 fewer tool calls.

GitHits gave Codex the SQLx 0.9 changelog, the SqlSafeStr and QueryBuilder docs, the relevant source, and a real SQLite LIKE example. Together, they showed that AssertSqlSafe would only silence the new type check, while push_bind would also preserve SQL injection safety.

Without GitHits, Codex reached the same answer through 19 web searches and 52 shell calls, including crate downloads and local source inspection. GitHits did not produce a different patch; it made the safety decision with much less searching.

Get started

GitHits in one command

Install GitHits or refresh an existing setup with the same command.

npx -y githits@latest init