sequel 3.21.0 → 3.29.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.
- data/CHANGELOG +413 -3
- data/README.rdoc +20 -6
- data/Rakefile +23 -16
- data/bin/sequel +1 -5
- data/doc/association_basics.rdoc +210 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +86 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +115 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +15 -7
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +5 -31
- data/lib/sequel/adapters/jdbc/db2.rb +44 -0
- data/lib/sequel/adapters/jdbc/derby.rb +217 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +26 -17
- data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
- data/lib/sequel/adapters/jdbc/mysql.rb +9 -10
- data/lib/sequel/adapters/jdbc/oracle.rb +67 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +6 -11
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +41 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +107 -38
- data/lib/sequel/adapters/mock.rb +315 -0
- data/lib/sequel/adapters/mysql.rb +78 -182
- data/lib/sequel/adapters/mysql2.rb +24 -23
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +0 -5
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +2 -4
- data/lib/sequel/adapters/oracle.rb +349 -51
- data/lib/sequel/adapters/postgres.rb +169 -21
- data/lib/sequel/adapters/shared/access.rb +21 -6
- data/lib/sequel/adapters/shared/db2.rb +288 -0
- data/lib/sequel/adapters/shared/firebird.rb +214 -0
- data/lib/sequel/adapters/shared/informix.rb +45 -0
- data/lib/sequel/adapters/shared/mssql.rb +108 -65
- data/lib/sequel/adapters/shared/mysql.rb +56 -13
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +185 -34
- data/lib/sequel/adapters/shared/postgres.rb +107 -58
- data/lib/sequel/adapters/shared/progress.rb +0 -6
- data/lib/sequel/adapters/shared/sqlite.rb +168 -41
- data/lib/sequel/adapters/sqlite.rb +27 -18
- data/lib/sequel/adapters/swift/mysql.rb +9 -5
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +6 -4
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +152 -17
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +63 -0
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +46 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +100 -19
- data/lib/sequel/database/query.rb +153 -58
- data/lib/sequel/database/schema_generator.rb +8 -5
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +194 -57
- data/lib/sequel/dataset/features.rb +81 -8
- data/lib/sequel/dataset/graph.rb +8 -7
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +5 -6
- data/lib/sequel/dataset/prepared_statements.rb +32 -15
- data/lib/sequel/dataset/query.rb +223 -42
- data/lib/sequel/dataset/sql.rb +58 -61
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +997 -331
- data/lib/sequel/model/base.rb +386 -129
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +15 -8
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +65 -7
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +6 -1
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +12 -25
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +107 -51
- data/lib/sequel/timezones.rb +44 -35
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +65 -29
- data/spec/adapters/mysql_spec.rb +122 -123
- data/spec/adapters/oracle_spec.rb +48 -76
- data/spec/adapters/postgres_spec.rb +213 -61
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +20 -31
- data/spec/core/database_spec.rb +729 -508
- data/spec/core/dataset_spec.rb +980 -1044
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +378 -0
- data/spec/core/object_graph_spec.rb +48 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/class_table_inheritance_spec.rb +1 -1
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/identity_map_spec.rb +162 -0
- data/spec/extensions/instance_hooks_spec.rb +71 -0
- data/spec/extensions/many_through_many_spec.rb +195 -20
- data/spec/extensions/migration_spec.rb +17 -17
- data/spec/extensions/named_timezones_spec.rb +22 -2
- data/spec/extensions/nested_attributes_spec.rb +4 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
- data/spec/extensions/prepared_statements_spec.rb +72 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
- data/spec/extensions/serialization_spec.rb +5 -8
- data/spec/extensions/single_table_inheritance_spec.rb +11 -0
- data/spec/extensions/spec_helper.rb +7 -1
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/to_dot_spec.rb +3 -5
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +522 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +375 -62
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +304 -116
- data/spec/integration/prepared_statement_test.rb +200 -120
- data/spec/integration/schema_test.rb +161 -30
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +172 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +174 -7
- data/spec/model/associations_spec.rb +849 -661
- data/spec/model/base_spec.rb +255 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +640 -676
- data/spec/model/hooks_spec.rb +309 -67
- data/spec/model/model_spec.rb +207 -167
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +321 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +95 -38
|
@@ -93,13 +93,14 @@ module Sequel
|
|
|
93
93
|
def bytea(s) ::Sequel::SQL::Blob.new(Adapter.unescape_bytea(s)) end
|
|
94
94
|
def integer(s) s.to_i end
|
|
95
95
|
def float(s) s.to_f end
|
|
96
|
-
def
|
|
97
|
-
def date(s) ::Sequel.string_to_date(s) end
|
|
98
|
-
def date_iso(s) ::Date.new(*s.split("-").map{|x| x.to_i}) end
|
|
99
|
-
def time(s) ::Sequel.string_to_time(s) end
|
|
100
|
-
def timestamp(s) ::Sequel.database_to_application_timestamp(s) end
|
|
96
|
+
def date(s) ::Date.new(*s.split("-").map{|x| x.to_i}) end
|
|
101
97
|
end.new
|
|
102
98
|
|
|
99
|
+
# Hash with type name symbols and callable values for converting PostgreSQL types.
|
|
100
|
+
# Non-builtin types that don't have fixed numbers should use this to register
|
|
101
|
+
# conversion procs.
|
|
102
|
+
PG_NAMED_TYPES = {}
|
|
103
|
+
|
|
103
104
|
# Hash with integer keys and callable values for converting PostgreSQL types.
|
|
104
105
|
PG_TYPES = {}
|
|
105
106
|
{
|
|
@@ -107,9 +108,8 @@ module Sequel
|
|
|
107
108
|
[17] => tt.method(:bytea),
|
|
108
109
|
[20, 21, 22, 23, 26] => tt.method(:integer),
|
|
109
110
|
[700, 701] => tt.method(:float),
|
|
110
|
-
[790, 1700] =>
|
|
111
|
-
[1083, 1266] =>
|
|
112
|
-
[1114, 1184] => tt.method(:timestamp)
|
|
111
|
+
[790, 1700] => ::BigDecimal.method(:new),
|
|
112
|
+
[1083, 1266] => ::Sequel.method(:string_to_time),
|
|
113
113
|
}.each do |k,v|
|
|
114
114
|
k.each{|n| PG_TYPES[n] = v}
|
|
115
115
|
end
|
|
@@ -123,7 +123,7 @@ module Sequel
|
|
|
123
123
|
|
|
124
124
|
# Modify the type translator for the date type depending on the value given.
|
|
125
125
|
def self.use_iso_date_format=(v)
|
|
126
|
-
PG_TYPES[1082] = TYPE_TRANSLATOR.method(
|
|
126
|
+
PG_TYPES[1082] = v ? TYPE_TRANSLATOR.method(:date) : Sequel.method(:string_to_date)
|
|
127
127
|
@use_iso_date_format = v
|
|
128
128
|
end
|
|
129
129
|
self.use_iso_date_format = true
|
|
@@ -131,7 +131,10 @@ module Sequel
|
|
|
131
131
|
# PGconn subclass for connection specific methods used with the
|
|
132
132
|
# pg, postgres, or postgres-pr driver.
|
|
133
133
|
class Adapter < ::PGconn
|
|
134
|
+
DISCONNECT_ERROR_RE = /\Acould not receive data from server: Software caused connection abort/
|
|
135
|
+
|
|
134
136
|
include Sequel::Postgres::AdapterMethods
|
|
137
|
+
|
|
135
138
|
self.translate_results = false if respond_to?(:translate_results=)
|
|
136
139
|
|
|
137
140
|
# Hash of prepared statements for this connection. Keys are
|
|
@@ -150,20 +153,23 @@ module Sequel
|
|
|
150
153
|
end
|
|
151
154
|
@prepared_statements = {} if SEQUEL_POSTGRES_USES_PG
|
|
152
155
|
end
|
|
153
|
-
|
|
156
|
+
|
|
154
157
|
# Raise a Sequel::DatabaseDisconnectError if a PGError is raised and
|
|
155
158
|
# the connection status cannot be determined or it is not OK.
|
|
156
159
|
def check_disconnect_errors
|
|
157
160
|
begin
|
|
158
161
|
yield
|
|
159
162
|
rescue PGError =>e
|
|
163
|
+
disconnect = false
|
|
160
164
|
begin
|
|
161
165
|
s = status
|
|
162
166
|
rescue PGError
|
|
163
|
-
|
|
167
|
+
disconnect = true
|
|
164
168
|
end
|
|
165
169
|
status_ok = (s == Adapter::CONNECTION_OK)
|
|
166
|
-
|
|
170
|
+
disconnect ||= !status_ok
|
|
171
|
+
disconnect ||= e.message =~ DISCONNECT_ERROR_RE
|
|
172
|
+
disconnect ? raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)) : raise
|
|
167
173
|
ensure
|
|
168
174
|
block if status_ok
|
|
169
175
|
end
|
|
@@ -176,7 +182,7 @@ module Sequel
|
|
|
176
182
|
begin
|
|
177
183
|
block_given? ? yield(q) : q.cmd_tuples
|
|
178
184
|
ensure
|
|
179
|
-
q.clear
|
|
185
|
+
q.clear if q
|
|
180
186
|
end
|
|
181
187
|
end
|
|
182
188
|
|
|
@@ -194,6 +200,10 @@ module Sequel
|
|
|
194
200
|
include Sequel::Postgres::DatabaseMethods
|
|
195
201
|
|
|
196
202
|
set_adapter_scheme :postgres
|
|
203
|
+
|
|
204
|
+
# A hash of conversion procs, keyed by type integer (oid) and
|
|
205
|
+
# having callable values for the conversion proc for that type.
|
|
206
|
+
attr_reader :conversion_procs
|
|
197
207
|
|
|
198
208
|
# Add the primary_keys and primary_key_sequences instance variables,
|
|
199
209
|
# so we can get the correct return values for inserted rows.
|
|
@@ -225,14 +235,10 @@ module Sequel
|
|
|
225
235
|
end
|
|
226
236
|
conn.db = self
|
|
227
237
|
conn.apply_connection_settings
|
|
238
|
+
@conversion_procs ||= get_conversion_procs(conn)
|
|
228
239
|
conn
|
|
229
240
|
end
|
|
230
241
|
|
|
231
|
-
# Return instance of Sequel::Postgres::Dataset with the given options.
|
|
232
|
-
def dataset(opts = nil)
|
|
233
|
-
Postgres::Dataset.new(self, opts)
|
|
234
|
-
end
|
|
235
|
-
|
|
236
242
|
# Execute the given SQL with the given args on an available connection.
|
|
237
243
|
def execute(sql, opts={}, &block)
|
|
238
244
|
check_database_errors do
|
|
@@ -253,6 +259,119 @@ module Sequel
|
|
|
253
259
|
end
|
|
254
260
|
end
|
|
255
261
|
|
|
262
|
+
if SEQUEL_POSTGRES_USES_PG
|
|
263
|
+
# +copy_table+ uses PostgreSQL's +COPY+ SQL statement to return formatted
|
|
264
|
+
# results directly to the caller. This method is only supported if pg is the
|
|
265
|
+
# underlying ruby driver. This method should only be called if you want
|
|
266
|
+
# results returned to the client. If you are using +COPY FROM+ or +COPY TO+
|
|
267
|
+
# with a filename, you should just use +run+ instead of this method. This
|
|
268
|
+
# method does not currently support +COPY FROM STDIN+, but that may be supported
|
|
269
|
+
# in the future.
|
|
270
|
+
#
|
|
271
|
+
# The table argument supports the following types:
|
|
272
|
+
#
|
|
273
|
+
# String :: Uses the first argument directly as literal SQL. If you are using
|
|
274
|
+
# a version of PostgreSQL before 9.0, you will probably want to
|
|
275
|
+
# use a string if you are using any options at all, as the syntax
|
|
276
|
+
# Sequel uses for options is only compatible with PostgreSQL 9.0+.
|
|
277
|
+
# Dataset :: Uses a query instead of a table name when copying.
|
|
278
|
+
# other :: Uses a table name (usually a symbol) when copying.
|
|
279
|
+
#
|
|
280
|
+
# The following options are respected:
|
|
281
|
+
#
|
|
282
|
+
# :format :: The format to use. text is the default, so this should be :csv or :binary.
|
|
283
|
+
# :options :: An options SQL string to use, which should contain comma separated options.
|
|
284
|
+
# :server :: The server on which to run the query.
|
|
285
|
+
#
|
|
286
|
+
# If a block is provided, the method continually yields to the block, one yield
|
|
287
|
+
# per row. If a block is not provided, a single string is returned with all
|
|
288
|
+
# of the data.
|
|
289
|
+
def copy_table(table, opts={})
|
|
290
|
+
sql = if table.is_a?(String)
|
|
291
|
+
sql = table
|
|
292
|
+
else
|
|
293
|
+
if opts[:options] || opts[:format]
|
|
294
|
+
options = " ("
|
|
295
|
+
options << "FORMAT #{opts[:format]}" if opts[:format]
|
|
296
|
+
options << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
|
|
297
|
+
options << ')'
|
|
298
|
+
end
|
|
299
|
+
table = if table.is_a?(::Sequel::Dataset)
|
|
300
|
+
"(#{table.sql})"
|
|
301
|
+
else
|
|
302
|
+
literal(table)
|
|
303
|
+
end
|
|
304
|
+
sql = "COPY #{table} TO STDOUT#{options}"
|
|
305
|
+
end
|
|
306
|
+
synchronize(opts[:server]) do |conn|
|
|
307
|
+
conn.execute(sql)
|
|
308
|
+
begin
|
|
309
|
+
if block_given?
|
|
310
|
+
while buf = conn.get_copy_data
|
|
311
|
+
yield buf
|
|
312
|
+
end
|
|
313
|
+
nil
|
|
314
|
+
else
|
|
315
|
+
b = ''
|
|
316
|
+
b << buf while buf = conn.get_copy_data
|
|
317
|
+
b
|
|
318
|
+
end
|
|
319
|
+
ensure
|
|
320
|
+
raise DatabaseDisconnectError, "disconnecting as a partial COPY may leave the connection in an unusable state" if buf
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Listens on the given channel (or multiple channels if channel is an array), waiting for notifications.
|
|
326
|
+
# After a notification is received, or the timeout has passed, stops listening to the channel. Options:
|
|
327
|
+
#
|
|
328
|
+
# :after_listen :: An object that responds to +call+ that is called with the underlying connection after the LISTEN
|
|
329
|
+
# statement is sent, but before the connection starts waiting for notifications.
|
|
330
|
+
# :loop :: Whether to continually wait for notifications, instead of just waiting for a single
|
|
331
|
+
# notification. If this option is given, a block must be provided. If this object responds to call, it is
|
|
332
|
+
# called with the underlying connection after each notification is received (after the block is called).
|
|
333
|
+
# If a :timeout option is used, and a callable object is given, the object will also be called if the
|
|
334
|
+
# timeout expires. If :loop is used and you want to stop listening, you can either break from inside the
|
|
335
|
+
# block given to #listen, or you can throw :stop from inside the :loop object's call method or the block.
|
|
336
|
+
# :server :: The server on which to listen, if the sharding support is being used.
|
|
337
|
+
# :timeout :: How long to wait for a notification, in seconds (can provide a float value for
|
|
338
|
+
# fractional seconds). If not given or nil, waits indefinitely.
|
|
339
|
+
#
|
|
340
|
+
# This method is only supported if pg is used as the underlying ruby driver. It returns the
|
|
341
|
+
# channel the notification was sent to (as a string), unless :loop was used, in which case it returns nil.
|
|
342
|
+
# If a block is given, it is yielded 3 arguments:
|
|
343
|
+
# * the channel the notification was sent to (as a string)
|
|
344
|
+
# * the backend pid of the notifier (as an integer),
|
|
345
|
+
# * and the payload of the notification (as a string or nil).
|
|
346
|
+
def listen(channels, opts={}, &block)
|
|
347
|
+
check_database_errors do
|
|
348
|
+
synchronize(opts[:server]) do |conn|
|
|
349
|
+
begin
|
|
350
|
+
channels = Array(channels)
|
|
351
|
+
channels.each{|channel| conn.execute("LISTEN #{channel}")}
|
|
352
|
+
opts[:after_listen].call(conn) if opts[:after_listen]
|
|
353
|
+
timeout = opts[:timeout] ? [opts[:timeout]] : []
|
|
354
|
+
if l = opts[:loop]
|
|
355
|
+
raise Error, 'calling #listen with :loop requires a block' unless block
|
|
356
|
+
loop_call = l.respond_to?(:call)
|
|
357
|
+
catch(:stop) do
|
|
358
|
+
loop do
|
|
359
|
+
conn.wait_for_notify(*timeout, &block)
|
|
360
|
+
l.call(conn) if loop_call
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
nil
|
|
364
|
+
else
|
|
365
|
+
conn.wait_for_notify(*timeout, &block)
|
|
366
|
+
end
|
|
367
|
+
ensure
|
|
368
|
+
conn.execute("UNLISTEN *")
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
|
|
256
375
|
private
|
|
257
376
|
|
|
258
377
|
# Convert exceptions raised from the block into DatabaseErrors.
|
|
@@ -305,12 +424,29 @@ module Sequel
|
|
|
305
424
|
end
|
|
306
425
|
end
|
|
307
426
|
end
|
|
427
|
+
|
|
428
|
+
# Return the conversion procs hash to use for this database
|
|
429
|
+
def get_conversion_procs(conn)
|
|
430
|
+
procs = PG_TYPES.dup
|
|
431
|
+
procs[1114] = method(:to_application_timestamp)
|
|
432
|
+
procs[1184] = method(:to_application_timestamp)
|
|
433
|
+
conn.execute("SELECT oid, typname FROM pg_type where typtype = 'b'") do |res|
|
|
434
|
+
res.ntuples.times do |recnum|
|
|
435
|
+
if pr = PG_NAMED_TYPES[res.getvalue(recnum, 1).untaint.to_sym]
|
|
436
|
+
procs[res.getvalue(recnum, 0).to_i] ||= pr
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
procs
|
|
441
|
+
end
|
|
308
442
|
end
|
|
309
443
|
|
|
310
444
|
# Dataset class for PostgreSQL datasets that use the pg, postgres, or
|
|
311
445
|
# postgres-pr driver.
|
|
312
446
|
class Dataset < Sequel::Dataset
|
|
313
447
|
include Sequel::Postgres::DatasetMethods
|
|
448
|
+
|
|
449
|
+
Database::DatasetClass = self
|
|
314
450
|
|
|
315
451
|
# Yield all rows returned by executing the given SQL and converting
|
|
316
452
|
# the types.
|
|
@@ -372,11 +508,17 @@ module Sequel
|
|
|
372
508
|
end
|
|
373
509
|
LiteralString.new("#{prepared_arg_placeholder}#{i}#{"::#{type}" if type}")
|
|
374
510
|
end
|
|
511
|
+
|
|
512
|
+
# Always assume a prepared argument.
|
|
513
|
+
def prepared_arg?(k)
|
|
514
|
+
true
|
|
515
|
+
end
|
|
375
516
|
end
|
|
376
517
|
|
|
377
518
|
# Allow use of bind arguments for PostgreSQL using the pg driver.
|
|
378
519
|
module BindArgumentMethods
|
|
379
520
|
include ArgumentMapper
|
|
521
|
+
include ::Sequel::Postgres::DatasetMethods::PreparedStatementMethods
|
|
380
522
|
|
|
381
523
|
private
|
|
382
524
|
|
|
@@ -400,7 +542,12 @@ module Sequel
|
|
|
400
542
|
# pg driver.
|
|
401
543
|
module PreparedStatementMethods
|
|
402
544
|
include BindArgumentMethods
|
|
403
|
-
|
|
545
|
+
|
|
546
|
+
# Raise a more obvious error if you attempt to call a unnamed prepared statement.
|
|
547
|
+
def call(*)
|
|
548
|
+
raise Error, "Cannot call prepared statement without a name" if prepared_statement_name.nil?
|
|
549
|
+
super
|
|
550
|
+
end
|
|
404
551
|
|
|
405
552
|
private
|
|
406
553
|
|
|
@@ -427,7 +574,7 @@ module Sequel
|
|
|
427
574
|
ps.extend(BindArgumentMethods)
|
|
428
575
|
ps.call(bind_vars, &block)
|
|
429
576
|
end
|
|
430
|
-
|
|
577
|
+
|
|
431
578
|
# Prepare the given type of statement with the given name, and store
|
|
432
579
|
# it in the database to be called later.
|
|
433
580
|
def prepare(type, name=nil, *values)
|
|
@@ -483,8 +630,9 @@ module Sequel
|
|
|
483
630
|
# field numers, type conversion procs, and name symbol arrays.
|
|
484
631
|
def fetch_rows_set_cols(res)
|
|
485
632
|
cols = []
|
|
633
|
+
procs = db.conversion_procs
|
|
486
634
|
res.nfields.times do |fieldnum|
|
|
487
|
-
cols << [fieldnum,
|
|
635
|
+
cols << [fieldnum, procs[res.ftype(fieldnum)], output_identifier(res.fname(fieldnum))]
|
|
488
636
|
end
|
|
489
637
|
@columns = cols.map{|c| c.at(2)}
|
|
490
638
|
cols
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
module Access
|
|
3
3
|
module DatabaseMethods
|
|
4
|
+
# Access uses type :access as the database_type
|
|
4
5
|
def database_type
|
|
5
6
|
:access
|
|
6
7
|
end
|
|
7
8
|
|
|
8
|
-
def dataset(opts = nil)
|
|
9
|
-
ds = super
|
|
10
|
-
ds.extend(DatasetMethods)
|
|
11
|
-
ds
|
|
12
|
-
end
|
|
13
|
-
|
|
14
9
|
# Doesn't work, due to security restrictions on MSysObjects
|
|
15
10
|
def tables
|
|
16
11
|
from(:MSysObjects).filter(:Type=>1, :Flags=>0).select_map(:Name).map{|x| x.to_sym}
|
|
17
12
|
end
|
|
18
13
|
|
|
14
|
+
# Access uses type Counter for an autoincrementing keys
|
|
19
15
|
def serial_primary_key_options
|
|
20
16
|
{:primary_key => true, :type=>:Counter}
|
|
21
17
|
end
|
|
@@ -34,16 +30,35 @@ module Sequel
|
|
|
34
30
|
module DatasetMethods
|
|
35
31
|
SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'limit distinct columns from join where group order having compounds')
|
|
36
32
|
|
|
33
|
+
# Access doesn't support INTERSECT or EXCEPT
|
|
37
34
|
def supports_intersect_except?
|
|
38
35
|
false
|
|
39
36
|
end
|
|
40
37
|
|
|
41
38
|
private
|
|
42
39
|
|
|
40
|
+
# Access uses # to quote dates
|
|
41
|
+
def literal_date(d)
|
|
42
|
+
d.strftime('#%Y-%m-%d#')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Access uses # to quote datetimes
|
|
46
|
+
def literal_datetime(t)
|
|
47
|
+
t.strftime('#%Y-%m-%d %H:%M:%S#')
|
|
48
|
+
end
|
|
49
|
+
alias literal_time literal_datetime
|
|
50
|
+
|
|
51
|
+
# Access uses TOP for limits
|
|
52
|
+
def select_limit_sql(sql)
|
|
53
|
+
sql << " TOP #{@opts[:limit]}" if @opts[:limit]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Access uses [] for quoting identifiers
|
|
43
57
|
def quoted_identifier(v)
|
|
44
58
|
"[#{v}]"
|
|
45
59
|
end
|
|
46
60
|
|
|
61
|
+
# Access requires the limit clause come before other clauses
|
|
47
62
|
def select_clause_methods
|
|
48
63
|
SELECT_CLAUSE_METHODS
|
|
49
64
|
end
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
Sequel.require 'adapters/utils/emulate_offset_with_row_number'
|
|
2
|
+
|
|
3
|
+
module Sequel
|
|
4
|
+
module DB2
|
|
5
|
+
@use_clob_as_blob = true
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
# Whether to use clob as the generic File type, true by default.
|
|
9
|
+
attr_accessor :use_clob_as_blob
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module DatabaseMethods
|
|
13
|
+
AUTOINCREMENT = 'GENERATED ALWAYS AS IDENTITY'.freeze
|
|
14
|
+
NOT_NULL = ' NOT NULL'.freeze
|
|
15
|
+
NULL = ''.freeze
|
|
16
|
+
|
|
17
|
+
# DB2 always uses :db2 as it's database type
|
|
18
|
+
def database_type
|
|
19
|
+
:db2
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Return the database version as a string. Don't rely on this,
|
|
23
|
+
# it may return an integer in the future.
|
|
24
|
+
def db2_version
|
|
25
|
+
return @db2_version if @db2_version
|
|
26
|
+
@db2_version = metadata_dataset.with_sql("select service_level from sysibmadm.env_inst_info").first[:service_level]
|
|
27
|
+
end
|
|
28
|
+
alias_method :server_version, :db2_version
|
|
29
|
+
|
|
30
|
+
# Use SYSIBM.SYSCOLUMNS to get the information on the tables.
|
|
31
|
+
def schema_parse_table(table, opts = {})
|
|
32
|
+
m = output_identifier_meth(opts[:dataset])
|
|
33
|
+
im = input_identifier_meth(opts[:dataset])
|
|
34
|
+
metadata_dataset.with_sql("SELECT * FROM SYSIBM.SYSCOLUMNS WHERE TBNAME = #{literal(im.call(table))} ORDER BY COLNO").
|
|
35
|
+
collect do |column|
|
|
36
|
+
column[:db_type] = column.delete(:typename)
|
|
37
|
+
if column[:db_type] == "DECIMAL"
|
|
38
|
+
column[:db_type] << "(#{column[:longlength]},#{column[:scale]})"
|
|
39
|
+
end
|
|
40
|
+
column[:allow_null] = column.delete(:nulls) == 'Y'
|
|
41
|
+
column[:primary_key] = column.delete(:identity) == 'Y' || !column[:keyseq].nil?
|
|
42
|
+
column[:type] = schema_column_type(column[:db_type])
|
|
43
|
+
[ m.call(column.delete(:name)), column]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Use SYSCAT.TABLES to get the tables for the database
|
|
48
|
+
def tables
|
|
49
|
+
metadata_dataset.
|
|
50
|
+
with_sql("SELECT TABNAME FROM SYSCAT.TABLES WHERE TYPE='T' AND OWNER = #{literal(input_identifier_meth.call(opts[:user]))}").
|
|
51
|
+
all.map{|h| output_identifier_meth.call(h[:tabname]) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Use SYSCAT.TABLES to get the views for the database
|
|
55
|
+
def views
|
|
56
|
+
metadata_dataset.
|
|
57
|
+
with_sql("SELECT TABNAME FROM SYSCAT.TABLES WHERE TYPE='V' AND OWNER = #{literal(input_identifier_meth.call(opts[:user]))}").
|
|
58
|
+
all.map{|h| output_identifier_meth.call(h[:tabname]) }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Use SYSCAT.INDEXES to get the indexes for the table
|
|
62
|
+
def indexes(table, opts = {})
|
|
63
|
+
metadata_dataset.
|
|
64
|
+
with_sql("SELECT INDNAME,UNIQUERULE,MADE_UNIQUE,SYSTEM_REQUIRED FROM SYSCAT.INDEXES WHERE TABNAME = #{literal(input_identifier_meth.call(table))}").
|
|
65
|
+
all.map{|h| Hash[ h.map{|k,v| [k.to_sym, v]} ] }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# Handle DB2 specific alter table operations.
|
|
71
|
+
def alter_table_sql(table, op)
|
|
72
|
+
case op[:op]
|
|
73
|
+
when :add_column
|
|
74
|
+
if op[:primary_key] && op[:auto_increment] && op[:type] == Integer
|
|
75
|
+
[
|
|
76
|
+
"ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op.merge(:auto_increment=>false, :primary_key=>false, :default=>0, :null=>false))}",
|
|
77
|
+
"ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{literal(op[:name])} DROP DEFAULT",
|
|
78
|
+
"ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{literal(op[:name])} SET #{AUTOINCREMENT}"
|
|
79
|
+
]
|
|
80
|
+
else
|
|
81
|
+
"ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op)}"
|
|
82
|
+
end
|
|
83
|
+
when :drop_column
|
|
84
|
+
"ALTER TABLE #{quote_schema_table(table)} DROP #{column_definition_sql(op)}"
|
|
85
|
+
when :rename_column # renaming is only possible after db2 v9.7
|
|
86
|
+
"ALTER TABLE #{quote_schema_table(table)} RENAME COLUMN #{quote_identifier(op[:name])} TO #{quote_identifier(op[:new_name])}"
|
|
87
|
+
when :set_column_type
|
|
88
|
+
"ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(op[:name])} SET DATA TYPE #{type_literal(op)}"
|
|
89
|
+
when :set_column_default
|
|
90
|
+
"ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(op[:name])} SET DEFAULT #{literal(op[:default])}"
|
|
91
|
+
when :add_constraint
|
|
92
|
+
if op[:type] == :unique
|
|
93
|
+
sqls = op[:columns].map{|c| ["ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(c)} SET NOT NULL", reorg_sql(table)]}
|
|
94
|
+
sqls << super
|
|
95
|
+
sqls.flatten
|
|
96
|
+
else
|
|
97
|
+
super
|
|
98
|
+
end
|
|
99
|
+
else
|
|
100
|
+
super
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# DB2 uses an identity column for autoincrement.
|
|
105
|
+
def auto_increment_sql
|
|
106
|
+
AUTOINCREMENT
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Add null/not null SQL fragment to column creation SQL.
|
|
110
|
+
def column_definition_null_sql(sql, column)
|
|
111
|
+
null = column.fetch(:null, column[:allow_null])
|
|
112
|
+
null = false if column[:primary_key]
|
|
113
|
+
|
|
114
|
+
sql << NOT_NULL if null == false
|
|
115
|
+
sql << NULL if null == true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Supply columns with NOT NULL if they are part of a composite
|
|
119
|
+
# primary/foreign key
|
|
120
|
+
def column_list_sql(g)
|
|
121
|
+
ks = []
|
|
122
|
+
g.constraints.each{|c| ks = c[:columns] if [:primary_key, :foreign_key].include? c[:type]}
|
|
123
|
+
g.columns.each{|c| c[:null] = false if ks.include?(c[:name]) }
|
|
124
|
+
super
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Here we use DGTT which has most backward compatibility, which uses
|
|
128
|
+
# DECLARE instead of CREATE. CGTT can only be used after version 9.7.
|
|
129
|
+
# http://www.ibm.com/developerworks/data/library/techarticle/dm-0912globaltemptable/
|
|
130
|
+
def create_table_sql(name, generator, options)
|
|
131
|
+
if options[:temp]
|
|
132
|
+
"DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)} (#{column_list_sql(generator)})"
|
|
133
|
+
else
|
|
134
|
+
super
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# DB2 has issues with quoted identifiers, so
|
|
139
|
+
# turn off database quoting by default.
|
|
140
|
+
def quote_identifiers_default
|
|
141
|
+
false
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# DB2 uses RENAME TABLE to rename tables.
|
|
145
|
+
def rename_table_sql(name, new_name)
|
|
146
|
+
"RENAME TABLE #{quote_schema_table(name)} TO #{quote_schema_table(new_name)}"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Run the REORG TABLE command for the table, necessary when
|
|
150
|
+
# the table has been altered.
|
|
151
|
+
def reorg(table)
|
|
152
|
+
synchronize(opts[:server]){|c| c.execute(reorg_sql(table))}
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# The SQL to use for REORGing a table.
|
|
156
|
+
def reorg_sql(table)
|
|
157
|
+
"CALL ADMIN_CMD(#{literal("REORG TABLE #{table}")})"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# We uses the clob type by default for Files.
|
|
161
|
+
# Note: if user select to use blob, then insert statement should use
|
|
162
|
+
# use this for blob value:
|
|
163
|
+
# cast(X'fffefdfcfbfa' as blob(2G))
|
|
164
|
+
def type_literal_generic_file(column)
|
|
165
|
+
::Sequel::DB2::use_clob_as_blob ? :clob : :blob
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# DB2 uses smallint to store booleans.
|
|
169
|
+
def type_literal_generic_trueclass(column)
|
|
170
|
+
:smallint
|
|
171
|
+
end
|
|
172
|
+
alias type_literal_generic_falseclass type_literal_generic_trueclass
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
module DatasetMethods
|
|
176
|
+
include EmulateOffsetWithRowNumber
|
|
177
|
+
|
|
178
|
+
BITWISE_METHOD_MAP = {:& =>:BITAND, :| => :BITOR, :^ => :BITXOR, :'B~'=>:BITNOT}
|
|
179
|
+
BOOL_TRUE = '1'.freeze
|
|
180
|
+
BOOL_FALSE = '0'.freeze
|
|
181
|
+
|
|
182
|
+
# DB2 casts strings using RTRIM and CHAR instead of VARCHAR.
|
|
183
|
+
def cast_sql(expr, type)
|
|
184
|
+
type == String ? "RTRIM(CHAR(#{literal(expr)}))" : super
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Handle DB2 specific LIKE and bitwise operator support, and
|
|
188
|
+
# emulate the extract method, which DB2 doesn't natively support.
|
|
189
|
+
def complex_expression_sql(op, args)
|
|
190
|
+
case op
|
|
191
|
+
when :ILIKE
|
|
192
|
+
super(:LIKE, [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1)) ])
|
|
193
|
+
when :"NOT ILIKE"
|
|
194
|
+
super(:"NOT LIKE", [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1)) ])
|
|
195
|
+
when :&, :|, :^
|
|
196
|
+
# works with db2 v9.5 and after
|
|
197
|
+
op = BITWISE_METHOD_MAP[op]
|
|
198
|
+
complex_expression_arg_pairs(args){|a, b| literal(SQL::Function.new(op, a, b))}
|
|
199
|
+
when :<<
|
|
200
|
+
complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * POWER(2, #{literal(b)}))"}
|
|
201
|
+
when :>>
|
|
202
|
+
complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / POWER(2, #{literal(b)}))"}
|
|
203
|
+
when :'B~'
|
|
204
|
+
literal(SQL::Function.new(:BITNOT, *args))
|
|
205
|
+
when :extract
|
|
206
|
+
"#{args.at(0)}(#{literal(args.at(1))})"
|
|
207
|
+
else
|
|
208
|
+
super
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# DB2 does not support IS TRUE.
|
|
213
|
+
def supports_is_true?
|
|
214
|
+
false
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# DB2 does not support multiple columns in IN.
|
|
218
|
+
def supports_multiple_column_in?
|
|
219
|
+
false
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# DB2 only allows * in SELECT if it is the only thing being selected.
|
|
223
|
+
def supports_select_all_and_column?
|
|
224
|
+
false
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# DB2 does not support fractional seconds in timestamps.
|
|
228
|
+
def supports_timestamp_usecs?
|
|
229
|
+
false
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# DB2 supports window functions
|
|
233
|
+
def supports_window_functions?
|
|
234
|
+
true
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# DB2 does not support WHERE 1.
|
|
238
|
+
def supports_where_true?
|
|
239
|
+
false
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
private
|
|
243
|
+
|
|
244
|
+
# DB2 needs the standard workaround to insert all default values into
|
|
245
|
+
# a table with more than one column.
|
|
246
|
+
def insert_supports_empty_values?
|
|
247
|
+
false
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Use 0 for false on DB2
|
|
251
|
+
def literal_false
|
|
252
|
+
BOOL_FALSE
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Use 1 for true on DB2
|
|
256
|
+
def literal_true
|
|
257
|
+
BOOL_TRUE
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Add a fallback table for empty from situation
|
|
261
|
+
def select_from_sql(sql)
|
|
262
|
+
@opts[:from] ? super : (sql << ' FROM "SYSIBM"."SYSDUMMY1"')
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Modify the sql to limit the number of rows returned
|
|
266
|
+
# Note:
|
|
267
|
+
#
|
|
268
|
+
# After db2 v9.7, MySQL flavored "LIMIT X OFFSET Y" can be enabled using
|
|
269
|
+
#
|
|
270
|
+
# db2set DB2_COMPATIBILITY_VECTOR=MYSQL
|
|
271
|
+
# db2stop
|
|
272
|
+
# db2start
|
|
273
|
+
#
|
|
274
|
+
# Support for this feature is not used in this adapter however.
|
|
275
|
+
def select_limit_sql(sql)
|
|
276
|
+
if l = @opts[:limit]
|
|
277
|
+
sql << " FETCH FIRST #{l == 1 ? 'ROW' : "#{literal(l)} ROWS"} ONLY"
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def _truncate_sql(table)
|
|
282
|
+
# "TRUNCATE #{table} IMMEDIATE" is only for newer version of db2, so we
|
|
283
|
+
# use the following one
|
|
284
|
+
"ALTER TABLE #{quote_schema_table(table)} ACTIVATE NOT LOGGED INITIALLY WITH EMPTY TABLE"
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
end
|