Skip to content

Commit 190700a

Browse files
authored
Add documentation to CAST operator. (#3668)
With #3647 we introduced support for `CAST` operator, this adds documentation of this operator, including supported casts, error codes, and degree of compliance to the SQL standard. This fixes #3662.
1 parent 7dc7393 commit 190700a

File tree

4 files changed

+318
-0
lines changed

4 files changed

+318
-0
lines changed

docs/sphinx/source/reference/Functions.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ This topic provides reference information for the system-defined functions.
77
.. toctree::
88
:maxdepth: 3
99

10+
Functions/cast_operator
1011
Functions/aggregate_functions
1112
Functions/scalar_functions
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
####
2+
CAST
3+
####
4+
5+
The CAST operator converts a value from one data type to another. CAST supports explicit type conversions according to SQL standard semantics.
6+
7+
Syntax
8+
######
9+
10+
.. code-block:: sql
11+
12+
CAST(expression AS target_type)
13+
14+
Parameters
15+
##########
16+
17+
* :sql:`expression`
18+
The value or expression to be converted.
19+
20+
* :sql:`target_type`
21+
The target data type. Can be a primitive type (:sql:`INTEGER`, :sql:`BIGINT`, :sql:`FLOAT`, :sql:`DOUBLE`, :sql:`STRING`, :sql:`BOOLEAN`) or an array type (e.g., :sql:`INTEGER ARRAY`, :sql:`STRING ARRAY`).
22+
23+
Supported Conversions
24+
#####################
25+
26+
Numeric Conversions
27+
-------------------
28+
29+
* Integer types: :sql:`INTEGER` ↔ :sql:`BIGINT`
30+
* Floating-point types: :sql:`FLOAT` ↔ :sql:`DOUBLE`
31+
* Mixed numeric: :sql:`INTEGER`/:sql:`BIGINT` ↔ :sql:`FLOAT`/:sql:`DOUBLE`
32+
* Narrowing conversions (e.g., :sql:`BIGINT` → :sql:`INTEGER`, :sql:`DOUBLE` → :sql:`FLOAT`) validate range and throw errors on overflow
33+
* Floating-point to INTEGER conversions use rounding (Math.round)
34+
35+
String Conversions
36+
------------------
37+
38+
* Any primitive type can be converted to :sql:`STRING`
39+
* :sql:`STRING` can be converted to numeric types (:sql:`INTEGER`, :sql:`BIGINT`, :sql:`FLOAT`, :sql:`DOUBLE`) with validation
40+
* Invalid string-to-numeric conversions throw errors
41+
42+
Boolean Conversions
43+
-------------------
44+
45+
* :sql:`BOOLEAN` → :sql:`INTEGER`: true = 1, false = 0
46+
* :sql:`INTEGER` → :sql:`BOOLEAN`: 0 = false, non-zero = true
47+
* :sql:`STRING` → :sql:`BOOLEAN`: accepts "true"/"1" → true, "false"/"0" → false (case-insensitive)
48+
49+
Array Conversions
50+
-----------------
51+
52+
* Arrays can be cast between compatible element types
53+
* Element type conversion rules follow the same rules as scalar conversions
54+
* Empty arrays can be cast to any array type
55+
* Invalid element conversions cause the entire operation to fail
56+
57+
SQL Standard Compatibility
58+
###########################
59+
60+
This implementation follows SQL standard CAST semantics with the following characteristics:
61+
62+
* Explicit type conversion (unlike implicit promotion)
63+
* Runtime validation with error reporting for invalid conversions
64+
* Range checking for narrowing conversions
65+
* :sql:`NULL` propagation: :sql:`CAST(NULL AS any_type)` returns :sql:`NULL`
66+
67+
**Empty Array Handling**: The system requires explicit :sql:`CAST` for empty array literals. An empty array literal ``[]`` without :sql:`CAST` is invalid and must be written as :sql:`CAST([] AS type ARRAY)` to specify the target element type. This ensures type safety and prevents ambiguity in array operations.
68+
69+
Examples
70+
########
71+
72+
Basic Numeric Conversions
73+
--------------------------
74+
75+
Convert INTEGER to different numeric types:
76+
77+
.. code-block:: sql
78+
79+
CREATE TABLE numbers(id BIGINT, value INTEGER, PRIMARY KEY(id))
80+
INSERT INTO numbers VALUES (1, 42)
81+
82+
SELECT CAST(value AS DOUBLE) AS value_as_double FROM numbers WHERE id = 1
83+
84+
Result:
85+
86+
.. list-table::
87+
:header-rows: 1
88+
89+
* - :sql:`value_as_double`
90+
* - :json:`42.0`
91+
92+
String to Numeric Conversion
93+
-----------------------------
94+
95+
Parse numeric strings:
96+
97+
.. code-block:: sql
98+
99+
CREATE TABLE data(id BIGINT, str_value STRING, PRIMARY KEY(id))
100+
INSERT INTO data VALUES (1, '123')
101+
102+
SELECT CAST(str_value AS INTEGER) AS parsed_number FROM data WHERE id = 1
103+
104+
Result:
105+
106+
.. list-table::
107+
:header-rows: 1
108+
109+
* - :sql:`parsed_number`
110+
* - :json:`123`
111+
112+
Numeric to String Conversion
113+
-----------------------------
114+
115+
Convert numbers to strings:
116+
117+
.. code-block:: sql
118+
119+
CREATE TABLE numbers(id BIGINT, value INTEGER, PRIMARY KEY(id))
120+
INSERT INTO numbers VALUES (1, 42)
121+
122+
SELECT CAST(value AS STRING) AS value_as_string FROM numbers WHERE id = 1
123+
124+
Result:
125+
126+
.. list-table::
127+
:header-rows: 1
128+
129+
* - :sql:`value_as_string`
130+
* - :json:`"42"`
131+
132+
Boolean Conversions
133+
--------------------
134+
135+
Convert between boolean and INTEGER:
136+
137+
.. code-block:: sql
138+
139+
CREATE TABLE flags(id BIGINT, active BOOLEAN, PRIMARY KEY(id))
140+
INSERT INTO flags VALUES (1, true), (2, false)
141+
142+
SELECT CAST(active AS INTEGER) AS active_as_int FROM flags
143+
144+
Result:
145+
146+
.. list-table::
147+
:header-rows: 1
148+
149+
* - :sql:`active_as_int`
150+
* - :json:`1`
151+
* - :json:`0`
152+
153+
Array Type Conversion
154+
----------------------
155+
156+
Convert arrays between element types:
157+
158+
.. code-block:: sql
159+
160+
CREATE TABLE arrays(id BIGINT, PRIMARY KEY(id))
161+
INSERT INTO arrays VALUES (1)
162+
163+
SELECT CAST([1, 2, 3] AS STRING ARRAY) AS string_array FROM arrays WHERE id = 1
164+
165+
Result:
166+
167+
.. list-table::
168+
:header-rows: 1
169+
170+
* - :sql:`string_array`
171+
* - :json:`["1", "2", "3"]`
172+
173+
Empty Array Casting
174+
-------------------
175+
176+
Empty arrays must specify target type:
177+
178+
.. code-block:: sql
179+
180+
CREATE TABLE arrays(id BIGINT, PRIMARY KEY(id))
181+
INSERT INTO arrays VALUES (1)
182+
183+
SELECT CAST([] AS INTEGER ARRAY) AS empty_int_array FROM arrays WHERE id = 1
184+
185+
Result:
186+
187+
.. list-table::
188+
:header-rows: 1
189+
190+
* - :sql:`empty_int_array`
191+
* - :json:`[]`
192+
193+
Nested Conversions
194+
------------------
195+
196+
Combine multiple CAST operations:
197+
198+
.. code-block:: sql
199+
200+
CREATE TABLE numbers(id BIGINT, value INTEGER, PRIMARY KEY(id))
201+
INSERT INTO numbers VALUES (1, 42)
202+
203+
SELECT CAST(CAST(value AS STRING) AS DOUBLE) AS nested_cast FROM numbers WHERE id = 1
204+
205+
Result:
206+
207+
.. list-table::
208+
:header-rows: 1
209+
210+
* - :sql:`nested_cast`
211+
* - :json:`42.0`
212+
213+
Error Handling
214+
##############
215+
216+
:sql:`CAST` operations that fail will raise a :sql:`INVALID_CAST` error (error code ``22F3H``). This includes:
217+
218+
* Invalid string-to-numeric conversions
219+
* Range overflow in narrowing conversions
220+
* Invalid boolean string values
221+
* Incompatible type conversions
222+
* :sql:`NULL` array element types
223+
224+
Invalid Conversions
225+
-------------------
226+
227+
String values that cannot be parsed as numbers result in errors:
228+
229+
.. code-block:: sql
230+
231+
CREATE TABLE data(id BIGINT, str_value STRING, PRIMARY KEY(id))
232+
INSERT INTO data VALUES (1, 'invalid')
233+
234+
SELECT CAST(str_value AS INTEGER) FROM data WHERE id = 1
235+
-- Error: Cannot cast string 'invalid' to INT
236+
-- Error Code: 22F3H (INVALID_CAST)
237+
238+
Range Overflow
239+
--------------
240+
241+
Narrowing conversions that exceed target type range result in errors:
242+
243+
.. code-block:: sql
244+
245+
CREATE TABLE numbers(id BIGINT, PRIMARY KEY(id))
246+
INSERT INTO numbers VALUES (1)
247+
248+
SELECT CAST(9223372036854775807 AS INTEGER) FROM numbers WHERE id = 1
249+
-- Error: Value out of range for INT
250+
-- Error Code: 22F3H (INVALID_CAST)

yaml-tests/src/test/java/DocumentationQueriesTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,9 @@ class DocumentationQueriesTests {
3333
void withDocumentationQueriesTests(YamlTest.Runner runner) throws Exception {
3434
runner.runYamsql(PREFIX + "/with-documentation-queries.yamsql");
3535
}
36+
37+
@TestTemplate
38+
void castDocumentationQueriesTests(YamlTest.Runner runner) throws Exception {
39+
runner.runYamsql(PREFIX + "/cast-documentation-queries.yamsql");
40+
}
3641
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
schema_template:
3+
create table numbers(id bigint, value integer, primary key(id))
4+
create table data(id bigint, str_value string, primary key(id))
5+
create table flags(id bigint, active boolean, primary key(id))
6+
create table arrays(id bigint, primary key(id))
7+
---
8+
setup:
9+
steps:
10+
- query: insert into numbers values (1, 42)
11+
- query: insert into data values (1, '123'), (2, 'invalid')
12+
- query: insert into flags values (1, true), (2, false)
13+
- query: insert into arrays values (1)
14+
---
15+
test_block:
16+
name: cast-documentation-tests
17+
preset: single_repetition_ordered
18+
tests:
19+
# Basic Numeric Conversions
20+
-
21+
- query: SELECT CAST(value AS DOUBLE) AS value_as_double FROM numbers WHERE id = 1
22+
- result: [{value_as_double: 42.0}]
23+
24+
# String to Numeric Conversion
25+
-
26+
- query: SELECT CAST(str_value AS INTEGER) AS parsed_number FROM data WHERE id = 1
27+
- result: [{parsed_number: 123}]
28+
29+
# Numeric to String Conversion
30+
-
31+
- query: SELECT CAST(value AS STRING) AS value_as_string FROM numbers WHERE id = 1
32+
- result: [{value_as_string: "42"}]
33+
34+
# Boolean Conversions
35+
-
36+
- query: SELECT CAST(active AS INTEGER) AS active_as_int FROM flags
37+
- unorderedResult: [{active_as_int: 1}, {active_as_int: 0}]
38+
39+
# Array Type Conversion
40+
-
41+
- query: SELECT CAST([1, 2, 3] AS STRING ARRAY) AS string_array FROM arrays WHERE id = 1
42+
- result: [{string_array: ["1", "2", "3"]}]
43+
44+
# Empty Array Casting
45+
-
46+
- query: SELECT CAST([] AS INTEGER ARRAY) AS empty_int_array FROM arrays WHERE id = 1
47+
- result: [{empty_int_array: []}]
48+
49+
# Nested Conversions
50+
-
51+
- query: SELECT CAST(CAST(value AS STRING) AS DOUBLE) AS nested_cast FROM numbers WHERE id = 1
52+
- result: [{nested_cast: 42.0}]
53+
54+
# Invalid Conversions - String to Integer Error
55+
-
56+
- query: SELECT CAST(str_value AS INTEGER) FROM data WHERE id = 2
57+
- error: "22F3H"
58+
59+
# Range Overflow - BIGINT to INT Error
60+
-
61+
- query: SELECT CAST(9223372036854775807 AS INTEGER) FROM numbers WHERE id = 1
62+
- error: "22F3H"

0 commit comments

Comments
 (0)