WL#529: Add CAST to FLOAT/DOUBLE/REAL
Affects: Server-8.0
—
Status: Complete
MySQL will add another CAST function to support cast operations to FLOATING point data types according to the SQL Standard. Rationale: Our current CAST capabilities do not permit users to cast values to floating point data types as required by standard SQL and supported by other DBMSs. Since implicit CASTs support a greater variety of cast possibilities, the explicit CAST support should be augmented to match it. For example: SELECT CAST(1/3 AS DOUBLE); # not allowed at this moment Will return: mysql> SELECT CAST(1/3 AS DOUBLE); Field 1: `CAST(1/3 AS DOUBLE)` Catalog: `def` Database: `` Table: `` Org_table: `` Type: DOUBLE Collation: binary (63) Length: 22 Max_length: 11 Decimals: 31 Flags: BINARY NUM +---------------------+ | CAST(1/3 AS DOUBLE) | +---------------------+ | 0.333333333 | +---------------------+ 1 row in set (0,00 sec)
FR1: CAST expressions must also support asfloating point data types: FLOAT(*), DOUBLE, DOUBLE PRECISION(**), REAL(***) ::= CAST AS ::= DOUBLE | DOUBLE PRECISION | REAL | FLOAT [ N ]; Example: CAST (1/3 AS FLOAT); ^^^^^ CAST (1/3 AS FLOAT(22)); ^^^^^^^^^ CAST (1/3 AS DOUBLE); ^^^^^^ CAST (1/3 AS DOUBLE PRECISION); ^^^^^^^^^^^^^^^^ CAST (1/3 AS REAL); ^^^^ Notes:(*) FLOAT is ambiguous in MySQL: it is both the 32bit floating point data type (which is REAL in SQL standard), and it can be used to specify a floating point type with the minimum specified binary precision. (**) DOUBLE PRECISION - a synonym for DOUBLE (in MySQL) (***) REAL - synonym for DOUBLE - unless REAL_AS_FLOAT sql_mode is specified. FR2: for FLOAT(N) as , if N is specified then, if N> 53 or N < 0, error should be returned. FR3: for FLOAT(N) as , if N is specified and N <= 24, then the cast will be to FLOAT ex: CAST(1/3 AS FLOAT(10)) <=> CAST (1/3 AS FLOAT) FR4: for FLOAT(N) as , if N is specified and N > 24, then the cast will be to DOUBLE ex: CAST(1/3 AS FLOAT(24)) <=> CAST (1/3 AS DOUBLE) FR5: if is REAL and sql_mode is set to REAL_AS_FLOAT then the cast will be to FLOAT ex: CAST(1/3 AS REAL) <=> CAST (1/3 AS FLOAT) FR6: if is REAL and sql_mode is NOT set to REAL_AS_FLOAT then the cast will be to DOUBLE ex: CAST(1/3 AS REAL) <=> CAST (1/3 AS DOUBLE)
Before discussing the cast function to float/double let's first mention how MySQL defines FLOAT/DOUBLE/REAL. - FLOAT/DOUBLE/DOUBLE PRECISION/REAL - FLOAT(N), where N BETWEEN 0-53 (*) - FLOAT/DOUBLE/REAL (M,D) (**) Since "FLOAT/DOUBLE/REAL (M,D)" is going to be deprecated soon, CAST (x AS floating-point-data-type) will only need the handle the first two cases. ----- (*) According to the SQL standard N should be the binary precision specifier, and the binary precision should be equal to or greater than the value of the specified precision (N). MySQL chose to translate this to either REAL (FLOAT) or DOUBLE. Ex. FLOAT(N) where N= 0-24 will be stored as FLOAT and N=25-53 will be stored as DOUBLE. (**) Non-standard syntax where (M,D) means that values can be stored with up to M digits in total, of which D digits may be after the decimal point. --- With regards to the source of the cast, we have the following specifications in the SQL2016 standard: The following chart shows the standard SQL possibilities for casting between approximate numeric and the other data types. "Y” indicates that the combination is syntactically valid without restriction; “M” indicates that the combination is valid (subject to other Syntax Rules in this Sub-clause being satisfied;) and “N” indicate that the combination is not valid. Source data type: EN AN DF C D T TS B RW Allowed: Y Y Y Y N N N N N Where: EN = Exact Numeric AN = Approximate Numeric DF = Decimal Floating-Point C = Character (Fixed- or Variable-Length, or Character Large Object) D = Date T = Time TS = Timestamp B = Binary (Fixed- or Variable-Length or Binary Large Object) RW = Row type Where client-facing MySQL data types are: EN = YEAR, TINYINT, SMALLINT, MEDIUMINT, INT, INTEGER, BIGINT,(BIT, BOOL, BOOLEAN) AN = FLOAT, DOUBLE, DOUBLE PRECISION, REAL DF = DECIMAL, DEC C = CHAR, VARCHAR, TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT D = DATE, DATETIME T = TIME TS = TIMESTAMP B = BINARY, VARBINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB, ENUM, SET, JSON, GEOMETRY (BIT is INTEGER in MySQL) RW = N/A MySQL support for cast will be extended beyond the SQL2016 standard and will only reject GEOMETRY.
Item_typecast_real class will be created to store the CAST details create_func_cast will handle the creation of Item_typecast_real and validation of the optional N parameter so that: - if N > 53 or N < 0, error Renamed existing typecast classes: INT_RESULT: Item_func_signed => Item_typecast_signed Item_func_unsigned => Item_typecast_unsigned DECIMAL_RESULT: Item_decimal_typecast => Item_typecast_decimal REAL_RESULT: Item_typecast_real (added in WL#529) STRING_RESULT(date/time related): Item_date_typecast => Item_typecast_date Item_time_typecast => Item_typecast_time Item_datetime_typecast => Item_typecast_datetime STRING_RESULT(will not be used by this WL): Item_func_binary => Item_typecast _binary Item_json_typecast => Item_typecast_json Item_char_typecast => Item_typecast_char Changes to the parser: cast_type: [....] | real_type opt_precision { $$.target = YYTHD->variables.sql_mode & MODE_REAL_AS_FLOAT ? ITEM_CAST_FLOAT : ITEM_CAST_DOUBLE; $$.charset= nullptr; $$.length= 0; $$.dec= 0; } | FLOAT_SYM float_options { $$.target = ITEM_CAST_FLOAT; $$.charset= nullptr; $$.length= $2.length; $$.dec= 0; }
Copyright (c) 2000, 2024, Oracle Corporation and/or its affiliates. All rights reserved.