mondrian-olap 0.5.0 → 1.2.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.
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