File: mssql_emulate_lateral_with_apply.rb

package info (click to toggle)
ruby-sequel 5.63.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 10,408 kB
  • sloc: ruby: 113,747; makefile: 3
file content (84 lines) | stat: -rw-r--r-- 2,807 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# frozen-string-literal: true
#
# The mssql_emulate_lateral_with_apply extension converts
# queries that use LATERAL into queries that use CROSS/OUTER
# APPLY, allowing code that works on databases that support
# LATERAL via Dataset#lateral to run on Microsoft SQL Server
# and Sybase SQLAnywhere.
#
# This is available as a separate extension instead of
# integrated into the Microsoft SQL Server and Sybase
# SQLAnywhere support because few people need it and there
# is a performance hit to code that doesn't use it.
#
# It is possible there are cases where this emulation does
# not work.  Users should probably verify that correct
# results are returned when using this extension.
#
# You can load this extension into specific datasets:
#
#   ds = DB[:table]
#   ds = ds.extension(:mssql_emulate_lateral_with_apply)
#
# Or you can load it into all of a database's datasets:
#
#   DB.extension(:mssql_emulate_lateral_with_apply)
#
# Related module: Sequel::MSSQL::EmulateLateralWithApply

#
module Sequel
  module MSSQL
    module EmulateLateralWithApply
      # If the table is a dataset that uses LATERAL,
      # convert it to a CROSS APPLY if it is a INNER
      # or CROSS JOIN, and an OUTER APPLY if it is a
      # LEFT JOIN.
      def join_table(type, table, expr=nil, *)
        if table.is_a?(Dataset) && table.opts[:lateral]
          table = table.clone(:lateral=>nil)
          case type
          when :inner
            type = :cross_apply
            table = table.where(expr)
            expr = nil
          when :cross
            type = :cross_apply
          when :left, :left_outer
            type = :outer_apply
            table = table.where(expr)
            expr = nil
          end
        end
        super
      end

      # When a FROM entry uses a LATERAL subquery,
      # convert that entry into a CROSS APPLY.
      def from(*source, &block)
        virtual_row_columns(source, block)
        lateral, source = source.partition{|t| t.is_a?(Sequel::Dataset) && t.opts[:lateral] || (t.is_a?(Sequel::SQL::AliasedExpression) && t.expression.is_a?(Sequel::Dataset) && t.expression.opts[:lateral])} unless source.empty?
        return super(*source, &nil) if !lateral || lateral.empty?

        ds = from(*source)
        lateral.each do |l|
          l = if l.is_a?(Sequel::SQL::AliasedExpression)
            l.expression.clone(:lateral=>nil).as(l.alias)
          else
            l.clone(:lateral=>nil)
          end
          ds = ds.cross_apply(l)
        end
        ds
      end
      
      # MSSQL can emulate lateral subqueries via CROSS/OUTER APPLY
      # when using this extension.
      def supports_lateral_subqueries?
        true
      end
    end
  end

  Dataset.register_extension(:mssql_emulate_lateral_with_apply, MSSQL::EmulateLateralWithApply)
end