Skip to content

ColumnNotFound error when querying with MySQL #2206

@ElectrifyPro

Description

@ElectrifyPro

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions