Previously, `TextRow::decode_with` would read a length-encoded field size
and attempt to advance the buffer by that amount. If the server sent a
malformed packet containing a length value larger than the remaining data
in the buffer, the call to `buf.advance(size)` would panic.
eg:
```
thread 'main' panicked at /home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bytes-1.10.1/src/bytes.rs:711:9:
cannot advance past remaining: 8590116092 <= 0
stack backtrace:
0: 0x56119b657e00 - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h6d42cc84fc840290
1: 0x56119b67edd3 - core::fmt::write::h5af61a909e3ec64d
2: 0x56119b653ee3 - std::io::Write::write_fmt::h5a7b54aa6e4a315d
3: 0x56119b657c52 - std::sys::backtrace::BacktraceLock::print::h555579e7396c26ac
4: 0x56119b658cef - std::panicking::default_hook::{{closure}}::h9128866118196224
5: 0x56119b658b5a - std::panicking::default_hook::h52e9e7314e0255f6
6: 0x56119b659712 - std::panicking::rust_panic_with_hook::h541791bcc774ef34
7: 0x56119b65949a - std::panicking::begin_panic_handler::{{closure}}::h6479a2f0137c7d19
8: 0x56119b658319 - std::sys::backtrace::__rust_end_short_backtrace::ha04e7c0fc61ded91
9: 0x56119b65912d - rust_begin_unwind
10: 0x56119b67c390 - core::panicking::panic_fmt::h5764ee7030b7a73d
11: 0x56119b572b18 - <sqlx_mysql::protocol::text::row::TextRow as sqlx_core::io::decode::ProtocolDecode<&[sqlx_mysql::column::MySqlColumn]>>::decode_with::h17ac8b44140b5469
12: 0x56119b42df1f - sqlx_mysql::connection::executor::<impl sqlx_mysql::connection::MySqlConnection>::run::{{closure}}::{{closure}}::{{closure}}::h4874a0f73925d55a
```
This commit introduces a bounds check immediately after reading the field length from a packet.
This panic condition was specifically observed when executing a TiDB
`BATCH ON ... DELETE` statement via `pool.execute()`. It sends an OK packet immediately followed by
a full result set describing the batch status (column defs, row data, EOF).
Observed TiDB response sequence for `BATCH DML` via `COM_QUERY`:
1. OK Packet (seq=1, `SERVER_MORE_RESULTS_EXISTS` = false)
2. Column Count Packet (seq=1, non-standard, protocol violation)
3. Column Definition Packet (seq=2)
4. Column Definition Packet (seq=3)
5. Text Row Data Packet (seq=4)
6. EOF Packet (seq=5, `SERVER_MORE_RESULTS_EXISTS` = false)
This differs from standard MySQL DML response (OK/ERR packet only) and
causes `sqlx` using `execute()` to attempt parsing the unexpected result
set packets after the initial OK packet.
* feat: Implement `get_transaction_depth` for drivers
* test: Verify `get_transaction_depth()` on postgres
* Refactor: `TransactionManager` delegation without BC
SQLite implementation is currently WIP
* Fix: Avoid breaking changes on `AnyConnectionBackend`
* Refactor: Remove verbose `SqliteConnection` typing
* Feat: Implementation for SQLite
I have included `AtomicUsize` in `WorkerSharedState`. Ideally, it is not desirable to execute `load` and `fetch_add` in two separate steps, but we decided to allow it here since there is only one thread writing. To prevent writing from other threads, the field itself was made private, and a getter method was provided with `pub(crate)`.
* Refactor: Same approach for `cached_statements_size`
ref: a66787d36d62876b55475ef2326d17bade817aed
* Fix: Add missing `is_in_transaction` for backend
* Doc: Remove verbose "synchronously" word
* Fix: Remove useless `mut` qualifier
* feat: add Connection::begin_with
This patch completes the plumbing of an optional statement from these methods to
`TransactionManager::begin` without any validation of the provided statement.
There is a new `Error::InvalidSavePoint` which is triggered by any attempt to
call `Connection::begin_with` when we are already inside of a transaction.
* feat: add Pool::begin_with and Pool::try_begin_with
* feat: add Error::BeginFailed and validate that custom "begin" statements are successful
* chore: add tests of Error::BeginFailed
* chore: add tests of Error::InvalidSavePointStatement
* chore: test begin_with works for all SQLite "BEGIN" statements
* chore: improve comment on Connection::begin_with
* feat: add default impl of `Connection::begin_with`
This makes the new method a non-breaking change.
* refactor: combine if statement + unwrap_or_else into one match
* feat: use in-memory SQLite DB to avoid conflicts across tests run in parallel
* feedback: remove public wrapper for sqlite3_txn_state
Move the wrapper directly into the test that uses it instead.
* fix: cache Status on MySqlConnection
* fix: compilation errors
* fix: format
* fix: postgres test
* refactor: delete `Connection::get_transaction_depth`
* fix: tests
---------
Co-authored-by: mpyw <ryosuke_i_628@yahoo.co.jp>
Co-authored-by: Duncan Fairbanks <duncanfairbanks6@gmail.com>
* feat: add polygon
* test: paths for pgpoints in polygon test
* fix: import typo
* chore(Sqlite): remove ci.db from repo (#3768)
* fix: CI
* Fix breakage from Rustup 1.28 <https://blog.rust-lang.org/2025/03/02/Rustup-1.28.0.html>
* Let `Swatinem/rust-cache` generate cache keys
* fix(ci): upgrade Ubuntu image to 24.04
For some reason the `cargo +beta clippy` step is failing because `libsqlite3-sys` starts requiring Glibc >= 2.39 but I don't have time to figure out why and I can't reproduce it in a clean environment.
---------
Co-authored-by: joeydewaal <99046430+joeydewaal@users.noreply.github.com>
Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
For some reason the `cargo +beta clippy` step is failing because `libsqlite3-sys` starts requiring Glibc >= 2.39 but I don't have time to figure out why and I can't reproduce it in a clean environment.
* feat: add geometry path
* fix: paths to pg point
* test: remove array tests for path
* Fix readme: uuid feature is gating for all repos (#3720)
The readme previously stated that the uuid feature is only for postres but it actually also gates the functionality in mysql and sqlite.
* Replace some futures_util APIs with std variants (#3721)
* feat(sqlx-cli): Add flag to disable automatic loading of .env files (#3724)
* Add flag to disable automatic loading of .env files
* Update sqlx-cli/src/opt.rs
Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
---------
Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
* chore: expose bstr feature (#3714)
* chore: replace rustls-pemfile with rustls-pki-types (#3725)
* QueryBuilder: add `debug_assert` when `push_values` is passed an empty set of tuples (#3734)
* throw a warning in tracing so that the empty tuples would be noticed
* use debug assertion to throw a panic in debug mode
* fix: merge conflicts
* chore(cli): remove unused async-trait crate from dependencies (#3754)
* Update pull_request_template.md
* Fix example calculation (#3741)
* Avoid privilege requirements by using an advisory lock in test setup (postgres). (#3753)
* feat(sqlx-postgres): use advisory lock to avoid setup race condition
* fix(sqlx-postgres): numeric hex constants not supported before postgres 16
* Small doc correction. (#3755)
When sqlx-core/src/from_row.rs was updated to implement FromRow for tuples of up to 16 values, a comment was left stating that it was implemented up to tuples of 9 values.
* Update FAQ.md
* refactor(cli): replace promptly with dialoguer (#3669)
* docs(pool): recommend actix-web ThinData over Data to avoid two Arcs (#3762)
Both actix_web::web::Data and sqlx::PgPool internally wrap an Arc. Thus,
using Data<PgPool> as an extractor in an actix-web route handler results
in two Arcs wrapping the data of interest, which isn't ideal.
Actix-web 4.9.0 introduced a new web::ThinData extractor for cases like
this, where the data is already wrapped in an `Arc` (or is otherwise
similarly cheap and sensible to simply clone), which doesn't wrap the
inner value in a (second) Arc.
Since the new extractor is better suited to the task, suggest it in
place of web::Data when giving an example on how to share a pool.
* fix: merge conflicts
* fix: use types mod from main
* fix: merge conflicts
* fix: merge conflicts
* fix: merge conflicts
* fix: ordering of types mod
* fix: path import
* test: no array test for path
---------
Co-authored-by: Jon Thacker <thacker.jon@gmail.com>
Co-authored-by: Paolo Barbolini <paolo.barbolini@m4ss.net>
Co-authored-by: Ben Wilber <benwilber@users.noreply.github.com>
Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
Co-authored-by: joeydewaal <99046430+joeydewaal@users.noreply.github.com>
Co-authored-by: tottoto <tottotodev@gmail.com>
Co-authored-by: Ethan Wang <mailme@ethanavania.org>
Co-authored-by: Stefan Schindler <dns2utf8@users.noreply.github.com>
Co-authored-by: kildrens <5198060+kildrens@users.noreply.github.com>
Co-authored-by: Marti Serra <marti.serra+github@protonmail.com>
Co-authored-by: Jonas Malaco <jonas@protocubo.io>
* feat: implement serialze no copy on lockedsqlitehandle
* feat: implement serialize on sqliteconnection
* feat: implement deserialize on sqliteconnection and add sqlitebuf wrapper type
* refactor: misc sqlite type and deserialize refactoring
* chore: misc clippy refactoring
* fix: misc refactoring and fixes
- pass non-owned byte slice to deserialize
- `SqliteBufError` and better error handling
- more impl for `SqliteOnwedBuf` so it can be used as a slice
- default serialize for `SqliteConnection`
* refactor: move serialize and deserialize on worker thread
This implements `Command::Serialize` and `Command::Deserialize` and moves the
serialize and deserialize logic to the worker thread.
`Serialize` will need some more iterations as it's not clear whether it would
need to wait for other write transactions before running.
* refactor: misc refactoring and changes
- Merged deserialize module with serialize module
- Moved `SqliteOwnedBuf` into serialize module
- Fixed rustdocs
* chore: API tweaks, better docs, tests
* fix: unused import
* fix: export `SqliteOwnedBuf`, docs and safety tweaks
---------
Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
Both actix_web::web::Data and sqlx::PgPool internally wrap an Arc. Thus,
using Data<PgPool> as an extractor in an actix-web route handler results
in two Arcs wrapping the data of interest, which isn't ideal.
Actix-web 4.9.0 introduced a new web::ThinData extractor for cases like
this, where the data is already wrapped in an `Arc` (or is otherwise
similarly cheap and sensible to simply clone), which doesn't wrap the
inner value in a (second) Arc.
Since the new extractor is better suited to the task, suggest it in
place of web::Data when giving an example on how to share a pool.
When sqlx-core/src/from_row.rs was updated to implement FromRow for tuples of up to 16 values, a comment was left stating that it was implemented up to tuples of 9 values.
The `try_from` and `json` sections are "Field attributes" so they should probably be part of the corresponding section instead of subsections of "Manual implementation". `flatten` should be H4 instead of H3, since "Field attributes" is H3 and all other field attribute sections are H4 too.