bmg 0.16.7 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ca0b8ab7a34fca3dbf7cb37774b099289a8e15cf42fd381b9ee88f3ac01ff81
4
- data.tar.gz: e96b6905b920b0cf70e52227ffe19dcd40ce3a9263deadf032a628348f4c340c
3
+ metadata.gz: 0d94c440e4e3c70b16735c6d31e3ba50a4be12430d347d9ac8cff6622bc64fb3
4
+ data.tar.gz: 1443c66b0c1c621f97b2f2f8bea2c522c07151ec4bbef71b45585078635c5b7b
5
5
  SHA512:
6
- metadata.gz: 6727a3c5b475e5a69765b0f2d4093df4f2aa2ee67364589ee8c0a8e3d368acf50cbe092e7651791e3b13f70ee4d51718921166cac62595998f0b0de2775b1b54
7
- data.tar.gz: ef2c1b8eb520f5a4a3a7a24a95f7afcbb96be47e77872dbd55100a0369bd65d7c4d173234d4966591a803106b4937505c5d36ab8ee59d8fde2d6c261988e3ab8
6
+ metadata.gz: 7eba5332a684097f8cd95a1c28463bbb1e5b004788bf3b3133a55a0c1cf1b5b5335a41924b9ba98cae10fe81f2c4b0ad70bb27d4f97618a8d18a7dbc0f48265f
7
+ data.tar.gz: 0241a9d8b895ca70df1a7f705ceecce062369810a8b4f60e1f314db0ab2888dc0060ad2f37697b7c83ab11cd2eaefd13e8445d1486d9827f294766bd9f3471aa
data/Gemfile CHANGED
@@ -1,2 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
  gemspec
3
+
4
+ gem "predicate", github: "enspirit/predicate", branch: "placeholders"
5
+ # gem "predicate", path: "../predicate"
@@ -12,7 +12,21 @@ module Bmg
12
12
 
13
13
  # Whether we need to convert each image as an Array,
14
14
  # instead of keeping a Relation instance
15
- array: false
15
+ array: false,
16
+
17
+ # The strategy to use for actual image algorithm. Default is
18
+ # :refilter_right. Possible values are:
19
+ #
20
+ # - :index_right : builds a memory index with tuples from right, then
21
+ # passes left tuples and joins them with the index values.
22
+ #
23
+ # - :refilter_right : the left operand is materialized and all
24
+ # distinct values collected. The right operand is lately restricted
25
+ # to only those matching values. :index_right is then applied on
26
+ # resulting operabds. This option only applies when (optimized) `on`
27
+ # contains one attribute only. ; it fallbacks on :index_right
28
+ # otherwise.
29
+ strategy: :refilter_right
16
30
 
17
31
  }
18
32
 
@@ -31,7 +45,55 @@ module Bmg
31
45
 
32
46
  public
33
47
 
34
- def each
48
+ def each(*args, &bl)
49
+ (options[:jit_optimized] ? self : jit_optimize)._each(*args, &bl)
50
+ end
51
+
52
+ def to_ast
53
+ [ :image, left.to_ast, right.to_ast, as, on, options.dup ]
54
+ end
55
+
56
+ protected
57
+
58
+ def _each(*args, &bl)
59
+ case s = options[:strategy]
60
+ when :index_right then _each_index_right(*args, &bl)
61
+ when :refilter_right then _each_refilter_right(*args, &bl)
62
+ else
63
+ raise ArgumentError, "Unknown strategy `#{s}`"
64
+ end
65
+ end
66
+
67
+ def _each_index_right(*args, &bl)
68
+ left_rel, right_rel = self.left, self.right
69
+ _each_implem(left_rel, right_rel, *args, &bl)
70
+ end
71
+
72
+ def _each_refilter_right(*args, &bl)
73
+ left_rel, right_rel = self.left, self.right
74
+
75
+ # find matching keys on left and rebind the right
76
+ # placeholder to them
77
+ values = left_rel.map{|t| t[on.first] }
78
+ placeholder = options[:refilter_right][:placeholder]
79
+ right_rel = right_rel.bind(placeholder => values)
80
+
81
+ _each_implem(left_rel, right_rel, *args, &bl)
82
+ end
83
+
84
+ def _each_implem(left_rel, right_rel, *args)
85
+ # build right index
86
+ index = build_right_index(right_rel)
87
+
88
+ # each left with image from right index
89
+ left_rel.each do |tuple|
90
+ key = tuple_project(tuple, on)
91
+ image = index[key] || (options[:array] ? [] : empty_image)
92
+ yield tuple.merge(as => image)
93
+ end
94
+ end
95
+
96
+ def build_right_index(right)
35
97
  index = Hash.new{|h,k| h[k] = empty_image }
36
98
  right.each_with_object(index) do |t, index|
37
99
  key = tuple_project(t, on)
@@ -42,15 +104,54 @@ module Bmg
42
104
  ix[k] = v.to_a
43
105
  end
44
106
  end
45
- left.each do |tuple|
46
- key = tuple_project(tuple, on)
47
- image = index[key] || (options[:array] ? [] : empty_image)
48
- yield tuple.merge(as => image)
107
+ index
108
+ end
109
+
110
+ protected ### jit_optimization
111
+
112
+ def jit_optimize
113
+ case s = options[:strategy]
114
+ when :index_right then jit_index_right
115
+ when :refilter_right then jit_refilter_right
116
+ else
117
+ raise ArgumentError, "Unknown strategy `#{s}`"
49
118
  end
50
119
  end
51
120
 
52
- def to_ast
53
- [ :image, left.to_ast, right.to_ast, as, on, options.dup ]
121
+ def jit_index_right
122
+ Image.new(
123
+ type,
124
+ left,
125
+ right,
126
+ as,
127
+ on,
128
+ options.merge(jit_optimized: true))
129
+ end
130
+
131
+ def jit_refilter_right
132
+ ltc = left.type.predicate.constants
133
+ rtc = right.type.predicate.constants
134
+ jit_allbut, jit_on = on.partition{|attr|
135
+ ltc.has_key?(attr) && rtc.has_key?(attr) && ltc[attr] == rtc[attr]
136
+ }
137
+ if jit_on.size == 1
138
+ p = Predicate.placeholder
139
+ Image.new(
140
+ type,
141
+ left.materialize,
142
+ right.restrict(Predicate.in(jit_on.first, p)).allbut(jit_allbut),
143
+ as,
144
+ jit_on,
145
+ options.merge(jit_optimized: true, refilter_right: { placeholder: p }))
146
+ else
147
+ Image.new(
148
+ type,
149
+ left,
150
+ right.allbut(jit_allbut),
151
+ as,
152
+ jit_on,
153
+ options.merge(jit_optimized: true, strategy: :index_right))
154
+ end
54
155
  end
55
156
 
56
157
  protected ### optimization
@@ -68,7 +169,7 @@ module Bmg
68
169
  def _restrict(type, predicate)
69
170
  on_as, rest = predicate.and_split([as])
70
171
  if rest.tautology?
71
- # push none situation: on_as is still the full predicate
172
+ # push index_right situation: on_as is still the full predicate
72
173
  super
73
174
  else
74
175
  # rest makes no reference to `as` and can be pushed
@@ -126,6 +227,16 @@ module Bmg
126
227
  Relation::InMemory.new(image_type, Set.new)
127
228
  end
128
229
 
230
+ public
231
+
232
+ def to_s
233
+ options[:jit_optimized] ? super : jit_optimize.to_s
234
+ end
235
+
236
+ def inspect
237
+ options[:jit_optimized] ? super : jit_optimize.inspect
238
+ end
239
+
129
240
  end # class Project
130
241
  end # module Operator
131
242
  end # module Bmg
@@ -21,6 +21,10 @@ module Bmg
21
21
 
22
22
  public
23
23
 
24
+ def bind(binding)
25
+ Restrict.new(type, operand.bind(binding), predicate.bind(binding))
26
+ end
27
+
24
28
  def each
25
29
  @operand.each do |tuple|
26
30
  yield(tuple) if @predicate.evaluate(tuple)
@@ -3,9 +3,13 @@ module Bmg
3
3
  module Binary
4
4
  include Operator
5
5
 
6
+ def bind(binding)
7
+ _with_operands(left.bind(binding), right.bind(binding))
8
+ end
9
+
6
10
  protected
7
11
 
8
- attr_reader :left, :right
12
+ attr_accessor :left, :right
9
13
 
10
14
  def _visit(parent, visitor)
11
15
  visitor.call(self, parent)
@@ -13,6 +17,13 @@ module Bmg
13
17
  right.send(:_visit, self, visitor)
14
18
  end
15
19
 
20
+ def _with_operands(left, right)
21
+ dup.tap{|d|
22
+ d.left = left
23
+ d.right = right
24
+ }
25
+ end
26
+
16
27
  def operands
17
28
  [left, right]
18
29
  end
@@ -3,9 +3,17 @@ module Bmg
3
3
  module Nary
4
4
  include Operator
5
5
 
6
+ def bind(binding)
7
+ _with_operands(operands.map{|op| op.bind(binding) })
8
+ end
9
+
6
10
  protected
7
11
 
8
- attr_reader :operands
12
+ attr_accessor :operands
13
+
14
+ def _with_operands(operands)
15
+ dup.tap{|d| d.operands = operands }
16
+ end
9
17
 
10
18
  def _visit(parent, visitor)
11
19
  visitor.call(self, parent)
@@ -3,15 +3,23 @@ module Bmg
3
3
  module Unary
4
4
  include Operator
5
5
 
6
+ def bind(binding)
7
+ _with_operand(operand.bind(binding))
8
+ end
9
+
6
10
  protected
7
11
 
8
- attr_reader :operand
12
+ attr_accessor :operand
9
13
 
10
14
  def _visit(parent, visitor)
11
15
  visitor.call(self, parent)
12
16
  operand._visit(self, visitor)
13
17
  end
14
18
 
19
+ def _with_operand(operand)
20
+ dup.tap{|d| d.operand = operand }
21
+ end
22
+
15
23
  def operands
16
24
  [operand]
17
25
  end
@@ -13,6 +13,10 @@ module Bmg
13
13
  Relation::Empty.new(type)
14
14
  end
15
15
 
16
+ def bind(binding)
17
+ self
18
+ end
19
+
16
20
  def with_typecheck
17
21
  dup.tap{|r|
18
22
  r.type = r.type.with_typecheck
@@ -50,7 +50,7 @@ module Bmg
50
50
  dataset = dataset.select(*selection)
51
51
  dataset = dataset.distinct if sexpr.distinct?
52
52
  dataset = dataset.where(predicate) if predicate
53
- dataset = dataset.group(*grouping) if grouping
53
+ dataset = dataset.group(grouping) if grouping
54
54
  dataset = dataset.order_by(*order) if order
55
55
  dataset = dataset.limit(limit, offset == 0 ? nil : offset) if limit or offset
56
56
  dataset
@@ -85,3 +85,4 @@ require_relative 'processor/semi_join'
85
85
  require_relative 'processor/flatten'
86
86
  require_relative 'processor/requalify'
87
87
  require_relative 'processor/summarize'
88
+ require_relative 'processor/bind'
@@ -0,0 +1,23 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Bind < Processor
5
+
6
+ def initialize(binding, builder)
7
+ super(builder)
8
+ @binding = binding
9
+ end
10
+
11
+ def on_select_exp(sexpr)
12
+ if w = sexpr.where_clause
13
+ pred = Predicate::Grammar.sexpr(w.predicate.bind(@binding))
14
+ sexpr.with_update(:where_clause, [ :where_clause, pred ])
15
+ else
16
+ sexpr
17
+ end
18
+ end
19
+
20
+ end # class Bind
21
+ end # class Processor
22
+ end # module Sql
23
+ end # module Bmg
@@ -9,7 +9,7 @@ module Bmg
9
9
  h[k.to_s] = builder.next_qualifier!
10
10
  }
11
11
  end
12
- attr_reader :requalify
12
+ attr_reader :requalify
13
13
 
14
14
  alias :on_select_exp :copy_and_apply
15
15
  alias :on_missing :copy_and_apply
@@ -18,6 +18,12 @@ module Bmg
18
18
 
19
19
  public
20
20
 
21
+ def bind(binding)
22
+ expr = before_use(self.expr)
23
+ expr = Processor::Bind.new(binding, builder).call(expr)
24
+ _instance(type, builder, expr)
25
+ end
26
+
21
27
  def each(&bl)
22
28
  raise NotImplementedError
23
29
  end
@@ -1,8 +1,8 @@
1
1
  module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 16
5
- TINY = 7
4
+ MINOR = 17
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bmg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.7
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-15 00:00:00.000000000 Z
11
+ date: 2020-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: predicate
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.2'
19
+ version: '2.3'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 2.2.1
22
+ version: 2.3.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: '2.2'
29
+ version: '2.3'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 2.2.1
32
+ version: 2.3.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: rake
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -222,6 +222,7 @@ files:
222
222
  - lib/bmg/sql/nodes/with_spec.rb
223
223
  - lib/bmg/sql/processor.rb
224
224
  - lib/bmg/sql/processor/all.rb
225
+ - lib/bmg/sql/processor/bind.rb
225
226
  - lib/bmg/sql/processor/clip.rb
226
227
  - lib/bmg/sql/processor/constants.rb
227
228
  - lib/bmg/sql/processor/distinct.rb