mondrian-olap 0.5.0 → 0.6.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
  SHA1:
3
- metadata.gz: a82185c2c1e818166ad00f6a79629772eda89fd6
4
- data.tar.gz: 48189b91d855f7dc3df6842d91360068285be951
3
+ metadata.gz: 33377438a5e2533d61b3304824a4e0aefe545f68
4
+ data.tar.gz: 13ef2ecd466795a07f43252231e4e7ad586c1e45
5
5
  SHA512:
6
- metadata.gz: d11c3fb9718d6a81be7f534c1b96a6cf731b64019a947a01bbfb58e3a2d52453bd334c5f083ef05981093657f66b3b4572f64748ae0aa4382f4c6a03c445aa9f
7
- data.tar.gz: 5f588afd736a0e8c62f05b5a9d56aa75fe181e46373d4025d85522532b8371a3fb439e3d000339ed70ad61d0f8c99ce37e17b9ddc693cfe44a4884ff557c375f
6
+ metadata.gz: c0ac6bc10f6ed6b4725d0991131402735e50c9c4cbc3de016a8714c7ceca5ce420ce9b5090fe006ae5495f0e8add0cf4f4cbb773b2f3da35767481e60b04a7d4
7
+ data.tar.gz: b7a47e4872dd58434b05e8d07b99d06d73d1ef023be953b4be00a5de2bd6c18db6e943496cecf1b3cad0fab60a5e3850b1084b7e31896533df3d1e6f2112d03c
@@ -1,3 +1,18 @@
1
+ ### 0.6.0 / 2014-11-10
2
+
3
+ * New features
4
+ * upgraded to latest Mondrian 3.8.0 version
5
+ * connection with generic JDBC driver using jdbc_driver and jdbc_url parameters
6
+ * added hierarchy and parent attributes for calculated member schema definition element
7
+ * added visible attribute for cube, dimension, virtual_cube_dimension, hierarchy and level schema definition elements
8
+ * added query builder generate method
9
+ * added schema parameters and query execution with parameters
10
+ * updated specs to pass on Java 8
11
+ * Improvements
12
+ * set defaultRowPrefetch property for Oracle connection
13
+ * Bug fixes
14
+ * fixed result drill_through method with just all members selection
15
+
1
16
  ### 0.5.0 / 2013-11-29
2
17
 
3
18
  * New features
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2010-2013 Raimonds Simanovskis
3
+ Copyright (c) 2010-2014 Raimonds Simanovskis
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -12,7 +12,7 @@ One of the most popular open-source OLAP engines is [Mondrian](http://mondrian.p
12
12
 
13
13
  mondrian-olap is JRuby gem which includes Mondrian OLAP engine and provides Ruby DSL for creating OLAP schemas on top of relational database schemas and provides MDX query language and query builder Ruby methods for making analytical queries.
14
14
 
15
- mondrian-olap is used in [eazyBI data analysis and reporting web application](https://eazybi.com). [eazyBI remote setup](https://eazybi.com/help/remote-setup) can be used to create easy-to-use web based reports and dashboards on top of mondrian-olap based backend database. There is also [mondrian-olap demo Rails application for trying MDX queries](https://github.com/rsim/mondrian_demo).
15
+ mondrian-olap is used in [eazyBI data analysis and reporting web application](https://eazybi.com). [Private eazyBI](https://eazybi.com/help/private-eazybi) can be used to create easy-to-use web based reports and dashboards on top of mondrian-olap based backend database. There is also [mondrian-olap demo Rails application for trying MDX queries](https://github.com/rsim/mondrian_demo).
16
16
 
17
17
  USAGE
18
18
  -----
@@ -56,42 +56,42 @@ require "mondrian-olap"
56
56
  schema = Mondrian::OLAP::Schema.define do
57
57
  cube 'Sales' do
58
58
  table 'sales'
59
- dimension 'Customers', :foreign_key => 'customer_id' do
60
- hierarchy :has_all => true, :all_member_name => 'All Customers', :primary_key => 'id' do
59
+ dimension 'Customers', foreign_key: 'customer_id' do
60
+ hierarchy has_all: true, all_member_name: 'All Customers', primary_key: 'id' do
61
61
  table 'customers'
62
- level 'Country', :column => 'country', :unique_members => true
63
- level 'State Province', :column => 'state_province', :unique_members => true
64
- level 'City', :column => 'city', :unique_members => false
65
- level 'Name', :column => 'fullname', :unique_members => true
62
+ level 'Country', column: 'country', unique_members: true
63
+ level 'State Province', column: 'state_province', unique_members: true
64
+ level 'City', column: 'city', unique_members: false
65
+ level 'Name', column: 'fullname', unique_members: true
66
66
  end
67
67
  end
68
- dimension 'Products', :foreign_key => 'product_id' do
69
- hierarchy :has_all => true, :all_member_name => 'All Products',
70
- :primary_key => 'id', :primary_key_table => 'products' do
71
- join :left_key => 'product_class_id', :right_key => 'id' do
68
+ dimension 'Products', foreign_key: 'product_id' do
69
+ hierarchy has_all: true, all_member_name: 'All Products',
70
+ primary_key: 'id', primary_key_table: 'products' do
71
+ join left_key: 'product_class_id', right_key: 'id' do
72
72
  table 'products'
73
73
  table 'product_classes'
74
74
  end
75
- level 'Product Family', :table => 'product_classes', :column => 'product_family', :unique_members => true
76
- level 'Brand Name', :table => 'products', :column => 'brand_name', :unique_members => false
77
- level 'Product Name', :table => 'products', :column => 'product_name', :unique_members => true
75
+ level 'Product Family', table: 'product_classes', column: 'product_family', unique_members: true
76
+ level 'Brand Name', table: 'products', column: 'brand_name', unique_members: false
77
+ level 'Product Name', table: 'products', column: 'product_name', unique_members: true
78
78
  end
79
79
  end
80
- dimension 'Time', :foreign_key => 'time_id', :type => 'TimeDimension' do
81
- hierarchy :has_all => false, :primary_key => 'id' do
80
+ dimension 'Time', foreign_key: 'time_id', type: 'TimeDimension' do
81
+ hierarchy has_all: false, primary_key: 'id' do
82
82
  table 'time'
83
- level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true, :level_type => 'TimeYears'
84
- level 'Quarter', :column => 'quarter', :unique_members => false, :level_type => 'TimeQuarters'
85
- level 'Month', :column => 'month_of_year', :type => 'Numeric', :unique_members => false, :level_type => 'TimeMonths'
83
+ level 'Year', column: 'the_year', type: 'Numeric', unique_members: true, level_type: 'TimeYears'
84
+ level 'Quarter', column: 'quarter', unique_members: false, level_type: 'TimeQuarters'
85
+ level 'Month', column: 'month_of_year', type: 'Numeric', unique_members: false, level_type: 'TimeMonths'
86
86
  end
87
- hierarchy 'Weekly', :has_all => false, :primary_key => 'id' do
87
+ hierarchy 'Weekly', has_all: false, primary_key: 'id' do
88
88
  table 'time'
89
- level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true, :level_type => 'TimeYears'
90
- level 'Week', :column => 'week_of_year', :type => 'Numeric', :unique_members => false, :level_type => 'TimeWeeks'
89
+ level 'Year', column: 'the_year', type: 'Numeric', unique_members: true, level_type: 'TimeYears'
90
+ level 'Week', column: 'week_of_year', type: 'Numeric', unique_members: false, level_type: 'TimeWeeks'
91
91
  end
92
92
  end
93
- measure 'Unit Sales', :column => 'unit_sales', :aggregator => 'sum'
94
- measure 'Store Sales', :column => 'store_sales', :aggregator => 'sum'
93
+ measure 'Unit Sales', column: 'unit_sales', aggregator: 'sum'
94
+ measure 'Store Sales', column: 'store_sales', aggregator: 'sum'
95
95
  end
96
96
  end
97
97
  ```
@@ -104,12 +104,12 @@ When schema is defined it is necessary to establish OLAP connection to database.
104
104
  require "jdbc/mysql"
105
105
 
106
106
  olap = Mondrian::OLAP::Connection.create(
107
- :driver => 'mysql',
108
- :host => 'localhost,
109
- :database => 'mondrian_test',
110
- :username => 'mondrian_user',
111
- :password => 'secret',
112
- :schema => schema
107
+ driver: 'mysql',
108
+ host: 'localhost,
109
+ database: 'mondrian_test',
110
+ username: 'mondrian_user',
111
+ password: 'secret',
112
+ schema: schema
113
113
  )
114
114
  ```
115
115
 
@@ -171,7 +171,7 @@ Here is example of more complex query "Get sales amount and profit % of top 50 p
171
171
  olap.from('Sales').
172
172
  with_member('[Measures].[ProfitPct]').
173
173
  as('Val((Measures.[Store Sales] - Measures.[Store Cost]) / Measures.[Store Sales])',
174
- :format_string => 'Percent').
174
+ format_string: 'Percent').
175
175
  columns('[Measures].[Store Sales]', '[Measures].[ProfitPct]').
176
176
  rows('[Products].children').crossjoin('[Customers].[Canada]', '[Customers].[USA]').
177
177
  top_count(50, '[Measures].[Store Sales]').
@@ -251,13 +251,13 @@ subset of measures and dimension members. Here is example of data access role de
251
251
  schema = Mondrian::OLAP::Schema.define do
252
252
  # ... cube definitions ...
253
253
  role 'California manager' do
254
- schema_grant :access => 'none' do
255
- cube_grant :cube => 'Sales', :access => 'all' do
256
- dimension_grant :dimension => '[Measures]', :access => 'all'
257
- hierarchy_grant :hierarchy => '[Customers]', :access => 'custom',
258
- :top_level => '[Customers].[State Province]', :bottom_level => '[Customers].[City]' do
259
- member_grant :member => '[Customers].[USA].[CA]', :access => 'all'
260
- member_grant :member => '[Customers].[USA].[CA].[Los Angeles]', :access => 'none'
254
+ schema_grant access: 'none' do
255
+ cube_grant cube: 'Sales', access: 'all' do
256
+ dimension_grant dimension: '[Measures]', access: 'all'
257
+ hierarchy_grant hierarchy: '[Customers]', access: 'custom',
258
+ top_level: '[Customers].[State Province]', bottom_level: '[Customers].[City]' do
259
+ member_grant member: '[Customers].[USA].[CA]', access: 'all'
260
+ member_grant member: '[Customers].[USA].[CA].[Los Angeles]', access: 'none'
261
261
  end
262
262
  end
263
263
  end
@@ -270,9 +270,9 @@ See more examples of data access roles in `spec/connection_role_spec.rb`.
270
270
  REQUIREMENTS
271
271
  ------------
272
272
 
273
- mondrian-olap gem is compatible with JRuby versions 1.6 and 1.7 and Java 6 and 7 VM. mondrian-olap works only with JRuby and not with other Ruby implementations as it includes Mondrian OLAP Java libraries.
273
+ mondrian-olap gem is compatible with JRuby version 1.7 and Java 6, 7 or 8 VM. mondrian-olap works only with JRuby and not with other Ruby implementations as it includes Mondrian OLAP Java libraries.
274
274
 
275
- mondrian-olap currently supports MySQL, PostgreSQL, Oracle, LucidDB and Microsoft SQL Server databases. When using MySQL, PostgreSQL or LucidDB databases then install jdbc-mysql, jdbc-postgres or jdbc-luciddb gem and require "jdbc/mysql", "jdbc/postgres" or "jdbc/luciddb" to load the corresponding JDBC database driver. When using Oracle then include Oracle JDBC driver (`ojdbc6.jar` for Java 6) in `CLASSPATH` or copy to `JRUBY_HOME/lib` or require it in application manually. When using SQL Server you can choose between the jTDS or Microsoft JDBC drivers. If you use jTDS require "jdbc/jtds". If you use the Microsoft JDBC driver include `sqljdbc.jar` or `sqljdbc4.jar` in `CLASSPATH` or copy to `JRUBY_HOME/lib` or require it in application manually.
275
+ mondrian-olap supports MySQL, PostgreSQL, Oracle, LucidDB and Microsoft SQL Server databases as well as other databases that are supported by Mondrian OLAP engine (using jdbc_driver and jdbc_url connection parameters). When using MySQL, PostgreSQL or LucidDB databases then install jdbc-mysql, jdbc-postgres or jdbc-luciddb gem and require "jdbc/mysql", "jdbc/postgres" or "jdbc/luciddb" to load the corresponding JDBC database driver. When using Oracle then include Oracle JDBC driver (`ojdbc6.jar` for Java 6) in `CLASSPATH` or copy to `JRUBY_HOME/lib` or require it in application manually. When using SQL Server you can choose between the jTDS or Microsoft JDBC drivers. If you use jTDS require "jdbc/jtds". If you use the Microsoft JDBC driver include `sqljdbc.jar` or `sqljdbc4.jar` in `CLASSPATH` or copy to `JRUBY_HOME/lib` or require it in application manually.
276
276
 
277
277
  INSTALL
278
278
  -------
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.6.0
@@ -7,7 +7,7 @@ module Mondrian
7
7
  connection
8
8
  end
9
9
 
10
- attr_reader :raw_connection, :raw_catalog, :raw_schema
10
+ attr_reader :raw_connection, :raw_catalog, :raw_schema, :raw_schema_reader
11
11
 
12
12
  def initialize(params={})
13
13
  @params = params
@@ -29,6 +29,13 @@ module Mondrian
29
29
  props.setProperty('JdbcUser', @params[:username]) if @params[:username]
30
30
  props.setProperty('JdbcPassword', @params[:password]) if @params[:password]
31
31
 
32
+ # on Oracle increase default row prefetch size
33
+ # as default 10 is very low and slows down loading of all dimension members
34
+ if @driver == 'oracle'
35
+ prefetch_rows = @params[:prefetch_rows] || 100
36
+ props.setProperty("jdbc.defaultRowPrefetch", prefetch_rows.to_s)
37
+ end
38
+
32
39
  conn_string = connection_string
33
40
 
34
41
  # latest Mondrian version added ClassResolver which uses current thread class loader to load some classes
@@ -47,6 +54,7 @@ module Mondrian
47
54
  @raw_catalog = @raw_connection.getOlapCatalog
48
55
  # currently it is assumed that there is just one schema per connection catalog
49
56
  @raw_schema = @raw_catalog.getSchemas.first
57
+ @raw_schema_reader = @raw_connection.getMondrianConnection.getSchemaReader
50
58
  @connected = true
51
59
  true
52
60
  end
@@ -63,13 +71,21 @@ module Mondrian
63
71
  true
64
72
  end
65
73
 
66
- def execute(query_string)
74
+ def execute(query_string, parameters = {})
67
75
  Error.wrap_native_exception do
68
76
  statement = @raw_connection.prepareOlapStatement(query_string)
77
+ set_statement_parameters(statement, parameters)
69
78
  Result.new(self, statement.executeQuery())
70
79
  end
71
80
  end
72
81
 
82
+ # access mondrian.olap.Parameter object
83
+ def mondrian_parameter(parameter_name)
84
+ Error.wrap_native_exception do
85
+ @raw_schema_reader.getParameter(parameter_name)
86
+ end
87
+ end
88
+
73
89
  def execute_drill_through(query_string)
74
90
  Error.wrap_native_exception do
75
91
  statement = @raw_connection.createStatement
@@ -195,6 +211,14 @@ module Mondrian
195
211
  pool.close if pool && !pool.isClosed
196
212
  end
197
213
 
214
+ # unregister MBean
215
+ mbs = Java::JavaLangManagement::ManagementFactory.getPlatformMBeanServer
216
+ mbean_name = Java::JavaxManagement::ObjectName.new("mondrian.server:type=Server-#{static_mondrian_server.getId}")
217
+ begin
218
+ mbs.unregisterMBean(mbean_name)
219
+ rescue Java::JavaxManagement::InstanceNotFoundException
220
+ end
221
+
198
222
  true
199
223
  end
200
224
 
@@ -255,6 +279,8 @@ module Mondrian
255
279
  uri << ";applicationName=#{@params[:application_name]}" if @params[:application_name]
256
280
  uri << ";instanceName=#{@params[:instance_name]}" if @params[:instance_name]
257
281
  uri
282
+ when 'jdbc'
283
+ @params[:jdbc_url] or raise ArgumentError, 'missing jdbc_url parameter'
258
284
  else
259
285
  raise ArgumentError, 'unknown JDBC driver'
260
286
  end
@@ -274,6 +300,8 @@ module Mondrian
274
300
  'net.sourceforge.jtds.jdbc.Driver'
275
301
  when 'sqlserver'
276
302
  'com.microsoft.sqlserver.jdbc.SQLServerDriver'
303
+ when 'jdbc'
304
+ @params[:jdbc_driver] or raise ArgumentError, 'missing jdbc_driver parameter'
277
305
  else
278
306
  raise ArgumentError, 'unknown JDBC driver'
279
307
  end
@@ -301,6 +329,25 @@ module Mondrian
301
329
  "'#{string.gsub("'","''")}'"
302
330
  end
303
331
 
332
+ def set_statement_parameters(statement, parameters)
333
+ if parameters && !parameters.empty?
334
+ # define addtional parameters which can be accessed from user defined functions
335
+ if parameters[:define_parameters]
336
+ parameters = parameters.dup
337
+ define_parameters = parameters.delete(:define_parameters)
338
+ query_validator = statement.getQuery.createValidator
339
+ define_parameters.each do |dp_name, dp_value|
340
+ dp_type_class = dp_value.is_a?(Numeric) ? Java::MondrianOlapType::NumericType : Java::MondrianOlapType::StringType
341
+ query_validator.createOrLookupParam(true, dp_name, dp_type_class.new, nil, nil)
342
+ parameters[dp_name] = dp_value
343
+ end
344
+ end
345
+ parameters.each do |parameter_name, value|
346
+ statement.getQuery.setParameter(parameter_name, value)
347
+ end
348
+ end
349
+ end
350
+
304
351
  end
305
352
  end
306
353
  end
@@ -46,6 +46,10 @@ module Mondrian
46
46
  annotations_for(@raw_cube)
47
47
  end
48
48
 
49
+ def visible?
50
+ @raw_cube.isVisible
51
+ end
52
+
49
53
  def dimensions
50
54
  @dimenstions ||= @raw_cube.getDimensions.map{|d| Dimension.new(self, d)}
51
55
  end
@@ -132,6 +136,10 @@ module Mondrian
132
136
  annotations_for(@raw_dimension)
133
137
  end
134
138
 
139
+ def visible?
140
+ @raw_dimension.isVisible
141
+ end
142
+
135
143
  end
136
144
 
137
145
  class Hierarchy
@@ -207,6 +215,10 @@ module Mondrian
207
215
  annotations_for(@raw_hierarchy)
208
216
  end
209
217
 
218
+ def visible?
219
+ @raw_hierarchy.isVisible
220
+ end
221
+
210
222
  end
211
223
 
212
224
  class Level
@@ -260,6 +272,10 @@ module Mondrian
260
272
  annotations_for(@raw_level)
261
273
  end
262
274
 
275
+ def visible?
276
+ @raw_level.isVisible
277
+ end
278
+
263
279
  end
264
280
 
265
281
  class Member
@@ -44,7 +44,7 @@ module Mondrian
44
44
  bt = @native_error.backtrace
45
45
  if @root_cause
46
46
  root_cause_bt = Array(@root_cause.backtrace)
47
- root_cause_bt[0,5].reverse.each do |bt_line|
47
+ root_cause_bt[0,10].reverse.each do |bt_line|
48
48
  bt.unshift "root cause: #{bt_line}"
49
49
  end
50
50
  bt.unshift "root cause: #{@root_cause.java_class.name}: #{@root_cause.message.chomp}"
@@ -47,7 +47,7 @@ module Mondrian
47
47
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
48
48
  def #{method}(*axis_members)
49
49
  raise ArgumentError, "cannot use #{method} method before axis or with_set method" unless @current_set
50
- raise ArgumentError, "specify list of members for #{method} method" if axis_members.empty?
50
+ raise ArgumentError, "specify set of members for #{method} method" if axis_members.empty?
51
51
  members = axis_members.length == 1 && axis_members[0].is_a?(Array) ? axis_members[0] : axis_members
52
52
  @current_set.replace [:#{method}, @current_set.clone, members]
53
53
  self
@@ -57,7 +57,7 @@ module Mondrian
57
57
 
58
58
  def except(*axis_members)
59
59
  raise ArgumentError, "cannot use except method before axis or with_set method" unless @current_set
60
- raise ArgumentError, "specify list of members for except method" if axis_members.empty?
60
+ raise ArgumentError, "specify set of members for except method" if axis_members.empty?
61
61
  members = axis_members.length == 1 && axis_members[0].is_a?(Array) ? axis_members[0] : axis_members
62
62
  if [:crossjoin, :nonempty_crossjoin].include? @current_set[0]
63
63
  @current_set[2] = [:except, @current_set[2], members]
@@ -87,6 +87,19 @@ module Mondrian
87
87
  self
88
88
  end
89
89
 
90
+ def generate(*axis_members)
91
+ raise ArgumentError, "cannot use generate method before axis or with_set method" unless @current_set
92
+ all = if axis_members.last == :all
93
+ axis_members.pop
94
+ 'ALL'
95
+ end
96
+ raise ArgumentError, "specify set of members for generate method" if axis_members.empty?
97
+ members = axis_members.length == 1 && axis_members[0].is_a?(Array) ? axis_members[0] : axis_members
98
+ @current_set.replace [:generate, @current_set.clone, members]
99
+ @current_set << all if all
100
+ self
101
+ end
102
+
90
103
  VALID_ORDERS = ['ASC', 'BASC', 'DESC', 'BDESC']
91
104
 
92
105
  def order(expression, direction)
@@ -216,9 +229,9 @@ module Mondrian
216
229
  mdx
217
230
  end
218
231
 
219
- def execute
232
+ def execute(parameters = {})
220
233
  Error.wrap_native_exception do
221
- @connection.execute to_mdx
234
+ @connection.execute to_mdx, parameters
222
235
  end
223
236
  end
224
237
 
@@ -299,6 +312,8 @@ module Mondrian
299
312
  when :filter
300
313
  as_alias = members[3] ? " AS #{members[3]}" : nil
301
314
  "FILTER(#{members_to_mdx(members[1])}#{as_alias}, #{members[2]})"
315
+ when :generate
316
+ "GENERATE(#{members_to_mdx(members[1])}, #{members_to_mdx(members[2])}#{members[3] && ", #{members[3]}"})"
302
317
  when :order
303
318
  "ORDER(#{members_to_mdx(members[1])}, #{expression_to_mdx(members[2])}, #{members[3]})"
304
319
  when :top_count, :bottom_count
@@ -8,6 +8,8 @@ module Mondrian
8
8
  @raw_cell_set = raw_cell_set
9
9
  end
10
10
 
11
+ attr_reader :raw_cell_set
12
+
11
13
  def axes_count
12
14
  axes.length
13
15
  end
@@ -248,6 +250,10 @@ module Mondrian
248
250
  if sql_non_extended =~ /\Aselect (.*) from (.*) where (.*) order by (.*)\Z/
249
251
  non_extended_from = $2
250
252
  non_extended_where = $3
253
+ # if drill through total measure with just all members selection
254
+ elsif sql_non_extended =~ /\Aselect (.*) from (.*)\Z/
255
+ non_extended_from = $2
256
+ non_extended_where = "1 = 1" # dummy true condition
251
257
  else
252
258
  raise ArgumentError, "cannot parse drill through SQL: #{sql_non_extended}"
253
259
  end
@@ -50,10 +50,12 @@ module Mondrian
50
50
  public
51
51
 
52
52
  attributes :name, :description, :measures_caption
53
- elements :annotations, :dimension, :cube, :virtual_cube, :role, :user_defined_function
53
+ elements :annotations, :parameter, :dimension, :cube, :virtual_cube, :role, :user_defined_function
54
54
 
55
55
  class Cube < SchemaElement
56
56
  attributes :name, :description, :caption,
57
+ # Whether this cube is visible in the user-interface. Default true.
58
+ :visible,
57
59
  # The name of the measure that would be taken as the default measure of the cube.
58
60
  :default_measure,
59
61
  # Should the Fact table data for this Cube be cached by Mondrian or not.
@@ -84,6 +86,8 @@ module Mondrian
84
86
 
85
87
  class Dimension < SchemaElement
86
88
  attributes :name, :description, :caption,
89
+ # Whether this dimension is visible in the user-interface. Default true.
90
+ :visible,
87
91
  # The dimension's type may be one of "Standard" or "Time".
88
92
  # A time dimension will allow the use of the MDX time functions (WTD, YTD, QTD, etc.).
89
93
  # Use a standard dimension if the dimension is not a time-related dimension.
@@ -121,6 +125,8 @@ module Mondrian
121
125
 
122
126
  class Hierarchy < SchemaElement
123
127
  attributes :name, :description, :caption,
128
+ # Whether this hierarchy is visible in the user-interface. Default true.
129
+ :visible,
124
130
  # Whether this hierarchy has an 'all' member.
125
131
  :has_all,
126
132
  # Name of the 'all' member. If this attribute is not specified,
@@ -137,6 +143,8 @@ module Mondrian
137
143
  # The name of the table which contains primary_key.
138
144
  # If the hierarchy has only one table, defaults to that; it is required.
139
145
  :primary_key_table,
146
+ #
147
+ :default_member,
140
148
  # Should be set to the level (if such a level exists) at which depth it is known
141
149
  # that all members have entirely unique rows, allowing SQL GROUP BY clauses to be completely eliminated from the query.
142
150
  :unique_key_level_name
@@ -160,6 +168,8 @@ module Mondrian
160
168
 
161
169
  class Level < SchemaElement
162
170
  attributes :name, :description, :caption,
171
+ # Whether this level is visible in the user-interface. Default true.
172
+ :visible,
163
173
  # The name of the table that the column comes from.
164
174
  # If this hierarchy is based upon just one table, defaults to the name of that table;
165
175
  # otherwise, it is required.
@@ -187,6 +197,12 @@ module Mondrian
187
197
  # for example, "DATE '2006-06-01'".
188
198
  # Default value: 'String'
189
199
  :type,
200
+ # Indicates the Java type that Mondrian uses to store this level's key column.
201
+ # It also determines the JDBC method that Mondrian will call to retrieve the column;
202
+ # for example, if the Java type is 'int', Mondrian will call 'ResultSet.getInt(int)'.
203
+ # Usually this attribute is not needed, because Mondrian can choose a sensible type based on the type of the database column.
204
+ # Allowable values are: 'int', 'long', 'Object', 'String'.
205
+ :internal_type,
190
206
  # Whether members are unique across all parents.
191
207
  # For example, zipcodes are unique across all states.
192
208
  # The first level's members are always unique.
@@ -288,8 +304,12 @@ module Mondrian
288
304
 
289
305
  class CalculatedMember < SchemaElement
290
306
  attributes :name, :description, :caption,
291
- # Name of the dimension which this member belongs to.
307
+ # Name of the dimension which this member belongs to. Cannot be used if :hieararchy is specified.
292
308
  :dimension,
309
+ # Full unique name of the hierarchy that this member belongs to.
310
+ :hierarchy,
311
+ # Fully-qualified name of the parent member. If not specified, the member will be at the lowest level (besides the 'all' level) in the hierarchy.
312
+ :parent,
293
313
  # Format string with which to format cells of this measure. For more details, see the mondrian.util.Format class.
294
314
  :format_string,
295
315
  # Whether this member is visible in the user-interface. Default true.
@@ -312,6 +332,8 @@ module Mondrian
312
332
 
313
333
  class VirtualCube < SchemaElement
314
334
  attributes :name, :description, :caption,
335
+ # Whether this cube is visible in the user-interface. Default true.
336
+ :visible,
315
337
  # The name of the measure that would be taken as the default measure of the cube.
316
338
  :default_measure,
317
339
  # Whether element is enabled - if true, then the VirtualCube is realized otherwise it is ignored.
@@ -322,7 +344,9 @@ module Mondrian
322
344
  class VirtualCubeDimension < SchemaElement
323
345
  attributes :name,
324
346
  # Name of the cube which the dimension belongs to, or unspecified if the dimension is shared
325
- :cube_name
347
+ :cube_name,
348
+ # Whether this dimension is visible in the user-interface. Default true.
349
+ :visible
326
350
  end
327
351
 
328
352
  class VirtualCubeMeasure < SchemaElement
@@ -473,6 +497,18 @@ module Mondrian
473
497
  class Annotation < SchemaElement
474
498
  content :text
475
499
  end
500
+
501
+ class Parameter < SchemaElement
502
+ attributes :name, :description,
503
+ # Indicates the type of this parameter: String, Numeric, Integer, Boolean, Date, Time, Timestamp, or Member.
504
+ :type,
505
+ # If false, statement cannot change the value of this parameter; the parameter becomes effectively constant
506
+ # (provided that its default value expression always returns the same value). Default is true.
507
+ :modifiable,
508
+ # Expression for the default value of this parameter.
509
+ :default_value
510
+ end
511
+
476
512
  end
477
513
  end
478
514
  end
@@ -45,7 +45,7 @@ describe "Connection" do
45
45
  schema_field = @olap.raw_schema.getClass.getDeclaredField("schema")
46
46
  schema_field.setAccessible(true)
47
47
  private_schema = schema_field.get(@olap.raw_schema)
48
- private_schema.getDialect.java_class.name.should == case MONDRIAN_DRIVER
48
+ private_schema.getDialect.java_class.name.should == case MONDRIAN_DRIVER.split('_').last
49
49
  when 'mysql' then 'mondrian.spi.impl.MySqlDialect'
50
50
  when 'postgresql' then 'mondrian.spi.impl.PostgreSqlDialect'
51
51
  when 'oracle' then 'mondrian.spi.impl.OracleDialect'
@@ -10,17 +10,21 @@ describe "Cube" do
10
10
  caption 'Sales caption'
11
11
  annotations :foo => 'bar'
12
12
  table 'sales'
13
+ visible true
13
14
  dimension 'Gender', :foreign_key => 'customer_id' do
14
15
  description 'Gender description'
15
16
  caption 'Gender caption'
17
+ visible true
16
18
  hierarchy :has_all => true, :primary_key => 'id' do
17
19
  description 'Gender hierarchy description'
18
20
  caption 'Gender hierarchy caption'
19
21
  all_member_name 'All Genders'
20
22
  all_member_caption 'All Genders caption'
21
23
  table 'customers'
24
+ visible true
22
25
  level 'Gender', :column => 'gender', :unique_members => true,
23
26
  :description => 'Gender level description', :caption => 'Gender level caption' do
27
+ visible true
24
28
  # Dimension values SQL generated by caption_expression fails on PostgreSQL and MS SQL
25
29
  if %w(mysql oracle).include?(MONDRIAN_DRIVER)
26
30
  caption_expression do
@@ -56,6 +60,10 @@ describe "Cube" do
56
60
  level 'Week', :column => 'weak_of_year', :type => 'Numeric', :unique_members => false, :level_type => 'TimeWeeks'
57
61
  end
58
62
  end
63
+ calculated_member 'Last week' do
64
+ hierarchy '[Time.Weekly]'
65
+ formula 'Tail([Time.Weekly].[Week].Members).Item(0)'
66
+ end
59
67
  measure 'Unit Sales', :column => 'unit_sales', :aggregator => 'sum', :annotations => {:foo => 'bar'}
60
68
  measure 'Store Sales', :column => 'store_sales', :aggregator => 'sum'
61
69
  measure 'Store Cost', :column => 'store_cost', :aggregator => 'sum', :visible => false
@@ -92,6 +100,10 @@ describe "Cube" do
92
100
  @olap.cube('Sales').annotations.should == {'foo' => 'bar'}
93
101
  end
94
102
 
103
+ it "should be visible" do
104
+ @olap.cube('Sales').should be_visible
105
+ end
106
+
95
107
  describe "dimensions" do
96
108
  before(:all) do
97
109
  @cube = @olap.cube('Sales')
@@ -147,6 +159,11 @@ describe "Cube" do
147
159
  it "should get dimension empty annotations" do
148
160
  @cube.dimension('Gender').annotations.should == {}
149
161
  end
162
+
163
+ it "should be visible" do
164
+ @cube.dimension('Gender').should be_visible
165
+ end
166
+
150
167
  end
151
168
 
152
169
  describe "dimension hierarchies" do
@@ -208,6 +225,11 @@ describe "Cube" do
208
225
  it "should get hierarchy empty annotations" do
209
226
  @cube.dimension('Gender').hierarchy.annotations.should == {}
210
227
  end
228
+
229
+ it "should be visible" do
230
+ @cube.dimension('Gender').hierarchies.first.should be_visible
231
+ end
232
+
211
233
  end
212
234
 
213
235
  describe "hierarchy values" do
@@ -288,6 +310,10 @@ describe "Cube" do
288
310
  @cube.dimension('Gender').hierarchy.level('Gender').annotations.should == {}
289
311
  end
290
312
 
313
+ it "should be visible" do
314
+ @cube.dimension('Gender').hierarchy.level('Gender').should be_visible
315
+ end
316
+
291
317
  end
292
318
 
293
319
  describe "members" do
@@ -356,6 +382,10 @@ describe "Cube" do
356
382
  @cube.member('[Customers].[Non-USA]').should be_calculated
357
383
  end
358
384
 
385
+ it "should be calculated when member is calculated in non-default hierarchy" do
386
+ @cube.member('[Time.Weekly].[Last week]').should be_calculated
387
+ end
388
+
359
389
  it "should not be calculated in query when calculated member defined in schema" do
360
390
  @cube.member('[Customers].[Non-USA]').should_not be_calculated_in_query
361
391
  end
@@ -384,11 +414,11 @@ describe "Cube" do
384
414
  @cube.member('[Time].[2011]').dimension_type.should == :time
385
415
  end
386
416
 
387
- it "should be visble when member is visible" do
417
+ it "should be visible when member is visible" do
388
418
  @cube.member('[Measures].[Store Sales]').should be_visible
389
419
  end
390
420
 
391
- it "should not be visble when member is not visible" do
421
+ it "should not be visible when member is not visible" do
392
422
  @cube.member('[Measures].[Store Cost]').should_not be_visible
393
423
  end
394
424
 
@@ -1,8 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe "Query" do
4
- def quote_table_name(name)
5
- ActiveRecord::Base.connection.quote_table_name(name)
4
+ def qt(name)
5
+ ActiveRecord::Base.connection.quote_table_name(name.to_s)
6
6
  end
7
7
 
8
8
  before(:all) do
@@ -21,9 +21,9 @@ describe "Query" do
21
21
  FROM sales
22
22
  LEFT JOIN products ON sales.product_id = products.id
23
23
  LEFT JOIN product_classes ON products.product_class_id = product_classes.id
24
- LEFT JOIN #{quote_table_name('time')} ON sales.time_id = #{quote_table_name('time')}.id
24
+ LEFT JOIN #{qt :time} ON sales.time_id = #{qt :time}.id
25
25
  LEFT JOIN customers ON sales.customer_id = customers.id
26
- WHERE #{quote_table_name('time')}.the_year = 2010 AND #{quote_table_name('time')}.quarter = 'Q1'
26
+ WHERE #{qt :time}.the_year = 2010 AND #{qt :time}.quarter = 'Q1'
27
27
  AND customers.country = 'USA' AND customers.state_province = 'CA'
28
28
  GROUP BY product_classes.product_family
29
29
  ORDER BY product_classes.product_family
@@ -282,6 +282,18 @@ describe "Query" do
282
282
  end
283
283
  end
284
284
 
285
+ describe "generate" do
286
+ it "should generate new set" do
287
+ @query.rows('[Customers].[Country].Members').generate('[Customers].CurrentMember')
288
+ @query.rows.should == [:generate, ['[Customers].[Country].Members'], ['[Customers].CurrentMember']]
289
+ end
290
+
291
+ it "should generate new set with all option" do
292
+ @query.rows('[Customers].[Country].Members').generate('[Customers].CurrentMember', :all)
293
+ @query.rows.should == [:generate, ['[Customers].[Country].Members'], ['[Customers].CurrentMember'], 'ALL']
294
+ end
295
+ end
296
+
285
297
  describe "where" do
286
298
  it "should accept conditions" do
287
299
  @query.where('[Time].[2010].[Q1]', '[Customers].[USA].[CA]').should equal(@query)
@@ -605,6 +617,26 @@ describe "Query" do
605
617
  SQL
606
618
  end
607
619
 
620
+ it "should return query with generate" do
621
+ @query.columns('[Measures].[Unit Sales]', '[Measures].[Store Sales]').
622
+ rows('[Customers].[Country].Members').generate('[Customers].CurrentMember').
623
+ to_mdx.should be_like <<-SQL
624
+ SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS,
625
+ GENERATE([Customers].[Country].Members, [Customers].CurrentMember) ON ROWS
626
+ FROM [Sales]
627
+ SQL
628
+ end
629
+
630
+ it "should return query with generate all" do
631
+ @query.columns('[Measures].[Unit Sales]', '[Measures].[Store Sales]').
632
+ rows('[Customers].[Country].Members').generate('[Customers].CurrentMember', :all).
633
+ to_mdx.should be_like <<-SQL
634
+ SELECT {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS,
635
+ GENERATE([Customers].[Country].Members, [Customers].CurrentMember, ALL) ON ROWS
636
+ FROM [Sales]
637
+ SQL
638
+ end
639
+
608
640
  it "should return query including WITH MEMBER clause" do
609
641
  @query.
610
642
  with_member('[Measures].[ProfitPct]').
@@ -895,4 +927,50 @@ describe "Query" do
895
927
 
896
928
  end
897
929
 
930
+ describe "schema cache" do
931
+ before(:all) do
932
+ product_id = @sql.select_value("SELECT MIN(id) FROM products")
933
+ time_id = @sql.select_value("SELECT MIN(id) FROM #{qt :time}")
934
+ customer_id = @sql.select_value("SELECT MIN(id) FROM customers")
935
+ @condition = "product_id = #{product_id} AND time_id = #{time_id} AND customer_id = #{customer_id}"
936
+ # check expected initial value
937
+ @first_unit_sales = 1
938
+ @sql.select_value("SELECT unit_sales FROM sales WHERE #{@condition}").to_i.should == @first_unit_sales
939
+ end
940
+
941
+ after(:all) do
942
+ update_first_unit_sales(@first_unit_sales)
943
+ end
944
+
945
+ def create_olap_connection
946
+ @olap2.close if @olap2
947
+ @olap2 = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS_WITH_CATALOG)
948
+ end
949
+
950
+ def update_first_unit_sales(value)
951
+ @sql.update "UPDATE sales SET unit_sales = #{value} WHERE #{@condition}"
952
+ end
953
+
954
+ def query_unit_sales_value
955
+ @olap2.from('Sales').columns('[Measures].[Unit Sales]').execute.values.first
956
+ end
957
+
958
+ it "should flush schema cache" do
959
+ create_olap_connection
960
+ unit_sales = query_unit_sales_value
961
+
962
+ update_first_unit_sales(@first_unit_sales + 1)
963
+
964
+ # should still use previous value from cache
965
+ create_olap_connection
966
+ query_unit_sales_value.should == unit_sales
967
+
968
+ # should query new value from the database after flush schema cache
969
+ @olap2.flush_schema_cache
970
+ create_olap_connection
971
+ query_unit_sales_value.should == unit_sales + 1
972
+ end
973
+
974
+ end
975
+
898
976
  end
@@ -242,7 +242,7 @@ namespace :db do
242
242
  end
243
243
 
244
244
  namespace :spec do
245
- %w(mysql postgresql oracle luciddb mssql sqlserver).each do |driver|
245
+ %w(mysql jdbc_mysql postgresql oracle luciddb mssql sqlserver).each do |driver|
246
246
  desc "Run specs with #{driver} driver"
247
247
  task driver do
248
248
  ENV['MONDRIAN_DRIVER'] = driver
@@ -253,7 +253,7 @@ namespace :spec do
253
253
 
254
254
  desc "Run specs with all primary database drivers"
255
255
  task :all do
256
- %w(mysql postgresql oracle mssql).each do |driver|
256
+ %w(mysql jdbc_mysql postgresql oracle mssql).each do |driver|
257
257
  Rake::Task["spec:#{driver}"].invoke
258
258
  end
259
259
  end
@@ -549,6 +549,27 @@ describe "Schema definition" do
549
549
  XML
550
550
  end
551
551
 
552
+ it "should render XML with dimension and hierarchy" do
553
+ @schema.define do
554
+ cube 'Sales' do
555
+ calculated_member 'Current week' do
556
+ hierarchy '[Time.Weekly]'
557
+ formula '[Time.Weekly].[Week].CurrentDateMember'
558
+ end
559
+ end
560
+ end
561
+ @schema.to_xml.should be_like <<-XML
562
+ <?xml version="1.0" encoding="UTF-8"?>
563
+ <Schema name="default">
564
+ <Cube name="Sales">
565
+ <CalculatedMember hierarchy="[Time.Weekly]" name="Current week">
566
+ <Formula>[Time.Weekly].[Week].CurrentDateMember</Formula>
567
+ </CalculatedMember>
568
+ </Cube>
569
+ </Schema>
570
+ XML
571
+ end
572
+
552
573
  it "should render embedded cube XML defintion before additional calculated member to XML" do
553
574
  @schema.define do
554
575
  cube 'Sales' do
@@ -824,6 +845,8 @@ describe "Schema definition" do
824
845
  end
825
846
 
826
847
  describe "User defined functions and formatters in JavaScript" do
848
+ next pending "not supported by Mondrian in Java 8" if ENV_JAVA["java.version"] >= "1.8"
849
+
827
850
  before(:each) do
828
851
  @schema.define do
829
852
  cube 'Sales' do
@@ -957,6 +980,8 @@ describe "Schema definition" do
957
980
  end
958
981
 
959
982
  describe "User defined functions and formatters in CoffeeScript" do
983
+ next pending "not supported by Mondrian in Java 8" if ENV_JAVA["java.version"] >= "1.8"
984
+
960
985
  before(:each) do
961
986
  @schema.define do
962
987
  cube 'Sales' do
@@ -1373,6 +1398,136 @@ describe "Schema definition" do
1373
1398
  end
1374
1399
  end
1375
1400
 
1401
+ describe "Parameters" do
1402
+ before(:each) do
1403
+ @schema.define do
1404
+ parameter 'Current User', :type => 'String', :modifiable => true, :default_value => "'demo'"
1405
+ parameter 'Current User 1', :type => 'String', :modifiable => true, :default_value => "''"
1406
+ parameter 'Default User', :type => 'String', :modifiable => false, :default_value => "'default'"
1407
+ cube 'Sales' do
1408
+ table 'sales'
1409
+ measure 'Unit Sales', :column => 'unit_sales', :aggregator => 'sum'
1410
+ end
1411
+ user_defined_function 'ParameterValue' do
1412
+ ruby :shared do
1413
+ parameters :string
1414
+ returns :scalar
1415
+ syntax :function
1416
+ def call_with_evaluator(evaluator, parameter_name)
1417
+ parameter = evaluator.getQuery.getSchemaReader(false).getParameter(parameter_name)
1418
+ parameter && parameter.getValue
1419
+ end
1420
+ end
1421
+ end
1422
+ end
1423
+ @olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
1424
+ end
1425
+
1426
+ it "should render XML" do
1427
+ @schema.to_xml.should be_like <<-XML
1428
+ <?xml version="1.0" encoding="UTF-8"?>
1429
+ <Schema name="default">
1430
+ <Parameter defaultValue="'demo'" modifiable="true" name="Current User" type="String"/>
1431
+ <Parameter defaultValue="''" modifiable="true" name="Current User 1" type="String"/>
1432
+ <Parameter defaultValue="'default'" modifiable="false" name="Default User" type="String"/>
1433
+ <Cube name="Sales">
1434
+ <Table name="sales"/>
1435
+ <Measure aggregator="sum" column="unit_sales" name="Unit Sales"/>
1436
+ </Cube>
1437
+ <UserDefinedFunction className="rubyobj.Mondrian.OLAP.Schema.UserDefinedFunction.ParametervalueUdf" name="ParameterValue"/>
1438
+ </Schema>
1439
+ XML
1440
+ end
1441
+
1442
+ it "should get parameter definition from connection" do
1443
+ parameter = @olap.mondrian_parameter('Current User')
1444
+ parameter.should_not be_nil
1445
+ parameter.name.should == 'Current User'
1446
+ parameter.description.should be_nil
1447
+ parameter.should be_modifiable
1448
+ parameter.scope.to_s.should == 'Schema'
1449
+ parameter.type.to_s.should == 'STRING'
1450
+ end
1451
+
1452
+ it "should not get parameter definition with invalid name" do
1453
+ @olap.mondrian_parameter('Current User 2').should be_nil
1454
+ end
1455
+
1456
+ it "should get default parameter value with ParamRef" do
1457
+ result = @olap.from('Sales').
1458
+ with_member('[Measures].[Current User]').as("ParamRef('Current User')").
1459
+ columns('[Measures].[Current User]').execute
1460
+ result.values.should == ['demo']
1461
+ end
1462
+
1463
+ it "should execute query with schema parameter value and get value with ParamRef" do
1464
+ result = @olap.from('Sales').
1465
+ with_member('[Measures].[Current User]').as("ParamRef('Current User 1')").
1466
+ columns('[Measures].[Current User]').execute("Current User 1" => "test")
1467
+ result.values.should == ['test']
1468
+ end
1469
+
1470
+ it "should execute query with query parameter value and get value with Parameter" do
1471
+ result = @olap.from('Sales').
1472
+ with_member('[Measures].[Current User]').as("Parameter('Current User 2', String, 'demo2')").
1473
+ columns('[Measures].[Current User]').execute("Current User 2" => "test2")
1474
+ result.values.should == ['test2']
1475
+ end
1476
+
1477
+ # can be used in user defined functions
1478
+ it "should execute query with additional defined parameter string value" do
1479
+ result = @olap.from('Sales').
1480
+ with_member('[Measures].[Parameter]').as("ParameterValue('String Parameter')").
1481
+ columns('[Measures].[Parameter]').execute(:define_parameters => {"String Parameter" => "test"})
1482
+ result.values.should == ['test']
1483
+ end
1484
+
1485
+ it "should execute query with additional defined parameter integer value" do
1486
+ result = @olap.from('Sales').
1487
+ with_member('[Measures].[Parameter]').as("ParameterValue('Integer Parameter')").
1488
+ columns('[Measures].[Parameter]').execute(:define_parameters => {"Integer Parameter" => 123})
1489
+ result.values.should == [123]
1490
+ end
1491
+
1492
+ it "should execute query with additional defined parameter double value" do
1493
+ result = @olap.from('Sales').
1494
+ with_member('[Measures].[Parameter]').as("ParameterValue('Double Parameter')").
1495
+ columns('[Measures].[Parameter]').execute(:define_parameters => {"Double Parameter" => 123.456})
1496
+ result.values.should == [123.456]
1497
+ end
1498
+
1499
+ it "should execute query with additional defined parameter nil value" do
1500
+ result = @olap.from('Sales').
1501
+ with_member('[Measures].[Parameter]').as("ParameterValue('Nil Parameter')").
1502
+ columns('[Measures].[Parameter]').execute(:define_parameters => {"Nil Parameter" => nil})
1503
+ result.values.should == [nil]
1504
+ end
1505
+
1506
+ it "should fail if executing with invalid parameter name" do
1507
+ expect {
1508
+ @olap.from('Sales').
1509
+ with_member('[Measures].[Current User]').as("'dummy'").
1510
+ columns('[Measures].[Current User]').execute("Current User 2" => "test2")
1511
+ }.to raise_error {|e|
1512
+ e.should be_kind_of(Mondrian::OLAP::Error)
1513
+ e.message.should == "mondrian.olap.MondrianException: Mondrian Error:Unknown parameter 'Current User 2'"
1514
+ e.root_cause_message.should == "Unknown parameter 'Current User 2'"
1515
+ }
1516
+ end
1517
+
1518
+ it "should fail if executing with non-modifiable parameter" do
1519
+ expect {
1520
+ @olap.from('Sales').
1521
+ with_member('[Measures].[Current User]').as("'dummy'").
1522
+ columns('[Measures].[Current User]').execute("Default User" => "test")
1523
+ }.to raise_error {|e|
1524
+ e.should be_kind_of(Mondrian::OLAP::Error)
1525
+ e.message.should == "mondrian.olap.MondrianException: Mondrian Error:Parameter 'Default User' (defined at 'Schema' scope) is not modifiable"
1526
+ e.root_cause_message.should == "Parameter 'Default User' (defined at 'Schema' scope) is not modifiable"
1527
+ }
1528
+ end
1529
+ end
1530
+
1376
1531
  end
1377
1532
 
1378
1533
  describe "connection with schema" do
@@ -19,7 +19,7 @@ DATABASE_NAME = ENV["#{env_prefix}_DATABASE_NAME"] || ENV['DATABASE_NAME
19
19
  DATABASE_INSTANCE = ENV["#{env_prefix}_DATABASE_INSTANCE"] || ENV['DATABASE_INSTANCE']
20
20
 
21
21
  case MONDRIAN_DRIVER
22
- when 'mysql'
22
+ when 'mysql', 'jdbc_mysql'
23
23
  require 'jdbc/mysql'
24
24
  JDBC_DRIVER = 'com.mysql.jdbc.Driver'
25
25
  when 'postgresql'
@@ -75,15 +75,25 @@ end
75
75
 
76
76
  CATALOG_FILE = File.expand_path('../fixtures/MondrianTest.xml', __FILE__) unless defined?(CATALOG_FILE)
77
77
 
78
- CONNECTION_PARAMS = {
79
- # uncomment to test PostgreSQL SSL connection
80
- # :properties => {'ssl'=>'true','sslfactory'=>'org.postgresql.ssl.NonValidatingFactory'},
81
- :driver => MONDRIAN_DRIVER,
82
- :host => DATABASE_HOST,
83
- :database => DATABASE_NAME,
84
- :username => DATABASE_USER,
85
- :password => DATABASE_PASSWORD
86
- }
78
+ CONNECTION_PARAMS = if MONDRIAN_DRIVER =~ /^jdbc/
79
+ {
80
+ :driver => 'jdbc',
81
+ :jdbc_url => "jdbc:#{MONDRIAN_DRIVER.split('_').last}://#{DATABASE_HOST}/#{DATABASE_NAME}",
82
+ :jdbc_driver => JDBC_DRIVER,
83
+ :username => DATABASE_USER,
84
+ :password => DATABASE_PASSWORD
85
+ }
86
+ else
87
+ {
88
+ # uncomment to test PostgreSQL SSL connection
89
+ # :properties => {'ssl'=>'true','sslfactory'=>'org.postgresql.ssl.NonValidatingFactory'},
90
+ :driver => MONDRIAN_DRIVER,
91
+ :host => DATABASE_HOST,
92
+ :database => DATABASE_NAME,
93
+ :username => DATABASE_USER,
94
+ :password => DATABASE_PASSWORD
95
+ }
96
+ end
87
97
 
88
98
  case MONDRIAN_DRIVER
89
99
  when 'oracle'
@@ -126,6 +136,14 @@ when 'sqlserver'
126
136
  :password => CONNECTION_PARAMS[:password],
127
137
  :connection_alive_sql => 'SELECT 1'
128
138
  }
139
+ when /jdbc/
140
+ AR_CONNECTION_PARAMS = {
141
+ :adapter => 'jdbc',
142
+ :driver => JDBC_DRIVER,
143
+ :url => CONNECTION_PARAMS[:jdbc_url],
144
+ :username => CONNECTION_PARAMS[:username],
145
+ :password => CONNECTION_PARAMS[:password]
146
+ }
129
147
  else
130
148
  AR_CONNECTION_PARAMS = {
131
149
  # uncomment to test PostgreSQL SSL connection
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mondrian-olap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Raimonds Simanovskis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-29 00:00:00.000000000 Z
11
+ date: 2014-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -236,20 +236,21 @@ files:
236
236
  - VERSION
237
237
  - lib/mondrian-olap.rb
238
238
  - lib/mondrian/olap.rb
239
- - lib/mondrian/jars/commons-collections-3.2.jar
240
- - lib/mondrian/jars/commons-dbcp-1.2.1.jar
239
+ - lib/mondrian/jars/commons-collections-3.2.1.jar
240
+ - lib/mondrian/jars/commons-dbcp-1.4.jar
241
+ - lib/mondrian/jars/commons-io-2.2.jar
241
242
  - lib/mondrian/jars/commons-logging-1.1.1.jar
242
243
  - lib/mondrian/jars/commons-math-1.1.jar
243
- - lib/mondrian/jars/commons-pool-1.2.jar
244
- - lib/mondrian/jars/commons-vfs-1.0.jar
244
+ - lib/mondrian/jars/commons-pool-1.5.7.jar
245
+ - lib/mondrian/jars/commons-vfs-20100924-pentaho.jar
245
246
  - lib/mondrian/jars/eigenbase-properties-1.1.2.jar
246
247
  - lib/mondrian/jars/eigenbase-resgen-1.3.1.jar
247
248
  - lib/mondrian/jars/eigenbase-xom-1.3.1.jar
248
249
  - lib/mondrian/jars/javacup-10k.jar
249
- - lib/mondrian/jars/log4j-1.2.14.jar
250
+ - lib/mondrian/jars/log4j-1.2.17.jar
250
251
  - lib/mondrian/jars/log4j.properties
251
- - lib/mondrian/jars/mondrian.jar
252
- - lib/mondrian/jars/olap4j-1.0.1.539.jar
252
+ - lib/mondrian/jars/mondrian-3.8.0.0-209.jar
253
+ - lib/mondrian/jars/olap4j-1.2.0.jar
253
254
  - lib/mondrian/olap/connection.rb
254
255
  - lib/mondrian/olap/cube.rb
255
256
  - lib/mondrian/olap/error.rb