diff --git a/core/schema.rs b/core/schema.rs index 379a69acc..17d18f74c 100644 --- a/core/schema.rs +++ b/core/schema.rs @@ -176,6 +176,7 @@ impl PseudoTable { self.columns.push(Column { name: normalize_ident(name), ty, + ty_str: ty.to_string(), primary_key, is_rowid_alias: false, notnull: false, @@ -245,30 +246,42 @@ fn create_table( // and the value of this column are the same. // https://www.sqlite.org/lang_createtable.html#rowids_and_the_integer_primary_key let mut typename_exactly_integer = false; - let ty = match col_def.col_type { + let (ty, ty_str) = match col_def.col_type { Some(data_type) => { + let s = data_type.name.as_str(); + let ty_str = if matches!( + s.to_uppercase().as_str(), + "TEXT" | "INT" | "INTEGER" | "BLOB" | "REAL" + ) { + s.to_uppercase().to_string() + } else { + s.to_string() + }; + // https://www.sqlite.org/datatype3.html - let type_name = data_type.name.as_str().to_uppercase(); + let type_name = ty_str.to_uppercase(); if type_name.contains("INT") { typename_exactly_integer = type_name == "INTEGER"; - Type::Integer + (Type::Integer, ty_str) } else if type_name.contains("CHAR") || type_name.contains("CLOB") || type_name.contains("TEXT") { - Type::Text - } else if type_name.contains("BLOB") || type_name.is_empty() { - Type::Blob + (Type::Text, ty_str) + } else if type_name.contains("BLOB") { + (Type::Blob, ty_str) + } else if type_name.is_empty() { + (Type::Blob, "".to_string()) } else if type_name.contains("REAL") || type_name.contains("FLOA") || type_name.contains("DOUB") { - Type::Real + (Type::Real, ty_str) } else { - Type::Numeric + (Type::Numeric, ty_str) } } - None => Type::Null, + None => (Type::Null, "".to_string()), }; let mut default = None; @@ -298,6 +311,7 @@ fn create_table( cols.push(Column { name: normalize_ident(&name), ty, + ty_str, primary_key, is_rowid_alias: typename_exactly_integer && primary_key, notnull, @@ -348,6 +362,8 @@ pub fn _build_pseudo_table(columns: &[ResultColumn]) -> PseudoTable { pub struct Column { pub name: String, pub ty: Type, + // many sqlite operations like table_info retain the original string + pub ty_str: String, pub primary_key: bool, pub is_rowid_alias: bool, pub notnull: bool, @@ -388,6 +404,7 @@ pub fn sqlite_schema_table() -> BTreeTable { Column { name: "type".to_string(), ty: Type::Text, + ty_str: "TEXT".to_string(), primary_key: false, is_rowid_alias: false, notnull: false, @@ -396,6 +413,7 @@ pub fn sqlite_schema_table() -> BTreeTable { Column { name: "name".to_string(), ty: Type::Text, + ty_str: "TEXT".to_string(), primary_key: false, is_rowid_alias: false, notnull: false, @@ -404,6 +422,7 @@ pub fn sqlite_schema_table() -> BTreeTable { Column { name: "tbl_name".to_string(), ty: Type::Text, + ty_str: "TEXT".to_string(), primary_key: false, is_rowid_alias: false, notnull: false, @@ -412,6 +431,7 @@ pub fn sqlite_schema_table() -> BTreeTable { Column { name: "rootpage".to_string(), ty: Type::Integer, + ty_str: "INT".to_string(), primary_key: false, is_rowid_alias: false, notnull: false, @@ -420,6 +440,7 @@ pub fn sqlite_schema_table() -> BTreeTable { Column { name: "sql".to_string(), ty: Type::Text, + ty_str: "TEXT".to_string(), primary_key: false, is_rowid_alias: false, notnull: false, @@ -769,6 +790,51 @@ mod tests { Ok(()) } + #[test] + pub fn test_col_type_string_integer() -> Result<()> { + let sql = r#"CREATE TABLE t1 (a InTeGeR);"#; + let table = BTreeTable::from_sql(sql, 0)?; + let column = table.get_column("a").unwrap().1; + assert_eq!(column.ty_str, "INTEGER"); + Ok(()) + } + + #[test] + pub fn test_col_type_string_int() -> Result<()> { + let sql = r#"CREATE TABLE t1 (a InT);"#; + let table = BTreeTable::from_sql(sql, 0)?; + let column = table.get_column("a").unwrap().1; + assert_eq!(column.ty_str, "INT"); + Ok(()) + } + + #[test] + pub fn test_col_type_string_blob() -> Result<()> { + let sql = r#"CREATE TABLE t1 (a bLoB);"#; + let table = BTreeTable::from_sql(sql, 0)?; + let column = table.get_column("a").unwrap().1; + assert_eq!(column.ty_str, "BLOB"); + Ok(()) + } + + #[test] + pub fn test_col_type_string_empty() -> Result<()> { + let sql = r#"CREATE TABLE t1 (a);"#; + let table = BTreeTable::from_sql(sql, 0)?; + let column = table.get_column("a").unwrap().1; + assert_eq!(column.ty_str, ""); + Ok(()) + } + + #[test] + pub fn test_col_type_string_some_nonsense() -> Result<()> { + let sql = r#"CREATE TABLE t1 (a someNonsenseName);"#; + let table = BTreeTable::from_sql(sql, 0)?; + let column = table.get_column("a").unwrap().1; + assert_eq!(column.ty_str, "someNonsenseName"); + Ok(()) + } + #[test] pub fn test_sqlite_schema() { let expected = r#"CREATE TABLE sqlite_schema ( @@ -841,6 +907,7 @@ mod tests { columns: vec![Column { name: "a".to_string(), ty: Type::Integer, + ty_str: "INT".to_string(), primary_key: false, is_rowid_alias: false, notnull: false, diff --git a/core/translate/group_by.rs b/core/translate/group_by.rs index 5f7aa7aae..284f9e478 100644 --- a/core/translate/group_by.rs +++ b/core/translate/group_by.rs @@ -165,11 +165,13 @@ pub fn emit_group_by<'a>( .map(|agg| agg.args.len()) .sum::(); // sorter column names do not matter + let ty = crate::schema::Type::Null; let pseudo_columns = (0..sorter_column_count) .map(|i| Column { name: i.to_string(), primary_key: false, - ty: crate::schema::Type::Null, + ty, + ty_str: ty.to_string(), is_rowid_alias: false, notnull: false, default: None, diff --git a/core/translate/order_by.rs b/core/translate/order_by.rs index 1435510d3..6e6341239 100644 --- a/core/translate/order_by.rs +++ b/core/translate/order_by.rs @@ -67,11 +67,13 @@ pub fn emit_order_by( let sort_loop_end_label = program.allocate_label(); let mut pseudo_columns = vec![]; for (i, _) in order_by.iter().enumerate() { + let ty = crate::schema::Type::Null; pseudo_columns.push(Column { // Names don't matter. We are tracking which result column is in which position in the ORDER BY clause in m.result_column_indexes_in_orderby_sorter. name: format!("sort_key_{}", i), primary_key: false, - ty: crate::schema::Type::Null, + ty, + ty_str: ty.to_string(), is_rowid_alias: false, notnull: false, default: None, @@ -84,10 +86,12 @@ pub fn emit_order_by( continue; } } + let ty = crate::schema::Type::Null; pseudo_columns.push(Column { name: rc.expr.to_string(), primary_key: false, - ty: crate::schema::Type::Null, + ty, + ty_str: ty.to_string(), is_rowid_alias: false, notnull: false, default: None, diff --git a/core/translate/plan.rs b/core/translate/plan.rs index 76d0a334c..075e6f93f 100644 --- a/core/translate/plan.rs +++ b/core/translate/plan.rs @@ -273,6 +273,7 @@ impl TableReference { .map(|rc| Column { name: rc.name.clone(), ty: Type::Text, // FIXME: infer proper type + ty_str: "TEXT".to_string(), is_rowid_alias: false, primary_key: false, notnull: false,