sequel 3.43.0 → 3.44.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 +32 -0
- data/doc/association_basics.rdoc +10 -3
- data/doc/release_notes/3.37.0.txt +1 -1
- data/doc/release_notes/3.44.0.txt +152 -0
- data/lib/sequel/adapters/ado.rb +0 -6
- data/lib/sequel/adapters/db2.rb +0 -3
- data/lib/sequel/adapters/dbi.rb +0 -6
- data/lib/sequel/adapters/ibmdb.rb +0 -3
- data/lib/sequel/adapters/jdbc.rb +8 -12
- data/lib/sequel/adapters/jdbc/as400.rb +2 -18
- data/lib/sequel/adapters/jdbc/derby.rb +10 -0
- data/lib/sequel/adapters/jdbc/h2.rb +10 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +10 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +5 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -4
- data/lib/sequel/adapters/mock.rb +5 -0
- data/lib/sequel/adapters/mysql2.rb +4 -13
- data/lib/sequel/adapters/odbc.rb +0 -5
- data/lib/sequel/adapters/oracle.rb +3 -5
- data/lib/sequel/adapters/postgres.rb +2 -1
- data/lib/sequel/adapters/shared/access.rb +10 -0
- data/lib/sequel/adapters/shared/cubrid.rb +9 -0
- data/lib/sequel/adapters/shared/db2.rb +10 -0
- data/lib/sequel/adapters/shared/mssql.rb +10 -0
- data/lib/sequel/adapters/shared/mysql.rb +14 -0
- data/lib/sequel/adapters/shared/oracle.rb +15 -0
- data/lib/sequel/adapters/shared/postgres.rb +26 -2
- data/lib/sequel/adapters/shared/sqlite.rb +15 -0
- data/lib/sequel/adapters/tinytds.rb +5 -32
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +2 -37
- data/lib/sequel/core.rb +3 -3
- data/lib/sequel/database/misc.rb +40 -4
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +33 -12
- data/lib/sequel/dataset/actions.rb +51 -2
- data/lib/sequel/dataset/features.rb +0 -6
- data/lib/sequel/dataset/sql.rb +1 -1
- data/lib/sequel/exceptions.rb +22 -7
- data/lib/sequel/extensions/columns_introspection.rb +30 -5
- data/lib/sequel/extensions/pg_auto_parameterize.rb +9 -0
- data/lib/sequel/model/associations.rb +50 -37
- data/lib/sequel/model/base.rb +30 -1
- data/lib/sequel/plugins/eager_each.rb +17 -21
- data/lib/sequel/plugins/identity_map.rb +2 -1
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
- data/lib/sequel/sql.rb +4 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +32 -2
- data/spec/adapters/sqlite_spec.rb +20 -0
- data/spec/core/database_spec.rb +40 -0
- data/spec/core/dataset_spec.rb +91 -4
- data/spec/core/mock_adapter_spec.rb +2 -1
- data/spec/core/schema_generator_spec.rb +4 -0
- data/spec/core/schema_spec.rb +9 -3
- data/spec/extensions/association_dependencies_spec.rb +3 -3
- data/spec/extensions/columns_introspection_spec.rb +28 -2
- data/spec/extensions/eager_each_spec.rb +0 -1
- data/spec/extensions/identity_map_spec.rb +3 -2
- data/spec/extensions/migration_spec.rb +6 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +2 -2
- data/spec/extensions/rcte_tree_spec.rb +2 -2
- data/spec/extensions/single_table_inheritance_spec.rb +3 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +1 -1
- data/spec/extensions/validation_class_methods_spec.rb +8 -0
- data/spec/integration/associations_test.rb +4 -4
- data/spec/integration/database_test.rb +68 -20
- data/spec/integration/dataset_test.rb +48 -0
- data/spec/integration/schema_test.rb +25 -1
- data/spec/model/associations_spec.rb +21 -8
- data/spec/model/dataset_methods_spec.rb +58 -18
- metadata +4 -2
@@ -30,6 +30,11 @@ module Sequel
|
|
30
30
|
|
31
31
|
private
|
32
32
|
|
33
|
+
DATABASE_ERROR_REGEXPS = {/Abort due to constraint violation/ => ConstraintViolation}.freeze
|
34
|
+
def database_error_regexps
|
35
|
+
DATABASE_ERROR_REGEXPS
|
36
|
+
end
|
37
|
+
|
33
38
|
# Use last_insert_rowid() to get the last inserted id.
|
34
39
|
def last_insert_id(conn, opts={})
|
35
40
|
statement(conn) do |stmt|
|
@@ -18,7 +18,7 @@ module Sequel
|
|
18
18
|
# than getObject() for this column avoids the problem.
|
19
19
|
# Reference: http://social.msdn.microsoft.com/Forums/en/sqldataaccess/thread/20df12f3-d1bf-4526-9daa-239a83a8e435
|
20
20
|
module MetadataDatasetMethods
|
21
|
-
def process_result_set_convert(cols, result
|
21
|
+
def process_result_set_convert(cols, result)
|
22
22
|
while result.next
|
23
23
|
row = {}
|
24
24
|
cols.each do |n, i, p|
|
@@ -40,18 +40,16 @@ module Sequel
|
|
40
40
|
v
|
41
41
|
end
|
42
42
|
end
|
43
|
-
row.delete(rn) if rn
|
44
43
|
yield row
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
48
|
-
def process_result_set_no_convert(cols, result
|
47
|
+
def process_result_set_no_convert(cols, result)
|
49
48
|
while result.next
|
50
49
|
row = {}
|
51
50
|
cols.each do |n, i|
|
52
51
|
row[n] = (n == :is_autoincrement ? result.getString(i) : result.getObject(i))
|
53
52
|
end
|
54
|
-
row.delete(rn) if rn
|
55
53
|
yield row
|
56
54
|
end
|
57
55
|
end
|
data/lib/sequel/adapters/mock.rb
CHANGED
@@ -138,21 +138,12 @@ module Sequel
|
|
138
138
|
# Yield all rows matching this dataset.
|
139
139
|
def fetch_rows(sql)
|
140
140
|
execute(sql) do |r|
|
141
|
-
if identifier_output_method
|
142
|
-
|
143
|
-
@columns = cols2 = cols.map{|c| output_identifier(c.to_s)}
|
144
|
-
cs = cols.zip(cols2)
|
145
|
-
r.each(:cast_booleans=>convert_tinyint_to_bool?) do |row|
|
146
|
-
h = {}
|
147
|
-
cs.each do |a, b|
|
148
|
-
h[b] = row[a]
|
149
|
-
end
|
150
|
-
yield h
|
151
|
-
end
|
141
|
+
@columns = if identifier_output_method
|
142
|
+
r.fields.map!{|c| output_identifier(c.to_s)}
|
152
143
|
else
|
153
|
-
|
154
|
-
r.each(:cast_booleans=>convert_tinyint_to_bool?){|h| yield h}
|
144
|
+
r.fields
|
155
145
|
end
|
146
|
+
r.each(:cast_booleans=>convert_tinyint_to_bool?){|h| yield h}
|
156
147
|
end
|
157
148
|
self
|
158
149
|
end
|
data/lib/sequel/adapters/odbc.rb
CHANGED
@@ -105,16 +105,11 @@ module Sequel
|
|
105
105
|
i = -1
|
106
106
|
cols = s.columns(true).map{|c| [output_identifier(c.name), i+=1]}
|
107
107
|
columns = cols.map{|c| c.at(0)}
|
108
|
-
if opts[:offset] && offset_returns_row_number_column?
|
109
|
-
rn = row_number_column
|
110
|
-
columns.delete(rn)
|
111
|
-
end
|
112
108
|
@columns = columns
|
113
109
|
if rows = s.fetch_all
|
114
110
|
rows.each do |row|
|
115
111
|
hash = {}
|
116
112
|
cols.each{|n,i| hash[n] = convert_odbc_value(row[i])}
|
117
|
-
hash.delete(rn) if rn
|
118
113
|
yield hash
|
119
114
|
end
|
120
115
|
end
|
@@ -37,7 +37,9 @@ module Sequel
|
|
37
37
|
dbname = opts[:host]
|
38
38
|
end
|
39
39
|
conn = OCI8.new(opts[:user], opts[:password], dbname, opts[:privilege])
|
40
|
-
|
40
|
+
if prefetch_rows = opts.fetch(:prefetch_rows, 100)
|
41
|
+
conn.prefetch_rows = typecast_value_integer(prefetch_rows)
|
42
|
+
end
|
41
43
|
conn.autocommit = true
|
42
44
|
conn.non_blocking = true
|
43
45
|
|
@@ -383,18 +385,14 @@ module Sequel
|
|
383
385
|
|
384
386
|
def fetch_rows(sql)
|
385
387
|
execute(sql) do |cursor|
|
386
|
-
offset = @opts[:offset]
|
387
|
-
rn = row_number_column
|
388
388
|
cps = db.conversion_procs
|
389
389
|
cols = columns = cursor.get_col_names.map{|c| output_identifier(c)}
|
390
390
|
metadata = cursor.column_metadata
|
391
391
|
cm = cols.zip(metadata).map{|c, m| [c, cps[m.data_type]]}
|
392
|
-
columns = cols.reject{|x| x == rn} if offset
|
393
392
|
@columns = columns
|
394
393
|
while r = cursor.fetch
|
395
394
|
row = {}
|
396
395
|
r.zip(cm).each{|v, (c, cp)| row[c] = ((v && cp) ? cp.call(v) : v)}
|
397
|
-
row.delete(rn) if offset
|
398
396
|
yield row
|
399
397
|
end
|
400
398
|
end
|
@@ -289,7 +289,8 @@ module Sequel
|
|
289
289
|
|
290
290
|
# +copy_into+ uses PostgreSQL's +COPY FROM STDIN+ SQL statement to do very fast inserts
|
291
291
|
# into a table using input preformatting in either CSV or PostgreSQL text format.
|
292
|
-
# This method is only supported if pg is the underlying ruby driver.
|
292
|
+
# This method is only supported if pg 0.14.0+ is the underlying ruby driver.
|
293
|
+
# This method should only be called if you want
|
293
294
|
# results returned to the client. If you are using +COPY FROM+
|
294
295
|
# with a filename, you should just use +run+ instead of this method.
|
295
296
|
#
|
@@ -43,6 +43,16 @@ module Sequel
|
|
43
43
|
run(ds.into(name).sql)
|
44
44
|
end
|
45
45
|
|
46
|
+
DATABASE_ERROR_REGEXPS = {
|
47
|
+
/The changes you requested to the table were not successful because they would create duplicate values in the index, primary key, or relationship/ => UniqueConstraintViolation,
|
48
|
+
/You cannot add or change a record because a related record is required|The record cannot be deleted or changed because table/ => ForeignKeyConstraintViolation,
|
49
|
+
/One or more values are prohibited by the validation rule/ => CheckConstraintViolation,
|
50
|
+
/You must enter a value in the .+ field|cannot contain a Null value because the Required property for this field is set to True/ => NotNullConstraintViolation,
|
51
|
+
}.freeze
|
52
|
+
def database_error_regexps
|
53
|
+
DATABASE_ERROR_REGEXPS
|
54
|
+
end
|
55
|
+
|
46
56
|
# The SQL to drop an index for the table.
|
47
57
|
def drop_index_sql(table, op)
|
48
58
|
"DROP INDEX #{quote_identifier(op[:name] || default_index_name(table, op[:columns]))} ON #{quote_schema_table(table)}"
|
@@ -126,6 +126,15 @@ module Sequel
|
|
126
126
|
:query
|
127
127
|
end
|
128
128
|
|
129
|
+
DATABASE_ERROR_REGEXPS = {
|
130
|
+
/Operation would have caused one or more unique constraint violations/ => UniqueConstraintViolation,
|
131
|
+
/The constraint of the foreign key .+ is invalid|Update\/Delete operations are restricted by the foreign key/ => ForeignKeyConstraintViolation,
|
132
|
+
/cannot be made NULL/ => NotNullConstraintViolation,
|
133
|
+
}.freeze
|
134
|
+
def database_error_regexps
|
135
|
+
DATABASE_ERROR_REGEXPS
|
136
|
+
end
|
137
|
+
|
129
138
|
# CUBRID is case insensitive, so don't modify identifiers
|
130
139
|
def identifier_input_method_default
|
131
140
|
nil
|
@@ -154,6 +154,16 @@ module Sequel
|
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
157
|
+
DATABASE_ERROR_REGEXPS = {
|
158
|
+
/DB2 SQL Error: SQLCODE=-803, SQLSTATE=23505|One or more values in the INSERT statement, UPDATE statement, or foreign key update caused by a DELETE statement are not valid because the primary key, unique constraint or unique index/ => UniqueConstraintViolation,
|
159
|
+
/DB2 SQL Error: (SQLCODE=-530, SQLSTATE=23503|SQLCODE=-532, SQLSTATE=23504)|The insert or update value of the FOREIGN KEY .+ is not equal to any value of the parent key of the parent table|A parent row cannot be deleted because the relationship .+ restricts the deletion/ => ForeignKeyConstraintViolation,
|
160
|
+
/DB2 SQL Error: SQLCODE=-545, SQLSTATE=23513|The requested operation is not allowed because a row does not satisfy the check constraint/ => CheckConstraintViolation,
|
161
|
+
/DB2 SQL Error: SQLCODE=-407, SQLSTATE=23502|Assignment of a NULL value to a NOT NULL column/ => NotNullConstraintViolation,
|
162
|
+
}.freeze
|
163
|
+
def database_error_regexps
|
164
|
+
DATABASE_ERROR_REGEXPS
|
165
|
+
end
|
166
|
+
|
157
167
|
# DB2 has issues with quoted identifiers, so
|
158
168
|
# turn off database quoting by default.
|
159
169
|
def quote_identifiers_default
|
@@ -238,6 +238,16 @@ module Sequel
|
|
238
238
|
run(ds.into(name).sql)
|
239
239
|
end
|
240
240
|
|
241
|
+
DATABASE_ERROR_REGEXPS = {
|
242
|
+
/Violation of UNIQUE KEY constraint/ => UniqueConstraintViolation,
|
243
|
+
/conflicted with the (FOREIGN KEY.*|REFERENCE) constraint/ => ForeignKeyConstraintViolation,
|
244
|
+
/conflicted with the CHECK constraint/ => CheckConstraintViolation,
|
245
|
+
/column does not allow nulls/ => NotNullConstraintViolation,
|
246
|
+
}.freeze
|
247
|
+
def database_error_regexps
|
248
|
+
DATABASE_ERROR_REGEXPS
|
249
|
+
end
|
250
|
+
|
241
251
|
# The name of the constraint for setting the default value on the table and column.
|
242
252
|
# The SQL used to select default constraints utilizes MSSQL catalog views which were introduced in 2005.
|
243
253
|
# This method intentionally does not support MSSQL 2000.
|
@@ -350,6 +350,15 @@ module Sequel
|
|
350
350
|
"#{super}#{" ENGINE=#{engine}" if engine}#{" DEFAULT CHARSET=#{charset}" if charset}#{" DEFAULT COLLATE=#{collate}" if collate}"
|
351
351
|
end
|
352
352
|
|
353
|
+
DATABASE_ERROR_REGEXPS = {
|
354
|
+
/Duplicate entry .+ for key/ => UniqueConstraintViolation,
|
355
|
+
/foreign key constraint fails/ => ForeignKeyConstraintViolation,
|
356
|
+
/cannot be null/ => NotNullConstraintViolation,
|
357
|
+
}.freeze
|
358
|
+
def database_error_regexps
|
359
|
+
DATABASE_ERROR_REGEXPS
|
360
|
+
end
|
361
|
+
|
353
362
|
# Backbone of the tables and views support using SHOW FULL TABLES.
|
354
363
|
def full_tables(type, opts)
|
355
364
|
m = output_identifier_meth
|
@@ -430,6 +439,11 @@ module Sequel
|
|
430
439
|
true
|
431
440
|
end
|
432
441
|
|
442
|
+
# MySQL supports CREATE OR REPLACE VIEW.
|
443
|
+
def supports_create_or_replace_view?
|
444
|
+
true
|
445
|
+
end
|
446
|
+
|
433
447
|
# Respect the :size option if given to produce
|
434
448
|
# tinyblob, mediumblob, and longblob if :tiny,
|
435
449
|
# :medium, or :long is given.
|
@@ -136,6 +136,16 @@ module Sequel
|
|
136
136
|
sql
|
137
137
|
end
|
138
138
|
|
139
|
+
DATABASE_ERROR_REGEXPS = {
|
140
|
+
/unique constraint .+ violated/ => UniqueConstraintViolation,
|
141
|
+
/integrity constraint .+ violated/ => ForeignKeyConstraintViolation,
|
142
|
+
/check constraint .+ violated/ => CheckConstraintViolation,
|
143
|
+
/cannot insert NULL into|cannot update .+ to NULL/ => NotNullConstraintViolation,
|
144
|
+
}.freeze
|
145
|
+
def database_error_regexps
|
146
|
+
DATABASE_ERROR_REGEXPS
|
147
|
+
end
|
148
|
+
|
139
149
|
def default_sequence_name(table, column)
|
140
150
|
"seq_#{table}_#{column}"
|
141
151
|
end
|
@@ -160,6 +170,11 @@ module Sequel
|
|
160
170
|
end
|
161
171
|
end
|
162
172
|
|
173
|
+
# Oracle supports CREATE OR REPLACE VIEW.
|
174
|
+
def supports_create_or_replace_view?
|
175
|
+
true
|
176
|
+
end
|
177
|
+
|
163
178
|
# Oracle's integer/:number type handles larger values than
|
164
179
|
# most other databases's bigint types, so it should be
|
165
180
|
# safe to use for Bignum.
|
@@ -53,14 +53,14 @@ module Sequel
|
|
53
53
|
end
|
54
54
|
|
55
55
|
class CreateTableGenerator < Sequel::Schema::Generator
|
56
|
-
# Add an exclusion constraint when creating the table.
|
56
|
+
# Add an exclusion constraint when creating the table. Elements should be
|
57
57
|
# an array of 2 element arrays, with the first element being the column or
|
58
58
|
# expression the exclusion constraint is applied to, and the second element
|
59
59
|
# being the operator to use for the column/expression to check for exclusion.
|
60
60
|
#
|
61
61
|
# Example:
|
62
62
|
#
|
63
|
-
#
|
63
|
+
# exclude([[:col1, '&&'], [:col2, '=']])
|
64
64
|
# # EXCLUDE USING gist (col1 WITH &&, col2 WITH =)
|
65
65
|
#
|
66
66
|
# Options supported:
|
@@ -89,6 +89,9 @@ module Sequel
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
+
# Error raised when Sequel determines a PostgreSQL exclusion constraint has been violated.
|
93
|
+
class ExclusionConstraintViolation < Sequel::ConstraintViolation; end
|
94
|
+
|
92
95
|
# Methods shared by Database instances that connect to PostgreSQL.
|
93
96
|
module DatabaseMethods
|
94
97
|
EXCLUDE_SCHEMAS = /pg_*|information_schema/i
|
@@ -627,6 +630,17 @@ module Sequel
|
|
627
630
|
end
|
628
631
|
end
|
629
632
|
|
633
|
+
DATABASE_ERROR_REGEXPS = {
|
634
|
+
/duplicate key value violates unique constraint/ => UniqueConstraintViolation,
|
635
|
+
/violates foreign key constraint/ => ForeignKeyConstraintViolation,
|
636
|
+
/violates check constraint/ => CheckConstraintViolation,
|
637
|
+
/violates not-null constraint/ => NotNullConstraintViolation,
|
638
|
+
/conflicting key value violates exclusion constraint/ => ExclusionConstraintViolation,
|
639
|
+
}.freeze
|
640
|
+
def database_error_regexps
|
641
|
+
DATABASE_ERROR_REGEXPS
|
642
|
+
end
|
643
|
+
|
630
644
|
# SQL for doing fast table insert from stdin.
|
631
645
|
def copy_into_sql(table, opts)
|
632
646
|
sql = "COPY #{literal(table)}"
|
@@ -717,6 +731,11 @@ module Sequel
|
|
717
731
|
"CREATE TRIGGER #{name} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} ON #{quote_schema_table(table)}#{' FOR EACH ROW' if opts[:each_row]} EXECUTE PROCEDURE #{function}(#{Array(opts[:args]).map{|a| literal(a)}.join(', ')})"
|
718
732
|
end
|
719
733
|
|
734
|
+
# DDL fragment for initial part of CREATE VIEW statement
|
735
|
+
def create_view_prefix_sql(name, options)
|
736
|
+
"CREATE #{'OR REPLACE 'if options[:replace]}#{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}"
|
737
|
+
end
|
738
|
+
|
720
739
|
# The errors that the main adapters can raise, depends on the adapter being used
|
721
740
|
def database_error_classes
|
722
741
|
CONVERTED_EXCEPTIONS
|
@@ -919,6 +938,11 @@ module Sequel
|
|
919
938
|
true
|
920
939
|
end
|
921
940
|
|
941
|
+
# PostgreSQL supports CREATE OR REPLACE VIEW.
|
942
|
+
def supports_create_or_replace_view?
|
943
|
+
true
|
944
|
+
end
|
945
|
+
|
922
946
|
# Handle bigserial type if :serial option is present
|
923
947
|
def type_literal_generic_bignum(column)
|
924
948
|
column[:serial] ? :bigserial : super
|
@@ -312,6 +312,21 @@ module Sequel
|
|
312
312
|
ps
|
313
313
|
end
|
314
314
|
|
315
|
+
# SQLite support creating temporary views.
|
316
|
+
def create_view_prefix_sql(name, options)
|
317
|
+
"CREATE #{'TEMPORARY 'if options[:temp]}VIEW #{quote_schema_table(name)}"
|
318
|
+
end
|
319
|
+
|
320
|
+
DATABASE_ERROR_REGEXPS = {
|
321
|
+
/is not unique\z/ => UniqueConstraintViolation,
|
322
|
+
/foreign key constraint failed\z/ => ForeignKeyConstraintViolation,
|
323
|
+
/\A(SQLITE ERROR 19 \(CONSTRAINT\) : )?constraint failed\z/ => ConstraintViolation,
|
324
|
+
/may not be NULL\z/ => NotNullConstraintViolation,
|
325
|
+
}.freeze
|
326
|
+
def database_error_regexps
|
327
|
+
DATABASE_ERROR_REGEXPS
|
328
|
+
end
|
329
|
+
|
315
330
|
# The array of column schema hashes for the current columns in the table
|
316
331
|
def defined_columns_for(table)
|
317
332
|
cols = parse_pragma(table, {})
|
@@ -18,6 +18,7 @@ module Sequel
|
|
18
18
|
opts = server_opts(server)
|
19
19
|
opts[:username] = opts[:user]
|
20
20
|
c = TinyTds::Client.new(opts)
|
21
|
+
c.query_options.merge!(:cache_rows=>false)
|
21
22
|
|
22
23
|
if (ts = opts[:textsize])
|
23
24
|
sql = "SET TEXTSIZE #{typecast_value_integer(ts)}"
|
@@ -215,40 +216,12 @@ module Sequel
|
|
215
216
|
# various cases.
|
216
217
|
def fetch_rows(sql)
|
217
218
|
execute(sql) do |result|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
columns = cols = result.fields.map{|c| output_identifier(c)}
|
222
|
-
if offset
|
223
|
-
rn = row_number_column
|
224
|
-
columns = columns.dup
|
225
|
-
columns.delete(rn)
|
226
|
-
end
|
227
|
-
@columns = columns
|
228
|
-
#if identifier_output_method
|
229
|
-
each_opts[:as] = :array
|
230
|
-
result.each(each_opts) do |r|
|
231
|
-
h = {}
|
232
|
-
cols.zip(r).each{|k, v| h[k] = v}
|
233
|
-
h.delete(rn) if rn
|
234
|
-
yield h
|
235
|
-
end
|
236
|
-
=begin
|
237
|
-
# Temporarily disable this optimization, as tiny_tds uses string keys
|
238
|
-
# if result.fields is called before result.each(:symbolize_keys=>true).
|
239
|
-
# See https://github.com/rails-sqlserver/tiny_tds/issues/57
|
219
|
+
@columns = result.fields.map!{|c| output_identifier(c)}
|
220
|
+
if db.timezone == :utc
|
221
|
+
result.each(:timezone=>:utc){|r| yield r}
|
240
222
|
else
|
241
|
-
|
242
|
-
if offset
|
243
|
-
result.each(each_opts) do |r|
|
244
|
-
r.delete(rn) if rn
|
245
|
-
yield r
|
246
|
-
end
|
247
|
-
else
|
248
|
-
result.each(each_opts, &Proc.new)
|
249
|
-
end
|
223
|
+
result.each{|r| yield r}
|
250
224
|
end
|
251
|
-
=end
|
252
225
|
end
|
253
226
|
self
|
254
227
|
end
|
@@ -1,36 +1,5 @@
|
|
1
1
|
module Sequel
|
2
2
|
module EmulateOffsetWithRowNumber
|
3
|
-
# When a subselect that uses :offset is used in IN or NOT IN,
|
4
|
-
# use a nested subselect that only includes the first column
|
5
|
-
# instead of the ROW_NUMBER column added by the emulated offset support.
|
6
|
-
def complex_expression_sql_append(sql, op, args)
|
7
|
-
case op
|
8
|
-
when :IN, :"NOT IN"
|
9
|
-
ds = args.at(1)
|
10
|
-
if ds.is_a?(Sequel::Dataset) && ds.opts[:offset]
|
11
|
-
c = ds.opts[:select].first
|
12
|
-
case c
|
13
|
-
when Symbol
|
14
|
-
t, cl, a = split_symbol(c)
|
15
|
-
if a
|
16
|
-
c = SQL::Identifier.new(a)
|
17
|
-
elsif t
|
18
|
-
c = SQL::Identifier.new(cl)
|
19
|
-
end
|
20
|
-
when SQL::AliasedExpression
|
21
|
-
c = SQL::Identifier.new(c.aliaz)
|
22
|
-
when SQL::QualifiedIdentifier
|
23
|
-
c = SQL::Identifier.new(c.column)
|
24
|
-
end
|
25
|
-
super(sql, op, [args.at(0), ds.from_self.select(c)])
|
26
|
-
else
|
27
|
-
super
|
28
|
-
end
|
29
|
-
else
|
30
|
-
super
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
3
|
# Emulate OFFSET support with the ROW_NUMBER window function
|
35
4
|
#
|
36
5
|
# The implementation is ugly, cloning the current dataset and modifying
|
@@ -47,6 +16,7 @@ module Sequel
|
|
47
16
|
raise(Error, "#{db.database_type} requires an order be provided if using an offset")
|
48
17
|
end
|
49
18
|
|
19
|
+
columns = clone(:append_sql=>'').columns
|
50
20
|
dsa1 = dataset_alias(1)
|
51
21
|
rn = row_number_column
|
52
22
|
sql = @opts[:append_sql] || ''
|
@@ -54,6 +24,7 @@ module Sequel
|
|
54
24
|
unordered.
|
55
25
|
select_append{ROW_NUMBER(:over, :order=>order){}.as(rn)}.
|
56
26
|
from_self(:alias=>dsa1).
|
27
|
+
select(*columns).
|
57
28
|
limit(@opts[:limit]).
|
58
29
|
where(SQL::Identifier.new(rn) > o).
|
59
30
|
order(rn))
|
@@ -67,11 +38,5 @@ module Sequel
|
|
67
38
|
def default_offset_order
|
68
39
|
clone(:append_sql=>'').columns
|
69
40
|
end
|
70
|
-
|
71
|
-
# This emulation adds an extra row number column that should be
|
72
|
-
# eliminated.
|
73
|
-
def offset_returns_row_number_column?
|
74
|
-
true
|
75
|
-
end
|
76
41
|
end
|
77
42
|
end
|