Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wip/adr/add sqlserver offset #12206

Draft
wants to merge 13 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions distribution/lib/Standard/Database/0.0.0-dev/src/DB_Table.enso
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import project.Internal.Aggregate_Helper
import project.Internal.Base_Generator
import project.Internal.Common.Database_Join_Helper
import project.Internal.Common.Lookup_Query_Helper
import project.Internal.Common.Offset_Helpers
import project.Internal.Common.Row_Number_Helpers
import project.Internal.DB_Data_Link_Helpers
import project.Internal.Helpers
Expand Down Expand Up @@ -3180,9 +3181,38 @@ type DB_Table
@default (self-> Widget_Helpers.make_fill_default_value_selector2)
@group_by Widget_Helpers.make_column_name_multi_selector
@order_by Widget_Helpers.make_order_by_selector
offset self columns:(Vector (Integer | Text | Regex | By_Type))=(Missing_Argument.throw "columns") n:Integer=-1 fill_with:Fill_With=..Nothing (group_by:(Vector | Text | Integer | Regex)=[]) (order_by:(Vector | Text)=[]) (set_mode:Set_Mode=..Add) (on_problems:Problem_Behavior=..Report_Warning) -> Table =
_ = [columns, n, fill_with, group_by, order_by, set_mode, on_problems]
Error.throw (Unsupported_Database_Operation.Error "offset")
offset self columns:(Vector (Integer | Text | Regex | By_Type))=(Missing_Argument.throw "columns") n:Integer=-1 fill_with:Fill_With=..Nothing (group_by:(Vector | Text | Integer | Regex)=[]) (order_by:(Vector | Text)=[]) (set_mode:Set_Mode=..Add) (on_problems:Problem_Behavior=..Report_Warning) -> DB_Table =
Feature.Offset.if_supported_else_throw self.connection.dialect "offset" <|
problem_builder = Problem_Builder.new error_on_missing_columns=True
grouping_columns = self.columns_helper.select_columns_helper group_by Case_Sensitivity.Default True problem_builder
grouping_columns.each column->
if column.value_type.is_floating_point then
problem_builder.report_other_warning (Floating_Point_Equality.Error column.name)
ordering = Table_Helpers.resolve_order_by self.columns order_by problem_builder
resolved_columns = self.columns_helper.select_columns_helper columns Case_Sensitivity.Default True problem_builder
problem_builder.attach_problems_before on_problems <| if columns.is_empty then self else
order_descriptors = case ordering.is_empty of
False -> ordering.map element->
column = element.column
associated_selector = element.associated_selector
self.connection.dialect.prepare_order_descriptor column associated_selector.direction text_ordering=Nothing
True -> case self.default_ordering of
Nothing -> Error.throw (Illegal_Argument.Error "The table has no existing ordering (e.g. from a `sort` operation or primary key). `offset` requires an ordering in database.")
descriptors -> descriptors
grouping_expressions = (grouping_columns.map _.as_internal).map .expression
new_exprs = resolved_columns.map c->(Offset_Helpers.make_offset n (c.as_internal) order_descriptors grouping_expressions)

type_mapping = self.connection.dialect.get_type_mapping
infer_from_database_callback expression =
SQL_Type_Reference.new self.connection self.context expression
new_type_refs = new_exprs.map expr->(type_mapping.infer_return_type infer_from_database_callback "OFFSET" [] expr)

new_names = resolved_columns.map c->(if set_mode==Set_Mode.Add then self.column_naming_helper.function_name "offset" [c, n, fill_with] else c.name)
new_columns = (new_names.zip new_type_refs).zip new_exprs a->b->(Internal_Column.Value a.first a.second b)

updated_table = new_columns.fold self t-> col->
t.set (self.make_column col)
updated_table.as_subquery

## PRIVATE

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ type SQL_Generator
order_part = (SQL_Builder.join ", " orders) . prefix_if_present " ORDER BY "

limit_part = case ctx.limit of
Nothing -> ""
Nothing -> "TOP 100 PERCENT "
_ : Integer -> dialect.get_limit_sql_modifier ctx.limit

extensions = ctx.extensions.map extension->
Expand Down Expand Up @@ -467,7 +467,7 @@ base_dialect_operations =
nulls = [["IS_NULL", make_right_unary_op "IS NULL"], ["FILL_NULL", make_function "COALESCE"]]
contains = [["IS_IN", make_is_in], ["IS_IN_COLUMN", make_is_in_column]]
types = [simple_cast]
windows = [["ROW_NUMBER", make_row_number], ["ROW_NUMBER_IN_GROUP", make_row_number_in_group]]
windows = [["ROW_NUMBER", make_row_number], ["ROW_NUMBER_IN_GROUP", make_row_number_in_group], ["LEAD", make_lead_lag "LEAD"], ["LAG", make_lead_lag "LAG"]]
base_dict = Dictionary.from_vector (arith + logic + compare + functions + agg + counts + text + nulls + contains + types + windows)
Dialect_Operations.Value base_dict

Expand Down Expand Up @@ -554,6 +554,20 @@ make_row_number (arguments : Vector) (metadata : Row_Number_Metadata) = if argum
SQL_Builder.code "PARTITION BY " ++ SQL_Builder.join ", " grouping
SQL_Builder.code "(row_number() OVER (" ++ group_part ++ " ORDER BY " ++ SQL_Builder.join ", " ordering ++ ") * " ++ step.paren ++ " + " ++ offset.paren ++ ")"

## PRIVATE
make_lead_lag lead_lag:Text arguments:Vector metadata:Row_Number_Metadata -> SQL_Builder = if arguments.length < 3 then Error.throw (Illegal_State.Error "Wrong amount of parameters in LEAD/LAG IR. This is a bug in the Database library.") else
n = arguments.at 0
colName = arguments.at 1

ordering_and_grouping = arguments.drop 2
ordering = ordering_and_grouping.drop (..Last metadata.groupings_count)
grouping = ordering_and_grouping.take (..Last metadata.groupings_count)

group_part = if grouping.length == 0 then "" else
SQL_Builder.code "PARTITION BY " ++ SQL_Builder.join ", " grouping

SQL_Builder.code "(" ++ lead_lag ++ "(" ++ colName ++ ", " ++ n ++ ", NULL) OVER (" ++ group_part ++ " ORDER BY " ++ SQL_Builder.join ", " ordering ++ "))"

## PRIVATE
A helper for `lookup_and_replace`, and perhaps other operation.
It creates an expression that returns a row number within a group.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from Standard.Base import all

import project.Internal.IR.Operation_Metadata
import project.Internal.IR.Order_Descriptor.Order_Descriptor
import project.Internal.IR.SQL_Expression.SQL_Expression
import project.Internal.IR.Internal_Column.Internal_Column

## PRIVATE
make_offset (n : Integer) (colName: Internal_Column) (order_descriptors : Vector Order_Descriptor) (grouping_expressions : Vector SQL_Expression) -> SQL_Expression =
params = [SQL_Expression.Literal n.abs.to_text, colName.expression] + order_descriptors + grouping_expressions
metadata = Operation_Metadata.Row_Number_Metadata.Value grouping_expressions.length
lead_lag = if n<0 then "LAG" else "LEAD"
SQL_Expression.Operation lead_lag params metadata
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ type SQLServer_Dialect
Feature.Join -> True
Feature.Union -> True
Feature.Aggregate -> True
Feature.Offset -> True
_ -> False

## PRIVATE
Expand Down
7 changes: 4 additions & 3 deletions distribution/lib/Standard/Table/0.0.0-dev/src/Table.enso
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ type Table
Error.throw (Illegal_Argument.Error "Each column must be represented by a pair whose first element is the column name and the second element is a vector of elements that will constitute that column, or an existing column. Got: "+columns.to_text)
cols = columns.map on_problems=No_Wrap.Value c->
case c of
v : Vector ->
if v.length != 2 then invalid_input_shape else
Column.from_vector (v.at 0) (v.at 1) . java_column
v : Vector -> case v.length of
2 -> Column.from_vector (v.at 0) (v.at 1) . java_column
3 -> Column.from_vector (v.at 0) (v.at 1) (v.at 2) . java_column
_ -> invalid_input_shape
col : Column -> col.java_column
_ -> invalid_input_shape
Panic.recover Illegal_Argument <|
Expand Down
Loading
Loading