Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e675d17
cases: text cast to BINARY under the HEX input format
kvlonge Nov 6, 2026
c061da6
evidence: record text casts to BINARY under the HEX input format
kvlonge Nov 6, 2026
d92cf53
cases: tag the BINARY(2) overflow case as the error Snowflake raised
kvlonge Nov 6, 2026
902d301
refactor: move the recorded time zone names into a time_zones domain
kvlonge Nov 6, 2026
cfc7268
BINARY type and the VARCHAR to BINARY cast from the recorded receipts
kvlonge Nov 6, 2026
6a16e3e
Byte-wise LENGTH, LEFT/RIGHT/SUBSTR, LPAD/RPAD, POSITION and concaten…
kvlonge Nov 6, 2026
29f1095
coverage: re-record the translation results baseline for BINARY
kvlonge Nov 6, 2026
13a2797
Declare obligations for the VARCHAR to BINARY cast cases
kvlonge Nov 6, 2026
d45bb0e
Refuse BINARY to BINARY(n) and out-of-range BINARY lengths (#129 revi…
kvlonge Nov 6, 2026
7928dad
Check the length of a BINARY value cast to BINARY(n) (#129 review rou…
kvlonge Nov 6, 2026
57820de
cases: BINARY values cast to BINARY(n), fitting and too long
kvlonge Nov 6, 2026
5c904d2
evidence: record BINARY values cast to BINARY(n)
kvlonge Nov 6, 2026
6a58b71
Declare obligations for BINARY values cast to BINARY(n)
kvlonge Nov 6, 2026
e0fec44
cases: say that a BINARY value cast to a shorter BINARY raises
kvlonge Nov 6, 2026
5b4dead
cases: BINARY values cast with :: to BINARY(n), fitting and too long
kvlonge Nov 6, 2026
bc53610
evidence: record BINARY values cast with :: to BINARY(n)
kvlonge Nov 6, 2026
572b3ea
cases: say that a BINARY value cast with :: to a shorter BINARY raises
kvlonge Nov 6, 2026
0ce7f74
Declare obligations for BINARY values cast to BINARY(n) with ::
kvlonge Nov 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions cases/translation/functions/cast.cast-as.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,85 @@ rows = [
query = "SELECT CAST(x AS NUMBER) AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["null"]

[[case]]
id = "t006_text_to_binary"
description = "Hex text in upper, lower and mixed case cast to BINARY under BINARY_INPUT_FORMAT HEX. Catches: the text's UTF-8 bytes taken instead of its hex digits, or case-sensitive hex"
columns = [{ name = "v", type = "VARCHAR" }]
rows = [
["'ABCD'"],
["'00ff10'"],
["'4a4B'"],
]
query = "SELECT CAST(v AS BINARY) AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["type-combination"]

[[case]]
id = "t007_binary_empty_and_null"
description = "Empty text and NULL cast to BINARY. Catches: empty text read as NULL, or NULL as empty"
columns = [{ name = "v", type = "VARCHAR" }]
rows = [
["''"],
["NULL"],
]
query = "SELECT CAST(v AS BINARY) AS r, CAST(v AS BINARY) IS NULL AS n FROM input ORDER BY ordinal"
order = "ordered"
tags = ["boundary"]

[[case]]
id = "t008_binary_odd_length"
description = "Hex text of odd length cast to BINARY; no page says what an odd digit count does, so the receipt decides. Catches: a padded or truncated byte"
columns = [{ name = "v", type = "VARCHAR" }]
rows = [
["'ABC'"],
]
query = "SELECT CAST(v AS BINARY) AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["error"]

[[case]]
id = "t009_binary_invalid_digit"
description = "Text with a non-hex character cast to BINARY. Catches: the character skipped or read as 0"
columns = [{ name = "v", type = "VARCHAR" }]
rows = [
["'0G'"],
]
query = "SELECT CAST(v AS BINARY) AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["error"]

[[case]]
id = "t010_binary_length"
description = "Hex text of two and three bytes cast to BINARY(2), with its length; Snowflake raises for the three-byte value, failing the query. Catches: the excess bytes silently truncated, or the declared length ignored"
columns = [{ name = "v", type = "VARCHAR" }]
rows = [
["'ABCD'"],
["'ABCDEF'"],
]
query = "SELECT CAST(v AS BINARY(2)) AS r, LENGTH(CAST(v AS BINARY(2))) AS l FROM input ORDER BY ordinal"
order = "ordered"
tags = ["error"]

[[case]]
id = "t011_binary_to_binary_fits"
description = "A BINARY value cast to a BINARY(n) it fits, with its length. Catches: the bytes changed or re-read as hex text"
columns = [{ name = "b", type = "BINARY" }]
rows = [
["'AABB'"],
["NULL"],
]
query = "SELECT CAST(b AS BINARY(2)) AS r, LENGTH(CAST(b AS BINARY(2))) AS l FROM input ORDER BY ordinal"
order = "ordered"
tags = ["boundary"]

[[case]]
id = "t012_binary_to_shorter_binary"
description = "A three-byte BINARY value cast to BINARY(2); a BINARY value raises 100145 here, exactly as the cast of hex text does (t010). Catches: the excess byte silently truncated"
columns = [{ name = "b", type = "BINARY" }]
rows = [
["'AABBCC'"],
]
query = "SELECT CAST(b AS BINARY(2)) AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["error"]
35 changes: 35 additions & 0 deletions cases/translation/functions/cast.double-colon.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,38 @@ rows = [
query = "SELECT x::NUMBER AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["null"]

[[case]]
id = "t006_text_to_binary"
description = "Hex text cast to BINARY with ::, beside NULL. Catches: :: read differently from CAST"
columns = [{ name = "v", type = "VARCHAR" }]
rows = [
["'00ff10'"],
["NULL"],
]
query = "SELECT v::BINARY AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["type-combination"]

[[case]]
id = "t007_binary_to_binary_fits"
description = "A BINARY value cast with :: to a BINARY(n) it fits, with its length, beside NULL. Catches: :: read differently from CAST, or the bytes re-read as hex text"
columns = [{ name = "b", type = "BINARY" }]
rows = [
["'AABB'"],
["NULL"],
]
query = "SELECT b::BINARY(2) AS r, LENGTH(b::BINARY(2)) AS l FROM input ORDER BY ordinal"
order = "ordered"
tags = ["boundary"]

[[case]]
id = "t008_binary_to_shorter_binary"
description = "A three-byte BINARY value cast with :: to BINARY(2); :: raises 100145 here, exactly as CAST does (cast-as t012). Catches: the excess byte silently truncated"
columns = [{ name = "b", type = "BINARY" }]
rows = [
["'AABBCC'"],
]
query = "SELECT b::BINARY(2) AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["error"]
14 changes: 14 additions & 0 deletions cases/translation/functions/try-cast.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,17 @@ rows = [
query = "SELECT TRY_CAST(v AS NUMBER) AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["null"]

[[case]]
id = "t006_text_to_binary"
description = "TRY_CAST of valid hex, odd-length hex, a non-hex character and NULL to BINARY. Catches: an error instead of NULL, or a partial value"
columns = [{ name = "v", type = "VARCHAR" }]
rows = [
["'4a4B'"],
["'ABC'"],
["'0G'"],
["NULL"],
]
query = "SELECT TRY_CAST(v AS BINARY) AS r FROM input ORDER BY ordinal"
order = "ordered"
tags = ["type-combination"]
122 changes: 122 additions & 0 deletions coverage/translation/obligations/functions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5692,6 +5692,84 @@ reading = "the page: converts the expression to the target type; a scale too sma
cases = ["cases/translation/functions/cast.cast-as.toml#t005_null_source_expr"]
required = true

[[obligation]]
id = "sf.functions.cast.cast-as.t006"
form = "sf.functions.cast.cast-as"
kind = "type_combination"
target = "VARCHAR to BINARY"
note = "Hex text in upper, lower and mixed case cast to BINARY under BINARY_INPUT_FORMAT HEX."
catches = "the text's UTF-8 bytes taken instead of its hex digits, or the hex read case-sensitively"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the binary input and output page: under BINARY_INPUT_FORMAT HEX (the default) each byte is two hex digits, 0 to 9 and A to F, and text to binary is case-insensitive"
cases = ["cases/translation/functions/cast.cast-as.toml#t006_text_to_binary"]
required = true

[[obligation]]
id = "sf.functions.cast.cast-as.t007"
form = "sf.functions.cast.cast-as"
kind = "boundary"
subkind = "empty_string"
target = "empty_string"
note = "Empty text and NULL cast to BINARY."
catches = "empty text read as NULL, or NULL as an empty value"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the binary input and output page: under BINARY_INPUT_FORMAT HEX (the default) each byte is two hex digits, 0 to 9 and A to F, and text to binary is case-insensitive"
cases = ["cases/translation/functions/cast.cast-as.toml#t007_binary_empty_and_null"]
required = true

[[obligation]]
id = "sf.functions.cast.cast-as.t008"
form = "sf.functions.cast.cast-as"
kind = "error_parity"
target = "error"
note = "Hex text of odd length cast to BINARY. No page says what an odd digit count does; each byte being two digits, the receipt shows Snowflake raises (100115)."
catches = "a padded or truncated byte returned instead of the error"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the binary input and output page: under BINARY_INPUT_FORMAT HEX (the default) each byte is two hex digits, 0 to 9 and A to F, and text to binary is case-insensitive"
cases = ["cases/translation/functions/cast.cast-as.toml#t008_binary_odd_length"]
required = true

[[obligation]]
id = "sf.functions.cast.cast-as.t009"
form = "sf.functions.cast.cast-as"
kind = "error_parity"
target = "error"
note = "Text with a non-hex character cast to BINARY, which Snowflake raises (100115)."
catches = "the character skipped or read as 0"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the binary input and output page: under BINARY_INPUT_FORMAT HEX (the default) each byte is two hex digits, 0 to 9 and A to F, and text to binary is case-insensitive"
cases = ["cases/translation/functions/cast.cast-as.toml#t009_binary_invalid_digit"]
required = true

[[obligation]]
id = "sf.functions.cast.cast-as.t010"
form = "sf.functions.cast.cast-as"
kind = "error_parity"
target = "error"
note = "Two- and three-byte hex text cast to BINARY(2); the three-byte value raises (100145) and fails the query."
catches = "the excess bytes silently truncated, or the declared length ignored"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the text data types page: BINARY(N) declares the maximum number of bytes; the binary input and output page: under BINARY_INPUT_FORMAT HEX (the default) each byte is two hex digits, 0 to 9 and A to F, and text to binary is case-insensitive"
cases = ["cases/translation/functions/cast.cast-as.toml#t010_binary_length"]
required = true

[[obligation]]
id = "sf.functions.cast.cast-as.t011"
form = "sf.functions.cast.cast-as"
kind = "type_combination"
target = "BINARY to BINARY(n)"
note = "A two-byte BINARY value and NULL cast to BINARY(2), which it exactly fills, with the length."
catches = "the bytes changed or re-read as hex text, the length not 2, or the NULL lost"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the text data types page: BINARY(N) declares the maximum number of bytes"
cases = ["cases/translation/functions/cast.cast-as.toml#t011_binary_to_binary_fits"]
required = true

[[obligation]]
id = "sf.functions.cast.cast-as.t012"
form = "sf.functions.cast.cast-as"
kind = "error_parity"
target = "error"
note = "A three-byte BINARY value cast to BINARY(2); the receipt shows Snowflake raises 100145 (22000), as it does for hex text (t010)."
catches = "the excess byte silently truncated instead of the error"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the text data types page: BINARY(N) declares the maximum number of bytes"
cases = ["cases/translation/functions/cast.cast-as.toml#t012_binary_to_shorter_binary"]
required = true

[[obligation]]
id = "sf.functions.cast.double-colon.t001"
form = "sf.functions.cast.double-colon"
Expand Down Expand Up @@ -5748,6 +5826,39 @@ reading = "the page: converts the expression to the target type; a scale too sma
cases = ["cases/translation/functions/cast.double-colon.toml#t005_null_source_expr"]
required = true

[[obligation]]
id = "sf.functions.cast.double-colon.t006"
form = "sf.functions.cast.double-colon"
kind = "type_combination"
target = "VARCHAR to BINARY"
note = "Hex text cast to BINARY with ::, beside NULL."
catches = ":: read differently from CAST, or the NULL not kept"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the binary input and output page: under BINARY_INPUT_FORMAT HEX (the default) each byte is two hex digits, 0 to 9 and A to F, and text to binary is case-insensitive"
cases = ["cases/translation/functions/cast.double-colon.toml#t006_text_to_binary"]
required = true

[[obligation]]
id = "sf.functions.cast.double-colon.t007"
form = "sf.functions.cast.double-colon"
kind = "type_combination"
target = "BINARY to BINARY(n)"
note = "A two-byte BINARY value and NULL cast with :: to BINARY(2), which it exactly fills, with the length."
catches = ":: read differently from CAST, the bytes re-read as hex text, the length not 2, or the NULL lost"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the text data types page: BINARY(N) declares the maximum number of bytes"
cases = ["cases/translation/functions/cast.double-colon.toml#t007_binary_to_binary_fits"]
required = true

[[obligation]]
id = "sf.functions.cast.double-colon.t008"
form = "sf.functions.cast.double-colon"
kind = "error_parity"
target = "error"
note = "A three-byte BINARY value cast with :: to BINARY(2); the receipt shows Snowflake raises 100145 (22000), as CAST does (cast-as t012)."
catches = "the excess byte silently truncated instead of the error"
reading = "the page: converts the expression to the target type; a scale too small to hold the value rounds it; a precision too small raises an error; the text data types page: BINARY(N) declares the maximum number of bytes"
cases = ["cases/translation/functions/cast.double-colon.toml#t008_binary_to_shorter_binary"]
required = true

[[obligation]]
id = "sf.functions.cbrt.t001"
form = "sf.functions.cbrt"
Expand Down Expand Up @@ -30934,6 +31045,17 @@ reading = "the page: like CAST, but NULL where the conversion fails; only string
cases = ["cases/translation/functions/try-cast.toml#t005_null_source_string_expr"]
required = true

[[obligation]]
id = "sf.functions.try-cast.t006"
form = "sf.functions.try-cast"
kind = "type_combination"
target = "VARCHAR to BINARY"
note = "Valid hex, odd-length hex, a non-hex character and NULL under TRY_CAST to BINARY. The page does not list BINARY among the targets; the receipt shows Snowflake accepts it and returns NULL for the two invalid values."
catches = "an error raised instead of NULL, or a partial value"
reading = "the page: like CAST, but NULL where the conversion fails; only string expressions are accepted, to VARCHAR, NUMBER, DOUBLE, BOOLEAN, DATE, TIME or a timestamp type; the binary input and output page: under BINARY_INPUT_FORMAT HEX (the default) each byte is two hex digits, 0 to 9 and A to F, and text to binary is case-insensitive"
cases = ["cases/translation/functions/try-cast.toml#t006_text_to_binary"]
required = true

[[obligation]]
id = "sf.functions.try-decrypt.t001"
form = "sf.functions.try-decrypt"
Expand Down
Loading