mondrian-olap 0.5.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/Changelog.md +86 -0
  3. data/LICENSE-Mondrian.txt +87 -0
  4. data/LICENSE.txt +1 -1
  5. data/README.md +43 -40
  6. data/VERSION +1 -1
  7. data/lib/mondrian/jars/commons-collections-3.2.2.jar +0 -0
  8. data/lib/mondrian/jars/commons-dbcp-1.4.jar +0 -0
  9. data/lib/mondrian/jars/commons-io-2.2.jar +0 -0
  10. data/lib/mondrian/jars/commons-lang-2.6.jar +0 -0
  11. data/lib/mondrian/jars/commons-logging-1.2.jar +0 -0
  12. data/lib/mondrian/jars/commons-pool-1.5.7.jar +0 -0
  13. data/lib/mondrian/jars/commons-vfs2-2.2.jar +0 -0
  14. data/lib/mondrian/jars/eigenbase-xom-1.3.5.jar +0 -0
  15. data/lib/mondrian/jars/guava-17.0.jar +0 -0
  16. data/lib/mondrian/jars/log4j-1.2.17.jar +0 -0
  17. data/lib/mondrian/jars/log4j.properties +2 -4
  18. data/lib/mondrian/jars/mondrian-9.1.0.0.jar +0 -0
  19. data/lib/mondrian/jars/olap4j-1.2.0.jar +0 -0
  20. data/lib/mondrian/olap/connection.rb +252 -67
  21. data/lib/mondrian/olap/cube.rb +63 -2
  22. data/lib/mondrian/olap/error.rb +37 -8
  23. data/lib/mondrian/olap/query.rb +41 -21
  24. data/lib/mondrian/olap/result.rb +163 -44
  25. data/lib/mondrian/olap/schema.rb +42 -3
  26. data/lib/mondrian/olap/schema_element.rb +25 -6
  27. data/lib/mondrian/olap/schema_udf.rb +21 -16
  28. data/spec/connection_role_spec.rb +69 -13
  29. data/spec/connection_spec.rb +3 -2
  30. data/spec/cube_cache_control_spec.rb +261 -0
  31. data/spec/cube_spec.rb +32 -4
  32. data/spec/fixtures/MondrianTest.xml +1 -6
  33. data/spec/fixtures/MondrianTestOracle.xml +1 -6
  34. data/spec/mondrian_spec.rb +71 -1
  35. data/spec/query_spec.rb +323 -25
  36. data/spec/rake_tasks.rb +253 -159
  37. data/spec/schema_definition_spec.rb +314 -61
  38. data/spec/spec_helper.rb +115 -45
  39. data/spec/support/data/customers.csv +10902 -0
  40. data/spec/support/data/product_classes.csv +101 -0
  41. data/spec/support/data/products.csv +101 -0
  42. data/spec/support/data/sales.csv +101 -0
  43. data/spec/support/data/time.csv +731 -0
  44. metadata +126 -124
  45. data/LICENSE-Mondrian.html +0 -259
  46. data/lib/mondrian/jars/commons-collections-3.2.jar +0 -0
  47. data/lib/mondrian/jars/commons-dbcp-1.2.1.jar +0 -0
  48. data/lib/mondrian/jars/commons-logging-1.1.1.jar +0 -0
  49. data/lib/mondrian/jars/commons-pool-1.2.jar +0 -0
  50. data/lib/mondrian/jars/commons-vfs-1.0.jar +0 -0
  51. data/lib/mondrian/jars/eigenbase-xom-1.3.1.jar +0 -0
  52. data/lib/mondrian/jars/log4j-1.2.14.jar +0 -0
  53. data/lib/mondrian/jars/mondrian.jar +0 -0
  54. data/lib/mondrian/jars/olap4j-1.0.1.539.jar +0 -0
data/spec/rake_tasks.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  namespace :db do
2
4
  task :require_spec_helper do
3
5
  require File.expand_path("../spec_helper", __FILE__)
@@ -40,12 +42,56 @@ namespace :db do
40
42
  t.string :lname, :limit => 30
41
43
  t.string :fullname, :limit => 60
42
44
  t.string :gender, :limit => 30
45
+ t.integer :promotion_id
46
+ t.string :related_fullname, :limit => 60
47
+ # Mondrian does not support properties with Oracle CLOB type
48
+ # as it tries to GROUP BY all columns when loading a dimension table
49
+ if MONDRIAN_DRIVER == 'oracle'
50
+ t.string :description, :limit => 4000
51
+ else
52
+ t.text :description
53
+ end
54
+ end
55
+
56
+ if MONDRIAN_DRIVER == 'oracle'
57
+
58
+ execute "DROP TABLE PROMOTIONS" rescue nil
59
+ execute "DROP SEQUENCE PROMOTIONS_SEQ" rescue nil
60
+
61
+ execute <<~SQL
62
+ CREATE TABLE PROMOTIONS(
63
+ ID NUMBER(*,0) NOT NULL,
64
+ PROMOTION VARCHAR2(30 CHAR),
65
+ SEQUENCE NUMBER(38,0),
66
+ PRIMARY KEY ("ID")
67
+ )
68
+ SQL
69
+ execute "CREATE SEQUENCE PROMOTIONS_SEQ"
70
+ else
71
+ create_table :promotions, :force => true do |t|
72
+ t.string :promotion, :limit => 30
73
+ t.integer :sequence
74
+ end
75
+ end
76
+
77
+ case MONDRIAN_DRIVER
78
+ when /mysql/
79
+ execute "ALTER TABLE customers MODIFY COLUMN id BIGINT NOT NULL AUTO_INCREMENT"
80
+ when /postgresql/
81
+ execute "ALTER TABLE customers ALTER COLUMN id SET DATA TYPE bigint"
82
+ when /mssql|sqlserver/
83
+ sql = "SELECT name FROM sysobjects WHERE xtype = 'PK' AND parent_obj=OBJECT_ID('customers')"
84
+ primary_key_constraint = select_value(sql)
85
+ execute "ALTER TABLE customers DROP CONSTRAINT #{primary_key_constraint}"
86
+ execute "ALTER TABLE customers ALTER COLUMN id BIGINT"
87
+ execute "ALTER TABLE customers ADD CONSTRAINT #{primary_key_constraint} PRIMARY KEY (id)"
43
88
  end
44
89
 
45
90
  create_table :sales, :force => true, :id => false do |t|
46
91
  t.integer :product_id
47
92
  t.integer :time_id
48
93
  t.integer :customer_id
94
+ t.integer :promotion_id
49
95
  t.decimal :store_sales, :precision => 10, :scale => 4
50
96
  t.decimal :store_cost, :precision => 10, :scale => 4
51
97
  t.decimal :unit_sales, :precision => 10, :scale => 4
@@ -53,188 +99,236 @@ namespace :db do
53
99
  end
54
100
  end
55
101
 
56
- task :setup_luciddb => :require_spec_helper do
57
- # create link to mysql database to import tables
58
- # see description at http://pub.eigenbase.org/wiki/LucidDbCreateForeignServer
59
- if MONDRIAN_DRIVER == 'luciddb'
60
- conn = ActiveRecord::Base.connection
61
- conn.execute "drop schema mondrian_test_source cascade" rescue nil
62
- conn.execute "drop server mondrian_test_source" rescue nil
63
- conn.execute "create schema mondrian_test_source"
64
- conn.execute <<-SQL
65
- create server mondrian_test_source
66
- foreign data wrapper sys_jdbc
67
- options(
68
- driver_class 'com.mysql.jdbc.Driver',
69
- url 'jdbc:mysql://localhost/mondrian_test?characterEncoding=utf-8&useCursorFetch=true',
70
- user_name 'mondrian_test',
71
- password 'mondrian_test',
72
- login_timeout '10',
73
- fetch_size '1000',
74
- validation_query 'select 1',
75
- schema_name 'MONDRIAN_TEST',
76
- table_types 'TABLE')
77
- SQL
78
- conn.execute "import foreign schema mondrian_test from server mondrian_test_source into mondrian_test_source"
79
- end
80
- end
81
-
82
102
  task :define_models => :require_spec_helper do
83
- unless MONDRIAN_DRIVER == 'luciddb'
84
- class TimeDimension < ActiveRecord::Base
85
- self.table_name = "time"
86
- validates_presence_of :the_date
87
- before_create do
88
- self.the_day = the_date.strftime("%A")
89
- self.the_month = the_date.strftime("%B")
90
- self.the_year = the_date.strftime("%Y").to_i
91
- self.day_of_month = the_date.strftime("%d").to_i
92
- self.week_of_year = the_date.strftime("%W").to_i
93
- self.month_of_year = the_date.strftime("%m").to_i
94
- self.quarter = "Q#{(month_of_year-1)/3+1}"
95
- end
96
- end
97
- class Product < ActiveRecord::Base
98
- belongs_to :product_class
99
- end
100
- class ProductClass < ActiveRecord::Base
101
- end
102
- class Customer < ActiveRecord::Base
103
- end
104
- class Sales < ActiveRecord::Base
105
- self.table_name = "sales"
106
- belongs_to :time_by_day
107
- belongs_to :product
108
- belongs_to :customer
103
+ class TimeDimension < ActiveRecord::Base
104
+ self.table_name = "time"
105
+ validates_presence_of :the_date
106
+ before_create do
107
+ self.the_day = the_date.strftime("%A")
108
+ self.the_month = the_date.strftime("%B")
109
+ self.the_year = the_date.strftime("%Y").to_i
110
+ self.day_of_month = the_date.strftime("%d").to_i
111
+ self.week_of_year = the_date.strftime("%W").to_i
112
+ self.month_of_year = the_date.strftime("%m").to_i
113
+ self.quarter = "Q#{(month_of_year-1)/3+1}"
109
114
  end
110
115
  end
116
+ class Product < ActiveRecord::Base
117
+ belongs_to :product_class
118
+ end
119
+ class ProductClass < ActiveRecord::Base
120
+ end
121
+ class Customer < ActiveRecord::Base
122
+ end
123
+ class Promotion < ActiveRecord::Base
124
+ end
125
+ class Sales < ActiveRecord::Base
126
+ self.table_name = "sales"
127
+ belongs_to :time_by_day
128
+ belongs_to :product
129
+ belongs_to :customer
130
+ end
111
131
  end
112
132
 
113
133
  desc "Create test data"
114
- task :create_data => [:create_tables, :setup_luciddb, :create_time_data, :create_product_data, :create_customer_data, :create_sales_data]
134
+ task :create_data => [:create_tables] + ( %w(vertica snowflake).include?(ENV['MONDRIAN_DRIVER']) ? [:import_data] :
135
+ [ :create_time_data, :create_product_data, :create_promotion_data, :create_customer_data, :create_sales_data ] )
115
136
 
116
137
  task :create_time_data => :define_models do
117
138
  puts "==> Creating time dimension"
118
- if MONDRIAN_DRIVER == 'luciddb'
119
- ActiveRecord::Base.connection.execute 'truncate table "TIME"'
120
- ActiveRecord::Base.connection.execute 'insert into "TIME" select * from mondrian_test_source."time"'
121
- ActiveRecord::Base.connection.execute 'analyze table "TIME" compute statistics for all columns'
122
- else
123
- TimeDimension.delete_all
124
- start_time = Time.local(2010,1,1)
125
- (2*365).times do |i|
126
- TimeDimension.create!(:the_date => start_time + i.day)
127
- end
139
+ TimeDimension.delete_all
140
+ start_time = Time.utc(2010,1,1)
141
+ (2*365).times do |i|
142
+ TimeDimension.create!(:the_date => start_time + i.day)
128
143
  end
129
144
  end
130
145
 
131
146
  task :create_product_data => :define_models do
132
147
  puts "==> Creating product data"
133
- if MONDRIAN_DRIVER == 'luciddb'
134
- ActiveRecord::Base.connection.execute 'truncate table product_classes'
135
- ActiveRecord::Base.connection.execute 'truncate table products'
136
- ActiveRecord::Base.connection.execute 'insert into product_classes select * from mondrian_test_source."product_classes"'
137
- ActiveRecord::Base.connection.execute 'insert into products select * from mondrian_test_source."products"'
138
- ActiveRecord::Base.connection.execute 'analyze table product_classes compute statistics for all columns'
139
- ActiveRecord::Base.connection.execute 'analyze table products compute statistics for all columns'
140
- else
141
- Product.delete_all
142
- ProductClass.delete_all
143
- families = ["Drink", "Food", "Non-Consumable"]
144
- (1..100).each do |i|
145
- product_class = ProductClass.create!(
146
- :product_family => families[i % 3],
147
- :product_department => "Department #{i}",
148
- :product_category => "Category #{i}",
149
- :product_subcategory => "Subcategory #{i}"
150
- )
151
- Product.create!(
152
- # LucidDB is not returning inserted ID therefore doing it hard way
153
- :product_class_id => ProductClass.where(:product_category => "Category #{i}").to_a.first.id,
154
- :brand_name => "Brand #{i}",
155
- :product_name => "Product #{i}"
156
- )
157
- end
148
+ Product.delete_all
149
+ ProductClass.delete_all
150
+ families = ["Drink", "Food", "Non-Consumable"]
151
+ (1..100).each do |i|
152
+ product_class = ProductClass.create!(
153
+ :product_family => families[i % 3],
154
+ :product_department => "Department #{i}",
155
+ :product_category => "Category #{i}",
156
+ :product_subcategory => "Subcategory #{i}"
157
+ )
158
+ Product.create!(
159
+ :product_class_id => ProductClass.where(:product_category => "Category #{i}").to_a.first.id,
160
+ :brand_name => "Brand #{i}",
161
+ :product_name => "Product #{i}"
162
+ )
163
+ end
164
+ end
165
+
166
+ task :create_promotion_data => :define_models do
167
+ puts "==> Creating promotion data"
168
+ Promotion.delete_all
169
+ (1..10).each do |i|
170
+ Promotion.create!(promotion: "Promotion #{i}", sequence: i)
158
171
  end
159
172
  end
160
173
 
161
174
  task :create_customer_data => :define_models do
162
175
  puts "==> Creating customer data"
163
- if MONDRIAN_DRIVER == 'luciddb'
164
- ActiveRecord::Base.connection.execute 'truncate table customers'
165
- ActiveRecord::Base.connection.execute 'insert into customers select * from mondrian_test_source."customers"'
166
- ActiveRecord::Base.connection.execute 'analyze table customers compute statistics for all columns'
167
- else
168
- Customer.delete_all
169
- i = 0
170
- [
171
- ["Canada", "BC", "Burnaby"],["Canada", "BC", "Cliffside"],["Canada", "BC", "Haney"],["Canada", "BC", "Ladner"],
172
- ["Canada", "BC", "Langford"],["Canada", "BC", "Langley"],["Canada", "BC", "Metchosin"],["Canada", "BC", "N. Vancouver"],
173
- ["Canada", "BC", "Newton"],["Canada", "BC", "Oak Bay"],["Canada", "BC", "Port Hammond"],["Canada", "BC", "Richmond"],
174
- ["Canada", "BC", "Royal Oak"],["Canada", "BC", "Shawnee"],["Canada", "BC", "Sooke"],["Canada", "BC", "Vancouver"],
175
- ["Canada", "BC", "Victoria"],["Canada", "BC", "Westminster"],
176
- ["Mexico", "DF", "San Andres"],["Mexico", "DF", "Santa Anita"],["Mexico", "DF", "Santa Fe"],["Mexico", "DF", "Tixapan"],
177
- ["Mexico", "Guerrero", "Acapulco"],["Mexico", "Jalisco", "Guadalajara"],["Mexico", "Mexico", "Mexico City"],
178
- ["Mexico", "Oaxaca", "Tlaxiaco"],["Mexico", "Sinaloa", "La Cruz"],["Mexico", "Veracruz", "Orizaba"],
179
- ["Mexico", "Yucatan", "Merida"],["Mexico", "Zacatecas", "Camacho"],["Mexico", "Zacatecas", "Hidalgo"],
180
- ["USA", "CA", "Altadena"],["USA", "CA", "Arcadia"],["USA", "CA", "Bellflower"],["USA", "CA", "Berkeley"],
181
- ["USA", "CA", "Beverly Hills"],["USA", "CA", "Burbank"],["USA", "CA", "Burlingame"],["USA", "CA", "Chula Vista"],
182
- ["USA", "CA", "Colma"],["USA", "CA", "Concord"],["USA", "CA", "Coronado"],["USA", "CA", "Daly City"],
183
- ["USA", "CA", "Downey"],["USA", "CA", "El Cajon"],["USA", "CA", "Fremont"],["USA", "CA", "Glendale"],
184
- ["USA", "CA", "Grossmont"],["USA", "CA", "Imperial Beach"],["USA", "CA", "La Jolla"],["USA", "CA", "La Mesa"],
185
- ["USA", "CA", "Lakewood"],["USA", "CA", "Lemon Grove"],["USA", "CA", "Lincoln Acres"],["USA", "CA", "Long Beach"],
186
- ["USA", "CA", "Los Angeles"],["USA", "CA", "Mill Valley"],["USA", "CA", "National City"],["USA", "CA", "Newport Beach"],
187
- ["USA", "CA", "Novato"],["USA", "CA", "Oakland"],["USA", "CA", "Palo Alto"],["USA", "CA", "Pomona"],
188
- ["USA", "CA", "Redwood City"],["USA", "CA", "Richmond"],["USA", "CA", "San Carlos"],["USA", "CA", "San Diego"],
189
- ["USA", "CA", "San Francisco"],["USA", "CA", "San Gabriel"],["USA", "CA", "San Jose"],["USA", "CA", "Santa Cruz"],
190
- ["USA", "CA", "Santa Monica"],["USA", "CA", "Spring Valley"],["USA", "CA", "Torrance"],["USA", "CA", "West Covina"],
191
- ["USA", "CA", "Woodland Hills"],
192
- ["USA", "OR", "Albany"],["USA", "OR", "Beaverton"],["USA", "OR", "Corvallis"],["USA", "OR", "Lake Oswego"],
193
- ["USA", "OR", "Lebanon"],["USA", "OR", "Milwaukie"],["USA", "OR", "Oregon City"],["USA", "OR", "Portland"],
194
- ["USA", "OR", "Salem"],["USA", "OR", "W. Linn"],["USA", "OR", "Woodburn"],
195
- ["USA", "WA", "Anacortes"],["USA", "WA", "Ballard"],["USA", "WA", "Bellingham"],["USA", "WA", "Bremerton"],
196
- ["USA", "WA", "Burien"],["USA", "WA", "Edmonds"],["USA", "WA", "Everett"],["USA", "WA", "Issaquah"],
197
- ["USA", "WA", "Kirkland"],["USA", "WA", "Lynnwood"],["USA", "WA", "Marysville"],["USA", "WA", "Olympia"],
198
- ["USA", "WA", "Port Orchard"],["USA", "WA", "Puyallup"],["USA", "WA", "Redmond"],["USA", "WA", "Renton"],
199
- ["USA", "WA", "Seattle"],["USA", "WA", "Sedro Woolley"],["USA", "WA", "Spokane"],["USA", "WA", "Tacoma"],
200
- ["USA", "WA", "Walla Walla"],["USA", "WA", "Yakima"]
201
- ].each do |country, state, city|
202
- i += 1
203
- Customer.create!(
204
- :country => country,
205
- :state_province => state,
206
- :city => city,
207
- :fname => "First#{i}",
208
- :lname => "Last#{i}",
209
- :fullname => "First#{i} Last#{i}",
210
- :gender => i % 2 == 0 ? "M" : "F"
211
- )
176
+ Customer.delete_all
177
+ promotions = Promotion.order("id").to_a
178
+ i = 0
179
+ [
180
+ ["Canada", "BC", "Burnaby"],["Canada", "BC", "Cliffside"],["Canada", "BC", "Haney"],["Canada", "BC", "Ladner"],
181
+ ["Canada", "BC", "Langford"],["Canada", "BC", "Langley"],["Canada", "BC", "Metchosin"],["Canada", "BC", "N. Vancouver"],
182
+ ["Canada", "BC", "Newton"],["Canada", "BC", "Oak Bay"],["Canada", "BC", "Port Hammond"],["Canada", "BC", "Richmond"],
183
+ ["Canada", "BC", "Royal Oak"],["Canada", "BC", "Shawnee"],["Canada", "BC", "Sooke"],["Canada", "BC", "Vancouver"],
184
+ ["Canada", "BC", "Victoria"],["Canada", "BC", "Westminster"],
185
+ ["Mexico", "DF", "San Andres"],["Mexico", "DF", "Santa Anita"],["Mexico", "DF", "Santa Fe"],["Mexico", "DF", "Tixapan"],
186
+ ["Mexico", "Guerrero", "Acapulco"],["Mexico", "Jalisco", "Guadalajara"],["Mexico", "Mexico", "Mexico City"],
187
+ ["Mexico", "Oaxaca", "Tlaxiaco"],["Mexico", "Sinaloa", "La Cruz"],["Mexico", "Veracruz", "Orizaba"],
188
+ ["Mexico", "Yucatan", "Merida"],["Mexico", "Zacatecas", "Camacho"],["Mexico", "Zacatecas", "Hidalgo"],
189
+ ["USA", "CA", "Altadena"],["USA", "CA", "Arcadia"],["USA", "CA", "Bellflower"],["USA", "CA", "Berkeley"],
190
+ ["USA", "CA", "Beverly Hills"],["USA", "CA", "Burbank"],["USA", "CA", "Burlingame"],["USA", "CA", "Chula Vista"],
191
+ ["USA", "CA", "Colma"],["USA", "CA", "Concord"],["USA", "CA", "Coronado"],["USA", "CA", "Daly City"],
192
+ ["USA", "CA", "Downey"],["USA", "CA", "El Cajon"],["USA", "CA", "Fremont"],["USA", "CA", "Glendale"],
193
+ ["USA", "CA", "Grossmont"],["USA", "CA", "Imperial Beach"],["USA", "CA", "La Jolla"],["USA", "CA", "La Mesa"],
194
+ ["USA", "CA", "Lakewood"],["USA", "CA", "Lemon Grove"],["USA", "CA", "Lincoln Acres"],["USA", "CA", "Long Beach"],
195
+ ["USA", "CA", "Los Angeles"],["USA", "CA", "Mill Valley"],["USA", "CA", "National City"],["USA", "CA", "Newport Beach"],
196
+ ["USA", "CA", "Novato"],["USA", "CA", "Oakland"],["USA", "CA", "Palo Alto"],["USA", "CA", "Pomona"],
197
+ ["USA", "CA", "Redwood City"],["USA", "CA", "Richmond"],["USA", "CA", "San Carlos"],["USA", "CA", "San Diego"],
198
+ ["USA", "CA", "San Francisco"],["USA", "CA", "San Gabriel"],["USA", "CA", "San Jose"],["USA", "CA", "Santa Cruz"],
199
+ ["USA", "CA", "Santa Monica"],["USA", "CA", "Spring Valley"],["USA", "CA", "Torrance"],["USA", "CA", "West Covina"],
200
+ ["USA", "CA", "Woodland Hills"],
201
+ ["USA", "OR", "Albany"],["USA", "OR", "Beaverton"],["USA", "OR", "Corvallis"],["USA", "OR", "Lake Oswego"],
202
+ ["USA", "OR", "Lebanon"],["USA", "OR", "Milwaukie"],["USA", "OR", "Oregon City"],["USA", "OR", "Portland"],
203
+ ["USA", "OR", "Salem"],["USA", "OR", "W. Linn"],["USA", "OR", "Woodburn"],
204
+ ["USA", "WA", "Anacortes"],["USA", "WA", "Ballard"],["USA", "WA", "Bellingham"],["USA", "WA", "Bremerton"],
205
+ ["USA", "WA", "Burien"],["USA", "WA", "Edmonds"],["USA", "WA", "Everett"],["USA", "WA", "Issaquah"],
206
+ ["USA", "WA", "Kirkland"],["USA", "WA", "Lynnwood"],["USA", "WA", "Marysville"],["USA", "WA", "Olympia"],
207
+ ["USA", "WA", "Port Orchard"],["USA", "WA", "Puyallup"],["USA", "WA", "Redmond"],["USA", "WA", "Renton"],
208
+ ["USA", "WA", "Seattle"],["USA", "WA", "Sedro Woolley"],["USA", "WA", "Spokane"],["USA", "WA", "Tacoma"],
209
+ ["USA", "WA", "Walla Walla"],["USA", "WA", "Yakima"]
210
+ ].each do |country, state, city|
211
+ i += 1
212
+ Customer.create!(
213
+ :country => country,
214
+ :state_province => state,
215
+ :city => city,
216
+ :fname => "First#{i}",
217
+ :lname => "Last#{i}",
218
+ :fullname => "First#{i} Last#{i}",
219
+ :gender => i % 2 == 0 ? "M" : "F",
220
+ :promotion_id => promotions[i % 10].id,
221
+ :related_fullname => "First#{i} Last#{i}",
222
+ :description => 100.times.map{"1234567890"}.join("\n")
223
+ )
224
+ end
225
+ # Create additional customer with large ID
226
+ attributes = {
227
+ :id => 10_000_000_000,
228
+ :country => "USA",
229
+ :state_province => "CA",
230
+ :city => "Rīga", # For testing UTF-8 characters
231
+ :fname => "Big",
232
+ :lname => "Number",
233
+ :fullname => "Big Number",
234
+ :gender => "M",
235
+ :promotion_id => promotions.first.id,
236
+ :related_fullname => "Big Number"
237
+ }
238
+ case MONDRIAN_DRIVER
239
+ when /mssql|sqlserver/
240
+ Customer.connection.with_identity_insert_enabled("customers") do
241
+ Customer.create!(attributes)
212
242
  end
243
+ else
244
+ Customer.create!(attributes)
213
245
  end
214
246
  end
215
247
 
216
248
  task :create_sales_data => :define_models do
217
249
  puts "==> Creating sales data"
218
- if MONDRIAN_DRIVER == 'luciddb'
219
- ActiveRecord::Base.connection.execute 'truncate table sales'
220
- ActiveRecord::Base.connection.execute 'insert into sales select * from mondrian_test_source."sales"'
221
- ActiveRecord::Base.connection.execute 'analyze table sales compute statistics for all columns'
222
- else
223
- Sales.delete_all
224
- count = 100
225
- # LucidDB does not support LIMIT therefore select all and limit in Ruby
226
- products = Product.order("id").to_a[0...count]
227
- times = TimeDimension.order("id").to_a[0...count]
228
- customers = Customer.order("id").to_a[0...count]
229
- count.times do |i|
230
- Sales.create!(
231
- :product_id => products[i].id,
232
- :time_id => times[i].id,
233
- :customer_id => customers[i].id,
234
- :store_sales => BigDecimal("2#{i}.12"),
235
- :store_cost => BigDecimal("1#{i}.1234"),
236
- :unit_sales => i+1
237
- )
250
+ Sales.delete_all
251
+ count = 100
252
+ products = Product.order("id").to_a[0...count]
253
+ times = TimeDimension.order("id").to_a[0...count]
254
+ customers = Customer.order("id").to_a[0...count]
255
+ promotions = Promotion.order("id").to_a[0...count]
256
+ count.times do |i|
257
+ Sales.create!(
258
+ :product_id => products[i].id,
259
+ :time_id => times[i].id,
260
+ :customer_id => customers[i].id,
261
+ :promotion_id => promotions[i % 10].id,
262
+ :store_sales => BigDecimal("2#{i}.12"),
263
+ :store_cost => BigDecimal("1#{i}.1234"),
264
+ :unit_sales => i+1
265
+ )
266
+ end
267
+ end
268
+
269
+ export_data_dir = File.expand_path("spec/support/data")
270
+ table_names = %w(time product_classes products customers sales)
271
+
272
+ desc "Export test data"
273
+ task :export_data => :create_data do
274
+ require "csv"
275
+ puts "==> Exporting data"
276
+ conn = ActiveRecord::Base.connection
277
+ table_names.each do |table_name|
278
+ column_names = conn.columns(table_name).map(&:name)
279
+ csv_content = conn.select_rows("SELECT #{column_names.join(',')} FROM #{table_name}").map do |row|
280
+ row.map do |value|
281
+ case value
282
+ when Time
283
+ value.utc.to_s(:db)
284
+ else
285
+ value
286
+ end
287
+ end.to_csv
288
+ end.join
289
+ file_path = File.expand_path("#{table_name}.csv", export_data_dir)
290
+ File.open(file_path, "w") do |file|
291
+ file.write column_names.to_csv
292
+ file.write csv_content
293
+ end
294
+ end
295
+ end
296
+
297
+ task :import_data => :require_spec_helper do
298
+ puts "==> Importing data"
299
+ conn = ActiveRecord::Base.connection
300
+
301
+ case MONDRIAN_DRIVER
302
+ when 'vertica'
303
+ table_names.each do |table_name|
304
+ puts "==> Truncate #{table_name}"
305
+ conn.execute "TRUNCATE TABLE #{table_name}"
306
+ puts "==> Copy into #{table_name}"
307
+ file_path = "#{export_data_dir}/#{table_name}.csv"
308
+ columns_string = File.open(file_path) { |f| f.gets }.chomp
309
+ count = conn.execute "COPY #{table_name}(#{columns_string}) FROM LOCAL '#{file_path}' " \
310
+ "PARSER public.fcsvparser(header='true') ABORT ON ERROR REJECTMAX 0"
311
+ puts "==> Loaded #{count} records"
312
+ end
313
+
314
+ when 'snowflake'
315
+ conn.execute <<-SQL
316
+ CREATE OR REPLACE FILE FORMAT csv
317
+ TYPE = 'CSV' COMPRESSION = 'AUTO' FIELD_DELIMITER = ',' RECORD_DELIMITER = '\\n' SKIP_HEADER = 1
318
+ FIELD_OPTIONALLY_ENCLOSED_BY = '\\042' TRIM_SPACE = FALSE ERROR_ON_COLUMN_COUNT_MISMATCH = TRUE ESCAPE = 'NONE'
319
+ ESCAPE_UNENCLOSED_FIELD = 'NONE' DATE_FORMAT = 'AUTO' TIMESTAMP_FORMAT = 'AUTO' NULL_IF = ('')
320
+ SQL
321
+ conn.execute "CREATE OR REPLACE STAGE csv_stage FILE_FORMAT = csv"
322
+ conn.execute "PUT file://#{export_data_dir}/*.csv @csv_stage AUTO_COMPRESS = TRUE"
323
+ table_names.each do |table_name|
324
+ puts "==> Truncate #{table_name}"
325
+ conn.execute "TRUNCATE TABLE #{table_name}"
326
+ puts "==> Copy into #{table_name}"
327
+ file_path = "#{export_data_dir}/#{table_name}.csv"
328
+ columns_string = File.open(file_path) { |f| f.gets }.chomp
329
+ count = conn.execute "COPY INTO #{table_name}(#{columns_string}) FROM @csv_stage/#{table_name}.csv.gz " \
330
+ "FILE_FORMAT = (FORMAT_NAME = csv)"
331
+ puts "==> Loaded #{count} records"
238
332
  end
239
333
  end
240
334
  end
@@ -242,7 +336,7 @@ namespace :db do
242
336
  end
243
337
 
244
338
  namespace :spec do
245
- %w(mysql postgresql oracle luciddb mssql sqlserver).each do |driver|
339
+ %w(mysql jdbc_mysql postgresql oracle mssql sqlserver vertica snowflake).each do |driver|
246
340
  desc "Run specs with #{driver} driver"
247
341
  task driver do
248
342
  ENV['MONDRIAN_DRIVER'] = driver
@@ -253,7 +347,7 @@ namespace :spec do
253
347
 
254
348
  desc "Run specs with all primary database drivers"
255
349
  task :all do
256
- %w(mysql postgresql oracle mssql).each do |driver|
350
+ %w(mysql jdbc_mysql postgresql oracle mssql).each do |driver|
257
351
  Rake::Task["spec:#{driver}"].invoke
258
352
  end
259
353
  end