From 5d5e85bcbad3e43d39e6128b1afe626d7467eff9 Mon Sep 17 00:00:00 2001 From: Richard Newman Date: Tue, 13 Jun 2017 17:26:53 -0700 Subject: [PATCH] Pre: ensure that constant floats end up as floats in SQL, never integers. --- query-translator/tests/translate.rs | 4 ++-- sql/src/lib.rs | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/query-translator/tests/translate.rs b/query-translator/tests/translate.rs index 5b3b0c1f..c37fe698 100644 --- a/query-translator/tests/translate.rs +++ b/query-translator/tests/translate.rs @@ -226,7 +226,7 @@ fn test_unknown_attribute_double_value() { // In general, doubles _could_ be 1.0, which might match a boolean or a ref. Set tag = 5 to // make sure we only match numbers. - assert_eq!(sql, "SELECT DISTINCT `datoms00`.e AS `?x` FROM `datoms` AS `datoms00` WHERE `datoms00`.v = 9.95 AND `datoms00`.value_type_tag = 5"); + assert_eq!(sql, "SELECT DISTINCT `datoms00`.e AS `?x` FROM `datoms` AS `datoms00` WHERE `datoms00`.v = 9.95e0 AND `datoms00`.value_type_tag = 5"); assert_eq!(args, vec![]); } @@ -295,7 +295,7 @@ fn test_numeric_gte_known_attribute() { let schema = prepopulated_typed_schema(ValueType::Double); let query = r#"[:find ?x :where [?x :foo/bar ?y] [(>= ?y 12.9)]]"#; let SQLQuery { sql, args } = translate(&schema, query); - assert_eq!(sql, "SELECT DISTINCT `datoms00`.e AS `?x` FROM `datoms` AS `datoms00` WHERE `datoms00`.a = 99 AND `datoms00`.v >= 12.9"); + assert_eq!(sql, "SELECT DISTINCT `datoms00`.e AS `?x` FROM `datoms` AS `datoms00` WHERE `datoms00`.a = 99 AND `datoms00`.v >= 1.29e1"); assert_eq!(args, vec![]); } diff --git a/sql/src/lib.rs b/sql/src/lib.rs index b7b7ab0c..84583d17 100644 --- a/sql/src/lib.rs +++ b/sql/src/lib.rs @@ -160,7 +160,14 @@ impl QueryBuilder for SQLiteQueryBuilder { &Ref(entid) => self.push_sql(entid.to_string().as_str()), &Boolean(v) => self.push_sql(if v { "1" } else { "0" }), &Long(v) => self.push_sql(v.to_string().as_str()), - &Double(OrderedFloat(v)) => self.push_sql(v.to_string().as_str()), + &Double(OrderedFloat(v)) => { + // Rust's floats print without a trailing '.' in some cases. + // https://github.com/rust-lang/rust/issues/30967 + // We format with 'e' -- scientific notation -- so that SQLite treats them as + // floats and not integers. This is most noticeable for fulltext scores, which + // will currently (2017-06) always be 0, and need to round-trip as doubles. + self.push_sql(format!("{:e}", v).as_str()); + }, &Instant(dt) => { self.push_sql(format!("{}", dt.to_micros()).as_str()); // TODO: argument instead? }, @@ -260,9 +267,13 @@ mod tests { s.push_static_arg(string_arg("frobnicate")); s.push_sql(" OR "); s.push_static_arg(string_arg("swoogle")); + s.push_sql(" OR "); + s.push_identifier("bar").unwrap(); + s.push_sql(" = "); + s.push_typed_value(&TypedValue::Double(1.0.into())).unwrap(); let q = s.finish(); - assert_eq!(q.sql.as_str(), "SELECT `foo` WHERE `bar` = $v0 OR $v1"); + assert_eq!(q.sql.as_str(), "SELECT `foo` WHERE `bar` = $v0 OR $v1 OR `bar` = 1e0"); assert_eq!(q.args, vec![("$v0".to_string(), string_arg("frobnicate")), ("$v1".to_string(), string_arg("swoogle"))]);