diff --git a/cases/relational/unaliased_round_current.toml b/cases/relational/unaliased_round_current.toml new file mode 100644 index 000000000..652671265 --- /dev/null +++ b/cases/relational/unaliased_round_current.toml @@ -0,0 +1,92 @@ +# The names Snowflake gives unaliased ROUND and current-time items, as a playground query writes them. +# The recorded column names are the receipts for naming them. +category = "relational" +construct = "node:alias" +session_profile = "utc-v1" + +[[case]] +id = "unaliased_round" +description = "Unaliased ROUND with one and two arguments, in upper and lower case and with inner spaces, over a NULL, a half and a negative." +columns = [{ name = "n", type = "NUMBER(10,2)" }] +rows = [ + ["1.25"], + ["1.25"], + ["-2.55"], + ["NULL"], +] +query = "SELECT ROUND(n, 1), ROUND(n), round( n, 0 ) FROM input" +order = "ordered" +tags = ["null", "boundary", "duplicates"] + +[[case]] +id = "unaliased_round_no_rows" +description = "Unaliased ROUND over no rows still names its columns." +columns = [{ name = "n", type = "NUMBER(10,2)" }] +rows = [ + ["1.00"], +] +query = "SELECT ROUND(n, 1), ROUND(n) FROM input WHERE n > 5" +order = "ordered" +tags = ["empty-input"] + +[[case]] +id = "unaliased_current_time" +description = "Unaliased CURRENT_DATE(), CURRENT_DATE and CURRENT_TIMESTAMP(): only the column names and types are the receipt; the values read the clock, so it is typing evidence." +evidence = "typing" +columns = [{ name = "n", type = "NUMBER(10,2)" }] +rows = [ + ["1.00"], +] +query = "SELECT CURRENT_DATE(), CURRENT_DATE, CURRENT_TIMESTAMP() FROM input" +order = "ordered" +tags = ["boundary"] + +[[case]] +id = "unaliased_distinct_aggregates" +description = "Unaliased SUM, MAX and AVG over DISTINCT, over a duplicate and a NULL. The aggregates are one query and the row expressions another, since one select list cannot hold both without GROUP BY; each item is written as given." +columns = [{ name = "n", type = "NUMBER(10,2)" }, { name = "g", type = "VARCHAR" }] +rows = [ + ["1.50", "'12'"], + ["1.50", "'12'"], + ["NULL", "NULL"], + ["-2.25", "'-3'"], +] +query = "SELECT SUM(DISTINCT n), MAX(DISTINCT n), AVG(DISTINCT n) FROM input" +order = "ordered" +tags = ["null", "duplicates"] + +[[case]] +id = "unaliased_distinct_aggregates_no_rows" +description = "The unaliased DISTINCT aggregates over no rows still name their columns." +columns = [{ name = "n", type = "NUMBER(10,2)" }, { name = "g", type = "VARCHAR" }] +rows = [ + ["1.00", "'1'"], +] +query = "SELECT SUM(DISTINCT n), MAX(DISTINCT n), AVG(DISTINCT n) FROM input WHERE n > 5" +order = "ordered" +tags = ["empty-input"] + +[[case]] +id = "unaliased_row_expressions" +description = "Unaliased COALESCE with a column and with literals only, CAST of numeric text to INTEGER, and lower with a space before its closing parenthesis, over a duplicate and a NULL." +columns = [{ name = "n", type = "NUMBER(10,2)" }, { name = "g", type = "VARCHAR" }] +rows = [ + ["1.50", "'12'"], + ["1.50", "'12'"], + ["NULL", "NULL"], + ["-2.25", "'-3'"], +] +query = "SELECT COALESCE(n, 0, 1), COALESCE(1, 2), CAST(g AS INTEGER), lower(g ) FROM input" +order = "bag" +tags = ["null", "duplicates"] + +[[case]] +id = "unaliased_row_expressions_no_rows" +description = "The unaliased row expressions over no rows still name their columns." +columns = [{ name = "n", type = "NUMBER(10,2)" }, { name = "g", type = "VARCHAR" }] +rows = [ + ["1.00", "'1'"], +] +query = "SELECT COALESCE(n, 0, 1), COALESCE(1, 2), CAST(g AS INTEGER), lower(g ) FROM input WHERE n > 5" +order = "bag" +tags = ["empty-input"] diff --git a/coverage/translation/results-baseline.json b/coverage/translation/results-baseline.json index 9101a26fd..1f2b8cd77 100644 --- a/coverage/translation/results-baseline.json +++ b/coverage/translation/results-baseline.json @@ -6718,6 +6718,13 @@ "relational/unaliased_output_names.toml#unaliased_group_count": "matching", "relational/unaliased_output_names.toml#unaliased_literals": "matching", "relational/unaliased_output_names.toml#unaliased_over_no_rows": "matching", + "relational/unaliased_round_current.toml#unaliased_current_time": "shape_only", + "relational/unaliased_round_current.toml#unaliased_distinct_aggregates": "refused", + "relational/unaliased_round_current.toml#unaliased_distinct_aggregates_no_rows": "refused", + "relational/unaliased_round_current.toml#unaliased_round": "matching", + "relational/unaliased_round_current.toml#unaliased_round_no_rows": "matching", + "relational/unaliased_round_current.toml#unaliased_row_expressions": "matching", + "relational/unaliased_round_current.toml#unaliased_row_expressions_no_rows": "matching", "relational/union_by_name.toml#union_all_by_name_reordered": "matching", "relational/union_by_name.toml#union_by_name_case_insensitive": "matching", "relational/union_by_name.toml#union_by_name_chain": "matching", diff --git a/crates/sqlquack-core/src/diagnostics/constants.rs b/crates/sqlquack-core/src/diagnostics/constants.rs index 3f804a21f..87894fa98 100644 --- a/crates/sqlquack-core/src/diagnostics/constants.rs +++ b/crates/sqlquack-core/src/diagnostics/constants.rs @@ -175,8 +175,9 @@ pub const CODES: &[CodeEntry] = &[ a converted query must return the same column names. SQLQuack emits Snowflake's name \ only for the shapes recorded results verify, named by their text upper-cased as \ written: literals, columns and COUNT, SUM, MAX, AVG, LOWER, UPPER and COALESCE of \ - columns, a column plus, minus, times, divided by or concatenated with a literal, and \ - a column cast to INTEGER, written with single spaces and at most one line break. \ + columns, ROUND of a column, a column plus, minus, times, divided by or concatenated \ + with a literal, a column cast to INTEGER, and CURRENT_DATE, CURRENT_DATE() or \ + CURRENT_TIMESTAMP(), written with single spaces and at most one line break. \ Other items, such as paths, CASE, nested calls or other functions, are refused \ rather than converted with a different column name. An alias fixes the name in both \ engines.", diff --git a/crates/sqlquack-duckdb/src/temporal/constants.rs b/crates/sqlquack-duckdb/src/temporal/constants.rs index 8e20055df..8380f8848 100644 --- a/crates/sqlquack-duckdb/src/temporal/constants.rs +++ b/crates/sqlquack-duckdb/src/temporal/constants.rs @@ -166,3 +166,7 @@ pub const DATE_FROM_PARTS: &str = "duckdb.date_from_parts"; pub const TIMESTAMP_FROM_PARTS: &str = "duckdb.timestamp_from_parts"; /// The dates whose every instant DuckDB's nanosecond timestamps hold. pub const NANOSECOND_DATE_RANGE: (&str, &str) = ("1677-09-22", "2262-04-10"); +/// DuckDB's current date as a call, which a select item's alias `CURRENT_DATE` cannot capture. +pub const DUCKDB_CURRENT_DATE: &str = "current_date()"; +/// DuckDB's current timestamp as a call, which an alias `CURRENT_TIMESTAMP` cannot capture. +pub const DUCKDB_CURRENT_TIMESTAMP: &str = "get_current_timestamp()"; diff --git a/crates/sqlquack-rules/src/catalogue/constants.rs b/crates/sqlquack-rules/src/catalogue/constants.rs index 70e85d60e..1d6212b15 100644 --- a/crates/sqlquack-rules/src/catalogue/constants.rs +++ b/crates/sqlquack-rules/src/catalogue/constants.rs @@ -1250,7 +1250,7 @@ pub const RULES: &[RuleSpec] = &[ RuleSpec { id: AVERAGE, constructs: &["fn:AVG"], - conditions: "A NUMBER of scale at most 6 and precision at most 26.", + conditions: "A NUMBER of scale at most 6 and precision at most 26. AVG(DISTINCT) of a NUMBER is refused, since Snowflake types it with 3 more decimal places and no recording shows how it rounds.", failures: &[FailureMode { kind: ErrorKind::NumericOverflow, snowflake: &[NUMBER_OUT_OF_RANGE], diff --git a/crates/sqlquack-rules/src/conversion/_helpers/expressions/calls.rs b/crates/sqlquack-rules/src/conversion/_helpers/expressions/calls.rs index 1fb5fa2c5..a10eb1062 100644 --- a/crates/sqlquack-rules/src/conversion/_helpers/expressions/calls.rs +++ b/crates/sqlquack-rules/src/conversion/_helpers/expressions/calls.rs @@ -499,6 +499,14 @@ impl AggregateCall<'_> { let _rule = log.rule(AVERAGE); let refuse = |reason: String| outside_conditions(node_construct("avg"), reason); let argument = self.argument("avg")?; + if !self.framed + && flag(self.payload, "distinct") + && matches!(argument.data_type, SnowflakeType::Number { .. }) + { + return Err(refuse( + "AVG(DISTINCT) of a NUMBER, which Snowflake types with 3 more decimal places, not 6, and no recording shows how it rounds".to_owned(), + )); + } let total = sum_type(argument.data_type, self.site.context, "avg").map_err(refuse)?; let data_type = match self.framed { true => framed_average(argument.data_type, log), diff --git a/crates/sqlquack-rules/src/conversion/_helpers/expressions/temporal_functions.rs b/crates/sqlquack-rules/src/conversion/_helpers/expressions/temporal_functions.rs index 37b8073a9..cb25e49cd 100644 --- a/crates/sqlquack-rules/src/conversion/_helpers/expressions/temporal_functions.rs +++ b/crates/sqlquack-rules/src/conversion/_helpers/expressions/temporal_functions.rs @@ -69,6 +69,7 @@ use crate::conversion::constants::{ ZONED_PARTS, }; use sqlquack_duckdb::raises::main::raised::raised; +use sqlquack_duckdb::temporal::constants::{DUCKDB_CURRENT_DATE, DUCKDB_CURRENT_TIMESTAMP}; use sqlquack_policy::policy::constants::{ CURRENT_TIME, DATE_TEXT_SPELLING, SESSION_TIMEZONE_UTC, TIME_ZONE_SPELLING, TIMESTAMP_RANGE, }; @@ -1189,9 +1190,9 @@ pub(crate) fn current_time( diverge(site.context, CURRENT_TIME, construct)?; diverge(site.context, SESSION_TIMEZONE_UTC, construct)?; Ok(match name { - "CURRENT_DATE" => Emitted::new("current_date".to_owned(), SnowflakeType::Date), + "CURRENT_DATE" => Emitted::new(DUCKDB_CURRENT_DATE.to_owned(), SnowflakeType::Date), _ => Emitted::new( - "current_timestamp".to_owned(), + DUCKDB_CURRENT_TIMESTAMP.to_owned(), SnowflakeType::TimestampLtz { precision: 9 }, ), }) diff --git a/crates/sqlquack-rules/src/conversion/_helpers/queries/output_names.rs b/crates/sqlquack-rules/src/conversion/_helpers/queries/output_names.rs index b4904c54e..03e9577e7 100644 --- a/crates/sqlquack-rules/src/conversion/_helpers/queries/output_names.rs +++ b/crates/sqlquack-rules/src/conversion/_helpers/queries/output_names.rs @@ -36,6 +36,19 @@ pub(crate) fn recorded_name_shape(item: &Value, text: &str) -> bool { || (named(&["COUNT"]) && matches!(node_kind(argument), Some(("star", _)))) }) } + "function" if arguments.is_empty() => { + only(&["name", "args", "no_parens"]) + && matches!( + text.to_ascii_uppercase().as_str(), + "CURRENT_DATE()" | "CURRENT_DATE" | "CURRENT_TIMESTAMP()" + ) + } + "function" if named(&["ROUND"]) => { + only(&["name", "args"]) + && arguments.get(2).is_none() + && arguments.first().is_some_and(plain_column) + && arguments.iter().skip(1).all(integer_literal) + } "function" => { only(&["name", "args"]) && named(OUTPUT_NAMED_FUNCTIONS) diff --git a/crates/sqlquack/tests/cli/test_output_names.rs b/crates/sqlquack/tests/cli/test_output_names.rs index 766fbb11c..cc64a44f0 100644 --- a/crates/sqlquack/tests/cli/test_output_names.rs +++ b/crates/sqlquack/tests/cli/test_output_names.rs @@ -23,6 +23,44 @@ fn given_unaliased_items_when_converted_and_run_on_duckdb_then_they_take_snowfla flags: &[], expected_names: vec!["N\n + 1".to_owned()], }, + ColumnNameTestCase { + description: "ROUND and the current-time items, named as recorded", + sql: "SELECT ROUND(n, 1), ROUND(n), round( n, 0 ), current_date(), CURRENT_DATE, \ + CURRENT_TIMESTAMP() FROM (SELECT 1.25 AS n) AS input", + flags: &[], + expected_names: vec![ + "ROUND(N, 1)".to_owned(), + "ROUND(N)".to_owned(), + "ROUND( N, 0 )".to_owned(), + "CURRENT_DATE()".to_owned(), + "CURRENT_DATE".to_owned(), + "CURRENT_TIMESTAMP()".to_owned(), + ], + }, + ColumnNameTestCase { + description: "an alias spelled as the current-time keyword runs on DuckDB", + sql: "SELECT CURRENT_DATE() AS current_date, CURRENT_TIMESTAMP() AS current_timestamp", + flags: &[], + expected_names: vec!["CURRENT_DATE".to_owned(), "CURRENT_TIMESTAMP".to_owned()], + }, + ColumnNameTestCase { + description: "DISTINCT aggregates, named as recorded", + sql: "SELECT SUM(DISTINCT n), MAX(DISTINCT n) FROM (SELECT 1.25 AS n) AS input", + flags: &[], + expected_names: vec!["SUM(DISTINCT N)".to_owned(), "MAX(DISTINCT N)".to_owned()], + }, + ColumnNameTestCase { + description: "COALESCE of three and of numbers, a text cast and a spaced call, as recorded", + sql: "SELECT COALESCE(n, 0, 1), COALESCE(1, 2), CAST(g AS INTEGER), lower(g ) \ + FROM (SELECT 1.25 AS n, '7' AS g) AS input", + flags: &[], + expected_names: vec![ + "COALESCE(N, 0, 1)".to_owned(), + "COALESCE(1, 2)".to_owned(), + "CAST(G AS INTEGER)".to_owned(), + "LOWER(G )".to_owned(), + ], + }, ColumnNameTestCase { description: "numbers keep their written form, upper-cased", sql: "SELECT 1.50, 1e3, -2, NULL, false", @@ -46,6 +84,25 @@ fn given_unaliased_items_when_converted_and_run_on_duckdb_then_they_take_snowfla } } +#[test] +fn given_avg_distinct_of_a_number_when_converting_then_it_refuses() { + let test_cases = [ConvertTestCase { + description: "AVG(DISTINCT) of a NUMBER, which Snowflake types NUMBER(25,5) for NUMBER(10,2), refuses", + sql: "SELECT AVG(DISTINCT n) AS a FROM (SELECT 1.25 AS n) AS input", + flags: &[], + mention: "AVG(DISTINCT) of a NUMBER", + expected_outcome: convert_outcome(1, false), + }]; + for test_case in test_cases { + assert_eq!( + run_convert(test_case.sql, test_case.flags, test_case.mention), + test_case.expected_outcome, + "{}", + test_case.description + ); + } +} + #[test] fn given_unaliased_items_no_receipt_names_when_converting_then_each_refuses_with_sq0009() { let test_cases = [ @@ -232,15 +289,22 @@ fn given_unaliased_items_no_receipt_names_when_converting_then_each_refuses_with expected_outcome: convert_outcome(1, false), }, ConvertTestCase { - description: "ROUND, which no receipt names yet refuses with SQ0009", - sql: "SELECT ROUND(n, 1) FROM input", + description: "ROUND of an expression, which no receipt names, refuses with SQ0009", + sql: "SELECT ROUND(n + 1, 1) FROM input", + flags: &["--schema", UNALIASED_SCHEMA], + mention: UNVERIFIED_NAME, + expected_outcome: convert_outcome(1, false), + }, + ConvertTestCase { + description: "CURRENT_TIMESTAMP without parentheses, which no receipt names, refuses with SQ0009", + sql: "SELECT CURRENT_TIMESTAMP FROM input", flags: &["--schema", UNALIASED_SCHEMA], mention: UNVERIFIED_NAME, expected_outcome: convert_outcome(1, false), }, ConvertTestCase { - description: "CURRENT_DATE(), which no receipt names yet refuses with SQ0009", - sql: "SELECT CURRENT_DATE() FROM input", + description: "CURRENT_DATE( ) with a space, which no receipt names, refuses with SQ0009", + sql: "SELECT CURRENT_DATE( ) FROM input", flags: &["--schema", UNALIASED_SCHEMA], mention: UNVERIFIED_NAME, expected_outcome: convert_outcome(1, false), diff --git a/evidence/results/03a4a84eb27f2f213174ea73ca1b0dc604892b2443238307bdb53d0f571fe26c.arrow b/evidence/results/03a4a84eb27f2f213174ea73ca1b0dc604892b2443238307bdb53d0f571fe26c.arrow new file mode 100644 index 000000000..5fc2bb60a Binary files /dev/null and b/evidence/results/03a4a84eb27f2f213174ea73ca1b0dc604892b2443238307bdb53d0f571fe26c.arrow differ diff --git a/evidence/results/03a4a84eb27f2f213174ea73ca1b0dc604892b2443238307bdb53d0f571fe26c.json b/evidence/results/03a4a84eb27f2f213174ea73ca1b0dc604892b2443238307bdb53d0f571fe26c.json new file mode 100644 index 000000000..57b4dc8d3 --- /dev/null +++ b/evidence/results/03a4a84eb27f2f213174ea73ca1b0dc604892b2443238307bdb53d0f571fe26c.json @@ -0,0 +1,88 @@ +{ + "arrow_sha256": "261e58fbaa07677713c9cb5fb326e3b02de3c82241f71950914c9aa3f3796db1", + "case_hash": "03a4a84eb27f2f213174ea73ca1b0dc604892b2443238307bdb53d0f571fe26c", + "columns": [ + { + "internal_size": null, + "name": "COALESCE(N, 0, 1)", + "nullable": false, + "precision": 10, + "scale": 2, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "COALESCE(1, 2)", + "nullable": false, + "precision": 1, + "scale": 0, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "CAST(G AS INTEGER)", + "nullable": false, + "precision": 38, + "scale": 0, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": 134217728, + "name": "LOWER(G )", + "nullable": false, + "precision": null, + "scale": null, + "type_code": 2, + "type_name": "TEXT" + } + ], + "connector": "snowflake-connector-python 4.7.2", + "duckdb_version": "v2.0.0", + "effective_parameters": { + "BINARY_INPUT_FORMAT": "HEX", + "BINARY_OUTPUT_FORMAT": "HEX", + "DATE_INPUT_FORMAT": "AUTO", + "DATE_OUTPUT_FORMAT": "YYYY-MM-DD", + "DEFAULT_NULL_ORDERING": "LAST", + "GEOGRAPHY_OUTPUT_FORMAT": "GeoJSON", + "GEOMETRY_OUTPUT_FORMAT": "GeoJSON", + "JSON_INDENT": "2", + "QUOTED_IDENTIFIERS_IGNORE_CASE": "false", + "STRICT_JSON_OUTPUT": "false", + "TIMESTAMP_DAY_IS_ALWAYS_24H": "false", + "TIMESTAMP_INPUT_FORMAT": "AUTO", + "TIMESTAMP_LTZ_OUTPUT_FORMAT": "", + "TIMESTAMP_NTZ_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3", + "TIMESTAMP_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3 TZHTZM", + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMESTAMP_TZ_OUTPUT_FORMAT": "", + "TIMEZONE": "UTC", + "TIME_INPUT_FORMAT": "AUTO", + "TIME_OUTPUT_FORMAT": "HH24:MI:SS", + "TWO_DIGIT_CENTURY_START": "1970", + "USE_CACHED_RESULT": "false", + "WEEK_OF_YEAR_POLICY": "0", + "WEEK_START": "0" + }, + "error": null, + "format": 1, + "outcome": "rows", + "parameters_sha256": "d094d15417903748055eca8fde8cf2884751253939f05ad5ad8d9bf14299ac61", + "query_id_sha256": "2ac39cda67c648de58cfdcd77a9d876c15950427554c30e1b0beb30004789363", + "recorded_at": "2026-11-06T10:29:57.611560+00:00", + "recorder": "sqlquack-record 0.1.0", + "row_count": 0, + "session_parameters": { + "DEFAULT_NULL_ORDERING": "LAST", + "QUOTED_IDENTIFIERS_IGNORE_CASE": false, + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMEZONE": "UTC", + "USE_CACHED_RESULT": false, + "WEEK_OF_YEAR_POLICY": 0, + "WEEK_START": 0 + }, + "warehouse_version": "10.40.102" +} diff --git a/evidence/results/08a45c3252e8e18e403cbaa753d55e04fb961d475e7dc4dfdc0dbca414e800e9.arrow b/evidence/results/08a45c3252e8e18e403cbaa753d55e04fb961d475e7dc4dfdc0dbca414e800e9.arrow new file mode 100644 index 000000000..abe799634 Binary files /dev/null and b/evidence/results/08a45c3252e8e18e403cbaa753d55e04fb961d475e7dc4dfdc0dbca414e800e9.arrow differ diff --git a/evidence/results/08a45c3252e8e18e403cbaa753d55e04fb961d475e7dc4dfdc0dbca414e800e9.json b/evidence/results/08a45c3252e8e18e403cbaa753d55e04fb961d475e7dc4dfdc0dbca414e800e9.json new file mode 100644 index 000000000..18231d505 --- /dev/null +++ b/evidence/results/08a45c3252e8e18e403cbaa753d55e04fb961d475e7dc4dfdc0dbca414e800e9.json @@ -0,0 +1,79 @@ +{ + "arrow_sha256": "b64aaba5473990f3aa3f171ca0f13dfccef9afd1e265b771fc09614edfb4eac3", + "case_hash": "08a45c3252e8e18e403cbaa753d55e04fb961d475e7dc4dfdc0dbca414e800e9", + "columns": [ + { + "internal_size": null, + "name": "CURRENT_DATE()", + "nullable": false, + "precision": null, + "scale": null, + "type_code": 3, + "type_name": "DATE" + }, + { + "internal_size": null, + "name": "CURRENT_DATE", + "nullable": false, + "precision": null, + "scale": null, + "type_code": 3, + "type_name": "DATE" + }, + { + "internal_size": null, + "name": "CURRENT_TIMESTAMP()", + "nullable": false, + "precision": 0, + "scale": 9, + "type_code": 6, + "type_name": "TIMESTAMP_LTZ" + } + ], + "connector": "snowflake-connector-python 4.7.2", + "duckdb_version": "v2.0.0", + "effective_parameters": { + "BINARY_INPUT_FORMAT": "HEX", + "BINARY_OUTPUT_FORMAT": "HEX", + "DATE_INPUT_FORMAT": "AUTO", + "DATE_OUTPUT_FORMAT": "YYYY-MM-DD", + "DEFAULT_NULL_ORDERING": "LAST", + "GEOGRAPHY_OUTPUT_FORMAT": "GeoJSON", + "GEOMETRY_OUTPUT_FORMAT": "GeoJSON", + "JSON_INDENT": "2", + "QUOTED_IDENTIFIERS_IGNORE_CASE": "false", + "STRICT_JSON_OUTPUT": "false", + "TIMESTAMP_DAY_IS_ALWAYS_24H": "false", + "TIMESTAMP_INPUT_FORMAT": "AUTO", + "TIMESTAMP_LTZ_OUTPUT_FORMAT": "", + "TIMESTAMP_NTZ_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3", + "TIMESTAMP_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3 TZHTZM", + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMESTAMP_TZ_OUTPUT_FORMAT": "", + "TIMEZONE": "UTC", + "TIME_INPUT_FORMAT": "AUTO", + "TIME_OUTPUT_FORMAT": "HH24:MI:SS", + "TWO_DIGIT_CENTURY_START": "1970", + "USE_CACHED_RESULT": "false", + "WEEK_OF_YEAR_POLICY": "0", + "WEEK_START": "0" + }, + "error": null, + "format": 1, + "outcome": "rows", + "parameters_sha256": "d094d15417903748055eca8fde8cf2884751253939f05ad5ad8d9bf14299ac61", + "query_id_sha256": "612c6a2914df8786e60cdd31848fcfac315460152cad7eba311abfc250ea1848", + "recorded_at": "2026-11-06T10:15:37.599612+00:00", + "recorder": "sqlquack-record 0.1.0", + "row_count": 1, + "session_parameters": { + "DEFAULT_NULL_ORDERING": "LAST", + "QUOTED_IDENTIFIERS_IGNORE_CASE": false, + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMEZONE": "UTC", + "USE_CACHED_RESULT": false, + "WEEK_OF_YEAR_POLICY": 0, + "WEEK_START": 0 + }, + "warehouse_version": "10.40.102" +} diff --git a/evidence/results/1751713bd19a381c5e374dc282685e9e96f2b6fb94602d2673c193686be33db3.arrow b/evidence/results/1751713bd19a381c5e374dc282685e9e96f2b6fb94602d2673c193686be33db3.arrow new file mode 100644 index 000000000..59e95046c Binary files /dev/null and b/evidence/results/1751713bd19a381c5e374dc282685e9e96f2b6fb94602d2673c193686be33db3.arrow differ diff --git a/evidence/results/1751713bd19a381c5e374dc282685e9e96f2b6fb94602d2673c193686be33db3.json b/evidence/results/1751713bd19a381c5e374dc282685e9e96f2b6fb94602d2673c193686be33db3.json new file mode 100644 index 000000000..dbcc84dce --- /dev/null +++ b/evidence/results/1751713bd19a381c5e374dc282685e9e96f2b6fb94602d2673c193686be33db3.json @@ -0,0 +1,79 @@ +{ + "arrow_sha256": "3167a8fc8b27f58e1797eacbca6add084b26b8e8f531218469c8fe6837c7fd69", + "case_hash": "1751713bd19a381c5e374dc282685e9e96f2b6fb94602d2673c193686be33db3", + "columns": [ + { + "internal_size": null, + "name": "SUM(DISTINCT N)", + "nullable": true, + "precision": 22, + "scale": 2, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "MAX(DISTINCT N)", + "nullable": true, + "precision": 10, + "scale": 2, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "AVG(DISTINCT N)", + "nullable": true, + "precision": 25, + "scale": 5, + "type_code": 0, + "type_name": "FIXED" + } + ], + "connector": "snowflake-connector-python 4.7.2", + "duckdb_version": "v2.0.0", + "effective_parameters": { + "BINARY_INPUT_FORMAT": "HEX", + "BINARY_OUTPUT_FORMAT": "HEX", + "DATE_INPUT_FORMAT": "AUTO", + "DATE_OUTPUT_FORMAT": "YYYY-MM-DD", + "DEFAULT_NULL_ORDERING": "LAST", + "GEOGRAPHY_OUTPUT_FORMAT": "GeoJSON", + "GEOMETRY_OUTPUT_FORMAT": "GeoJSON", + "JSON_INDENT": "2", + "QUOTED_IDENTIFIERS_IGNORE_CASE": "false", + "STRICT_JSON_OUTPUT": "false", + "TIMESTAMP_DAY_IS_ALWAYS_24H": "false", + "TIMESTAMP_INPUT_FORMAT": "AUTO", + "TIMESTAMP_LTZ_OUTPUT_FORMAT": "", + "TIMESTAMP_NTZ_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3", + "TIMESTAMP_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3 TZHTZM", + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMESTAMP_TZ_OUTPUT_FORMAT": "", + "TIMEZONE": "UTC", + "TIME_INPUT_FORMAT": "AUTO", + "TIME_OUTPUT_FORMAT": "HH24:MI:SS", + "TWO_DIGIT_CENTURY_START": "1970", + "USE_CACHED_RESULT": "false", + "WEEK_OF_YEAR_POLICY": "0", + "WEEK_START": "0" + }, + "error": null, + "format": 1, + "outcome": "rows", + "parameters_sha256": "d094d15417903748055eca8fde8cf2884751253939f05ad5ad8d9bf14299ac61", + "query_id_sha256": "081e444da48e148bd71ec3025d989f434804f35538bfadd3888e363beb070d94", + "recorded_at": "2026-11-06T10:29:57.611560+00:00", + "recorder": "sqlquack-record 0.1.0", + "row_count": 1, + "session_parameters": { + "DEFAULT_NULL_ORDERING": "LAST", + "QUOTED_IDENTIFIERS_IGNORE_CASE": false, + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMEZONE": "UTC", + "USE_CACHED_RESULT": false, + "WEEK_OF_YEAR_POLICY": 0, + "WEEK_START": 0 + }, + "warehouse_version": "10.40.102" +} diff --git a/evidence/results/1af29e9c87ebceb9155ea873c3d459d72d08fbfb0144e3bffc8ea04a8a57d0a4.arrow b/evidence/results/1af29e9c87ebceb9155ea873c3d459d72d08fbfb0144e3bffc8ea04a8a57d0a4.arrow new file mode 100644 index 000000000..7e8526596 Binary files /dev/null and b/evidence/results/1af29e9c87ebceb9155ea873c3d459d72d08fbfb0144e3bffc8ea04a8a57d0a4.arrow differ diff --git a/evidence/results/1af29e9c87ebceb9155ea873c3d459d72d08fbfb0144e3bffc8ea04a8a57d0a4.json b/evidence/results/1af29e9c87ebceb9155ea873c3d459d72d08fbfb0144e3bffc8ea04a8a57d0a4.json new file mode 100644 index 000000000..abc57b935 --- /dev/null +++ b/evidence/results/1af29e9c87ebceb9155ea873c3d459d72d08fbfb0144e3bffc8ea04a8a57d0a4.json @@ -0,0 +1,70 @@ +{ + "arrow_sha256": "7345db83a3987b347fdc6fc2c78c28b308f9cabd7ec485c00eaf86fe3edf8304", + "case_hash": "1af29e9c87ebceb9155ea873c3d459d72d08fbfb0144e3bffc8ea04a8a57d0a4", + "columns": [ + { + "internal_size": null, + "name": "ROUND(N, 1)", + "nullable": false, + "precision": 11, + "scale": 1, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "ROUND(N)", + "nullable": false, + "precision": 11, + "scale": 0, + "type_code": 0, + "type_name": "FIXED" + } + ], + "connector": "snowflake-connector-python 4.7.2", + "duckdb_version": "v2.0.0", + "effective_parameters": { + "BINARY_INPUT_FORMAT": "HEX", + "BINARY_OUTPUT_FORMAT": "HEX", + "DATE_INPUT_FORMAT": "AUTO", + "DATE_OUTPUT_FORMAT": "YYYY-MM-DD", + "DEFAULT_NULL_ORDERING": "LAST", + "GEOGRAPHY_OUTPUT_FORMAT": "GeoJSON", + "GEOMETRY_OUTPUT_FORMAT": "GeoJSON", + "JSON_INDENT": "2", + "QUOTED_IDENTIFIERS_IGNORE_CASE": "false", + "STRICT_JSON_OUTPUT": "false", + "TIMESTAMP_DAY_IS_ALWAYS_24H": "false", + "TIMESTAMP_INPUT_FORMAT": "AUTO", + "TIMESTAMP_LTZ_OUTPUT_FORMAT": "", + "TIMESTAMP_NTZ_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3", + "TIMESTAMP_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3 TZHTZM", + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMESTAMP_TZ_OUTPUT_FORMAT": "", + "TIMEZONE": "UTC", + "TIME_INPUT_FORMAT": "AUTO", + "TIME_OUTPUT_FORMAT": "HH24:MI:SS", + "TWO_DIGIT_CENTURY_START": "1970", + "USE_CACHED_RESULT": "false", + "WEEK_OF_YEAR_POLICY": "0", + "WEEK_START": "0" + }, + "error": null, + "format": 1, + "outcome": "rows", + "parameters_sha256": "d094d15417903748055eca8fde8cf2884751253939f05ad5ad8d9bf14299ac61", + "query_id_sha256": "d36e211fc3fed8074451f2d41339da299eeeeceb73885ff1d1ec59e72a80f902", + "recorded_at": "2026-11-06T10:15:37.599612+00:00", + "recorder": "sqlquack-record 0.1.0", + "row_count": 0, + "session_parameters": { + "DEFAULT_NULL_ORDERING": "LAST", + "QUOTED_IDENTIFIERS_IGNORE_CASE": false, + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMEZONE": "UTC", + "USE_CACHED_RESULT": false, + "WEEK_OF_YEAR_POLICY": 0, + "WEEK_START": 0 + }, + "warehouse_version": "10.40.102" +} diff --git a/evidence/results/337b2509d2c7ab371940e49d02b778a55fbd62d94b2db1a51bee058a5767f90b.arrow b/evidence/results/337b2509d2c7ab371940e49d02b778a55fbd62d94b2db1a51bee058a5767f90b.arrow new file mode 100644 index 000000000..5382dbee4 Binary files /dev/null and b/evidence/results/337b2509d2c7ab371940e49d02b778a55fbd62d94b2db1a51bee058a5767f90b.arrow differ diff --git a/evidence/results/337b2509d2c7ab371940e49d02b778a55fbd62d94b2db1a51bee058a5767f90b.json b/evidence/results/337b2509d2c7ab371940e49d02b778a55fbd62d94b2db1a51bee058a5767f90b.json new file mode 100644 index 000000000..e28a1e04c --- /dev/null +++ b/evidence/results/337b2509d2c7ab371940e49d02b778a55fbd62d94b2db1a51bee058a5767f90b.json @@ -0,0 +1,88 @@ +{ + "arrow_sha256": "ea71f02f9f2089868f312d773d4447f76b2ac6753d467d4b79f599dedf0048b8", + "case_hash": "337b2509d2c7ab371940e49d02b778a55fbd62d94b2db1a51bee058a5767f90b", + "columns": [ + { + "internal_size": null, + "name": "COALESCE(N, 0, 1)", + "nullable": false, + "precision": 10, + "scale": 2, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "COALESCE(1, 2)", + "nullable": false, + "precision": 1, + "scale": 0, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "CAST(G AS INTEGER)", + "nullable": true, + "precision": 38, + "scale": 0, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": 134217728, + "name": "LOWER(G )", + "nullable": true, + "precision": null, + "scale": null, + "type_code": 2, + "type_name": "TEXT" + } + ], + "connector": "snowflake-connector-python 4.7.2", + "duckdb_version": "v2.0.0", + "effective_parameters": { + "BINARY_INPUT_FORMAT": "HEX", + "BINARY_OUTPUT_FORMAT": "HEX", + "DATE_INPUT_FORMAT": "AUTO", + "DATE_OUTPUT_FORMAT": "YYYY-MM-DD", + "DEFAULT_NULL_ORDERING": "LAST", + "GEOGRAPHY_OUTPUT_FORMAT": "GeoJSON", + "GEOMETRY_OUTPUT_FORMAT": "GeoJSON", + "JSON_INDENT": "2", + "QUOTED_IDENTIFIERS_IGNORE_CASE": "false", + "STRICT_JSON_OUTPUT": "false", + "TIMESTAMP_DAY_IS_ALWAYS_24H": "false", + "TIMESTAMP_INPUT_FORMAT": "AUTO", + "TIMESTAMP_LTZ_OUTPUT_FORMAT": "", + "TIMESTAMP_NTZ_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3", + "TIMESTAMP_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3 TZHTZM", + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMESTAMP_TZ_OUTPUT_FORMAT": "", + "TIMEZONE": "UTC", + "TIME_INPUT_FORMAT": "AUTO", + "TIME_OUTPUT_FORMAT": "HH24:MI:SS", + "TWO_DIGIT_CENTURY_START": "1970", + "USE_CACHED_RESULT": "false", + "WEEK_OF_YEAR_POLICY": "0", + "WEEK_START": "0" + }, + "error": null, + "format": 1, + "outcome": "rows", + "parameters_sha256": "d094d15417903748055eca8fde8cf2884751253939f05ad5ad8d9bf14299ac61", + "query_id_sha256": "d372a413c8acce29934a82ca7fe445a0daa1c1f993c109e548f4da8723445c13", + "recorded_at": "2026-11-06T10:29:57.611560+00:00", + "recorder": "sqlquack-record 0.1.0", + "row_count": 4, + "session_parameters": { + "DEFAULT_NULL_ORDERING": "LAST", + "QUOTED_IDENTIFIERS_IGNORE_CASE": false, + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMEZONE": "UTC", + "USE_CACHED_RESULT": false, + "WEEK_OF_YEAR_POLICY": 0, + "WEEK_START": 0 + }, + "warehouse_version": "10.40.102" +} diff --git a/evidence/results/c6a1f49638c1bc38bfe62156c5c8dd4a075b86ce9c00f8f4fd95e7f226732dc0.arrow b/evidence/results/c6a1f49638c1bc38bfe62156c5c8dd4a075b86ce9c00f8f4fd95e7f226732dc0.arrow new file mode 100644 index 000000000..765c458c7 Binary files /dev/null and b/evidence/results/c6a1f49638c1bc38bfe62156c5c8dd4a075b86ce9c00f8f4fd95e7f226732dc0.arrow differ diff --git a/evidence/results/c6a1f49638c1bc38bfe62156c5c8dd4a075b86ce9c00f8f4fd95e7f226732dc0.json b/evidence/results/c6a1f49638c1bc38bfe62156c5c8dd4a075b86ce9c00f8f4fd95e7f226732dc0.json new file mode 100644 index 000000000..8740f3889 --- /dev/null +++ b/evidence/results/c6a1f49638c1bc38bfe62156c5c8dd4a075b86ce9c00f8f4fd95e7f226732dc0.json @@ -0,0 +1,79 @@ +{ + "arrow_sha256": "1324d64781cde97814e1b890605b500a7c0c4b8fbdbfe859fd267f02c1e12e39", + "case_hash": "c6a1f49638c1bc38bfe62156c5c8dd4a075b86ce9c00f8f4fd95e7f226732dc0", + "columns": [ + { + "internal_size": null, + "name": "SUM(DISTINCT N)", + "nullable": true, + "precision": 22, + "scale": 2, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "MAX(DISTINCT N)", + "nullable": true, + "precision": 10, + "scale": 2, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "AVG(DISTINCT N)", + "nullable": true, + "precision": 25, + "scale": 5, + "type_code": 0, + "type_name": "FIXED" + } + ], + "connector": "snowflake-connector-python 4.7.2", + "duckdb_version": "v2.0.0", + "effective_parameters": { + "BINARY_INPUT_FORMAT": "HEX", + "BINARY_OUTPUT_FORMAT": "HEX", + "DATE_INPUT_FORMAT": "AUTO", + "DATE_OUTPUT_FORMAT": "YYYY-MM-DD", + "DEFAULT_NULL_ORDERING": "LAST", + "GEOGRAPHY_OUTPUT_FORMAT": "GeoJSON", + "GEOMETRY_OUTPUT_FORMAT": "GeoJSON", + "JSON_INDENT": "2", + "QUOTED_IDENTIFIERS_IGNORE_CASE": "false", + "STRICT_JSON_OUTPUT": "false", + "TIMESTAMP_DAY_IS_ALWAYS_24H": "false", + "TIMESTAMP_INPUT_FORMAT": "AUTO", + "TIMESTAMP_LTZ_OUTPUT_FORMAT": "", + "TIMESTAMP_NTZ_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3", + "TIMESTAMP_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3 TZHTZM", + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMESTAMP_TZ_OUTPUT_FORMAT": "", + "TIMEZONE": "UTC", + "TIME_INPUT_FORMAT": "AUTO", + "TIME_OUTPUT_FORMAT": "HH24:MI:SS", + "TWO_DIGIT_CENTURY_START": "1970", + "USE_CACHED_RESULT": "false", + "WEEK_OF_YEAR_POLICY": "0", + "WEEK_START": "0" + }, + "error": null, + "format": 1, + "outcome": "rows", + "parameters_sha256": "d094d15417903748055eca8fde8cf2884751253939f05ad5ad8d9bf14299ac61", + "query_id_sha256": "7f69572c9d26a20edf37c2e0203592591bb666431de392db3ee6fe5a31d74a00", + "recorded_at": "2026-11-06T10:29:57.611560+00:00", + "recorder": "sqlquack-record 0.1.0", + "row_count": 1, + "session_parameters": { + "DEFAULT_NULL_ORDERING": "LAST", + "QUOTED_IDENTIFIERS_IGNORE_CASE": false, + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMEZONE": "UTC", + "USE_CACHED_RESULT": false, + "WEEK_OF_YEAR_POLICY": 0, + "WEEK_START": 0 + }, + "warehouse_version": "10.40.102" +} diff --git a/evidence/results/e45ba0c883892fe6d1f132128c0c7441518034208c7d0655f694b839e2bf1788.arrow b/evidence/results/e45ba0c883892fe6d1f132128c0c7441518034208c7d0655f694b839e2bf1788.arrow new file mode 100644 index 000000000..820504ea9 Binary files /dev/null and b/evidence/results/e45ba0c883892fe6d1f132128c0c7441518034208c7d0655f694b839e2bf1788.arrow differ diff --git a/evidence/results/e45ba0c883892fe6d1f132128c0c7441518034208c7d0655f694b839e2bf1788.json b/evidence/results/e45ba0c883892fe6d1f132128c0c7441518034208c7d0655f694b839e2bf1788.json new file mode 100644 index 000000000..2ce0e1ee9 --- /dev/null +++ b/evidence/results/e45ba0c883892fe6d1f132128c0c7441518034208c7d0655f694b839e2bf1788.json @@ -0,0 +1,79 @@ +{ + "arrow_sha256": "4e90f2d758188dc2495839edefc3b350719abb76ed00c4105023e5a6c19308a1", + "case_hash": "e45ba0c883892fe6d1f132128c0c7441518034208c7d0655f694b839e2bf1788", + "columns": [ + { + "internal_size": null, + "name": "ROUND(N, 1)", + "nullable": true, + "precision": 11, + "scale": 1, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "ROUND(N)", + "nullable": true, + "precision": 11, + "scale": 0, + "type_code": 0, + "type_name": "FIXED" + }, + { + "internal_size": null, + "name": "ROUND( N, 0 )", + "nullable": true, + "precision": 11, + "scale": 0, + "type_code": 0, + "type_name": "FIXED" + } + ], + "connector": "snowflake-connector-python 4.7.2", + "duckdb_version": "v2.0.0", + "effective_parameters": { + "BINARY_INPUT_FORMAT": "HEX", + "BINARY_OUTPUT_FORMAT": "HEX", + "DATE_INPUT_FORMAT": "AUTO", + "DATE_OUTPUT_FORMAT": "YYYY-MM-DD", + "DEFAULT_NULL_ORDERING": "LAST", + "GEOGRAPHY_OUTPUT_FORMAT": "GeoJSON", + "GEOMETRY_OUTPUT_FORMAT": "GeoJSON", + "JSON_INDENT": "2", + "QUOTED_IDENTIFIERS_IGNORE_CASE": "false", + "STRICT_JSON_OUTPUT": "false", + "TIMESTAMP_DAY_IS_ALWAYS_24H": "false", + "TIMESTAMP_INPUT_FORMAT": "AUTO", + "TIMESTAMP_LTZ_OUTPUT_FORMAT": "", + "TIMESTAMP_NTZ_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3", + "TIMESTAMP_OUTPUT_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3 TZHTZM", + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMESTAMP_TZ_OUTPUT_FORMAT": "", + "TIMEZONE": "UTC", + "TIME_INPUT_FORMAT": "AUTO", + "TIME_OUTPUT_FORMAT": "HH24:MI:SS", + "TWO_DIGIT_CENTURY_START": "1970", + "USE_CACHED_RESULT": "false", + "WEEK_OF_YEAR_POLICY": "0", + "WEEK_START": "0" + }, + "error": null, + "format": 1, + "outcome": "rows", + "parameters_sha256": "d094d15417903748055eca8fde8cf2884751253939f05ad5ad8d9bf14299ac61", + "query_id_sha256": "fa6821ae91be62a7a7239183aa56b6eef96d0eef6b7fecd358c16be53188347f", + "recorded_at": "2026-11-06T10:15:37.599612+00:00", + "recorder": "sqlquack-record 0.1.0", + "row_count": 4, + "session_parameters": { + "DEFAULT_NULL_ORDERING": "LAST", + "QUOTED_IDENTIFIERS_IGNORE_CASE": false, + "TIMESTAMP_TYPE_MAPPING": "TIMESTAMP_NTZ", + "TIMEZONE": "UTC", + "USE_CACHED_RESULT": false, + "WEEK_OF_YEAR_POLICY": 0, + "WEEK_START": 0 + }, + "warehouse_version": "10.40.102" +} diff --git a/website/src/content/docs/docs/diagnostics/reference.mdx b/website/src/content/docs/docs/diagnostics/reference.mdx index 61b308d1f..a6885d9a7 100644 --- a/website/src/content/docs/docs/diagnostics/reference.mdx +++ b/website/src/content/docs/docs/diagnostics/reference.mdx @@ -140,7 +140,7 @@ echo "SELECT HASH(1) AS h" | sqlquack convert --builtin-policy **this column has no alias, and SQLQuack has not verified the name Snowflake gives it** (`unaliased_output_name`) -Snowflake names an unaliased select item after the expression's text, and a converted query must return the same column names. SQLQuack emits Snowflake's name only for the shapes recorded results verify, named by their text upper-cased as written: literals, columns and COUNT, SUM, MAX, AVG, LOWER, UPPER and COALESCE of columns, a column plus, minus, times, divided by or concatenated with a literal, and a column cast to INTEGER, written with single spaces and at most one line break. Other items, such as paths, CASE, nested calls or other functions, are refused rather than converted with a different column name. An alias fixes the name in both engines. +Snowflake names an unaliased select item after the expression's text, and a converted query must return the same column names. SQLQuack emits Snowflake's name only for the shapes recorded results verify, named by their text upper-cased as written: literals, columns and COUNT, SUM, MAX, AVG, LOWER, UPPER and COALESCE of columns, ROUND of a column, a column plus, minus, times, divided by or concatenated with a literal, a column cast to INTEGER, and CURRENT_DATE, CURRENT_DATE() or CURRENT_TIMESTAMP(), written with single spaces and at most one line break. Other items, such as paths, CASE, nested calls or other functions, are refused rather than converted with a different column name. An alias fixes the name in both engines. **Help:** add an alias, e.g. `AS one`