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 bff37dca1106..4578d24d4bff 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 @@ -22,6 +22,7 @@ import Standard.Database.Internal.Postgres.Postgres_Type_Mapping.Postgres_Type_M import Standard.Database.Internal.SQL_Type_Mapping.SQL_Type_Mapping import Standard.Database.Internal.SQL_Type_Reference.SQL_Type_Reference import Standard.Database.Internal.Statement_Setter.Statement_Setter +import Standard.Database.SQL.SQL_Builder import Standard.Database.SQL_Statement.SQL_Statement import Standard.Database.SQL_Type.SQL_Type from Standard.Database.Errors import SQL_Error, Unsupported_Database_Operation @@ -33,7 +34,7 @@ import project.Database.Redshift.Internal.Redshift_Error_Mapper.Redshift_Error_M The dialect for Redshift connections. redshift : Redshift_Dialect redshift = - Redshift_Dialect.Value Postgres_Dialect.make_internal_generator_dialect + Redshift_Dialect.Value Postgres_Dialect.make_dialect_operations ## PRIVATE @@ -42,7 +43,7 @@ type Redshift_Dialect ## PRIVATE The dialect for Redshift connections. - Value internal_generator_dialect + Value dialect_operations ## PRIVATE Name of the dialect. @@ -57,15 +58,28 @@ type Redshift_Dialect according to the specific dialect. generate_sql : Query -> SQL_Statement generate_sql self query = - Base_Generator.generate_query self.internal_generator_dialect query . build + Base_Generator.generate_query self query . build + + ## PRIVATE + Generates SQL to truncate a table. + generate_truncate_table_sql : Text -> SQL_Builder + generate_truncate_table_sql self table_name = + Base_Generator.truncate_table_delete_from_style self table_name ## PRIVATE Wraps and possibly escapes the identifier so that it can be used in a generated query regardless of what characters it contains. The quotes used will depend on the dialect. - wrap_identifier : Text -> Text + wrap_identifier : Text -> SQL_Builder wrap_identifier self identifier = - self.internal_generator_dialect.wrap_identifier_raw identifier + Base_Generator.wrap_in_quotes identifier + + ## PRIVATE + Generates a SQL expression for a table literal. + make_table_literal : Vector (Vector Text) -> Vector Text -> Text -> SQL_Builder + make_table_literal self vecs column_names as_name = + Base_Generator.default_make_table_literal self.wrap_identifier vecs column_names as_name + ## PRIVATE Prepares an ordering descriptor. @@ -159,7 +173,7 @@ type Redshift_Dialect Checks if an operation is supported by the dialect. is_supported : Text -> Boolean is_supported self operation = - self.internal_generator_dialect.is_supported operation + self.dialect_operations.is_supported operation ## PRIVATE The default table types to use when listing tables. 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 58fc4adf142a..ef7675e0f2a5 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 @@ -21,6 +21,7 @@ import project.Internal.SQL_Type_Mapping.SQL_Type_Mapping import project.Internal.SQL_Type_Reference.SQL_Type_Reference import project.Internal.SQLite.SQLite_Dialect 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.Errors import SQL_Error, Unsupported_Database_Operation @@ -46,6 +47,13 @@ type Dialect _ = [query] Unimplemented.throw "This is an interface only." + ## PRIVATE + Generates SQL to truncate a table. + generate_truncate_table_sql : Text -> SQL_Builder + generate_truncate_table_sql self table_name = + _ = [table_name] + Unimplemented.throw "This is an interface only." + ## PRIVATE Prepares an ordering descriptor. diff --git a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso index 83abe30bf110..fbb5befcae7c 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso +++ b/distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Base_Generator.enso @@ -2,6 +2,7 @@ from Standard.Base import all import Standard.Base.Errors.Illegal_State.Illegal_State import project.Column_Constraint.Column_Constraint +import project.Dialect.Dialect import project.Internal.IR.Context.Context import project.Internal.IR.From_Spec.From_Spec import project.Internal.IR.Nulls_Order.Nulls_Order @@ -13,11 +14,11 @@ import project.SQL.SQL_Builder from project.Errors import Unsupported_Database_Operation from project.Internal.IR.Operation_Metadata import Row_Number_Metadata -type Internal_Dialect +type Dialect_Operations ## PRIVATE - An internal representation of a SQL dialect. + Operations supported by a particular SQL dialect and how they are implemeneted. Arguments: - operation_map: The mapping which maps operation names to their @@ -25,29 +26,18 @@ type Internal_Dialect builders for the arguments, and optionally an additional metadata argument, and should return a SQL builder yielding code for the whole operation. - - wrap_identifier_raw: A function that converts an arbitrary supported - identifier name in such a way that it can be used in the query; that - usually consists of wrapping the name in quotes and escaping any quotes - within it. - - make_table_literal: A function that generates a SQL expression for a - table literal. - Value (operation_map:(Map Text (Vector (SQL_Builder->SQL_Builder)))) (wrap_identifier_raw:(Text->Text)) (make_table_literal : Vector (Vector Text) -> Vector Text -> Text -> SQL_Builder) - - ## PRIVATE - wrap_identifier : Text -> SQL_Builder - wrap_identifier self identifier:Text = - SQL_Builder.code (self.wrap_identifier_raw identifier) + Value (operation_map:(Map Text (Vector (SQL_Builder->SQL_Builder)))) ## PRIVATE Creates a copy of the dialect that supports additional operations or overrides existing ones. - # extend_with : Vector [Text, Vector SQL_Builder -> SQL_Builder] -> Internal_Dialect - extend_with : Vector Any -> Internal_Dialect + # extend_with : Vector [Text, Vector SQL_Builder -> SQL_Builder] -> Dialect_Operations + extend_with : Vector Any -> Dialect_Operations extend_with self mappings = new_map = mappings.fold self.operation_map (m -> el -> m.insert (el.at 0) (el.at 1)) - Internal_Dialect.Value new_map self.wrap_identifier_raw self.make_table_literal + Dialect_Operations.Value new_map ## PRIVATE Checks if an operation is supported by the dialect. @@ -55,10 +45,6 @@ type Internal_Dialect is_supported self operation = self.operation_map.contains_key operation - ## PRIVATE - override_make_table_literal self (make_table_literal : Vector (Vector Text) -> Vector Text -> Text -> SQL_Builder) -> Internal_Dialect = - Internal_Dialect.Value self.operation_map self.wrap_identifier_raw make_table_literal - ## PRIVATE A helper function to create a binary operator. @@ -185,10 +171,10 @@ make_constant sql_code = This is the simplest way of escaping identifiers that should work across most dialects. -wrap_in_quotes : Text -> Text +wrap_in_quotes : Text -> SQL_Builder wrap_in_quotes identifier = escaped = identifier.replace '"' '""' - '"'+escaped+'"' + SQL_Builder.code ('"'+escaped+'"') ## PRIVATE @@ -196,7 +182,7 @@ wrap_in_quotes identifier = It is a base to help creating concrete dialects. It can be extended or completely overridden. -base_dialect = +base_dialect_operations = bin = name -> [name, make_binary_op name] unary = name -> [name, make_unary_op name] fun = name -> [name, make_function name] @@ -215,7 +201,7 @@ base_dialect = types = [simple_cast] windows = [["ROW_NUMBER", make_row_number], ["ROW_NUMBER_IN_GROUP", make_row_number_in_group]] base_map = Map.from_vector (arith + logic + compare + functions + agg + counts + text + nulls + contains + types + windows) - Internal_Dialect.Value base_map wrap_in_quotes (default_make_table_literal wrap_in_quotes) + Dialect_Operations.Value base_map ## PRIVATE is_empty = lift_unary_op "IS_EMPTY" arg-> @@ -315,7 +301,7 @@ make_row_number_in_group arguments = Arguments: - dialect: The SQL dialect in which the expression is being generated. - expr: The expression to generate SQL code for. -generate_expression : Internal_Dialect -> SQL_Expression | Order_Descriptor | Query -> SQL_Builder +generate_expression : Dialect -> SQL_Expression | Order_Descriptor | Query -> SQL_Builder generate_expression dialect expr = case expr of SQL_Expression.Column origin name -> dialect.wrap_identifier origin ++ '.' ++ dialect.wrap_identifier name @@ -325,7 +311,7 @@ generate_expression dialect expr = case expr of escaped = value.replace "'" "''" SQL_Builder.code ("'" + escaped + "'") SQL_Expression.Operation kind arguments metadata -> - op = dialect.operation_map.get kind (Error.throw <| Unsupported_Database_Operation.Error kind) + op = dialect.dialect_operations.operation_map.get kind (Error.throw <| Unsupported_Database_Operation.Error kind) parsed_args = arguments.map (generate_expression dialect) result = op parsed_args # If the function expects more arguments, we pass the metadata as the last argument. @@ -343,7 +329,7 @@ generate_expression dialect expr = case expr of Arguments: - dialect: The dialect for which to add the alias. - name: The name of the alias. -alias : Internal_Dialect -> Text -> SQL_Builder +alias : Dialect -> Text -> SQL_Builder alias dialect name = wrapped = dialect.wrap_identifier name SQL_Builder.code " AS " ++ wrapped @@ -355,7 +341,7 @@ alias dialect name = Arguments: - dialect: The SQL dialect for which the code is generated. - from_spec: A description of the FROM clause. -generate_from_part : Internal_Dialect -> From_Spec -> SQL_Builder +generate_from_part : Dialect -> From_Spec -> SQL_Builder generate_from_part dialect from_spec = case from_spec of From_Spec.Table name as_name _ -> dialect.wrap_identifier name ++ alias dialect as_name @@ -384,9 +370,7 @@ generate_from_part dialect from_spec = case from_spec of ## PRIVATE default_make_table_literal wrap_identifier vecs column_names as_name = values = SQL_Builder.join ", " (vecs.transpose.map (vec-> SQL_Builder.join ", " (vec.map SQL_Builder.interpolation) . paren)) - wrap_identifier_as_builder n = - SQL_Builder.code (wrap_identifier n) - structure = (wrap_identifier_as_builder as_name) ++ (SQL_Builder.join ", " (column_names.map wrap_identifier_as_builder) . paren) + structure = (wrap_identifier as_name) ++ (SQL_Builder.join ", " (column_names.map wrap_identifier) . paren) SQL_Builder.code "(VALUES " ++ values ++ ") AS " ++ structure ## PRIVATE @@ -420,7 +404,7 @@ make_not_equals a b = Arguments: - dialect: The SQL dialect for which the code is generated. - order_descriptor: A description of the ORDER clause. -generate_order : Internal_Dialect -> Order_Descriptor -> SQL_Builder +generate_order : Dialect -> Order_Descriptor -> SQL_Builder generate_order dialect order_descriptor = order_suffix = case order_descriptor.direction of Sort_Direction.Ascending -> " ASC" @@ -443,7 +427,7 @@ generate_order dialect order_descriptor = Arguments: - dialect: The SQL dialect for which the code is being generated. - ctx: A description of the SELECT clause. -generate_select_context : Internal_Dialect -> Context -> SQL_Builder +generate_select_context : Dialect -> Context -> SQL_Builder generate_select_context dialect ctx = gen_exprs exprs = exprs.map (generate_expression dialect) from_part = generate_from_part dialect ctx.from_spec @@ -466,7 +450,7 @@ generate_select_context dialect ctx = - table_name: The name of the table into which the values are being inserted. - pairs: The values to insert into the table, consisting of pairs of key, and expression returning a value. -generate_insert_query : Internal_Dialect -> Text -> Vector Any -> SQL_Builder +generate_insert_query : Dialect -> Text -> Vector Any -> SQL_Builder generate_insert_query dialect table_name pairs = names = SQL_Builder.join ", " <| pairs.map (.first >> dialect.wrap_identifier) values = SQL_Builder.join ", " <| pairs.map (.second >> generate_expression dialect) @@ -481,7 +465,7 @@ generate_insert_query dialect table_name pairs = Arguments: - dialect: The SQL dialect for which the code is being generated. - query: An IR describing the query. -generate_query : Internal_Dialect -> Query -> SQL_Builder +generate_query : Dialect -> Query -> SQL_Builder generate_query dialect query = case query of Query.Select columns ctx -> gen_column pair = (generate_expression dialect pair.second) ++ alias dialect pair.first @@ -504,7 +488,7 @@ generate_query dialect query = case query of maybe_if_exists = if if_exists then SQL_Builder.code "IF EXISTS " else SQL_Builder.empty SQL_Builder.code "DROP TABLE " ++ maybe_if_exists ++ dialect.wrap_identifier name Query.Truncate_Table name -> - SQL_Builder.code "DELETE FROM " ++ dialect.wrap_identifier name + dialect.generate_truncate_table_sql name Query.Insert_From_Select table_name column_names select_query -> case select_query of Query.Select _ _ -> inner_query = generate_query dialect select_query @@ -617,3 +601,15 @@ generate_column_description dialect descriptor = like a SQL query for the given dialect or is rather a table name. is_probably_a_query : Text -> Boolean is_probably_a_query text = (text.contains "SELECT ") || (text.contains "EXEC ") + +## PRIVATE + option for implementing generate_truncate_table_sql +truncate_table_delete_from_style : Dialect -> Text -> SQL_Builder +truncate_table_delete_from_style dialect table_name = + SQL_Builder.code "DELETE FROM " ++ dialect.wrap_identifier table_name + +## PRIVATE + option for implementing generate_truncate_table_sql +truncate_table_truncate_table_style : Dialect -> Text -> SQL_Builder +truncate_table_truncate_table_style dialect table_name = + SQL_Builder.code "TRUNCATE TABLE " ++ dialect.wrap_identifier table_name 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 14b16d1dc5ac..792e6cc9aea0 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 @@ -46,14 +46,14 @@ polyglot java import java.sql.Types The dialect of PostgreSQL databases. postgres : Postgres_Dialect postgres = - Postgres_Dialect.Value make_internal_generator_dialect + Postgres_Dialect.Value make_dialect_operations ## PRIVATE The dialect of PostgreSQL databases. type Postgres_Dialect ## PRIVATE The dialect of PostgreSQL databases. - Value internal_generator_dialect + Value dialect_operations ## PRIVATE Name of the dialect. @@ -69,23 +69,27 @@ type Postgres_Dialect according to the specific dialect. generate_sql : Query -> SQL_Statement generate_sql self query = - case query of - # Special handling to use TRUNCATE TABLE instead of the default (since being more portable) DELETE FROM. - Query.Truncate_Table name -> - wrapped_name = self.internal_generator_dialect.wrap_identifier name - # ONLY is used to avoid truncating other tables that inherit from this table, which is the default behaviour on Postgres. - (SQL_Builder.code "TRUNCATE TABLE ONLY " ++ wrapped_name) . build - _ -> - # Rely on the base generator for most queries. - Base_Generator.generate_query self.internal_generator_dialect query . build + Base_Generator.generate_query self query . build + + ## PRIVATE + Generates SQL to truncate a table. + generate_truncate_table_sql : Text -> SQL_Builder + generate_truncate_table_sql self table_name = + Base_Generator.truncate_table_truncate_table_style self table_name ## PRIVATE Wraps and possibly escapes the identifier so that it can be used in a generated query regardless of what characters it contains. The quotes used will depend on the dialect. - wrap_identifier : Text -> Text + wrap_identifier : Text -> SQL_Builder wrap_identifier self identifier = - self.internal_generator_dialect.wrap_identifier_raw identifier + Base_Generator.wrap_in_quotes identifier + + ## PRIVATE + Generates a SQL expression for a table literal. + make_table_literal : Vector (Vector Text) -> Vector Text -> Text -> SQL_Builder + make_table_literal self vecs column_names as_name = + Base_Generator.default_make_table_literal self.wrap_identifier vecs column_names as_name ## PRIVATE Prepares an ordering descriptor. @@ -242,7 +246,7 @@ type Postgres_Dialect Checks if an operation is supported by the dialect. is_supported : Text -> Boolean is_supported self operation = - self.internal_generator_dialect.is_supported operation + self.dialect_operations.is_supported operation ## PRIVATE The default table types to use when listing tables. @@ -299,7 +303,7 @@ type Postgres_Dialect _ -> base_type ## PRIVATE -make_internal_generator_dialect = +make_dialect_operations = cases = [["LOWER", Base_Generator.make_function "LOWER"], ["UPPER", Base_Generator.make_function "UPPER"]] text = [starts_with, contains, ends_with, agg_shortest, agg_longest, make_case_sensitive, ["REPLACE", replace], left, right]+concat_ops+cases+trim_ops counts = [agg_count_is_null, agg_count_empty, agg_count_not_empty, ["COUNT_DISTINCT", agg_count_distinct], ["COUNT_DISTINCT_INCLUDE_NULL", agg_count_distinct_include_null]] @@ -313,7 +317,7 @@ make_internal_generator_dialect = special_overrides = [is_null, is_empty] other = [["RUNTIME_ERROR", make_runtime_error_op]] my_mappings = text + counts + stats + first_last_aggregators + arith_extensions + bool + date_ops + special_overrides + other - Base_Generator.base_dialect . extend_with my_mappings + Base_Generator.base_dialect_operations . extend_with my_mappings ## PRIVATE This overrides the default behaviour, due to a weird behaviour of Postgres - 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 9cd7dfd32f7e..146a08bc5a57 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 @@ -38,7 +38,7 @@ from project.Errors import SQL_Error, Unsupported_Database_Operation The dialect of SQLite databases. sqlite : SQLite_Dialect sqlite = - SQLite_Dialect.Value make_internal_generator_dialect + SQLite_Dialect.Value make_dialect_operations ## PRIVATE @@ -47,7 +47,7 @@ type SQLite_Dialect ## PRIVATE The dialect of SQLite databases. - Value internal_generator_dialect + Value dialect_operations ## PRIVATE Name of the dialect. @@ -62,15 +62,28 @@ type SQLite_Dialect according to the specific dialect. generate_sql : Query -> SQL_Statement generate_sql self query = - Base_Generator.generate_query self.internal_generator_dialect query . build + Base_Generator.generate_query self query . build + + generate_truncate_table_sql : Text -> SQL_Builder + generate_truncate_table_sql self table_name = + Base_Generator.truncate_table_delete_from_style self table_name ## PRIVATE Wraps and possibly escapes the identifier so that it can be used in a generated query regardless of what characters it contains. The quotes used will depend on the dialect. - wrap_identifier : Text -> Text + wrap_identifier : Text -> SQL_Builder wrap_identifier self identifier = - self.internal_generator_dialect.wrap_identifier_raw identifier + Base_Generator.wrap_in_quotes identifier + + ## PRIVATE + Generates a SQL expression for a table literal. + make_table_literal : Vector (Vector Text) -> Vector Text -> Text -> SQL_Builder + make_table_literal self vecs column_names as_name = + values = SQL_Builder.join ", " (vecs.transpose.map (vec-> SQL_Builder.join ", " (vec.map SQL_Builder.interpolation) . paren)) + wrapped_name = self.wrap_identifier as_name + structure = wrapped_name ++ (SQL_Builder.join ", " (column_names.map self.wrap_identifier) . paren) + SQL_Builder.code "(WITH " ++ structure ++ " AS (VALUES " ++ values ++ ") SELECT * FROM " ++ wrapped_name ++ ") AS " ++ wrapped_name ## PRIVATE Prepares an ordering descriptor. @@ -234,7 +247,7 @@ type SQLite_Dialect Checks if an operation is supported by the dialect. is_supported : Text -> Boolean is_supported self operation = - self.internal_generator_dialect.is_supported operation + self.dialect_operations.is_supported operation ## PRIVATE The default table types to use when listing tables. @@ -255,7 +268,7 @@ type SQLite_Dialect implementation does not correctly handle temporary tables. fetch_primary_key : Connection -> Text -> Vector Text ! Nothing fetch_primary_key self connection table_name = - wrapped_name = self.internal_generator_dialect.wrap_identifier table_name + wrapped_name = self.wrap_identifier table_name query = SQL_Builder.code "pragma table_info(" ++ wrapped_name ++ ")" info_table = connection.read_statement query.build ## The `pk` field is non-zero if the columns is part of the primary key. @@ -283,7 +296,7 @@ type SQLite_Dialect value_type_for_upload_of_existing_column self column = column.value_type ## PRIVATE -make_internal_generator_dialect = +make_dialect_operations = text = [starts_with, contains, ends_with, make_case_sensitive, ["REPLACE", replace], left, right]+concat_ops+trim_ops counts = [agg_count_is_null, agg_count_empty, agg_count_not_empty, ["COUNT_DISTINCT", agg_count_distinct], ["COUNT_DISTINCT_INCLUDE_NULL", agg_count_distinct_include_null]] stats = [agg_stddev_pop, agg_stddev_samp] @@ -292,9 +305,7 @@ make_internal_generator_dialect = bool = [bool_or] my_mappings = text + counts + stats + arith_extensions + bool + other - Base_Generator.base_dialect - . extend_with my_mappings - . override_make_table_literal make_sqlite_table_literal + Base_Generator.base_dialect_operations . extend_with my_mappings ## PRIVATE unsupported name = @@ -512,11 +523,3 @@ make_runtime_error_op arguments = variable_to_defer = arguments.at 1 # We have to ensure that the implementation of SQLite that we use does not have a MATCH function defined which would make the code below succeed. SQL_Builder.code "match('[ENSO INVARIANT VIOLATED: '||" ++ error_message ++ "||'] ', " ++ variable_to_defer ++ ")" - -## PRIVATE -make_sqlite_table_literal vecs column_names as_name = - values = SQL_Builder.join ", " (vecs.transpose.map (vec-> SQL_Builder.join ", " (vec.map SQL_Builder.interpolation) . paren)) - wrap_identifier_as_builder n = SQL_Builder.code (Base_Generator.wrap_in_quotes n) - wrapped_name = wrap_identifier_as_builder as_name - structure = wrapped_name ++ (SQL_Builder.join ", " (column_names.map wrap_identifier_as_builder) . paren) - SQL_Builder.code "(WITH " ++ structure ++ " AS (VALUES " ++ values ++ ") SELECT * FROM " ++ wrapped_name ++ ") AS " ++ wrapped_name 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 ae84a10a476a..a555dbeed7df 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 @@ -49,14 +49,14 @@ import project.Internal.Snowflake_Type_Mapping.Snowflake_Type_Mapping The dialect of Snowflake databases. snowflake : Snowflake_Dialect snowflake = - Snowflake_Dialect.Value make_internal_generator_dialect + Snowflake_Dialect.Value make_dialect_operations ## PRIVATE The dialect of Snowflake databases. type Snowflake_Dialect ## PRIVATE The dialect of Snowflake databases. - Value internal_generator_dialect + Value dialect_operations ## PRIVATE Name of the dialect. @@ -71,22 +71,28 @@ type Snowflake_Dialect A function which generates SQL code from the internal representation according to the specific dialect. generate_sql : Query -> SQL_Statement - generate_sql self query = case query of - Query.Truncate_Table name -> - # Special handling to use TRUNCATE TABLE instead of the default DELETE FROM. - wrapped_name = self.internal_generator_dialect.wrap_identifier name - (SQL_Builder.code "TRUNCATE TABLE " ++ wrapped_name) . build - _ -> - # Rely on the base generator for most queries. - Base_Generator.generate_query self.internal_generator_dialect query . build + generate_sql self query = + Base_Generator.generate_query self query . build + + ## PRIVATE + Generates SQL to truncate a table. + generate_truncate_table_sql : Text -> SQL_Builder + generate_truncate_table_sql self table_name = + Base_Generator.truncate_table_truncate_table_style self table_name ## PRIVATE Wraps and possibly escapes the identifier so that it can be used in a generated query regardless of what characters it contains. The quotes used will depend on the dialect. - wrap_identifier : Text -> Text + wrap_identifier : Text -> SQL_Builder wrap_identifier self identifier = - self.internal_generator_dialect.wrap_identifier_raw identifier + Base_Generator.wrap_in_quotes identifier + + ## PRIVATE + Generates a SQL expression for a table literal. + make_table_literal : Vector (Vector Text) -> Vector Text -> Text -> SQL_Builder + make_table_literal self vecs column_names as_name = + Base_Generator.default_make_table_literal self.wrap_identifier vecs column_names as_name ## PRIVATE Prepares an ordering descriptor. @@ -213,7 +219,7 @@ type Snowflake_Dialect Checks if an operation is supported by the dialect. is_supported : Text -> Boolean is_supported self operation = - self.internal_generator_dialect.is_supported operation + self.dialect_operations.is_supported operation ## PRIVATE The default table types to use when listing tables. @@ -263,7 +269,7 @@ type Snowflake_Dialect _ -> base_type ## PRIVATE -make_internal_generator_dialect = +make_dialect_operations = cases = [["LOWER", Base_Generator.make_function "LOWER"], ["UPPER", Base_Generator.make_function "UPPER"]] text = [starts_with, contains, ends_with, agg_shortest, agg_longest, make_case_sensitive, ["REPLACE", replace], left, right]+concat_ops+cases+trim_ops counts = [agg_count_is_null, agg_count_empty, agg_count_not_empty, ["COUNT_DISTINCT", agg_count_distinct], ["COUNT_DISTINCT_INCLUDE_NULL", agg_count_distinct_include_null]] @@ -277,7 +283,7 @@ make_internal_generator_dialect = special_overrides = [] other = [["RUNTIME_ERROR", make_runtime_error_op]] my_mappings = text + counts + stats + first_last_aggregators + arith_extensions + bool + date_ops + special_overrides + other - Base_Generator.base_dialect . extend_with my_mappings + Base_Generator.base_dialect_operations . extend_with my_mappings ## PRIVATE agg_count_is_null = Base_Generator.lift_unary_op "COUNT_IS_NULL" arg-> diff --git a/test/Table_Tests/src/Database/Types/SQLite_Type_Mapping_Spec.enso b/test/Table_Tests/src/Database/Types/SQLite_Type_Mapping_Spec.enso index cca905e66bee..10b744a68f12 100644 --- a/test/Table_Tests/src/Database/Types/SQLite_Type_Mapping_Spec.enso +++ b/test/Table_Tests/src/Database/Types/SQLite_Type_Mapping_Spec.enso @@ -123,7 +123,7 @@ add_specs suite_builder = group_builder.specify "should be able to infer types for all supported operations" <| dialect = Dialect.sqlite - internal_mapping = dialect.internal_generator_dialect.operation_map + internal_mapping = dialect.dialect_operations.operation_map operation_type_mapping = SQLite_Type_Mapping.operations_map operation_type_mapping.keys.sort . should_equal internal_mapping.keys.sort diff --git a/test/Table_Tests/src/Database/Upload_Spec.enso b/test/Table_Tests/src/Database/Upload_Spec.enso index e1b66cec5459..7ed12d753210 100644 --- a/test/Table_Tests/src/Database/Upload_Spec.enso +++ b/test/Table_Tests/src/Database/Upload_Spec.enso @@ -259,7 +259,7 @@ add_specs suite_builder make_new_connection prefix persistent_connector=True = logs = log_file.read ..Plain_Text . lines deletes = logs.filter (_.contains "DROP") - wrapped_name = data.connection.dialect.wrap_identifier original_table_name + wrapped_name = data.connection.dialect.wrap_identifier original_table_name . build . unsafe_to_raw_sql deletes.each line-> if line.contains wrapped_name then Test.fail "The log file contains a dangerous DELETE statement for the original table: "+line