locomotive 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/lib/locomotive.rb +6 -0
  2. data/lib/locomotive/core_extensions.rb +6 -0
  3. data/lib/locomotive/core_extensions/array.rb +22 -0
  4. data/lib/locomotive/core_extensions/class.rb +47 -0
  5. data/lib/locomotive/core_extensions/hash.rb +7 -0
  6. data/lib/locomotive/core_extensions/inflector.rb +29 -0
  7. data/lib/locomotive/core_extensions/module.rb +77 -0
  8. data/lib/locomotive/core_extensions/symbol.rb +17 -0
  9. data/lib/locomotive/misc.rb +1 -0
  10. data/lib/locomotive/misc/type_check.rb +129 -0
  11. data/lib/locomotive/relational_algebra.rb +8 -0
  12. data/lib/locomotive/relational_algebra/attributes.rb +171 -0
  13. data/lib/locomotive/relational_algebra/operators.rb +15 -0
  14. data/lib/locomotive/relational_algebra/operators/abstraction.rb +2 -0
  15. data/lib/locomotive/relational_algebra/operators/abstraction/lambda.rb +83 -0
  16. data/lib/locomotive/relational_algebra/operators/abstraction/variable.rb +65 -0
  17. data/lib/locomotive/relational_algebra/operators/aggregation.rb +2 -0
  18. data/lib/locomotive/relational_algebra/operators/aggregation/aggr_builtin.rb +26 -0
  19. data/lib/locomotive/relational_algebra/operators/aggregation/aggregation.rb +76 -0
  20. data/lib/locomotive/relational_algebra/operators/basic_operators.rb +144 -0
  21. data/lib/locomotive/relational_algebra/operators/boolean.rb +4 -0
  22. data/lib/locomotive/relational_algebra/operators/boolean/and.rb +9 -0
  23. data/lib/locomotive/relational_algebra/operators/boolean/basic_boolean.rb +66 -0
  24. data/lib/locomotive/relational_algebra/operators/boolean/not.rb +56 -0
  25. data/lib/locomotive/relational_algebra/operators/boolean/or.rb +9 -0
  26. data/lib/locomotive/relational_algebra/operators/builtins.rb +3 -0
  27. data/lib/locomotive/relational_algebra/operators/builtins/arith_builtin.rb +37 -0
  28. data/lib/locomotive/relational_algebra/operators/builtins/basic_builtin.rb +20 -0
  29. data/lib/locomotive/relational_algebra/operators/builtins/function.rb +69 -0
  30. data/lib/locomotive/relational_algebra/operators/comparisons.rb +6 -0
  31. data/lib/locomotive/relational_algebra/operators/comparisons/basic_comparison.rb +65 -0
  32. data/lib/locomotive/relational_algebra/operators/comparisons/equal.rb +13 -0
  33. data/lib/locomotive/relational_algebra/operators/comparisons/greater.rb +13 -0
  34. data/lib/locomotive/relational_algebra/operators/comparisons/greater_equal.rb +14 -0
  35. data/lib/locomotive/relational_algebra/operators/comparisons/less.rb +21 -0
  36. data/lib/locomotive/relational_algebra/operators/comparisons/less_equal.rb +13 -0
  37. data/lib/locomotive/relational_algebra/operators/error.rb +1 -0
  38. data/lib/locomotive/relational_algebra/operators/error/error.rb +52 -0
  39. data/lib/locomotive/relational_algebra/operators/filter.rb +1 -0
  40. data/lib/locomotive/relational_algebra/operators/filter/select.rb +50 -0
  41. data/lib/locomotive/relational_algebra/operators/join.rb +5 -0
  42. data/lib/locomotive/relational_algebra/operators/join/basic_join.rb +9 -0
  43. data/lib/locomotive/relational_algebra/operators/join/cross.rb +28 -0
  44. data/lib/locomotive/relational_algebra/operators/join/equi_join.rb +61 -0
  45. data/lib/locomotive/relational_algebra/operators/join/predicates.rb +95 -0
  46. data/lib/locomotive/relational_algebra/operators/join/theta_join.rb +53 -0
  47. data/lib/locomotive/relational_algebra/operators/projections.rb +2 -0
  48. data/lib/locomotive/relational_algebra/operators/projections/attach.rb +67 -0
  49. data/lib/locomotive/relational_algebra/operators/projections/projection.rb +106 -0
  50. data/lib/locomotive/relational_algebra/operators/ranking.rb +6 -0
  51. data/lib/locomotive/relational_algebra/operators/ranking/basic_ranking.rb +67 -0
  52. data/lib/locomotive/relational_algebra/operators/ranking/rank.rb +9 -0
  53. data/lib/locomotive/relational_algebra/operators/ranking/rank_lists.rb +45 -0
  54. data/lib/locomotive/relational_algebra/operators/ranking/row_id.rb +24 -0
  55. data/lib/locomotive/relational_algebra/operators/ranking/row_number.rb +55 -0
  56. data/lib/locomotive/relational_algebra/operators/ranking/row_rank.rb +9 -0
  57. data/lib/locomotive/relational_algebra/operators/serialization.rb +2 -0
  58. data/lib/locomotive/relational_algebra/operators/serialization/basic_serialize.rb +9 -0
  59. data/lib/locomotive/relational_algebra/operators/serialization/serialize_relation.rb +105 -0
  60. data/lib/locomotive/relational_algebra/operators/set.rb +4 -0
  61. data/lib/locomotive/relational_algebra/operators/set/basic_set.rb +24 -0
  62. data/lib/locomotive/relational_algebra/operators/set/difference.rb +11 -0
  63. data/lib/locomotive/relational_algebra/operators/set/distinct.rb +35 -0
  64. data/lib/locomotive/relational_algebra/operators/set/union.rb +11 -0
  65. data/lib/locomotive/relational_algebra/operators/tables.rb +3 -0
  66. data/lib/locomotive/relational_algebra/operators/tables/literal_table.rb +95 -0
  67. data/lib/locomotive/relational_algebra/operators/tables/nil.rb +13 -0
  68. data/lib/locomotive/relational_algebra/operators/tables/ref_table.rb +75 -0
  69. data/lib/locomotive/relational_algebra/operators/typeing.rb +1 -0
  70. data/lib/locomotive/relational_algebra/operators/typeing/cast.rb +59 -0
  71. data/lib/locomotive/relational_algebra/ordering.rb +30 -0
  72. data/lib/locomotive/relational_algebra/query_information.rb +666 -0
  73. data/lib/locomotive/relational_algebra/rel_alg_ast_node.rb +51 -0
  74. data/lib/locomotive/relational_algebra/rel_alg_exceptions.rb +15 -0
  75. data/lib/locomotive/relational_algebra/schema.rb +87 -0
  76. data/lib/locomotive/relational_algebra/types.rb +86 -0
  77. data/lib/locomotive/tree_helpers.rb +3 -0
  78. data/lib/locomotive/tree_helpers/annotations.rb +58 -0
  79. data/lib/locomotive/tree_helpers/ast.rb +99 -0
  80. data/lib/locomotive/tree_helpers/ast_traversal.rb +43 -0
  81. data/lib/locomotive/utils.rb +2 -0
  82. data/lib/locomotive/utils/relalg2xml.rb +239 -0
  83. data/lib/locomotive/utils/xml.rb +47 -0
  84. metadata +157 -0
@@ -0,0 +1,13 @@
1
+ module Locomotive
2
+
3
+ module RelationalAlgebra
4
+
5
+ class Nil < Leaf
6
+ def clone
7
+ Nil.new
8
+ end
9
+ end
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,75 @@
1
+ module Locomotive
2
+
3
+ module RelationalAlgebra
4
+
5
+ class RefTbl < Leaf
6
+ def_node :table, :properties, :_keys_, :key
7
+ attr_reader :name,
8
+ :attributes,
9
+ :keys
10
+
11
+ private
12
+
13
+ def get_schema
14
+ mapping =
15
+ { :integer => RInt.instance,
16
+ :float => RDec.instance,
17
+ :string => RStr.instance }
18
+ id = 0
19
+ Schema.new(
20
+ Hash[*@attributes.collect do |attr, ty|
21
+ [Item.new(id += 1), [ty]]
22
+ end.flatten_once])
23
+ end
24
+
25
+ def get_name_mapping
26
+ id = 0
27
+ @attributes.collect do |attr, ty|
28
+ [ Item.new(id += 1), attr.clone ]
29
+ end.to_hash
30
+ end
31
+
32
+ public
33
+
34
+ attr_accessor :name
35
+ def_sig :name=, String
36
+ attr_reader :name_mapping
37
+
38
+ def initialize(name, attributes, keys)
39
+ @name = name
40
+ @attributes = attributes
41
+ @keys = keys
42
+ @name_mapping = get_name_mapping
43
+ self.schema = get_schema
44
+ end
45
+
46
+ def xml_kind
47
+ :ref_tbl
48
+ end
49
+
50
+ def xml_content
51
+ [properties do
52
+ _keys_ do
53
+ pos = -1
54
+ keys.map do |k|
55
+ key :name => k.to_xml, :position => pos += 1
56
+ end.join
57
+ end
58
+ end,
59
+ content do
60
+ table :name => name do
61
+ name_mapping.collect do |new,old|
62
+ column :name => new.to_xml, :tname => old.to_xml, :type => schema[new].first.to_xml
63
+ end.join
64
+ end
65
+ end].join
66
+ end
67
+
68
+ def clone
69
+ RefTbl.new(name.clone, attributes.clone, keys.clone)
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1 @@
1
+ require 'locomotive/relational_algebra/operators/typeing/cast'
@@ -0,0 +1,59 @@
1
+ module Locomotive
2
+
3
+ module RelationalAlgebra
4
+
5
+ class Cast < Unary
6
+ def_node :_type_
7
+
8
+ attr_accessor :res,
9
+ :type,
10
+ :item
11
+ def_sig :res=, ConstAttribute
12
+ def_sig :type=, RType
13
+ def_sig :item=, ConstAttribute
14
+
15
+ def initialize(op, res, item, type)
16
+ self.res,
17
+ self.type,
18
+ self.item = res, type, item
19
+ super(op)
20
+ end
21
+
22
+ def child=(op)
23
+ unless op.schema.attributes?([item])
24
+ raise CorruptedSchema,
25
+ "Schema #{op.schema.attributes} does not " \
26
+ "contain all attributes of #{item}."
27
+ end
28
+ self.schema = op.schema + Schema.new({ self.res => [self.type] })
29
+ super(op)
30
+ end
31
+
32
+ def xml_content
33
+ content do
34
+ [column(:name => res.to_xml, :new => true),
35
+ column(:name => item.to_xml, :new => false),
36
+ _type_(:name => type.to_xml)].join
37
+ end
38
+ end
39
+
40
+ def clone
41
+ Cast.new(
42
+ child.clone,
43
+ res.clone,
44
+ item.clone,
45
+ type.clone)
46
+ end
47
+
48
+ def set(var,plan)
49
+ Cast.new(
50
+ child.set(var,plan),
51
+ res.clone,
52
+ item.clone,
53
+ type.clone)
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,30 @@
1
+ module Locomotive
2
+
3
+ module RelationalAlgebra
4
+
5
+ # Sortdirection specifies which
6
+ # order a column should follow
7
+ class SortDirection
8
+ include Singleton
9
+
10
+ class << self
11
+ alias :dir :instance
12
+ end
13
+
14
+ def to_xml
15
+ self.class.to_s.split('::').last.downcase.to_sym
16
+ end
17
+
18
+ def clone
19
+ # singleton
20
+ self
21
+ end
22
+ end
23
+
24
+ # Sortdirection ascending
25
+ class Ascending < SortDirection; end
26
+ # Sortdirection descending
27
+ class Descending < SortDirection; end
28
+ end
29
+
30
+ end
@@ -0,0 +1,666 @@
1
+ module Locomotive
2
+
3
+ module RelationalAlgebra
4
+
5
+ # Forward declaration
6
+ class QueryInformationNode; end
7
+
8
+ class SurrogateList
9
+ public
10
+ delegate :[],
11
+ :to_a,
12
+ :each,
13
+ :keys,
14
+ :empty?,
15
+ :first,
16
+ :size,
17
+ :to => :surrogates
18
+
19
+ attr_accessor :surrogates
20
+ def_sig :surrogates=, { ConstAttribute => QueryInformationNode }
21
+
22
+ def initialize(hash)
23
+ self.surrogates = hash
24
+ end
25
+
26
+ def map(&block)
27
+ SurrogateList.new(
28
+ surrogates.map(&block).to_hash)
29
+ end
30
+
31
+ def +(sur)
32
+ SurrogateList.new(surrogates.merge(sur.surrogates))
33
+ end
34
+
35
+ def delete_if(&lambda)
36
+ SurrogateList.new(self.clone.surrogates.delete_if(&lambda))
37
+ end
38
+
39
+ def itapp(q_0, *itbls)
40
+ if itbls.any? { |i| self.keys != i.keys }
41
+ raise ITblsNotEqual,
42
+ "some itbls keys are not equal"
43
+ end
44
+
45
+ if self.empty? and
46
+ itbls.all? { |i| i.empty? }
47
+ return SurrogateList.new( {} )
48
+ end
49
+
50
+ c = self.first.first
51
+
52
+ q1_in = self[c]
53
+ qs_in = itbls.map { |itbl| itbl[c] }
54
+
55
+ q1 = q1_in.plan
56
+ qs = qs_in.map { |q| q.plan }
57
+ cols_q1, itbls_q1 = q1_in.column_structure, q1_in.surrogates
58
+ ord, ord_, item_, item__ = Iter.new(2), Iter.new(4),
59
+ Iter.new(3), Item.new(3)
60
+
61
+ # (1)
62
+ q1_ = q1.attach(AttachItem.new(ord, RAtomic.new(1, RNat.type)))
63
+ q = qs.zip(2..qs.size+1).reduce(q1_) do |p1,p2|
64
+ p1.union(
65
+ p2.first.attach(AttachItem.new(ord, RAtomic.new(p2.last, RNat.type))))
66
+ end.row_num(item_, [], [Iter.new(1), ord, Pos.new(1)])
67
+
68
+ #(2)
69
+ c_new = Iter.new(5)
70
+ q_ = q_0.project( ord => [ord_],
71
+ item_ => [item__],
72
+ c => [c_new] ).
73
+ theta_join(q, [Equivalence.new(ord_, ord),
74
+ Equivalence.new(c_new, Iter.new(1))] ).
75
+ project( { item__ => [Iter.new(1)],
76
+ Pos.new(1) => [Pos.new(1)],
77
+ item_ => itbls_q1.keys }.
78
+ merge(
79
+ (cols_q1 - itbls_q1.keys).items.collect do |col|
80
+ [col, [col]]
81
+ end.to_hash) )
82
+
83
+ # (3)
84
+ itbl_ = q1_in.surrogates.itapp(q, *qs_in.map { |q| q.surrogates })
85
+ # (4)
86
+ itbl__ = self.delete_if { |k,v| k == c}.
87
+ itapp(q_0, *itbls.map { |i| i.delete_if { |k,v| k == c} })
88
+ # (5)
89
+ SurrogateList.new( { c => QueryInformationNode.new(
90
+ q_, cols_q1, itbl_) } ) + itbl__
91
+ end
92
+
93
+ def itsel(q_0)
94
+ return SurrogateList.new({}) if self.empty?
95
+
96
+ c = self.first.first
97
+ cols, itbls, q = self[c].column_structure, self[c].surrogates, self[c].plan
98
+ c_ = (self.keys + cols.items).max.inc
99
+
100
+ # (1)
101
+ q_ = q.equi_join(q_0.project( c => [c_]), Iter.new(1), c_).
102
+ project( [Iter.new(1), Pos.new(1)] + cols.items )
103
+
104
+ itbls_ = itbls.itsel(q_)
105
+ itbls__ = self.delete_if { |k,v| k == c }.itsel(q_0)
106
+
107
+ SurrogateList.new(
108
+ { c => QueryInformationNode.new(q_, cols, itbls_) }.
109
+ merge( itbls__.to_a.to_hash ) )
110
+ end
111
+
112
+ def join
113
+ itbls = surrogates.to_a
114
+
115
+ itbls.rest.reduce(itbls.first.last) do |qi,surr|
116
+ # the query_information node
117
+ qin_j = surr.last
118
+
119
+ cols_j = surr.last.column_structure
120
+ itbls_j = surr.last.surrogates
121
+ cols_c = qi.column_structure
122
+ itbls_c = qi.surrogates
123
+
124
+ # adapt cols
125
+ cols_j_ = cols_j.clone
126
+ cols_j_.items.each { |i| i.inc!(qi.column_structure.count) }
127
+ # adapt itbls
128
+ itbls_j_ = itbls_j.map { |k,q| [k.inc(qi.column_structure.count), q] }
129
+
130
+ # calculate new plan
131
+ q_j = qin_j.plan.project({ Iter.new(1) => [Iter.new(2)],
132
+ Pos.new(1) => [Pos.new(2)] }.
133
+ merge(
134
+ cols_j.items.zip(cols_j_.items).
135
+ map do |old,new|
136
+ [old,[new]]
137
+ end.to_hash))
138
+
139
+ q_ = q_j.theta_join(qi.plan, [Equivalence.new(Iter.new(2), Iter.new(1)),
140
+ Equivalence.new(Pos.new(2), Pos.new(1))]).
141
+ project([Iter.new(1), Pos.new(1)] + cols_c.items + cols_j_.items)
142
+
143
+
144
+ QueryInformationNode.new(q_, cols_c + cols_j_, itbls_c + itbls_j_)
145
+ end
146
+ end
147
+
148
+ def set(var, plan)
149
+ self.map do |item, itbl|
150
+ [item,QueryInformationNode.new(itbl.plan.set(var, plan),
151
+ itbl.column_structure,
152
+ itbl.surrogates.set(var,plan))]
153
+ end
154
+ end
155
+
156
+ def clone
157
+ # only clone the attributes since we don't modify
158
+ # the plan
159
+ SurrogateList.new( surrogates.map { |k,v| [k.clone,v] }.to_hash )
160
+ end
161
+
162
+ def filter_and_adapt(items)
163
+ item_min = items.min
164
+ # we are modifying the structure itself
165
+ # so we have to clone it (sideeffect)
166
+ surr_new = self.delete_if do |it, itbl|
167
+ !items.member?(it)
168
+ end
169
+ # adapt the keys
170
+ surr_new.map { |k,p| [Item.new(k.id - (item_min.id - 1)), p] }
171
+ end
172
+ end
173
+
174
+ class ColumnStructureEntry
175
+ end
176
+
177
+ class OffsetType < ColumnStructureEntry
178
+ private
179
+ include Locomotive::XML
180
+ def_node :offset_
181
+
182
+ public
183
+ attr_reader :offset,
184
+ :type
185
+
186
+ def initialize(offset, type)
187
+ @offset = offset
188
+ @type = type
189
+ end
190
+
191
+ def items
192
+ [offset]
193
+ end
194
+
195
+ def offsets
196
+ [self]
197
+ end
198
+
199
+ def clone
200
+ OffsetType.new(offset.clone,
201
+ type.clone)
202
+ end
203
+
204
+ def to_xml
205
+ offset_ :item => offset.to_xml, :type => type.to_xml
206
+ end
207
+ end
208
+
209
+ class AttributeColumnStructure < ColumnStructureEntry
210
+ private
211
+ include Locomotive::XML
212
+ def_node :attribute_
213
+
214
+ public
215
+ attr_reader :attribute,
216
+ :column_structure
217
+
218
+ def initialize(attribute, cs)
219
+ @attribute = attribute
220
+ @column_structure = cs
221
+ end
222
+
223
+ def items
224
+ column_structure.items.flatten
225
+ end
226
+
227
+ def offsets
228
+ column_structure.offsets.flatten
229
+ end
230
+
231
+ def clone
232
+ AttributeColumnStructure.new(attribute.clone,
233
+ column_structure.clone)
234
+ end
235
+
236
+ def to_xml
237
+ attribute_ :name => attribute.to_xml do
238
+ column_structure.to_xml
239
+ end
240
+ end
241
+ end
242
+
243
+ class ColumnStructure
244
+ private
245
+ include Locomotive::XML
246
+ def_node :column_structure
247
+
248
+ def to_cs_entry(entry)
249
+ return entry if OffsetType === entry or
250
+ AttributeColumnStructure === entry
251
+
252
+ if !(Array === entry and entry.size == 2) then
253
+ raise ArgumentError,
254
+ "entry is not a column_structure_entry"
255
+ end
256
+
257
+ case
258
+ when Item === entry.first,
259
+ RType === entry.last then
260
+ OffsetType.new(entry.first, entry.last)
261
+ when Attribute === entry.first then
262
+ if Array === entry.last then
263
+ AttributeColumnStructure.new(entry.first,
264
+ ColumnStructure.new(entry.last))
265
+ elsif ColumnStructure === entry.last then
266
+ AttributeColumnStructure.new(entry.first,
267
+ entry.last)
268
+ end
269
+ else
270
+ raise ArgumentError,
271
+ "entry is not a column_structure_entry"
272
+ end
273
+ end
274
+
275
+ def search_by_attribute(attribute)
276
+ entries.select do |entry|
277
+ entry.attribute == attribute
278
+ end.first
279
+ end
280
+
281
+ def search_by_item(offset)
282
+ entries.select do |entry|
283
+ entry.offset == offset
284
+ end.first
285
+ end
286
+
287
+ public
288
+ attr_reader :entries
289
+
290
+ delegate :first,
291
+ :map,
292
+ :collect,
293
+ :count,
294
+ :zip,
295
+ :to => :entries
296
+
297
+ def initialize(entries)
298
+ @entries = entries.map do |entry|
299
+ to_cs_entry(entry)
300
+ end
301
+ end
302
+
303
+ def add(entries)
304
+ entries_ = entries
305
+
306
+ if ColumnStructure === entries then
307
+ entries_ = entries.entries
308
+ end
309
+
310
+ ColumnStructure.new(self.entries +
311
+ entries_.map { |e| to_cs_entry(e) })
312
+ end
313
+ alias :+ :add
314
+
315
+ def [](attribute_index)
316
+ # just look on the surface if you find the right attribute
317
+ case attribute_index
318
+ when Fixnum then
319
+ entries[attribute_index]
320
+ when Symbol then
321
+ # creating an attribute to be consistent in the signature
322
+ attribute = Attribute.new(attribute_index)
323
+ attr = search_by_attribute(attribute).
324
+ attr.nil? ? nil : attr.column_structure
325
+ when Attribute then
326
+ attr = search_by_attribute(attribute_index)
327
+ attr.nil? ? nil : attr.column_structure
328
+ when Item then
329
+ attr = search_by_attribute(attribute_index)
330
+ attr.nil? ? nil : ColumnStructure.new([search_by_item(attribute_index)])
331
+ else
332
+ raise ArgumentError,
333
+ "Argument should be a (Fixnum | Symbol | Attribute | Item)"
334
+ end
335
+ end
336
+
337
+ def -(array)
338
+ ColumnStructure.new(
339
+ entries.clone.delete_if do |entry|
340
+ case
341
+ when AttributeColumnStructure === entry then
342
+ array.any? { |a| entry.items.member? a }
343
+ when OffsetType === entry
344
+ array.member? entry.offset
345
+ else
346
+ raise StandardError, "Not a cs-entry"
347
+ end
348
+ end)
349
+ end
350
+
351
+ def clone
352
+ ColumnStructure.new(
353
+ entries.map { |e| e.clone })
354
+ end
355
+
356
+ def items
357
+ entries.map do |entry|
358
+ entry.items
359
+ end.flatten
360
+ end
361
+
362
+ def offsets
363
+ entries.map do |entry|
364
+ entry.offsets
365
+ end.flatten
366
+ end
367
+
368
+ def adapt
369
+ item_min = self.items.min
370
+ # we are modifying the structure
371
+ # itself (sideeffect) so we have to
372
+ # do a clone of it
373
+ cs_new = self.clone
374
+ cs_new.items.each do |it|
375
+ it.dec!(item_min.id - 1)
376
+ end
377
+ cs_new
378
+ end
379
+
380
+ def to_xml
381
+ column_structure do
382
+ entries.collect do |e|
383
+ e.to_xml
384
+ end.join
385
+ end
386
+ end
387
+ end
388
+
389
+ class SideEffects
390
+ private
391
+
392
+ def to_side_effect(side)
393
+ case
394
+ when Array === side then
395
+ side
396
+ when SideEffects === side then
397
+ side.side
398
+ when Operator === side then
399
+ [side]
400
+ end
401
+ end
402
+
403
+ public
404
+
405
+ attr_reader :side
406
+
407
+ def initialize(side)
408
+ @side = to_side_effect side
409
+ end
410
+
411
+ def add(side_effect)
412
+ SideEffects.new(
413
+ @side + to_side_effect(side_effect))
414
+ end
415
+ alias :+ :add
416
+
417
+
418
+ def plan
419
+ @side.reduce(Nil.new) do |s1, s2|
420
+ s1.error(s2, Item.new(1))
421
+ end
422
+ end
423
+ end
424
+
425
+ class QueryInformationNode
426
+ private
427
+
428
+ def to_cs_structure(cs_structure)
429
+ case
430
+ when Array === cs_structure then
431
+ ColumnStructure.new(cs_structure)
432
+ when ColumnStructure === cs_structure then
433
+ cs_structure
434
+ else raise ArgumentError,
435
+ "#{cs_structure.class} is not a column_structure"
436
+ end
437
+ end
438
+
439
+ def to_surrogates(surrogates)
440
+ case
441
+ when NilClass === surrogates then
442
+ SurrogateList.new({})
443
+ when Hash === surrogates then
444
+ SurrogateList.new(surrogates)
445
+ when SurrogateList === surrogates then
446
+ surrogates
447
+ else raise ArgumentError,
448
+ "surrogates doesn't seem to be a surrogate_list"
449
+ end
450
+ end
451
+
452
+ def to_side_effects(side_effects)
453
+ case
454
+ when NilClass === side_effects then
455
+ SideEffects.new([])
456
+ when Array === side_effects then
457
+ SideEffects.new(side_effects)
458
+ when SideEffects === side_effects then
459
+ side_effects
460
+ else raise ArgumentError,
461
+ "side_effects doesn't seem to be a side_effect"
462
+ end
463
+ end
464
+
465
+ public
466
+ attr_accessor :plan,
467
+ :column_structure,
468
+ :surrogates,
469
+ :side_effects,
470
+ :methods
471
+
472
+ def_sig :plan=, Operator
473
+ def_sig :column_structure=, ColumnStructure
474
+ def_sig :surrogates=, SurrogateList
475
+ def_sig :side_effects=, SideEffects
476
+ def_sig :methods=, { Symbol => RelLambda }
477
+
478
+ def initialize(plan, cs_structure, surrogates=nil, side_effects=nil, methods={})
479
+ self.plan,
480
+ self.column_structure,
481
+ self.surrogates,
482
+ self.side_effects = plan, to_cs_structure(cs_structure),
483
+ to_surrogates(surrogates),
484
+ to_side_effects(side_effects)
485
+
486
+ unless self.plan.schema.attributes?(self.column_structure.items) then
487
+ raise StandardError, "Queryplan doesn't contain all attributes of" \
488
+ " #{self.column_structure.items.inspect}"
489
+ end
490
+ self.methods = methods
491
+ end
492
+
493
+ def frag
494
+ itbls_hash = {}
495
+
496
+ column_structure.
497
+ zip(1..column_structure.count).each do |c, i|
498
+
499
+ cols_c = column_structure[i-1].column_structure.adapt
500
+ itbls_c = surrogates.filter_and_adapt(c.items)
501
+
502
+ q_c = plan.project({ Iter.new(1) => [Iter.new(1)],
503
+ Pos.new(1) => [Pos.new(1)] }.
504
+ merge(
505
+ c.items.zip(cols_c.items).
506
+ map do |old,new|
507
+ [old,[new]]
508
+ end.to_hash))
509
+
510
+ itbls_hash = itbls_hash.merge(
511
+ { Item.new(i) => QueryInformationNode.new(
512
+ q_c,
513
+ cols_c,
514
+ itbls_c) })
515
+ end
516
+
517
+ SurrogateList.new( itbls_hash )
518
+ end
519
+
520
+ def clone
521
+ QueryInformationNode.new(plan,
522
+ column_structure.clone,
523
+ surrogates.clone)
524
+ end
525
+ end
526
+
527
+ class ResultType
528
+ include Singleton
529
+
530
+ class << self
531
+ alias :type :instance
532
+ end
533
+
534
+ def to_xml
535
+ self.class.to_s.split("::").last.upcase
536
+ end
537
+
538
+ def clone
539
+ # singleton
540
+ self
541
+ end
542
+ end
543
+
544
+ class List < ResultType; end
545
+ class Atom < ResultType; end
546
+
547
+ class QueryPlan
548
+ private
549
+
550
+ include Locomotive::XML
551
+ def_node :query_plan,
552
+ :properties, :property
553
+
554
+ public
555
+
556
+ attr_reader :id,
557
+ :idref,
558
+ :colref,
559
+ :plan,
560
+ :cols,
561
+ :result_type
562
+
563
+ def initialize(plan, cols, id, result_type=nil, idref=nil, colref=nil)
564
+ @id = id
565
+ @idref = idref
566
+ @colref = colref
567
+ @result_type = result_type
568
+ @plan = plan
569
+ @cols = cols
570
+ end
571
+
572
+ def to_xml
573
+ attributes = { :id => id }
574
+ attributes.merge!({ :idref => idref }) if idref
575
+ attributes.merge!({ :colref => colref }) if colref
576
+
577
+ query_plan(attributes) do
578
+ p = []
579
+ p << properties do
580
+ property(:name => :overallResultType, :value => result_type.to_xml)
581
+ end if result_type
582
+ p << plan.serialize
583
+ p.join
584
+ end
585
+ end
586
+ end
587
+
588
+
589
+ class QueryPlanBundle
590
+ private
591
+ # def collect_surrogates(surr)
592
+ # lplans = []
593
+ # surr.each do |attr,q_in|
594
+ # lplans << [SerializeRelation.new(
595
+ # q_in.side_effects.plan, q_in.plan,
596
+ # Iter.new(1), Pos.new(1), q_in.column_structure.items),
597
+ # q_in.column_structure]
598
+ # lplans += collect_surrogates(q_in.surrogates)
599
+ # end
600
+ # lplans
601
+ # end
602
+
603
+ def collect_surrogates(items, last_id, surr)
604
+ next_id= last_id + 1
605
+ surr.surrogates.map do |attr,qin|
606
+ plan = qin.plan
607
+ cols = qin.column_structure
608
+ side = qin.side_effects.plan
609
+ surr = qin.surrogates
610
+
611
+ colref = items.index(attr) + 1
612
+
613
+ ser = SerializeRelation.new(
614
+ side, plan,
615
+ Iter.new(1), Pos.new(1), cols.items)
616
+ qp = QueryPlan.new(
617
+ ser, cols, next_id, nil, last_id, colref)
618
+ qps = collect_surrogates(cols.items, next_id, surr)
619
+ next_id += qps.flatten.size + 1
620
+ [qp] + qps
621
+ end
622
+ end
623
+
624
+ public
625
+ include Locomotive::XML
626
+ def_node :query_plan_bundle,
627
+ :csstructure
628
+
629
+
630
+ XML_Prolog = '<?xml version="1.0" encoding="UTF-8"?>'+"\n"
631
+
632
+ attr_accessor :query_plans
633
+ attr :cs_structure
634
+
635
+ def initialize(qin, type)
636
+ plan = qin.plan
637
+ cols = qin.column_structure
638
+ side = qin.side_effects.plan
639
+ surr = qin.surrogates
640
+
641
+ ser = SerializeRelation.new(
642
+ side, plan,
643
+ Iter.new(1), Pos.new(1),
644
+ cols.items)
645
+
646
+ qp = QueryPlan.new(ser, cols, 0, type)
647
+ self.query_plans = [qp, collect_surrogates(cols.items, 0, surr)].flatten
648
+ end
649
+
650
+ def to_xml
651
+ XML_Prolog +
652
+ query_plan_bundle do
653
+ query_plans.map do |qp|
654
+ qp.to_xml
655
+ end.join
656
+ end
657
+ end
658
+
659
+ def clone
660
+ QueryPlanBundle.new( logical_query_plans )
661
+ end
662
+ end
663
+
664
+ end
665
+
666
+ end