alf-sql 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +38 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +12 -0
- data/README.md +52 -0
- data/Rakefile +11 -0
- data/lib/alf-sql.rb +1 -0
- data/lib/alf/algebra/operand.rb +18 -0
- data/lib/alf/predicate/nodes.rb +20 -0
- data/lib/alf/predicate/nodes/and.rb +11 -0
- data/lib/alf/predicate/nodes/contradiction.rb +12 -0
- data/lib/alf/predicate/nodes/dyadic_comp.rb +14 -0
- data/lib/alf/predicate/nodes/eq.rb +11 -0
- data/lib/alf/predicate/nodes/exists.rb +14 -0
- data/lib/alf/predicate/nodes/expr.rb +20 -0
- data/lib/alf/predicate/nodes/gt.rb +11 -0
- data/lib/alf/predicate/nodes/gte.rb +11 -0
- data/lib/alf/predicate/nodes/identifier.rb +12 -0
- data/lib/alf/predicate/nodes/in.rb +31 -0
- data/lib/alf/predicate/nodes/literal.rb +12 -0
- data/lib/alf/predicate/nodes/lt.rb +11 -0
- data/lib/alf/predicate/nodes/lte.rb +11 -0
- data/lib/alf/predicate/nodes/nadic_bool.rb +18 -0
- data/lib/alf/predicate/nodes/native.rb +11 -0
- data/lib/alf/predicate/nodes/neq.rb +11 -0
- data/lib/alf/predicate/nodes/not.rb +14 -0
- data/lib/alf/predicate/nodes/or.rb +11 -0
- data/lib/alf/predicate/nodes/qualified_identifier.rb +12 -0
- data/lib/alf/predicate/nodes/tautology.rb +12 -0
- data/lib/alf/sql.rb +15 -0
- data/lib/alf/sql/builder.rb +152 -0
- data/lib/alf/sql/cog.rb +32 -0
- data/lib/alf/sql/compiler.rb +137 -0
- data/lib/alf/sql/grammar.rb +44 -0
- data/lib/alf/sql/grammar.sexp.yml +92 -0
- data/lib/alf/sql/loader.rb +2 -0
- data/lib/alf/sql/nodes/column_name.rb +25 -0
- data/lib/alf/sql/nodes/cross_join.rb +28 -0
- data/lib/alf/sql/nodes/except.rb +14 -0
- data/lib/alf/sql/nodes/expr.rb +90 -0
- data/lib/alf/sql/nodes/from_clause.rb +24 -0
- data/lib/alf/sql/nodes/inner_join.rb +37 -0
- data/lib/alf/sql/nodes/intersect.rb +14 -0
- data/lib/alf/sql/nodes/limit_clause.rb +19 -0
- data/lib/alf/sql/nodes/literal.rb +18 -0
- data/lib/alf/sql/nodes/name_intro.rb +23 -0
- data/lib/alf/sql/nodes/offset_clause.rb +19 -0
- data/lib/alf/sql/nodes/order_by_clause.rb +25 -0
- data/lib/alf/sql/nodes/order_by_term.rb +30 -0
- data/lib/alf/sql/nodes/qualified_name.rb +32 -0
- data/lib/alf/sql/nodes/range_var_name.rb +17 -0
- data/lib/alf/sql/nodes/select_exp.rb +101 -0
- data/lib/alf/sql/nodes/select_item.rb +37 -0
- data/lib/alf/sql/nodes/select_list.rb +31 -0
- data/lib/alf/sql/nodes/select_star.rb +15 -0
- data/lib/alf/sql/nodes/set_operator.rb +64 -0
- data/lib/alf/sql/nodes/set_quantifier.rb +20 -0
- data/lib/alf/sql/nodes/subquery_as.rb +28 -0
- data/lib/alf/sql/nodes/table_as.rb +31 -0
- data/lib/alf/sql/nodes/table_name.rb +17 -0
- data/lib/alf/sql/nodes/union.rb +14 -0
- data/lib/alf/sql/nodes/where_clause.rb +20 -0
- data/lib/alf/sql/nodes/with_exp.rb +50 -0
- data/lib/alf/sql/nodes/with_spec.rb +24 -0
- data/lib/alf/sql/processor.rb +85 -0
- data/lib/alf/sql/processor/all.rb +17 -0
- data/lib/alf/sql/processor/clip.rb +39 -0
- data/lib/alf/sql/processor/distinct.rb +17 -0
- data/lib/alf/sql/processor/flatten.rb +24 -0
- data/lib/alf/sql/processor/from_self.rb +29 -0
- data/lib/alf/sql/processor/join.rb +80 -0
- data/lib/alf/sql/processor/join_support.rb +27 -0
- data/lib/alf/sql/processor/limit_offset.rb +30 -0
- data/lib/alf/sql/processor/merge.rb +42 -0
- data/lib/alf/sql/processor/order_by.rb +32 -0
- data/lib/alf/sql/processor/rename.rb +25 -0
- data/lib/alf/sql/processor/reorder.rb +21 -0
- data/lib/alf/sql/processor/requalify.rb +24 -0
- data/lib/alf/sql/processor/semi_join.rb +57 -0
- data/lib/alf/sql/processor/star.rb +17 -0
- data/lib/alf/sql/processor/where.rb +25 -0
- data/lib/alf/sql/version.rb +16 -0
- data/spec/algebra/operand/test_to_sql.rb +32 -0
- data/spec/builder/test_order_by_clause.rb +44 -0
- data/spec/helpers/ast.rb +242 -0
- data/spec/helpers/compiler.rb +23 -0
- data/spec/nodes/column_name/test_as_name.rb +14 -0
- data/spec/nodes/column_name/test_qualifier.rb +14 -0
- data/spec/nodes/order_by_clause/test_to_ordering.rb +30 -0
- data/spec/nodes/order_by_term/test_as_name.rb +22 -0
- data/spec/nodes/order_by_term/test_direction.rb +22 -0
- data/spec/nodes/order_by_term/test_qualifier.rb +22 -0
- data/spec/nodes/select_exp/test_order_by_clause.rb +22 -0
- data/spec/nodes/select_item/test_as_name.rb +22 -0
- data/spec/predicate/nodes/exists/test_not.rb +20 -0
- data/spec/processor/clip/test_on_select_exp.rb +32 -0
- data/spec/processor/clip/test_on_select_list.rb +24 -0
- data/spec/processor/distinct/test_on_set_quantified.rb +31 -0
- data/spec/processor/from_self/test_on_nonjoin_exp.rb +60 -0
- data/spec/processor/from_self/test_on_with_exp.rb +22 -0
- data/spec/processor/merge/test_on_select_exp.rb +73 -0
- data/spec/processor/merge/test_on_with_exp.rb +56 -0
- data/spec/processor/order_by/test_on_select_exp.rb +24 -0
- data/spec/processor/rename/test_on_select_item.rb +30 -0
- data/spec/processor/rename/test_on_select_list.rb +22 -0
- data/spec/processor/reorder/test_on_select_list.rb +22 -0
- data/spec/processor/requalify/test_on_select_exp.rb +24 -0
- data/spec/processor/star/test_on_select_exp.rb +24 -0
- data/spec/processor/test_clip.rb +24 -0
- data/spec/processor/test_distinct.rb +24 -0
- data/spec/processor/test_on_select_exp.rb +28 -0
- data/spec/processor/test_on_set_operator.rb +28 -0
- data/spec/processor/test_rename.rb +24 -0
- data/spec/shared/compiled_examples.rb +13 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/test_sql.rb +10 -0
- data/tasks/bench.rake +40 -0
- data/tasks/gem.rake +8 -0
- data/tasks/test.rake +6 -0
- metadata +235 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
module WhereClause
|
|
4
|
+
include Expr
|
|
5
|
+
|
|
6
|
+
WHERE = "WHERE".freeze
|
|
7
|
+
|
|
8
|
+
def predicate
|
|
9
|
+
last
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_sql(buffer = "")
|
|
13
|
+
buffer << WHERE << SPACE
|
|
14
|
+
predicate.to_sql(buffer)
|
|
15
|
+
buffer
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end # module WhereClause
|
|
19
|
+
end # module Sql
|
|
20
|
+
end # module Alf
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
module WithExp
|
|
4
|
+
include Expr
|
|
5
|
+
extend Forwardable
|
|
6
|
+
|
|
7
|
+
WITH = "WITH".freeze
|
|
8
|
+
|
|
9
|
+
def with_exp?
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def with_spec
|
|
14
|
+
self[1]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def select_exp
|
|
18
|
+
last
|
|
19
|
+
end
|
|
20
|
+
def_delegators :select_exp, :select_list,
|
|
21
|
+
:where_clause,
|
|
22
|
+
:predicate,
|
|
23
|
+
:from_clause,
|
|
24
|
+
:table_spec,
|
|
25
|
+
:order_by_clause,
|
|
26
|
+
:limit_clause,
|
|
27
|
+
:offset_clause,
|
|
28
|
+
:desaliaser,
|
|
29
|
+
:to_attr_list,
|
|
30
|
+
:to_ordering,
|
|
31
|
+
:all?,
|
|
32
|
+
:distinct?,
|
|
33
|
+
:set_operator?,
|
|
34
|
+
:limit_or_offset?,
|
|
35
|
+
:join?,
|
|
36
|
+
:should_be_reused?
|
|
37
|
+
|
|
38
|
+
# to_xxx
|
|
39
|
+
|
|
40
|
+
def to_sql(buffer = "")
|
|
41
|
+
buffer << WITH << SPACE
|
|
42
|
+
self[1].to_sql(buffer)
|
|
43
|
+
buffer << SPACE
|
|
44
|
+
self[2].to_sql(buffer, false)
|
|
45
|
+
buffer
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end # module WithExp
|
|
49
|
+
end # module Sql
|
|
50
|
+
end # module Alf
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
module WithSpec
|
|
4
|
+
include Expr
|
|
5
|
+
|
|
6
|
+
def to_sql(buffer = "")
|
|
7
|
+
each_child do |child,index|
|
|
8
|
+
buffer << COMMA << SPACE unless index==0
|
|
9
|
+
child.to_sql(buffer)
|
|
10
|
+
end
|
|
11
|
+
buffer
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_hash
|
|
15
|
+
hash = {}
|
|
16
|
+
each_child do |child|
|
|
17
|
+
hash[child.table_name.value] = child.subquery
|
|
18
|
+
end
|
|
19
|
+
hash
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end # module WithSpec
|
|
23
|
+
end # module Sql
|
|
24
|
+
end # module Alf
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
class Processor < Sexpr::Rewriter
|
|
4
|
+
grammar Sql::Grammar
|
|
5
|
+
|
|
6
|
+
UnexpectedError = Class.new(Alf::Error)
|
|
7
|
+
|
|
8
|
+
def initialize(builder)
|
|
9
|
+
@builder = builder
|
|
10
|
+
end
|
|
11
|
+
attr_reader :builder
|
|
12
|
+
|
|
13
|
+
def on_with_exp(sexpr)
|
|
14
|
+
applied = apply(sexpr.select_exp)
|
|
15
|
+
if applied.with_exp?
|
|
16
|
+
merge_with_exps(sexpr, applied, applied.select_exp)
|
|
17
|
+
else
|
|
18
|
+
sexpr.with_update(-1, applied)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def on_set_operator(sexpr)
|
|
23
|
+
sexpr.each_with_index.map{|child,index|
|
|
24
|
+
index <= 1 ? child : apply(child)
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
alias :on_union :on_set_operator
|
|
28
|
+
alias :on_except :on_set_operator
|
|
29
|
+
alias :on_intersect :on_set_operator
|
|
30
|
+
|
|
31
|
+
def on_select_exp(sexpr)
|
|
32
|
+
sexpr.with_update(2, apply(sexpr[2]))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def merge_with_exps(left, right, main)
|
|
38
|
+
if left.with_exp? and right.with_exp?
|
|
39
|
+
[ :with_exp,
|
|
40
|
+
merge_with_specs(left.with_spec, right.with_spec),
|
|
41
|
+
main ]
|
|
42
|
+
elsif left.with_exp?
|
|
43
|
+
left.with_update(-1, main)
|
|
44
|
+
elsif right.with_exp?
|
|
45
|
+
right.with_update(-1, main)
|
|
46
|
+
else
|
|
47
|
+
main
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def merge_with_specs(left, right)
|
|
52
|
+
hash = left.to_hash.merge(right.to_hash){|k,v1,v2|
|
|
53
|
+
unless v1 == v2
|
|
54
|
+
msg = "Unexpected different SQL expr: "
|
|
55
|
+
msg << "`#{v1.to_sql}` vs. `#{v2.to_sql}`"
|
|
56
|
+
raise UnexpectedError, msg
|
|
57
|
+
end
|
|
58
|
+
v1
|
|
59
|
+
}
|
|
60
|
+
hash.map{|(k,v)| builder.name_intro(k,v) }.unshift(:with_spec)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def tautology
|
|
64
|
+
Predicate::Factory.tautology
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
require_relative 'processor/distinct'
|
|
71
|
+
require_relative 'processor/all'
|
|
72
|
+
require_relative 'processor/clip'
|
|
73
|
+
require_relative 'processor/star'
|
|
74
|
+
require_relative 'processor/rename'
|
|
75
|
+
require_relative 'processor/order_by'
|
|
76
|
+
require_relative 'processor/limit_offset'
|
|
77
|
+
require_relative 'processor/from_self'
|
|
78
|
+
require_relative 'processor/reorder'
|
|
79
|
+
require_relative 'processor/merge'
|
|
80
|
+
require_relative 'processor/where'
|
|
81
|
+
require_relative 'processor/join_support'
|
|
82
|
+
require_relative 'processor/join'
|
|
83
|
+
require_relative 'processor/semi_join'
|
|
84
|
+
require_relative 'processor/flatten'
|
|
85
|
+
require_relative 'processor/requalify'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
class Processor
|
|
4
|
+
class All < Processor
|
|
5
|
+
|
|
6
|
+
def on_set_quantified(sexpr)
|
|
7
|
+
sexpr.with_update(1, builder.all)
|
|
8
|
+
end
|
|
9
|
+
alias :on_union :on_set_quantified
|
|
10
|
+
alias :on_except :on_set_quantified
|
|
11
|
+
alias :on_intersect :on_set_quantified
|
|
12
|
+
alias :on_select_exp :on_set_quantified
|
|
13
|
+
|
|
14
|
+
end # class All
|
|
15
|
+
end # class Processor
|
|
16
|
+
end # module Sql
|
|
17
|
+
end # module Alf
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
class Processor
|
|
4
|
+
class Clip < Processor
|
|
5
|
+
|
|
6
|
+
def initialize(attributes, on_empty = :is_table_dee, builder)
|
|
7
|
+
super(builder)
|
|
8
|
+
@attributes = attributes
|
|
9
|
+
@on_empty = on_empty
|
|
10
|
+
end
|
|
11
|
+
attr_reader :attributes, :on_empty
|
|
12
|
+
|
|
13
|
+
def on_select_exp(sexpr)
|
|
14
|
+
catch(:empty){ return super(sexpr) }
|
|
15
|
+
send("select_#{on_empty}", sexpr)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def on_select_list(sexpr)
|
|
19
|
+
result = sexpr.select{|child|
|
|
20
|
+
(child == :select_list) or
|
|
21
|
+
attributes.include?(child.as_name.to_sym)
|
|
22
|
+
}
|
|
23
|
+
(result.size==1) ? throw(:empty) : result
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def select_is_table_dee(sexpr)
|
|
29
|
+
builder.select_is_table_dee(select_star(sexpr))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def select_star(sexpr)
|
|
33
|
+
All.new(builder).call(Star.new(builder).call(sexpr))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end # class Clip
|
|
37
|
+
end # class Processor
|
|
38
|
+
end # module Sql
|
|
39
|
+
end # module Alf
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
class Processor
|
|
4
|
+
class Distinct < Processor
|
|
5
|
+
|
|
6
|
+
def on_set_quantified(sexpr)
|
|
7
|
+
sexpr.with_update(1, builder.distinct)
|
|
8
|
+
end
|
|
9
|
+
alias :on_union :on_set_quantified
|
|
10
|
+
alias :on_except :on_set_quantified
|
|
11
|
+
alias :on_intersect :on_set_quantified
|
|
12
|
+
alias :on_select_exp :on_set_quantified
|
|
13
|
+
|
|
14
|
+
end # class Distinct
|
|
15
|
+
end # class Processor
|
|
16
|
+
end # module Sql
|
|
17
|
+
end # module Alf
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
class Processor
|
|
4
|
+
class Flatten < Processor
|
|
5
|
+
|
|
6
|
+
def on_with_exp(sexpr)
|
|
7
|
+
@subqueries = sexpr.with_spec.to_hash
|
|
8
|
+
apply(sexpr.select_exp)
|
|
9
|
+
end
|
|
10
|
+
attr_reader :subqueries
|
|
11
|
+
|
|
12
|
+
alias :on_select_exp :copy_and_apply
|
|
13
|
+
alias :on_missing :copy_and_apply
|
|
14
|
+
|
|
15
|
+
def on_table_as(sexpr)
|
|
16
|
+
return sexpr unless subqueries
|
|
17
|
+
return sexpr unless subquery = subqueries[sexpr.table_name]
|
|
18
|
+
[ :subquery_as, apply(subquery), sexpr.right ]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end # class Flatten
|
|
22
|
+
end # class Processor
|
|
23
|
+
end # module Sql
|
|
24
|
+
end # module Alf
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
class Processor
|
|
4
|
+
class FromSelf < Processor
|
|
5
|
+
|
|
6
|
+
def on_with_exp(sexpr)
|
|
7
|
+
q = builder.next_qualifier!
|
|
8
|
+
name_intro = builder.name_intro(q, sexpr.select_exp)
|
|
9
|
+
[ :with_exp,
|
|
10
|
+
sexpr.with_spec.dup.push(name_intro),
|
|
11
|
+
builder.select_all(sexpr.select_exp, q, q) ]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def on_nonjoin_exp(sexpr)
|
|
15
|
+
q = builder.next_qualifier!
|
|
16
|
+
[ :with_exp,
|
|
17
|
+
[:with_spec,
|
|
18
|
+
builder.name_intro(q, sexpr)],
|
|
19
|
+
builder.select_all(sexpr, q, q) ]
|
|
20
|
+
end
|
|
21
|
+
alias :on_union :on_nonjoin_exp
|
|
22
|
+
alias :on_except :on_nonjoin_exp
|
|
23
|
+
alias :on_intersect :on_nonjoin_exp
|
|
24
|
+
alias :on_select_exp :on_nonjoin_exp
|
|
25
|
+
|
|
26
|
+
end # class FromSelf
|
|
27
|
+
end # class Processor
|
|
28
|
+
end # module Sql
|
|
29
|
+
end # module Alf
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
class Processor
|
|
4
|
+
class Join < Processor
|
|
5
|
+
include JoinSupport
|
|
6
|
+
|
|
7
|
+
def initialize(right, builder)
|
|
8
|
+
super(builder)
|
|
9
|
+
@right = right
|
|
10
|
+
end
|
|
11
|
+
attr_reader :right
|
|
12
|
+
|
|
13
|
+
def call(sexpr)
|
|
14
|
+
if unjoinable?(sexpr)
|
|
15
|
+
call(builder.from_self(sexpr))
|
|
16
|
+
elsif unjoinable?(right)
|
|
17
|
+
Join.new(builder.from_self(right), builder).call(sexpr)
|
|
18
|
+
else
|
|
19
|
+
super(sexpr)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def apply_join_strategy(left, right)
|
|
26
|
+
[ :select_exp,
|
|
27
|
+
join_set_quantifiers(left, right),
|
|
28
|
+
join_select_lists(left, right),
|
|
29
|
+
join_from_clauses(left, right),
|
|
30
|
+
join_where_clauses(left, right),
|
|
31
|
+
join_order_by_clauses(left, right) ].compact
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def unjoinable?(sexpr)
|
|
35
|
+
sexpr.set_operator? or sexpr.limit_or_offset? or sexpr.join?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def join_set_quantifiers(left, right)
|
|
39
|
+
left_q, right_q = left.set_quantifier, right.set_quantifier
|
|
40
|
+
left_q == right_q ? left_q : builder.distinct
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def join_select_lists(left, right)
|
|
44
|
+
left_list, right_list = left.select_list, right.select_list
|
|
45
|
+
list = left_list.dup
|
|
46
|
+
right_list.each_child do |child, index|
|
|
47
|
+
list << child unless left_list.knows?(child.as_name)
|
|
48
|
+
end
|
|
49
|
+
list
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def join_from_clauses(left, right)
|
|
53
|
+
joincon = join_predicate(left, right)
|
|
54
|
+
join = if joincon.tautology?
|
|
55
|
+
[:cross_join, left.table_spec, right.table_spec]
|
|
56
|
+
else
|
|
57
|
+
[:inner_join, left.table_spec, right.table_spec, joincon]
|
|
58
|
+
end
|
|
59
|
+
left.from_clause.with_update(-1, join)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def join_where_clauses(left, right)
|
|
63
|
+
predicate = [ tautology, left.predicate, right.predicate ].compact
|
|
64
|
+
case predicate.size
|
|
65
|
+
when 1 then nil
|
|
66
|
+
when 2 then [ :where_clause, predicate.last ]
|
|
67
|
+
else [ :where_clause, predicate.reduce(:&) ]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def join_order_by_clauses(left, right)
|
|
72
|
+
order_by = [ left.order_by_clause, right.order_by_clause ].compact
|
|
73
|
+
return order_by.first if order_by.size <= 1
|
|
74
|
+
order_by.first + order_by.last.sexpr_body
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end # class Join
|
|
78
|
+
end # class Processor
|
|
79
|
+
end # module Sql
|
|
80
|
+
end # module Alf
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
class Processor
|
|
4
|
+
module JoinSupport
|
|
5
|
+
|
|
6
|
+
def on_main_exp(sexpr)
|
|
7
|
+
joined = apply_join_strategy(sexpr.select_exp, right.select_exp)
|
|
8
|
+
merge_with_exps(sexpr, right, joined)
|
|
9
|
+
end
|
|
10
|
+
alias :on_with_exp :on_main_exp
|
|
11
|
+
alias :on_select_exp :on_main_exp
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def join_predicate(left, right, commons = left.to_attr_list & right.to_attr_list)
|
|
16
|
+
commons = left.to_attr_list & right.to_attr_list
|
|
17
|
+
left_d, right_d = left.desaliaser, right.desaliaser
|
|
18
|
+
commons.to_a.inject(tautology){|cond, attr|
|
|
19
|
+
left_attr, right_attr = left_d[attr], right_d[attr]
|
|
20
|
+
cond &= Predicate::Factory.eq(left_attr, right_attr)
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end # class JoinSupport
|
|
25
|
+
end # class Processor
|
|
26
|
+
end # module Sql
|
|
27
|
+
end # module Alf
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Alf
|
|
2
|
+
module Sql
|
|
3
|
+
class Processor
|
|
4
|
+
class LimitOffset < Processor
|
|
5
|
+
|
|
6
|
+
def initialize(limit, offset, builder)
|
|
7
|
+
super(builder)
|
|
8
|
+
@limit = limit
|
|
9
|
+
@offset = offset
|
|
10
|
+
end
|
|
11
|
+
attr_reader :limit, :offset
|
|
12
|
+
|
|
13
|
+
def on_set_operator(sexpr)
|
|
14
|
+
apply(builder.from_self(sexpr))
|
|
15
|
+
end
|
|
16
|
+
alias :on_union :on_set_operator
|
|
17
|
+
alias :on_except :on_set_operator
|
|
18
|
+
alias :on_intersect :on_set_operator
|
|
19
|
+
|
|
20
|
+
def on_select_exp(sexpr)
|
|
21
|
+
sexpr = builder.from_self(sexpr) if obc = sexpr.limit_or_offset?
|
|
22
|
+
limit_clause = builder.limit_clause(limit)
|
|
23
|
+
offset_clause = builder.offset_clause(offset)
|
|
24
|
+
sexpr.with_push(limit_clause, offset_clause)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end # class LimitOffset
|
|
28
|
+
end # class Processor
|
|
29
|
+
end # module Sql
|
|
30
|
+
end # module Alf
|