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(mysql): support configuring the timezone via url
* test: add test case for mysql with timezone
---------
Co-authored-by: lo <lo@los-MacBook-Pro.local>
* impl AnyQueryResult for Sqlite and MySQL
* fix MySQL AnyQueryResult
* fix MySQL AnyQueryResult
* fix manifest
* rewrite `use` and address implementation concerns
* Fixed some rust docs intra-doc non functioning links
* Minor tweaks
* Added warning for MSSQL not being functional yet
* Fixed requested changes
* Readded missing time
* Aligned table
* Make encode and encode_by_ref fallible
This only changes the trait for now and makes it compile, calling .expect() on all users. Those will be removed in a later commit.
* PgNumeric: Turn TryFrom Decimal to an infallible From
* Turn panics in Encode implementations into errors
* Add Encode error analogous to the Decode error
* Propagate decode errors through Arguments::add
This pushes the panics one level further to mostly bind calls. Those will also be removed later.
* Only check argument encoding at the end
* Use Result in Query internally
* Implement query_with functions in terms of _with_result
* Surface encode errors when executing a query.
* Remove remaining panics in AnyConnectionBackend implementations
* PostgreSQL BigDecimal: Return encode error immediately
* Arguments: Add len method to report how many arguments were added
* Query::bind: Report which argument failed to encode
* IsNull: Add is_null method
* MySqlArguments: Replace manual bitmap code with NullBitMap helper type
* Roll back buffer in MySqlArguments if encoding fails
* Roll back buffer in SqliteArguments if encoding fails
* Roll back PgArgumentBuffer if encoding fails
When using the 'Any' driver with MySQL backend, fetch_optional
does not return the connection to the pool if no results
are returned from the query. This is due to not all of the packets
being read from the underlying stream.
This fix continues to read result packets from the stream until they
have all been exhausted (just like the normal MySql drivers
implementation of fetch_optional). In general, a better refactoring would
be to call the MySQL fetch_optional code in the Any driver, rather than
re-implementing and duplicating code.
Also clarifies the handling of `TIME` (we never realized it's used for both time-of-day and signed intervals) and adds appropriate impls for `std::time::Duration`, `time::Duration`, `chrono::TimeDelta`
* HasValueRef, HasArguments, HasStatement -> Database GATs
replace the associated types from the generic traits
`HasValueRef<'r>`, `HasArguments<'q>` and `HasStatement<'q>`
with generic associated types in `Database`
* fixup after rebase
---------
Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
* feat: add get_url to connect options
Add a get_url to connect options and implement it for all needed types;
include get_filename for sqlite. These changes make it easier to test
sqlx.
* refactor: use expect with message
* refactor: change method name to `to_url_lossy`
* fix: remove unused imports
* feat(mysql): provide options to disable default connection settings after connecting
* style(mysql): remove unecessary newlines and run rustfmt
* feat(mysql): allow to pass a custom timezone to the database after connecting
docs(mysql): improve docs for options set_names and no_engine_substitution
Exposes some of the main fields for PgConnectOptions
and MySqlConnectOptions. Exposed fields include: host,
port, socket, ssl mode, application name, and charset.