sequel 3.39.0 → 3.40.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/CHANGELOG +30 -0
  2. data/README.rdoc +4 -3
  3. data/doc/active_record.rdoc +1 -1
  4. data/doc/opening_databases.rdoc +7 -0
  5. data/doc/release_notes/3.40.0.txt +73 -0
  6. data/lib/sequel/adapters/ado.rb +29 -3
  7. data/lib/sequel/adapters/ado/access.rb +334 -0
  8. data/lib/sequel/adapters/ado/mssql.rb +0 -6
  9. data/lib/sequel/adapters/cubrid.rb +143 -0
  10. data/lib/sequel/adapters/jdbc.rb +26 -18
  11. data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
  12. data/lib/sequel/adapters/jdbc/derby.rb +7 -7
  13. data/lib/sequel/adapters/jdbc/hsqldb.rb +5 -0
  14. data/lib/sequel/adapters/jdbc/mysql.rb +9 -4
  15. data/lib/sequel/adapters/mysql.rb +0 -3
  16. data/lib/sequel/adapters/mysql2.rb +0 -3
  17. data/lib/sequel/adapters/oracle.rb +4 -1
  18. data/lib/sequel/adapters/postgres.rb +4 -4
  19. data/lib/sequel/adapters/shared/access.rb +205 -3
  20. data/lib/sequel/adapters/shared/cubrid.rb +216 -0
  21. data/lib/sequel/adapters/shared/db2.rb +7 -2
  22. data/lib/sequel/adapters/shared/mssql.rb +3 -34
  23. data/lib/sequel/adapters/shared/mysql.rb +4 -33
  24. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +11 -0
  25. data/lib/sequel/adapters/shared/oracle.rb +5 -0
  26. data/lib/sequel/adapters/shared/postgres.rb +2 -1
  27. data/lib/sequel/adapters/utils/split_alter_table.rb +36 -0
  28. data/lib/sequel/database/connecting.rb +1 -1
  29. data/lib/sequel/database/query.rb +30 -7
  30. data/lib/sequel/database/schema_methods.rb +7 -2
  31. data/lib/sequel/dataset/query.rb +9 -10
  32. data/lib/sequel/dataset/sql.rb +14 -26
  33. data/lib/sequel/extensions/pg_hstore.rb +19 -0
  34. data/lib/sequel/extensions/pg_row.rb +5 -5
  35. data/lib/sequel/plugins/association_pks.rb +121 -18
  36. data/lib/sequel/plugins/json_serializer.rb +19 -0
  37. data/lib/sequel/sql.rb +11 -0
  38. data/lib/sequel/version.rb +1 -1
  39. data/spec/adapters/postgres_spec.rb +42 -0
  40. data/spec/core/database_spec.rb +17 -0
  41. data/spec/core/dataset_spec.rb +11 -0
  42. data/spec/core/expression_filters_spec.rb +13 -0
  43. data/spec/extensions/association_pks_spec.rb +163 -3
  44. data/spec/extensions/pg_hstore_spec.rb +6 -0
  45. data/spec/extensions/pg_row_spec.rb +17 -0
  46. data/spec/integration/associations_test.rb +1 -1
  47. data/spec/integration/dataset_test.rb +13 -13
  48. data/spec/integration/plugin_test.rb +232 -7
  49. data/spec/integration/schema_test.rb +8 -12
  50. data/spec/integration/spec_helper.rb +1 -1
  51. data/spec/integration/type_test.rb +6 -0
  52. metadata +9 -2
data/CHANGELOG CHANGED
@@ -1,3 +1,33 @@
1
+ === 3.40.0 (2012-09-26)
2
+
3
+ * Add a cubrid adapter for accessing CUBRID databases via the cubrid gem (jeremyevans)
4
+
5
+ * Add a jdbc/cubrid adapter for accessing CUBRID databases via JDBC on JRuby (jeremyevans)
6
+
7
+ * Return OCI8::CLOB values as ruby Strings in the Oracle adapter (jeremyevans)
8
+
9
+ * Use clob for String :text=>true types on Oracle, DB2, HSQLDB, and Derby (jeremyevans) (#555)
10
+
11
+ * Allowing marshalling of Sequel::Postgres::HStore (jeremyevans) (#556)
12
+
13
+ * Quote channel identifier names when using LISTEN/NOTIFY on PostgreSQL (jeremyevans)
14
+
15
+ * Handle nil values when formatting bound variable arguments in the pg_row extension (jeremyevans) (#548)
16
+
17
+ * Handle nil values when parsing composite types in the pg_row extension (jeremyevans) (#548)
18
+
19
+ * Add :disconnect=>:retry option to Database#transaction, for automatically retrying the transaction on disconnect (jeremyevans)
20
+
21
+ * Greatly improved support on Microsoft Access (jeremyevans)
22
+
23
+ * Support Database#{schema,tables,views,indexes,foreign_key_list} when using ado/access adapter (ericgj) (#545, #546)
24
+
25
+ * Add ado/access adapter for accessing Microsoft Access via the ado adapter (jeremyevans)
26
+
27
+ * Combine disconnect error detection for mysql and mysql2 adapters (jeremyevans)
28
+
29
+ * Update the association_pks plugin to handle composite primary keys (chanks, jeremyevans) (#544)
30
+
1
31
  === 3.39.0 (2012-09-01)
2
32
 
3
33
  * Fix defaults_setter to set false default values (jeremyevans)
data/README.rdoc CHANGED
@@ -11,9 +11,10 @@ toolkit for Ruby.
11
11
  statements, bound variables, stored procedures, savepoints,
12
12
  two-phase commit, transaction isolation, master/slave
13
13
  configurations, and database sharding.
14
- * Sequel currently has adapters for ADO, Amalgalite, DataObjects,
15
- DB2, DBI, Firebird, IBM_DB, Informix, JDBC, MySQL, Mysql2, ODBC,
16
- OpenBase, Oracle, PostgreSQL, SQLite3, Swift, and TinyTDS.
14
+ * Sequel currently has adapters for ADO, Amalgalite, CUBRID,
15
+ DataObjects, DB2, DBI, Firebird, IBM_DB, Informix, JDBC, MySQL,
16
+ Mysql2, ODBC, OpenBase, Oracle, PostgreSQL, SQLite3, Swift, and
17
+ TinyTDS.
17
18
 
18
19
  == Resources
19
20
 
@@ -456,7 +456,7 @@ This part of the guide will list Sequel equivalents for ActiveRecord methods, ho
456
456
 
457
457
  ==== +abstract_class+, <tt>abstract_class=</tt>, <tt>abstract_class?</tt>
458
458
 
459
- With Sequel, these methods don't exist because it doesn't default to using single table inheritance in subclasses. ActiveRecord assumes that subclasses of Model classes use single table inheritance, and you have to set <tt>abstract_class = true</tt> to use an abstract class. In Sequel, you must use the +single_table_inheritance+ or +class_tabble_inheritance+ plugin to configure inheritance in the database.
459
+ With Sequel, these methods don't exist because it doesn't default to using single table inheritance in subclasses. ActiveRecord assumes that subclasses of Model classes use single table inheritance, and you have to set <tt>abstract_class = true</tt> to use an abstract class. In Sequel, you must use the +single_table_inheritance+ or +class_table_inheritance+ plugin to configure inheritance in the database.
460
460
 
461
461
  ==== +all+
462
462
 
@@ -148,6 +148,12 @@ Without a database argument, assumes a memory database, so you can do:
148
148
  Handles paths in the connection string similar to the SQLite adapter, so see
149
149
  the sqlite section below for details.
150
150
 
151
+ === cubrid
152
+
153
+ cubrid is a ruby extension for accessing a CUBRID database. Currently,
154
+ the ruby cubrid gem is in fairly rough state, with broken transaction
155
+ support and some other issues, but most things work.
156
+
151
157
  === db2
152
158
 
153
159
  Requires: db2/db2cli
@@ -266,6 +272,7 @@ Example connection strings:
266
272
  jdbc:db2://localhost:3700/database:user=user;password=password;
267
273
  jdbc:firebirdsql:localhost/3050:/path/to/database.fdb
268
274
  jdbc:jdbcprogress:T:hostname:port:database
275
+ jdbc:cubrid:hostname:port:database:::
269
276
 
270
277
  You can also use JNDI connection strings:
271
278
 
@@ -0,0 +1,73 @@
1
+ = New Features
2
+
3
+ * Sequel now has vastly improved support for Microsoft Access.
4
+
5
+ * Sequel now supports the CUBRID database, with a cubrid adapter
6
+ that uses the cubrid gem, and a jdbc/cubrid adapter for accessing
7
+ CUBRID via JDBC on JRuby.
8
+
9
+ * The association_pks plugin now supports composite keys.
10
+
11
+ * Database#transaction now accepts a :disconnect=>:retry option,
12
+ in which case it will automatically retry the block if it
13
+ detects a disconnection. This is potentially dangerous, and
14
+ should only be used if the entire block is idempotent. There
15
+ is also no checking against an infinite retry loop.
16
+
17
+ * SQL::CaseExpression#with_merged_expression has been added, for
18
+ converting a CaseExpression with an associated expression to
19
+ one without an associated expression, by merging the expression
20
+ into each condition.
21
+
22
+ = Other Improvements
23
+
24
+ * Sequel now quotes arguments/columns in common table expressions.
25
+
26
+ * Sequel now handles nil values correctly in the pg_row extension.
27
+
28
+ * Sequel::Postgres::HStore instances can now be marshalled.
29
+
30
+ * Sequel now uses clob for String :text=>true types on databases that
31
+ don't support a text type.
32
+
33
+ * On PostgreSQL, Sequel now quotes channel identifier names when using
34
+ LISTEN/NOTIFY.
35
+
36
+ * On PostgreSQL, Sequel now correctly handles the case where named
37
+ type conversion procs have been added before the Database object is
38
+ instantiated.
39
+
40
+ * On DB2, Sequel now explicitly sets NOT NULL for unique constraint
41
+ columns instead of foreign key columns. DB2 does not allow columns
42
+ in unique constraints to be NULL, but does allow foreign key columns
43
+ to be NULL.
44
+
45
+ * In the oracle adapter, clob values are now returned as ruby strings
46
+ upon retrieval.
47
+
48
+ * Sequel now detects more types of disconnections in the postgres,
49
+ mysql, and mysql2 adapters.
50
+
51
+ * If a database provides a default column value that isn't a ruby
52
+ string, it is used directly as the ruby default, instead of causing
53
+ the schema parsing to fail.
54
+
55
+ = Backwards Compatibility
56
+
57
+ * Code using Sequel's oracle adapter that expected clob values to be
58
+ returned as OCI8::CLOB instances needs to be modified to work with
59
+ ruby strings.
60
+
61
+ * Because Sequel now quotes column names in common table expressions,
62
+ those names are now case sensitive, which could break certain poorly
63
+ coded queries. Similar issues exist with the quoting of channel
64
+ identifier names in LISTEN/NOTIFY on PostgreSQL.
65
+
66
+ * The private Database#requires_return_generated_keys? method
67
+ has been removed from the jdbc adapter. Custom jdbc subadapters
68
+ relying on this method should override the private
69
+ Database#execute_statement_insert method instead to ensure that
70
+ RETURN_GENERATED_KEYS is used for insert statements.
71
+
72
+ * The private Dataset#argument_list and #argument_list_append methods
73
+ have been removed.
@@ -12,9 +12,9 @@ module Sequel
12
12
  super
13
13
  case @opts[:conn_string]
14
14
  when /Microsoft\.(Jet|ACE)\.OLEDB/io
15
- Sequel.ts_require 'adapters/shared/access'
16
- extend Sequel::Access::DatabaseMethods
17
- extend_datasets(Sequel::Access::DatasetMethods)
15
+ Sequel.ts_require 'adapters/ado/access'
16
+ extend Sequel::ADO::Access::DatabaseMethods
17
+ @dataset_class = ADO::Access::Dataset
18
18
  else
19
19
  @opts[:driver] ||= 'SQL Server'
20
20
  case @opts[:driver]
@@ -57,6 +57,32 @@ module Sequel
57
57
  handle
58
58
  end
59
59
 
60
+ # Just execute so it doesn't attempt to return the number of rows modified.
61
+ def execute_ddl(sql, opts={})
62
+ execute(sql, opts)
63
+ end
64
+
65
+ # Just execute so it doesn't attempt to return the number of rows modified.
66
+ def execute_insert(sql, opts={})
67
+ execute(sql, opts)
68
+ end
69
+
70
+ # Use pass by reference in WIN32OLE to get the number of affected rows,
71
+ # unless is a provider is in use (since some providers don't seem to
72
+ # return the number of affected rows, but the default provider appears
73
+ # to).
74
+ def execute_dui(sql, opts={})
75
+ return super if opts[:provider]
76
+ synchronize(opts[:server]) do |conn|
77
+ begin
78
+ log_yield(sql){conn.Execute(sql, 1)}
79
+ WIN32OLE::ARGV[1]
80
+ rescue ::WIN32OLERuntimeError => e
81
+ raise_error(e)
82
+ end
83
+ end
84
+ end
85
+
60
86
  def execute(sql, opts={})
61
87
  synchronize(opts[:server]) do |conn|
62
88
  begin
@@ -0,0 +1,334 @@
1
+ Sequel.require 'adapters/shared/access'
2
+ Sequel.require 'adapters/utils/split_alter_table'
3
+
4
+ module Sequel
5
+ module ADO
6
+ # Database and Dataset instance methods for Access specific
7
+ # support via ADO.
8
+ module Access
9
+ class AdoSchema
10
+ QUERY_TYPE = {
11
+ :columns => 4,
12
+ :indexes => 12,
13
+ :tables => 20,
14
+ :views => 23,
15
+ :foreign_keys => 27
16
+ }
17
+
18
+ attr_reader :type, :criteria
19
+
20
+ def initialize(type, crit)
21
+ @type = QUERY_TYPE[type]
22
+ @criteria = Array(crit)
23
+ end
24
+
25
+ class Column
26
+ DATA_TYPE = {
27
+ 2 => "SMALLINT",
28
+ 3 => "INTEGER",
29
+ 4 => "REAL",
30
+ 5 => "DOUBLE",
31
+ 6 => "MONEY",
32
+ 7 => "DATETIME",
33
+ 11 => "BIT",
34
+ 14 => "DECIMAL",
35
+ 16 => "TINYINT",
36
+ 17 => "BYTE",
37
+ 72 => "GUID",
38
+ 128 => "BINARY",
39
+ 130 => "TEXT",
40
+ 131 => "DECIMAL",
41
+ 201 => "TEXT",
42
+ 205 => "IMAGE"
43
+ }
44
+
45
+ def initialize(row)
46
+ @row = row
47
+ end
48
+
49
+ def [](col)
50
+ @row[col]
51
+ end
52
+
53
+ def allow_null
54
+ self["IS_NULLABLE"]
55
+ end
56
+
57
+ def default
58
+ self["COLUMN_DEFAULT"]
59
+ end
60
+
61
+ def db_type
62
+ t = DATA_TYPE[self["DATA_TYPE"]]
63
+ if t == "DECIMAL" && precision
64
+ t + "(#{precision.to_i},#{(scale || 0).to_i})"
65
+ elsif t == "TEXT" && maximum_length && maximum_length > 0
66
+ t + "(#{maximum_length.to_i})"
67
+ else
68
+ t
69
+ end
70
+ end
71
+
72
+ def precision
73
+ self["NUMERIC_PRECISION"]
74
+ end
75
+
76
+ def scale
77
+ self["NUMERIC_SCALE"]
78
+ end
79
+
80
+ def maximum_length
81
+ self["CHARACTER_MAXIMUM_LENGTH"]
82
+ end
83
+ end
84
+ end
85
+
86
+ module DatabaseMethods
87
+ include Sequel::Access::DatabaseMethods
88
+ include Sequel::Database::SplitAlterTable
89
+
90
+ DECIMAL_TYPE_RE = /decimal/io
91
+ LAST_INSERT_ID = "SELECT @@IDENTITY".freeze
92
+
93
+ # Remove cached schema after altering a table, since otherwise it can be cached
94
+ # incorrectly in the rename column case.
95
+ def alter_table(name, *)
96
+ super
97
+ remove_cached_schema(name)
98
+ nil
99
+ end
100
+
101
+ # Access doesn't let you disconnect if inside a transaction, so
102
+ # try rolling back an existing transaction first.
103
+ def disconnect_connection(conn)
104
+ conn.RollbackTrans rescue nil
105
+ super
106
+ end
107
+
108
+ def execute_insert(sql, opts={})
109
+ synchronize(opts[:server]) do |conn|
110
+ begin
111
+ r = log_yield(sql){conn.Execute(sql)}
112
+ res = log_yield(LAST_INSERT_ID){conn.Execute(LAST_INSERT_ID)}
113
+ res.getRows.transpose.each{|r| return r.shift}
114
+ rescue ::WIN32OLERuntimeError => e
115
+ raise_error(e)
116
+ end
117
+ end
118
+ nil
119
+ end
120
+
121
+ def tables(opts={})
122
+ m = output_identifier_meth
123
+ ado_schema_tables.map {|tbl| m.call(tbl['TABLE_NAME'])}
124
+ end
125
+
126
+ def views(opts={})
127
+ m = output_identifier_meth
128
+ ado_schema_views.map {|tbl| m.call(tbl['TABLE_NAME'])}
129
+ end
130
+
131
+ # Note OpenSchema returns compound indexes as multiple rows
132
+ def indexes(table_name,opts={})
133
+ m = output_identifier_meth
134
+ idxs = ado_schema_indexes(table_name).inject({}) do |memo, idx|
135
+ unless idx["PRIMARY_KEY"]
136
+ index = memo[m.call(idx["INDEX_NAME"])] ||= {
137
+ :columns=>[], :unique=>idx["UNIQUE"]
138
+ }
139
+ index[:columns] << m.call(idx["COLUMN_NAME"])
140
+ end
141
+ memo
142
+ end
143
+ idxs
144
+ end
145
+
146
+ # Note OpenSchema returns compound foreign key relationships as multiple rows
147
+ def foreign_key_list(table, opts={})
148
+ m = output_identifier_meth
149
+ fks = ado_schema_foreign_keys(table).inject({}) do |memo, fk|
150
+ name = m.call(fk['FK_NAME'])
151
+ specs = memo[name] ||= {
152
+ :columns => [],
153
+ :table => m.call(fk['PK_TABLE_NAME']),
154
+ :key => [],
155
+ :deferrable => fk['DEFERRABILITY'],
156
+ :name => name,
157
+ :on_delete => fk['DELETE_RULE'],
158
+ :on_update => fk['UPDATE_RULE']
159
+ }
160
+ specs[:columns] << m.call(fk['FK_COLUMN_NAME'])
161
+ specs[:key] << m.call(fk['PK_COLUMN_NAME'])
162
+ memo
163
+ end
164
+ fks.values
165
+ end
166
+
167
+ private
168
+
169
+ # Emulate rename_column by adding the column, copying data from the old
170
+ # column, and dropping the old column.
171
+ def alter_table_sql(table, op)
172
+ case op[:op]
173
+ when :rename_column
174
+ unless sch = op[:schema]
175
+ raise(Error, "can't find existing schema entry for #{op[:name]}") unless sch = op[:schema] || schema(table).find{|c| c.first == op[:name]}
176
+ sch = sch.last
177
+ end
178
+ [
179
+ alter_table_sql(table, :op=>:add_column, :name=>op[:new_name], :default=>sch[:ruby_default], :type=>sch[:db_type], :null=>sch[:allow_null]),
180
+ from(table).update_sql(op[:new_name]=>op[:name]),
181
+ alter_table_sql(table, :op=>:drop_column, :name=>op[:name])
182
+ ]
183
+ when :set_column_null, :set_column_default
184
+ raise(Error, "can't find existing schema entry for #{op[:name]}") unless sch = op[:schema] || schema(table).find{|c| c.first == op[:name]}
185
+ sch = sch.last
186
+
187
+ sch = if op[:op] == :set_column_null
188
+ sch.merge(:allow_null=>op[:null])
189
+ else
190
+ sch.merge(:ruby_default=>op[:default])
191
+ end
192
+
193
+ [
194
+ alter_table_sql(table, :op=>:rename_column, :name=>op[:name], :new_name=>:sequel_access_backup_column, :schema=>sch),
195
+ alter_table_sql(table, :op=>:rename_column, :new_name=>op[:name], :name=>:sequel_access_backup_column, :schema=>sch)
196
+ ]
197
+ else
198
+ super
199
+ end
200
+ end
201
+
202
+ def begin_transaction(conn, opts={})
203
+ log_yield('Transaction.begin'){conn.BeginTrans}
204
+ end
205
+
206
+ def commit_transaction(conn, opts={})
207
+ log_yield('Transaction.commit'){conn.CommitTrans}
208
+ end
209
+
210
+ def rollback_transaction(conn, opts={})
211
+ log_yield('Transaction.rollback'){conn.RollbackTrans}
212
+ end
213
+
214
+ def schema_column_type(db_type)
215
+ case db_type.downcase
216
+ when 'bit'
217
+ :boolean
218
+ when 'byte', 'guid'
219
+ :integer
220
+ when 'image'
221
+ :blob
222
+ else
223
+ super
224
+ end
225
+ end
226
+
227
+ def schema_parse_table(table_name, opts)
228
+ m = output_identifier_meth(opts[:dataset])
229
+ m2 = input_identifier_meth(opts[:dataset])
230
+ tn = m2.call(table_name.to_s)
231
+ idxs = ado_schema_indexes(tn)
232
+ ado_schema_columns(tn).map {|row|
233
+ specs = {
234
+ :allow_null => row.allow_null,
235
+ :db_type => row.db_type,
236
+ :default => row.default,
237
+ :primary_key => !!idxs.find {|idx|
238
+ idx["COLUMN_NAME"] == row["COLUMN_NAME"] &&
239
+ idx["PRIMARY_KEY"]
240
+ },
241
+ :type => if row.db_type =~ DECIMAL_TYPE_RE && row.scale == 0
242
+ :integer
243
+ else
244
+ schema_column_type(row.db_type)
245
+ end,
246
+ :ado_type => row["DATA_TYPE"]
247
+ }
248
+ specs[:default] = nil if blank_object?(specs[:default])
249
+ specs[:allow_null] = specs[:allow_null] && !specs[:primary_key]
250
+ [ m.call(row["COLUMN_NAME"]), specs ]
251
+ }
252
+ end
253
+
254
+ def ado_schema_tables
255
+ rows=[]
256
+ fetch_ado_schema(:tables, [nil,nil,nil,'TABLE']) do |row|
257
+ rows << row
258
+ end
259
+ rows
260
+ end
261
+
262
+ def ado_schema_views
263
+ rows=[]
264
+ fetch_ado_schema(:views, [nil,nil,nil]) do |row|
265
+ rows << row
266
+ end
267
+ rows
268
+ end
269
+
270
+ def ado_schema_indexes(table_name)
271
+ rows=[]
272
+ fetch_ado_schema(:indexes, [nil,nil,nil,nil,table_name.to_s]) do |row|
273
+ rows << row
274
+ end
275
+ rows
276
+ end
277
+
278
+ def ado_schema_columns(table_name)
279
+ rows=[]
280
+ fetch_ado_schema(:columns, [nil,nil,table_name.to_s,nil]) do |row|
281
+ rows << AdoSchema::Column.new(row)
282
+ end
283
+ rows.sort!{|a,b| a["ORDINAL_POSITION"] <=> b["ORDINAL_POSITION"]}
284
+ end
285
+
286
+ def ado_schema_foreign_keys(table_name)
287
+ rows=[]
288
+ fetch_ado_schema(:foreign_keys, [nil,nil,nil,nil,nil,table_name.to_s]) do |row|
289
+ rows << row
290
+ end
291
+ rows.sort!{|a,b| a["ORDINAL"] <=> b["ORDINAL"]}
292
+ end
293
+
294
+ def fetch_ado_schema(type, criteria=[])
295
+ execute_open_ado_schema(type, criteria) do |s|
296
+ cols = s.Fields.extend(Enumerable).map {|c| c.Name}
297
+ s.getRows.transpose.each do |r|
298
+ row = {}
299
+ cols.each{|c| row[c] = r.shift}
300
+ yield row
301
+ end unless s.eof
302
+ end
303
+ end
304
+
305
+ # This is like execute() in that it yields an ADO RecordSet, except
306
+ # instead of an SQL interface there's this OpenSchema call
307
+ # cf. http://msdn.microsoft.com/en-us/library/ee275721(v=bts.10)
308
+ #
309
+ def execute_open_ado_schema(type, criteria=[])
310
+ ado_schema = AdoSchema.new(type, criteria)
311
+ synchronize(opts[:server]) do |conn|
312
+ begin
313
+ r = log_yield("OpenSchema #{type.inspect}, #{criteria.inspect}") {
314
+ if ado_schema.criteria.empty?
315
+ conn.OpenSchema(ado_schema.type)
316
+ else
317
+ conn.OpenSchema(ado_schema.type, ado_schema.criteria)
318
+ end
319
+ }
320
+ yield(r) if block_given?
321
+ rescue ::WIN32OLERuntimeError => e
322
+ raise_error(e)
323
+ end
324
+ end
325
+ nil
326
+ end
327
+ end
328
+
329
+ class Dataset < ADO::Dataset
330
+ include Sequel::Access::DatasetMethods
331
+ end
332
+ end
333
+ end
334
+ end