Use NUMBER(38, 12) as default range for Snowflake DECIMALs (#10971)

This commit is contained in:
GregoryTravis 2024-09-09 14:31:09 -04:00 committed by GitHub
parent 414eee0b48
commit 2adb8bb86d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 69 additions and 56 deletions

View File

@ -26,6 +26,7 @@ import Standard.Database.SQL.SQL_Builder
import Standard.Database.SQL_Statement.SQL_Statement import Standard.Database.SQL_Statement.SQL_Statement
import Standard.Database.SQL_Type.SQL_Type import Standard.Database.SQL_Type.SQL_Type
from Standard.Database.Dialect import Temp_Table_Style from Standard.Database.Dialect import Temp_Table_Style
from Standard.Database.Dialect_Flags import all
from Standard.Database.Errors import SQL_Error, Unsupported_Database_Operation from Standard.Database.Errors import SQL_Error, Unsupported_Database_Operation
import project.Database.Redshift.Internal.Redshift_Error_Mapper.Redshift_Error_Mapper import project.Database.Redshift.Internal.Redshift_Error_Mapper.Redshift_Error_Mapper
@ -137,13 +138,12 @@ type Redshift_Dialect
supports_separate_nan : Boolean supports_separate_nan : Boolean
supports_separate_nan self = True supports_separate_nan self = True
## PRIVATE ## PRIVAITE
supports_negative_round_decimal_places : Boolean Specifies implementation details flags.
supports_negative_round_decimal_places self = True dialect_flags : Dialect_Flags
dialect_flags self -> Dialect_Flags =
## PRIVATE rounding = Rounding_Flags.Value supports_negative_decimal_places=True supports_float_decimal_places=False
supports_float_round_decimal_places : Boolean Dialect_Flags.Value rounding=rounding
supports_float_round_decimal_places self = False
## PRIVATE ## PRIVATE
Specifies how the database creates temp tables. Specifies how the database creates temp tables.

View File

@ -932,9 +932,9 @@ type DB_Column
# Don't use for banker's rounding # Don't use for banker's rounding
not_bankers = use_bankers.not not_bankers = use_bankers.not
# Don't use for negative decimal places, if the backend doesn't support it # Don't use for negative decimal places, if the backend doesn't support it
negative_dp_ok = decimal_places >= 0 || self.connection.dialect.supports_negative_round_decimal_places negative_dp_ok = decimal_places >= 0 || self.connection.dialect.dialect_flags.rounding.supports_negative_decimal_places
# Don't use for floating-point inputs if decimal_places != 0, for Postgres # Don't use for floating-point inputs if decimal_places != 0, for Postgres
dp_param_ok = decimal_places == 0 || self.value_type.is_floating_point.not || self.connection.dialect.supports_float_round_decimal_places dp_param_ok = decimal_places == 0 || self.value_type.is_floating_point.not || self.connection.dialect.dialect_flags.rounding.supports_float_decimal_places
not_bankers && negative_dp_ok && dp_param_ok not_bankers && negative_dp_ok && dp_param_ok
## PRIVATE ## PRIVATE

View File

@ -25,6 +25,7 @@ import project.Internal.Statement_Setter.Statement_Setter
import project.SQL.SQL_Builder import project.SQL.SQL_Builder
import project.SQL_Statement.SQL_Statement import project.SQL_Statement.SQL_Statement
import project.SQL_Type.SQL_Type import project.SQL_Type.SQL_Type
from project.Dialect_Flags import all
from project.Errors import SQL_Error, Unsupported_Database_Operation from project.Errors import SQL_Error, Unsupported_Database_Operation
from project.Internal.Result_Set import result_set_to_table from project.Internal.Result_Set import result_set_to_table
@ -149,17 +150,10 @@ type Dialect
supports_separate_nan self = supports_separate_nan self =
Unimplemented.throw "This is an interface only." Unimplemented.throw "This is an interface only."
## PRIVATE ## PRIVAITE
Specifies whether the Database ROUND() function supports negative Specifies implementation details flags.
decimal places. dialect_flags : Dialect_Flags
supports_negative_round_decimal_places : Boolean dialect_flags -> Dialect_Flags =
supports_negative_round_decimal_places self =
Unimplemented.throw "This is an interface only."
## PRIVATE
Specifies whether round() can take a decimal_places argument for floating point values.
supports_float_round_decimal_places : Boolean
supports_float_round_decimal_places self =
Unimplemented.throw "This is an interface only." Unimplemented.throw "This is an interface only."
## PRIVATE ## PRIVATE

View File

@ -0,0 +1,17 @@
from Standard.Base import all
## PRIVATE
Dialect flags are used to specify implementation details for different
dialects -- the existence or non-existence of certain features, or
differening implementations of the same feature.
Dialect flags differ from test config flags, in that they are used for
implementation (as well as testing). They also differ from feature flags,
since feature flags are user-facing, and can be used to identify features
that are not yet implemented.
type Dialect_Flags
Value (rounding : Rounding_Flags)
type Rounding_Flags
Value (supports_negative_decimal_places : Boolean) (supports_float_decimal_places : Boolean)

View File

@ -38,6 +38,7 @@ import project.SQL.SQL_Fragment
import project.SQL_Statement.SQL_Statement import project.SQL_Statement.SQL_Statement
import project.SQL_Type.SQL_Type import project.SQL_Type.SQL_Type
from project.Dialect import Temp_Table_Style from project.Dialect import Temp_Table_Style
from Standard.Database.Dialect_Flags import all
from project.Errors import SQL_Error, Unsupported_Database_Operation from project.Errors import SQL_Error, Unsupported_Database_Operation
from project.Internal.IR.Operation_Metadata import Date_Period_Metadata from project.Internal.IR.Operation_Metadata import Date_Period_Metadata
@ -174,13 +175,12 @@ type Postgres_Dialect
supports_separate_nan : Boolean supports_separate_nan : Boolean
supports_separate_nan self = True supports_separate_nan self = True
## PRIVATE ## PRIVAITE
supports_negative_round_decimal_places : Boolean Specifies implementation details flags.
supports_negative_round_decimal_places self = True dialect_flags : Dialect_Flags
dialect_flags self -> Dialect_Flags =
## PRIVATE rounding = Rounding_Flags.Value supports_negative_decimal_places=True supports_float_decimal_places=False
supports_float_round_decimal_places : Boolean Dialect_Flags.Value rounding=rounding
supports_float_round_decimal_places self = False
## PRIVATE ## PRIVATE
Specifies how the database creates temp tables. Specifies how the database creates temp tables.

View File

@ -35,6 +35,7 @@ import project.SQL.SQL_Builder
import project.SQL_Statement.SQL_Statement import project.SQL_Statement.SQL_Statement
import project.SQL_Type.SQL_Type import project.SQL_Type.SQL_Type
from project.Dialect import Temp_Table_Style from project.Dialect import Temp_Table_Style
from Standard.Database.Dialect_Flags import all
from project.Errors import SQL_Error, Unsupported_Database_Operation from project.Errors import SQL_Error, Unsupported_Database_Operation
## PRIVATE ## PRIVATE
@ -187,13 +188,12 @@ type SQLite_Dialect
supports_separate_nan : Boolean supports_separate_nan : Boolean
supports_separate_nan self = False supports_separate_nan self = False
## PRIVATE ## PRIVAITE
supports_negative_round_decimal_places : Boolean Specifies implementation details flags.
supports_negative_round_decimal_places self = False dialect_flags : Dialect_Flags
dialect_flags self -> Dialect_Flags =
## PRIVATE rounding = Rounding_Flags.Value supports_negative_decimal_places=False supports_float_decimal_places=True
supports_float_round_decimal_places : Boolean Dialect_Flags.Value rounding=rounding
supports_float_round_decimal_places self = True
## PRIVATE ## PRIVATE
Specifies how the database creates temp tables. Specifies how the database creates temp tables.

View File

@ -15,6 +15,7 @@ import project.Internal.IR.Query.Query
import project.SQL_Query.SQL_Query import project.SQL_Query.SQL_Query
from project.Dialect import Temp_Table_Style from project.Dialect import Temp_Table_Style
from project.Errors import SQL_Error, Table_Already_Exists, Unsupported_Database_Operation from project.Errors import SQL_Error, Table_Already_Exists, Unsupported_Database_Operation
from project.Internal.JDBC_Connection import log_sql_if_enabled
from project.Internal.Upload.Helpers.Argument_Checks import resolve_primary_key from project.Internal.Upload.Helpers.Argument_Checks import resolve_primary_key
from project.Internal.Upload.Helpers.Constants import default_batch_size from project.Internal.Upload.Helpers.Constants import default_batch_size
from project.Internal.Upload.Helpers.Error_Helpers import handle_upload_errors, internal_translate_known_upload_errors from project.Internal.Upload.Helpers.Error_Helpers import handle_upload_errors, internal_translate_known_upload_errors
@ -30,6 +31,7 @@ internal_create_table_structure connection table_name structure primary_key temp
validate_structure connection.base_connection.column_naming_helper aligned_structure <| validate_structure connection.base_connection.column_naming_helper aligned_structure <|
create_table_statement = prepare_create_table_statement connection table_name aligned_structure resolved_primary_key temporary on_problems create_table_statement = prepare_create_table_statement connection table_name aligned_structure resolved_primary_key temporary on_problems
update_result = create_table_statement.if_not_error <| update_result = create_table_statement.if_not_error <|
log_sql_if_enabled connection.jdbc_connection create_table_statement.to_text
connection.execute create_table_statement connection.execute create_table_statement
final_result = update_result.if_not_error table_name final_result = update_result.if_not_error table_name
final_result.catch SQL_Error sql_error-> final_result.catch SQL_Error sql_error->

View File

@ -39,6 +39,7 @@ import Standard.Database.SQL.SQL_Fragment
import Standard.Database.SQL_Statement.SQL_Statement import Standard.Database.SQL_Statement.SQL_Statement
import Standard.Database.SQL_Type.SQL_Type import Standard.Database.SQL_Type.SQL_Type
from Standard.Database.Dialect import Temp_Table_Style from Standard.Database.Dialect import Temp_Table_Style
from Standard.Database.Dialect_Flags import all
from Standard.Database.Errors import SQL_Error, Unsupported_Database_Operation from Standard.Database.Errors import SQL_Error, Unsupported_Database_Operation
from Standard.Database.Internal.IR.Operation_Metadata import Date_Period_Metadata from Standard.Database.Internal.IR.Operation_Metadata import Date_Period_Metadata
from Standard.Database.Internal.Statement_Setter import fill_hole_default from Standard.Database.Internal.Statement_Setter import fill_hole_default
@ -186,13 +187,12 @@ type SQLSever_Dialect
supports_separate_nan : Boolean supports_separate_nan : Boolean
supports_separate_nan self = True supports_separate_nan self = True
## PRIVATE ## PRIVAITE
supports_negative_round_decimal_places : Boolean Specifies implementation details flags.
supports_negative_round_decimal_places self = True dialect_flags : Dialect_Flags
dialect_flags self -> Dialect_Flags =
## PRIVATE rounding = Rounding_Flags.Value supports_negative_decimal_places=True supports_float_decimal_places=True
supports_float_round_decimal_places : Boolean Dialect_Flags.Value rounding=rounding
supports_float_round_decimal_places self = True
## PRIVATE ## PRIVATE
Specifies how the database creates temp tables. Specifies how the database creates temp tables.

View File

@ -43,6 +43,7 @@ import Standard.Database.SQL.SQL_Fragment
import Standard.Database.SQL_Statement.SQL_Statement import Standard.Database.SQL_Statement.SQL_Statement
import Standard.Database.SQL_Type.SQL_Type import Standard.Database.SQL_Type.SQL_Type
from Standard.Database.Dialect import Temp_Table_Style from Standard.Database.Dialect import Temp_Table_Style
from Standard.Database.Dialect_Flags import all
from Standard.Database.Errors import SQL_Error, Unsupported_Database_Operation from Standard.Database.Errors import SQL_Error, Unsupported_Database_Operation
from Standard.Database.Internal.IR.Operation_Metadata import Date_Period_Metadata from Standard.Database.Internal.IR.Operation_Metadata import Date_Period_Metadata
from Standard.Database.Internal.Statement_Setter import fill_hole_default from Standard.Database.Internal.Statement_Setter import fill_hole_default
@ -200,13 +201,12 @@ type Snowflake_Dialect
supports_separate_nan : Boolean supports_separate_nan : Boolean
supports_separate_nan self = True supports_separate_nan self = True
## PRIVATE ## PRIVAITE
supports_negative_round_decimal_places : Boolean Specifies implementation details flags.
supports_negative_round_decimal_places self = True dialect_flags : Dialect_Flags
dialect_flags self -> Dialect_Flags =
## PRIVATE rounding = Rounding_Flags.Value supports_negative_decimal_places=True supports_float_decimal_places=True
supports_float_round_decimal_places : Boolean Dialect_Flags.Value rounding=rounding
supports_float_round_decimal_places self = True
## PRIVATE ## PRIVATE
Specifies how the database creates temp tables. Specifies how the database creates temp tables.

View File

@ -33,7 +33,7 @@ type Snowflake_Type_Mapping
Value_Type.Float _ -> SQL_Type.Value Types.DOUBLE "FLOAT" Value_Type.Float _ -> SQL_Type.Value Types.DOUBLE "FLOAT"
Value_Type.Decimal precision scale -> case precision of Value_Type.Decimal precision scale -> case precision of
# If precision is not set, scale is also lost because SQL is unable to express a scale without a precision. # If precision is not set, scale is also lost because SQL is unable to express a scale without a precision.
Nothing -> SQL_Type.Value Types.DECIMAL "NUMBER" Nothing Nothing Nothing -> SQL_Type.Value Types.DECIMAL "NUMBER" 38 12
# Scale can be set or not, but if it is set, it must be in range 0-37. # Scale can be set or not, but if it is set, it must be in range 0-37.
# If scale or precision is out of range, we fall back to Nothing. # If scale or precision is out of range, we fall back to Nothing.
_ -> if (precision < 1) || (precision > 38) then SQL_Type.Value Types.DECIMAL "NUMBER" Nothing Nothing else _ -> if (precision < 1) || (precision > 38) then SQL_Type.Value Types.DECIMAL "NUMBER" Nothing Nothing else

View File

@ -465,11 +465,11 @@ snowflake_specific_spec suite_builder default_connection db_name setup =
col . cast Value_Type.Float . round 1 . value_type . should_equal Value_Type.Float col . cast Value_Type.Float . round 1 . value_type . should_equal Value_Type.Float
col . cast Value_Type.Integer . round 1 . value_type . should_equal (Value_Type.Decimal 38 0) col . cast Value_Type.Integer . round 1 . value_type . should_equal (Value_Type.Decimal 38 0)
col . cast Value_Type.Decimal . round 1 . value_type . should_equal (Value_Type.Decimal 38 0) col . cast Value_Type.Decimal . round 1 . value_type . should_equal (Value_Type.Decimal 38 1)
col . cast Value_Type.Float . round use_bankers=True . value_type . should_equal Value_Type.Float col . cast Value_Type.Float . round use_bankers=True . value_type . should_equal Value_Type.Float
col . cast Value_Type.Integer . round use_bankers=True . value_type . should_equal (Value_Type.Decimal 38 6) col . cast Value_Type.Integer . round use_bankers=True . value_type . should_equal (Value_Type.Decimal 38 12)
col . cast Value_Type.Decimal . round use_bankers=True . value_type . should_equal (Value_Type.Decimal 38 6) col . cast Value_Type.Decimal . round use_bankers=True . value_type . should_equal (Value_Type.Decimal 38 12)
col . cast Value_Type.Float . ceil . value_type . should_equal Value_Type.Float col . cast Value_Type.Float . ceil . value_type . should_equal Value_Type.Float
col . cast Value_Type.Integer . ceil . value_type . should_equal (Value_Type.Decimal 38 0) col . cast Value_Type.Integer . ceil . value_type . should_equal (Value_Type.Decimal 38 0)

View File

@ -1148,12 +1148,12 @@ add_specs suite_builder setup =
if setup.test_selection.supports_decimal_type then if setup.test_selection.supports_decimal_type then
group_builder.specify "ceil, floor and truncate should work correctly on Decimals" <| group_builder.specify "ceil, floor and truncate should work correctly on Decimals" <|
c = table_builder [["X", [Decimal.new "123492233720368547758075678.25", Decimal.new "15250331789246130610154663179243023788662739454197523.625", Decimal.new "-123492233720368547758075678.25", Decimal.new "-15250331789246130610154663179243023788662739454197523.625"]]] . at "X" c = table_builder [["X", [Decimal.new "123492233720368547758075678.25", Decimal.new "179243023788662739454197523.625", Decimal.new "-123492233720368547758075678.25", Decimal.new "-179243023788662739454197523.625"]]] . at "X"
c.value_type.is_decimal . should_be_true c.value_type.is_decimal . should_be_true
c.floor.to_vector.should_equal [Decimal.new "123492233720368547758075678.0", Decimal.new "15250331789246130610154663179243023788662739454197523.0", Decimal.new "-123492233720368547758075679.0", Decimal.new "-15250331789246130610154663179243023788662739454197524.0"] c.floor.to_vector.should_equal [Decimal.new "123492233720368547758075678.0", Decimal.new "179243023788662739454197523.0", Decimal.new "-123492233720368547758075679.0", Decimal.new "-179243023788662739454197524.0"]
c.ceil.to_vector.should_equal [Decimal.new "123492233720368547758075679.0", Decimal.new "15250331789246130610154663179243023788662739454197524.0", Decimal.new "-123492233720368547758075678.0", Decimal.new "-15250331789246130610154663179243023788662739454197523.0"] c.ceil.to_vector.should_equal [Decimal.new "123492233720368547758075679.0", Decimal.new "179243023788662739454197524.0", Decimal.new "-123492233720368547758075678.0", Decimal.new "-179243023788662739454197523.0"]
c.truncate.to_vector.should_equal [Decimal.new "123492233720368547758075678.0", Decimal.new "15250331789246130610154663179243023788662739454197523.0", Decimal.new "-123492233720368547758075678.0", Decimal.new "-15250331789246130610154663179243023788662739454197523.0"] c.truncate.to_vector.should_equal [Decimal.new "123492233720368547758075678.0", Decimal.new "179243023788662739454197523.0", Decimal.new "-123492233720368547758075678.0", Decimal.new "-179243023788662739454197523.0"]
group_builder.specify "round should work correctly on Decimals" <| group_builder.specify "round should work correctly on Decimals" <|
c = table_builder [["X", [Decimal.new "1.3", Decimal.new "1.5", Decimal.new "1.7", Decimal.new "-1.3", Decimal.new "-1.5", Decimal.new "-1.7"]]] . at "X" c = table_builder [["X", [Decimal.new "1.3", Decimal.new "1.5", Decimal.new "1.7", Decimal.new "-1.3", Decimal.new "-1.5", Decimal.new "-1.7"]]] . at "X"