From b95ced7828e7bbb45fd3ae557120164f44d9548d Mon Sep 17 00:00:00 2001 From: "Christopher H. Jordan" Date: Fri, 12 Sep 2025 17:04:14 +0800 Subject: [PATCH] fix: Allow column names like 'End' to be used This commit surrounds column names with square brackets so that any conflicts with SQL keywords don't cause errors. Looking at other PRs it looks like this also allows column names with spaces in them to be used. --- src/tds/codec/token/token_col_metadata.rs | 2 +- tests/bulk.rs | 34 +++++++++++++++++++++++ tests/query.rs | 27 ++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/tds/codec/token/token_col_metadata.rs b/src/tds/codec/token/token_col_metadata.rs index 53ffdf1c..6d49938d 100644 --- a/src/tds/codec/token/token_col_metadata.rs +++ b/src/tds/codec/token/token_col_metadata.rs @@ -25,7 +25,7 @@ pub struct MetaDataColumn<'a> { impl<'a> Display for MetaDataColumn<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{} ", self.col_name)?; + write!(f, "[{}] ", self.col_name)?; match &self.base.ty { TypeInfo::FixedLen(fixed) => match fixed { diff --git a/tests/bulk.rs b/tests/bulk.rs index 33b90637..08513b68 100644 --- a/tests/bulk.rs +++ b/tests/bulk.rs @@ -4,6 +4,7 @@ use once_cell::sync::Lazy; use std::cell::RefCell; use std::env; use std::sync::Once; +use tiberius::ColumnData; use tiberius::{IntoSql, Result, TokenRow}; #[cfg(all(feature = "tds73", feature = "chrono"))] @@ -218,3 +219,36 @@ test_bulk_type!(datetime2_7( 100, vec![DateTime::from_timestamp(1658524194, 123456789); 100].into_iter() )); + +#[test_on_runtimes] +async fn read_and_write_to_keyword_columns(mut conn: tiberius::Client) -> Result<()> +where + S: AsyncRead + AsyncWrite + Unpin + Send, +{ + let table = format!("##{}", random_table().await); + + conn.simple_query(format!("CREATE TABLE {} ([End] INT)", table)) + .await?; + + let mut req = conn.bulk_insert(&table).await.unwrap(); + for num in [6, 7, 8] { + let mut row = TokenRow::new(); + row.push(ColumnData::I32(Some(num))); + req.send(row).await.unwrap(); + } + let result = req.finalize().await.unwrap(); + assert_eq!(result.rows_affected(), &[3]); + + let rows = conn + .query(format!("SELECT [End] FROM {}", table), &[]) + .await? + .into_first_result() + .await?; + + assert_eq!(rows.len(), 3); + assert_eq!(Some(6), rows[0].get(0)); + assert_eq!(Some(7), rows[1].get(0)); + assert_eq!(Some(8), rows[2].get(0)); + + Ok(()) +} diff --git a/tests/query.rs b/tests/query.rs index 4cf3c62b..934f10c0 100644 --- a/tests/query.rs +++ b/tests/query.rs @@ -397,6 +397,33 @@ where Ok(()) } +#[test_on_runtimes] +async fn read_and_write_to_keyword_columns(mut conn: tiberius::Client) -> Result<()> +where + S: AsyncRead + AsyncWrite + Unpin + Send, +{ + let table = format!("##{}", random_table().await); + + conn.simple_query(format!("CREATE TABLE {} ([End] INT)", table)) + .await?; + + let res = conn + .execute(format!("INSERT INTO {} ([End]) VALUES (5)", table), &[]) + .await?; + + assert_eq!(1, res.total()); + + let rows = conn + .query(format!("SELECT [End] FROM {}", table), &[]) + .await? + .into_first_result() + .await?; + + assert_eq!(Some(5), rows[0].get(0)); + + Ok(()) +} + #[test_on_runtimes] async fn execute_insert_update_delete(mut conn: tiberius::Client) -> Result<()> where