-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Bug Description
I have this function in my code:
pub async fn fetch_post(&self, id: Option<usize>) -> Option<Post> {
let query = match id {
Some(id) => sqlx::query("SELECT id, title, date, text FROM posts WHERE id = ?")
.bind(id as u64),
None => sqlx::query("SELECT id, title, date, text FROM posts ORDER BY id DESC"),
};
query.fetch_one(&self.pool) // self.pool: sqlx::Pool<sqlx::MySql>
.await
.map(|row| match Post::from_row(&row) {
Ok(post) => post,
Err(err) => panic!("Failed to parse post: {:?} ({:?})", err, row),
})
.ok()
}Where Post is:
#[derive(sqlx::FromRow)]
pub struct Post {
id: u32,
title: String,
date: PrimitiveDateTime,
text: String,
}And the schema of the posts table in my database is (there are several records in this table):
+-------+--------------+------+-----+-------------------+-------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+-------------------+-------------------+
| id | int unsigned | NO | PRI | NULL | |
| title | varchar(128) | YES | | NULL | |
| date | datetime | YES | | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
| text | text | YES | | NULL | |
+-------+--------------+------+-----+-------------------+-------------------+
This is the bug: In my scenario, only the second query (None => sqlx::query("...) usually gets called. At some point, calling that query will start returning an sqlx::Error::ColumnNotFound error is returned instead (notice column_names is empty):
thread 'actix-server worker 0' panicked at 'Failed to parse post: ColumnNotFound("id") (MySqlRow { ..., columns: [MySqlColumn { ordinal: 0, name: id, type_info: ..., flags: ... }, MySqlColumn { ordinal: 1, name: title, type_info: ..., flags: ... }, MySqlColumn { ordinal: 2, name: date, type_info: ..., flags: ... }, MySqlColumn { ordinal: 3, name: text, type_info: ..., flags: ... }],, column_names: {} })'
Because column_names is empty, and indexing into a row relies on the existence of columns in column_names...
// sqlx-core/src/mysql/row.rs
impl ColumnIndex<MySqlRow> for &'_ str {
fn index(&self, row: &MySqlRow) -> Result<usize, Error> {
row.column_names // <-- always empty
.get(*self)
.ok_or_else(|| Error::ColumnNotFound((*self).into()))
.map(|v| *v)
}
}...Error::ColumnNotFound will keep on being returned. I'd imagine SQLx determines the columns involved in a SELECT query from the output of the database, so it seems like column_names being empty is a bug.
Minimal Reproduction
I know it's incredibly frustrating that I don't have any clear way to reproduce this, since it's such a niche issue...
Info
- SQLx version: 0.6.2
- SQLx features enabled:
["runtime-tokio-rustls", "mysql", "uuid", "time"] - Database server and version: MySQL 8.0.26
- Operating system: Linux
rustc --version:rustc 1.65.0 (897e37553 2022-11-02)