From 2adb8bb86d129a25c1f8bddca58809b7f454d872 Mon Sep 17 00:00:00 2001 From: GregoryTravis Date: Mon, 9 Sep 2024 14:31:09 -0400 Subject: [PATCH] Use `NUMBER(38, 12)` as default range for Snowflake `DECIMAL`s (#10971) --- .../Redshift/Internal/Redshift_Dialect.enso | 14 +++++++------- .../Database/0.0.0-dev/src/DB_Column.enso | 4 ++-- .../Database/0.0.0-dev/src/Dialect.enso | 16 +++++----------- .../Database/0.0.0-dev/src/Dialect_Flags.enso | 17 +++++++++++++++++ .../src/Internal/Postgres/Postgres_Dialect.enso | 14 +++++++------- .../src/Internal/SQLite/SQLite_Dialect.enso | 14 +++++++------- .../Upload/Operations/Internal_Core.enso | 2 ++ .../src/Internal/SQLServer_Dialect.enso | 14 +++++++------- .../src/Internal/Snowflake_Dialect.enso | 14 +++++++------- .../src/Internal/Snowflake_Type_Mapping.enso | 2 +- test/Snowflake_Tests/src/Snowflake_Spec.enso | 6 +++--- .../Column_Operations_Spec.enso | 8 ++++---- 12 files changed, 69 insertions(+), 56 deletions(-) create mode 100644 distribution/lib/Standard/Database/0.0.0-dev/src/Dialect_Flags.enso diff --git a/distribution/lib/Standard/AWS/0.0.0-dev/src/Database/Redshift/Internal/Redshift_Dialect.enso b/distribution/lib/Standard/AWS/0.0.0-dev/src/Database/Redshift/Internal/Redshift_Dialect.enso index 351d16fdc7a..0156aa901af 100644 --- a/distribution/lib/Standard/AWS/0.0.0-dev/src/Database/Redshift/Internal/Redshift_Dialect.enso +++ b/distribution/lib/Standard/AWS/0.0.0-dev/src/Database/Redshift/Internal/Redshift_Dialect.enso @@ -26,6 +26,7 @@ import Standard.Database.SQL.SQL_Builder import Standard.Database.SQL_Statement.SQL_Statement import Standard.Database.SQL_Type.SQL_Type 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 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 self = True - ## PRIVATE - supports_negative_round_decimal_places : Boolean - supports_negative_round_decimal_places self = True - - ## PRIVATE - supports_float_round_decimal_places : Boolean - supports_float_round_decimal_places self = False + ## PRIVAITE + Specifies implementation details flags. + dialect_flags : Dialect_Flags + dialect_flags self -> Dialect_Flags = + rounding = Rounding_Flags.Value supports_negative_decimal_places=True supports_float_decimal_places=False + Dialect_Flags.Value rounding=rounding ## PRIVATE Specifies how the database creates temp tables. diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Column.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Column.enso index c57ead5a07e..74b29ccf17e 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Column.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/DB_Column.enso @@ -932,9 +932,9 @@ type DB_Column # Don't use for banker's rounding not_bankers = use_bankers.not # 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 - 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 ## PRIVATE diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Dialect.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Dialect.enso index dd0eb2c4b18..9b2d850425a 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Dialect.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Dialect.enso @@ -25,6 +25,7 @@ import project.Internal.Statement_Setter.Statement_Setter import project.SQL.SQL_Builder import project.SQL_Statement.SQL_Statement import project.SQL_Type.SQL_Type +from project.Dialect_Flags import all from project.Errors import SQL_Error, Unsupported_Database_Operation from project.Internal.Result_Set import result_set_to_table @@ -149,17 +150,10 @@ type Dialect supports_separate_nan self = Unimplemented.throw "This is an interface only." - ## PRIVATE - Specifies whether the Database ROUND() function supports negative - decimal places. - supports_negative_round_decimal_places : Boolean - 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 = + ## PRIVAITE + Specifies implementation details flags. + dialect_flags : Dialect_Flags + dialect_flags -> Dialect_Flags = Unimplemented.throw "This is an interface only." ## PRIVATE diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Dialect_Flags.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Dialect_Flags.enso new file mode 100644 index 00000000000..e7d27f9a052 --- /dev/null +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Dialect_Flags.enso @@ -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) diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso index 9e2975ca6f5..7e2855c3476 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Dialect.enso @@ -38,6 +38,7 @@ import project.SQL.SQL_Fragment import project.SQL_Statement.SQL_Statement import project.SQL_Type.SQL_Type 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.Internal.IR.Operation_Metadata import Date_Period_Metadata @@ -174,13 +175,12 @@ type Postgres_Dialect supports_separate_nan : Boolean supports_separate_nan self = True - ## PRIVATE - supports_negative_round_decimal_places : Boolean - supports_negative_round_decimal_places self = True - - ## PRIVATE - supports_float_round_decimal_places : Boolean - supports_float_round_decimal_places self = False + ## PRIVAITE + Specifies implementation details flags. + dialect_flags : Dialect_Flags + dialect_flags self -> Dialect_Flags = + rounding = Rounding_Flags.Value supports_negative_decimal_places=True supports_float_decimal_places=False + Dialect_Flags.Value rounding=rounding ## PRIVATE Specifies how the database creates temp tables. diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso index a0a2add84d3..7f02b6a9e83 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso @@ -35,6 +35,7 @@ import project.SQL.SQL_Builder import project.SQL_Statement.SQL_Statement import project.SQL_Type.SQL_Type from project.Dialect import Temp_Table_Style +from Standard.Database.Dialect_Flags import all from project.Errors import SQL_Error, Unsupported_Database_Operation ## PRIVATE @@ -187,13 +188,12 @@ type SQLite_Dialect supports_separate_nan : Boolean supports_separate_nan self = False - ## PRIVATE - supports_negative_round_decimal_places : Boolean - supports_negative_round_decimal_places self = False - - ## PRIVATE - supports_float_round_decimal_places : Boolean - supports_float_round_decimal_places self = True + ## PRIVAITE + Specifies implementation details flags. + dialect_flags : Dialect_Flags + dialect_flags self -> Dialect_Flags = + rounding = Rounding_Flags.Value supports_negative_decimal_places=False supports_float_decimal_places=True + Dialect_Flags.Value rounding=rounding ## PRIVATE Specifies how the database creates temp tables. diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Upload/Operations/Internal_Core.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Upload/Operations/Internal_Core.enso index 1e5837cc780..7996662d981 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Upload/Operations/Internal_Core.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Upload/Operations/Internal_Core.enso @@ -15,6 +15,7 @@ import project.Internal.IR.Query.Query import project.SQL_Query.SQL_Query from project.Dialect import Temp_Table_Style 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.Constants import default_batch_size 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 <| 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 <| + log_sql_if_enabled connection.jdbc_connection create_table_statement.to_text connection.execute create_table_statement final_result = update_result.if_not_error table_name final_result.catch SQL_Error sql_error-> diff --git a/distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Dialect.enso b/distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Dialect.enso index 7c0a03c5e1e..694f5cd14b8 100644 --- a/distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Dialect.enso +++ b/distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Dialect.enso @@ -39,6 +39,7 @@ import Standard.Database.SQL.SQL_Fragment import Standard.Database.SQL_Statement.SQL_Statement import Standard.Database.SQL_Type.SQL_Type 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.Internal.IR.Operation_Metadata import Date_Period_Metadata from Standard.Database.Internal.Statement_Setter import fill_hole_default @@ -186,13 +187,12 @@ type SQLSever_Dialect supports_separate_nan : Boolean supports_separate_nan self = True - ## PRIVATE - supports_negative_round_decimal_places : Boolean - supports_negative_round_decimal_places self = True - - ## PRIVATE - supports_float_round_decimal_places : Boolean - supports_float_round_decimal_places self = True + ## PRIVAITE + Specifies implementation details flags. + dialect_flags : Dialect_Flags + dialect_flags self -> Dialect_Flags = + rounding = Rounding_Flags.Value supports_negative_decimal_places=True supports_float_decimal_places=True + Dialect_Flags.Value rounding=rounding ## PRIVATE Specifies how the database creates temp tables. diff --git a/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso b/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso index 0fec19137ba..8003a336718 100644 --- a/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso +++ b/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Dialect.enso @@ -43,6 +43,7 @@ import Standard.Database.SQL.SQL_Fragment import Standard.Database.SQL_Statement.SQL_Statement import Standard.Database.SQL_Type.SQL_Type 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.Internal.IR.Operation_Metadata import Date_Period_Metadata from Standard.Database.Internal.Statement_Setter import fill_hole_default @@ -200,13 +201,12 @@ type Snowflake_Dialect supports_separate_nan : Boolean supports_separate_nan self = True - ## PRIVATE - supports_negative_round_decimal_places : Boolean - supports_negative_round_decimal_places self = True - - ## PRIVATE - supports_float_round_decimal_places : Boolean - supports_float_round_decimal_places self = True + ## PRIVAITE + Specifies implementation details flags. + dialect_flags : Dialect_Flags + dialect_flags self -> Dialect_Flags = + rounding = Rounding_Flags.Value supports_negative_decimal_places=True supports_float_decimal_places=True + Dialect_Flags.Value rounding=rounding ## PRIVATE Specifies how the database creates temp tables. diff --git a/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Type_Mapping.enso b/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Type_Mapping.enso index 524624c7a75..30ed5810e71 100644 --- a/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Type_Mapping.enso +++ b/distribution/lib/Standard/Snowflake/0.0.0-dev/src/Internal/Snowflake_Type_Mapping.enso @@ -33,7 +33,7 @@ type Snowflake_Type_Mapping Value_Type.Float _ -> SQL_Type.Value Types.DOUBLE "FLOAT" 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. - 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. # 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 diff --git a/test/Snowflake_Tests/src/Snowflake_Spec.enso b/test/Snowflake_Tests/src/Snowflake_Spec.enso index 8e1f7643f52..c0814b5677b 100644 --- a/test/Snowflake_Tests/src/Snowflake_Spec.enso +++ b/test/Snowflake_Tests/src/Snowflake_Spec.enso @@ -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.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.Integer . 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 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 12) 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) diff --git a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso index e6478e52ab3..b8975e5fd51 100644 --- a/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso +++ b/test/Table_Tests/src/Common_Table_Operations/Column_Operations_Spec.enso @@ -1148,12 +1148,12 @@ add_specs suite_builder setup = if setup.test_selection.supports_decimal_type then 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.floor.to_vector.should_equal [Decimal.new "123492233720368547758075678.0", Decimal.new "15250331789246130610154663179243023788662739454197523.0", Decimal.new "-123492233720368547758075679.0", Decimal.new "-15250331789246130610154663179243023788662739454197524.0"] - c.ceil.to_vector.should_equal [Decimal.new "123492233720368547758075679.0", Decimal.new "15250331789246130610154663179243023788662739454197524.0", Decimal.new "-123492233720368547758075678.0", Decimal.new "-15250331789246130610154663179243023788662739454197523.0"] - c.truncate.to_vector.should_equal [Decimal.new "123492233720368547758075678.0", Decimal.new "15250331789246130610154663179243023788662739454197523.0", Decimal.new "-123492233720368547758075678.0", Decimal.new "-15250331789246130610154663179243023788662739454197523.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 "179243023788662739454197524.0", Decimal.new "-123492233720368547758075678.0", Decimal.new "-179243023788662739454197523.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" <| 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"