Skip to content

Commit bc32447

Browse files
authored
Introduce Value_Type.Null, fix edge cases for read_many (#11737)
- Closes #6281
1 parent 03c1c3c commit bc32447

File tree

67 files changed

+943
-284
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+943
-284
lines changed

distribution/lib/Standard/Base/0.0.0-dev/src/Data.enso

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import project.Data.Read.Many_Files_List.Many_Files_List
55
import project.Data.Read.Return_As.Return_As
66
import project.Data.Text.Encoding.Encoding
77
import project.Data.Text.Text
8+
import project.Data.Vector.No_Wrap
89
import project.Data.Vector.Vector
910
import project.Enso_Cloud.Data_Link.Data_Link
1011
import project.Enso_Cloud.Data_Link_Helpers
1112
import project.Error.Error
13+
import project.Errors.Common.Failed_To_Load
1214
import project.Errors.Common.Missing_Argument
1315
import project.Errors.File_Error.File_Error
1416
import project.Errors.Illegal_Argument.Illegal_Argument
@@ -145,9 +147,11 @@ read path=(Missing_Argument.throw "path") format=Auto_Detect (on_problems : Prob
145147
read_many : Many_Files_List -> File_Format -> Return_As -> Problem_Behavior -> Any ! File_Error
146148
read_many (paths : Many_Files_List = Missing_Argument.throw "paths") format=Auto_Detect return=..As_Merged_Table (on_problems : Problem_Behavior = ..Report_Warning) =
147149
return_as = Return_As.resolve return
148-
loaded_objects = paths.paths_to_load.map on_problems=on_problems path->
149-
Data.read path format on_problems
150-
return_as.make_return paths loaded_objects on_problems
150+
if paths.paths_to_load.contains Nothing then Error.throw (Illegal_Argument.Error Illegal_Argument.Error "`paths` cannot contain `Nothing`. Use `filter` with `..Not_Nothing` to remove.") else
151+
loaded_objects = paths.paths_to_load.map on_problems=No_Wrap.Value path->
152+
Data.read path format on_problems . catch Any error->
153+
Failed_To_Load.Warning path error
154+
return_as.make_return paths loaded_objects on_problems
151155

152156
## ALIAS load text, open text
153157
GROUP Input

distribution/lib/Standard/Base/0.0.0-dev/src/Data/Read/Many_Files_List.enso

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ import project.Data.Vector.Vector
77
used in `Data.read_many`.
88
type Many_Files_List
99
## PRIVATE
10+
Arguments:
11+
- original_value: The original value that represents a list of files.
12+
Some return modes may use it as it contains more information than just
13+
list of files (e.g. it can be a source table).
14+
- paths_to_load: A vector of paths to load. This is the fallback that can
15+
be used by any return mode if it does not recognize the original value.
16+
The vector is expected to contain values that can be passed into
17+
`Data.read` (so it can be Text, File, URI or any other kind of file -
18+
e.g. S3_File).
1019
Value original_value paths_to_load:Vector
1120

1221
## PRIVATE

distribution/lib/Standard/Base/0.0.0-dev/src/Data/Read/Return_As.enso

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import project.Data.Read.Many_Files_List.Many_Files_List
33
import project.Data.Text.Text
44
import project.Data.Vector.Vector
55
import project.Error.Error
6+
import project.Errors.Common.Failed_To_Load
67
import project.Errors.Common.Type_Error
78
import project.Errors.Illegal_Argument.Illegal_Argument
89
import project.Errors.Problem_Behavior.Problem_Behavior
910
import project.Function.Function
11+
import project.Meta
1012
import project.Metadata.Display
1113
import project.Metadata.Widget
1214
import project.Nothing.Nothing
@@ -33,7 +35,7 @@ type Return_As
3335
to_display_text self -> Text = self.underlying.to_display_text
3436

3537
## PRIVATE
36-
make_return self (input : Many_Files_List) (objects : Vector Any) (on_problems : Problem_Behavior) =
38+
make_return self (input : Many_Files_List) (objects : Vector (Any | Failed_To_Load)) (on_problems : Problem_Behavior) =
3739
self.underlying.make_return input objects on_problems
3840

3941
## PRIVATE
@@ -77,9 +79,17 @@ type Return_As_Base
7779
Panic.catch Type_Error (value:Return_As_Base) _->Nothing
7880

7981
## PRIVATE
80-
make_return self (input : Many_Files_List) (objects : Vector Any) (on_problems : Problem_Behavior) =
81-
_ = [input, on_problems]
82-
objects
82+
make_return self (input : Many_Files_List) (objects : Vector (Any | Failed_To_Load)) (on_problems : Problem_Behavior) =
83+
_ = input
84+
replace_with_nothing_and_propagate objects on_problems
85+
86+
## PRIVATE
87+
A helper method that takes a Vector and replaces `Failed_To_Load` with `Nothing`, raising them as warnings.
88+
replace_with_nothing_and_propagate (vector : Vector (Any | Failed_To_Load)) (on_problems : Problem_Behavior) =
89+
failed = vector.filter o-> o.is_a Failed_To_Load
90+
if failed.is_empty then vector else
91+
on_problems.attach_problems_before failed <|
92+
vector.map o-> if o.is_a Failed_To_Load then Nothing else o
8393

8494
## PRIVATE
8595
Return_As.from (that : Return_As_Base) =

distribution/lib/Standard/Base/0.0.0-dev/src/Errors/Common.enso

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,3 +607,13 @@ type Floating_Point_Equality
607607
"(Error (location = "+location+"))"
608608
Floating_Point_Equality.Used_As_Dictionary_Key value ->
609609
"(Used_As_Dictionary_Key (value = "+value.to_text+"))"
610+
611+
## A warning indicating that a file failed to be loaded.
612+
type Failed_To_Load
613+
## PRIVATE
614+
Warning path cause
615+
616+
## PRIVATE
617+
Create a human-readable version of the error.
618+
to_display_text : Text
619+
to_display_text self = "Failed to load file at path: "+self.path.to_display_text+": "+self.cause.to_display_text

distribution/lib/Standard/Database/0.0.0-dev/src/DB_Column.enso

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -597,12 +597,13 @@ type DB_Column
597597
cause a hard error, the value may be truncated or wrap-around etc.
598598
+ : DB_Column | Any -> DB_Column
599599
+ self other =
600-
op = case Value_Type_Helpers.resolve_addition_kind self other of
601-
Value_Type_Helpers.Addition_Kind.Numeric_Add -> "ADD_NUMBER"
602-
Value_Type_Helpers.Addition_Kind.Text_Concat -> "ADD_TEXT"
603-
op.if_not_error <|
604-
new_name = self.naming_helper.binary_operation_name "+" self other
605-
self.make_binary_op op other new_name
600+
new_name = self.naming_helper.binary_operation_name "+" self other
601+
case Value_Type_Helpers.resolve_addition_kind self other of
602+
Value_Type_Helpers.Addition_Kind.Numeric_Add ->
603+
self.make_binary_op "ADD_NUMBER" other new_name
604+
Value_Type_Helpers.Addition_Kind.Text_Concat ->
605+
self.make_binary_op "ADD_TEXT" other new_name
606+
Nothing -> self.const Nothing
606607

607608
## ALIAS minus, subtract, time difference
608609
GROUP Standard.Base.Operators
@@ -632,6 +633,7 @@ type DB_Column
632633
self.make_binary_op "-" other
633634
Value_Type_Helpers.Subtraction_Kind.Date_Time_Difference ->
634635
Error.throw (Unsupported_Database_Operation.Error "Subtracting date/time value")
636+
Nothing -> self.const Nothing
635637

636638
## ALIAS multiply, product, times
637639
GROUP Standard.Base.Operators

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Postgres/Postgres_Type_Mapping.enso

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ type Postgres_Type_Mapping
6464
but we may also consider using the standard SQL `bit(n)` and `bit varying(n)` types.
6565
See: https://www.postgresql.org/docs/current/datatype-bit.html
6666
SQL_Type.Value Types.BINARY "bytea" precision=max_precision
67+
Value_Type.Null ->
68+
Error.throw (Unsupported_Database_Type.Error "Null" "Postgres")
6769
Value_Type.Mixed ->
6870
Error.throw (Unsupported_Database_Type.Error "Mixed" "Postgres")
6971
Value_Type.Unsupported_Data_Type type_name underlying_type ->
@@ -146,7 +148,7 @@ type Postgres_Type_Mapping
146148
simple_types_map = Dictionary.from_vector <|
147149
ints = [[Types.SMALLINT, Value_Type.Integer Bits.Bits_16], [Types.BIGINT, Value_Type.Integer Bits.Bits_64], [Types.INTEGER, Value_Type.Integer Bits.Bits_32]]
148150
floats = [[Types.DOUBLE, Value_Type.Float Bits.Bits_64], [Types.REAL, Value_Type.Float Bits.Bits_32]]
149-
other = [[Types.DATE, Value_Type.Date], [Types.TIME, Value_Type.Time]]
151+
other = [[Types.DATE, Value_Type.Date], [Types.TIME, Value_Type.Time], [Types.NULL, Value_Type.Null]]
150152
ints + floats + other
151153

152154
## PRIVATE

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Dialect.enso

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,12 @@ type SQLite_Dialect
192192
adapt_unified_column : Internal_Column -> Value_Type -> (SQL_Expression -> SQL_Type_Reference) -> Internal_Column
193193
adapt_unified_column self column approximate_result_type infer_result_type_from_database_callback =
194194
_ = infer_result_type_from_database_callback
195-
# TODO [RW] This may be revisited with #6281.
196-
case approximate_result_type of
197-
Nothing -> column
198-
_ ->
199-
sql_type = self.get_type_mapping.value_type_to_sql approximate_result_type Problem_Behavior.Ignore
200-
new_expression = self.make_cast_expression column sql_type
201-
new_sql_type_reference = SQL_Type_Reference.from_constant sql_type
202-
Internal_Column.Value column.name new_sql_type_reference new_expression
195+
needs_cast = approximate_result_type != Value_Type.Null
196+
if needs_cast.not then column else
197+
sql_type = self.get_type_mapping.value_type_to_sql approximate_result_type Problem_Behavior.Ignore
198+
new_expression = self.make_cast_expression column sql_type
199+
new_sql_type_reference = SQL_Type_Reference.from_constant sql_type
200+
Internal_Column.Value column.name new_sql_type_reference new_expression
203201

204202
## PRIVATE
205203
Add an extra cast to adjust the output type of certain operations with
@@ -637,6 +635,9 @@ make_custom_cast column target_value_type type_mapping =
637635
result = Ref.new Nothing
638636
column_type =
639637
type_mapping.sql_type_to_value_type column.sql_type_reference.get
638+
if target_value_type == Value_Type.Null then
639+
result.put column.expression
640+
640641
if target_value_type.is_text && (column_type == Value_Type.Boolean) then
641642
expr = SQL_Expression.Operation "IIF" [column.expression, SQL_Expression.Literal "'true'", SQL_Expression.Literal "'false'"]
642643
result.put expr

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/SQLite/SQLite_Type_Mapping.enso

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ type SQLite_Type_Mapping
6060
Value_Type.Date -> unsupported_date_time
6161
Value_Type.Date_Time _ -> unsupported_date_time
6262
Value_Type.Binary _ _ -> SQLite_Types.blob
63+
Value_Type.Null -> SQLite_Types.null
6364
Value_Type.Mixed ->
6465
## The best we could do would be to store mixed values and
6566
report invalid type or coerce the values to Text. Both seem
@@ -151,7 +152,7 @@ simple_types_map = Dictionary.from_vector <|
151152
numerics = [Types.DECIMAL, Types.NUMERIC] . map x-> [x, default_float]
152153
strings = [Types.CHAR, Types.VARCHAR] . map x-> [x, default_text]
153154
blobs = [Types.BINARY, Types.BLOB, Types.CLOB] . map x-> [x, Value_Type.Binary]
154-
special_types = [[Types.BOOLEAN, Value_Type.Boolean]]
155+
special_types = [[Types.BOOLEAN, Value_Type.Boolean], [Types.NULL, Value_Type.Null]]
155156
ints + floats + numerics + strings + blobs + special_types
156157

157158
## PRIVATE
@@ -246,6 +247,9 @@ type SQLite_Types
246247
The artificial 6th affinity that is used to distinguish boolean columns.
247248
boolean = SQL_Type.Value Types.BOOLEAN "BOOLEAN"
248249

250+
## PRIVATE
251+
null = SQL_Type.Value Types.NULL "NULL"
252+
249253
## PRIVATE
250254
default_text = Value_Type.Char size=Nothing variable_length=True
251255

distribution/lib/Standard/Database/0.0.0-dev/src/Internal/Upload/Helpers/SQL_Helpers.enso

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ private
22

33
from Standard.Base import all
44
import Standard.Base.Data.Vector.No_Wrap
5+
import Standard.Base.Errors.Illegal_Argument.Illegal_Argument
56

67
import project.Column_Description.Column_Description
78
import project.Connection.Connection.Connection
@@ -10,6 +11,7 @@ import project.Internal.IR.Query.Query
1011
import project.Internal.IR.SQL_Expression.SQL_Expression
1112
import project.SQL_Query.SQL_Query
1213
import project.SQL_Statement.SQL_Statement
14+
from project.Errors import Unsupported_Database_Type
1315

1416
## PRIVATE
1517
make_batched_insert_template : Connection -> Text -> Vector (Vector Text) -> SQL_Query
@@ -32,6 +34,9 @@ prepare_create_table_statement connection table_name columns primary_key tempora
3234
type_mapping = connection.dialect.get_type_mapping
3335
column_descriptors = columns.map on_problems=No_Wrap.Value def->
3436
sql_type = type_mapping.value_type_to_sql def.value_type on_problems
37+
. catch Unsupported_Database_Type error->
38+
Error.throw (Illegal_Argument.Error "Definition for column ["+def.name+"] is invalid: "+error.to_display_text)
39+
3540
sql_type_text = type_mapping.sql_type_to_text sql_type
3641
Create_Column_Descriptor.Value def.name sql_type_text def.constraints
3742
connection.dialect.generate_sql <|

distribution/lib/Standard/Microsoft/0.0.0-dev/src/Internal/SQLServer_Type_Mapping.enso

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ type SQLServer_Type_Mapping
6262
True -> SQL_Type.Value Types.BINARY "VARBINARY" size
6363
False -> SQL_Type.Value Types.BINARY "BINARY" size
6464
Value_Type.Mixed -> Error.throw (Unsupported_Database_Type.Error "Mixed" "SQLServer")
65+
Value_Type.Null -> Error.throw (Unsupported_Database_Type.Error "Null" "SQLServer")
6566
Value_Type.Unsupported_Data_Type type_name underlying_type ->
6667
underlying_type.if_nothing <| Error.throw <| Illegal_Argument.Error <|
6768
"An unsupported SQL type ["+type_name.to_text+"] cannot be converted into an SQL type because it did not contain the SQL metadata needed to reconstruct it."
@@ -101,6 +102,7 @@ type SQLServer_Type_Mapping
101102
"varbinary" -> Value_Type.Binary size=sql_type.precision variable_length=True
102103
"binary" -> Value_Type.Binary size=sql_type.precision variable_length=False
103104
_ -> on_unknown_type sql_type
105+
Types.NULL -> Value_Type.Null
104106
_ -> case sql_type.name of
105107
"datetimeoffset" -> Value_Type.Date_Time with_timezone=True
106108
_ -> on_unknown_type sql_type

0 commit comments

Comments
 (0)