sequel 3.37.0 → 3.38.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/CHANGELOG +56 -0
  2. data/README.rdoc +82 -58
  3. data/Rakefile +6 -5
  4. data/bin/sequel +1 -1
  5. data/doc/active_record.rdoc +67 -52
  6. data/doc/advanced_associations.rdoc +33 -48
  7. data/doc/association_basics.rdoc +41 -51
  8. data/doc/cheat_sheet.rdoc +21 -21
  9. data/doc/core_extensions.rdoc +374 -0
  10. data/doc/dataset_basics.rdoc +5 -5
  11. data/doc/dataset_filtering.rdoc +47 -43
  12. data/doc/mass_assignment.rdoc +1 -1
  13. data/doc/migration.rdoc +4 -5
  14. data/doc/model_hooks.rdoc +3 -3
  15. data/doc/object_model.rdoc +31 -25
  16. data/doc/opening_databases.rdoc +19 -5
  17. data/doc/prepared_statements.rdoc +2 -2
  18. data/doc/querying.rdoc +109 -52
  19. data/doc/reflection.rdoc +6 -6
  20. data/doc/release_notes/3.38.0.txt +234 -0
  21. data/doc/schema_modification.rdoc +22 -13
  22. data/doc/sharding.rdoc +8 -9
  23. data/doc/sql.rdoc +154 -112
  24. data/doc/testing.rdoc +47 -7
  25. data/doc/thread_safety.rdoc +1 -1
  26. data/doc/transactions.rdoc +1 -1
  27. data/doc/validations.rdoc +1 -1
  28. data/doc/virtual_rows.rdoc +29 -43
  29. data/lib/sequel/adapters/do/postgres.rb +1 -4
  30. data/lib/sequel/adapters/jdbc.rb +14 -3
  31. data/lib/sequel/adapters/jdbc/db2.rb +9 -0
  32. data/lib/sequel/adapters/jdbc/derby.rb +41 -4
  33. data/lib/sequel/adapters/jdbc/jtds.rb +11 -0
  34. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -6
  35. data/lib/sequel/adapters/mock.rb +10 -4
  36. data/lib/sequel/adapters/postgres.rb +1 -28
  37. data/lib/sequel/adapters/shared/mssql.rb +23 -13
  38. data/lib/sequel/adapters/shared/postgres.rb +46 -0
  39. data/lib/sequel/adapters/swift.rb +21 -13
  40. data/lib/sequel/adapters/swift/mysql.rb +1 -0
  41. data/lib/sequel/adapters/swift/postgres.rb +4 -5
  42. data/lib/sequel/adapters/swift/sqlite.rb +2 -1
  43. data/lib/sequel/adapters/tinytds.rb +14 -2
  44. data/lib/sequel/adapters/utils/pg_types.rb +5 -0
  45. data/lib/sequel/core.rb +29 -17
  46. data/lib/sequel/database/query.rb +1 -1
  47. data/lib/sequel/database/schema_generator.rb +3 -0
  48. data/lib/sequel/dataset/actions.rb +5 -6
  49. data/lib/sequel/dataset/query.rb +7 -7
  50. data/lib/sequel/dataset/sql.rb +5 -18
  51. data/lib/sequel/extensions/core_extensions.rb +8 -12
  52. data/lib/sequel/extensions/pg_array.rb +59 -33
  53. data/lib/sequel/extensions/pg_array_ops.rb +32 -4
  54. data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
  55. data/lib/sequel/extensions/pg_hstore.rb +32 -17
  56. data/lib/sequel/extensions/pg_hstore_ops.rb +32 -3
  57. data/lib/sequel/extensions/pg_inet.rb +1 -2
  58. data/lib/sequel/extensions/pg_interval.rb +0 -1
  59. data/lib/sequel/extensions/pg_json.rb +41 -23
  60. data/lib/sequel/extensions/pg_range.rb +36 -11
  61. data/lib/sequel/extensions/pg_range_ops.rb +32 -4
  62. data/lib/sequel/extensions/pg_row.rb +572 -0
  63. data/lib/sequel/extensions/pg_row_ops.rb +164 -0
  64. data/lib/sequel/extensions/query.rb +3 -3
  65. data/lib/sequel/extensions/schema_dumper.rb +7 -8
  66. data/lib/sequel/extensions/select_remove.rb +1 -1
  67. data/lib/sequel/model/base.rb +1 -0
  68. data/lib/sequel/no_core_ext.rb +1 -1
  69. data/lib/sequel/plugins/pg_row.rb +121 -0
  70. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  71. data/lib/sequel/plugins/validation_helpers.rb +31 -0
  72. data/lib/sequel/sql.rb +64 -44
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/mssql_spec.rb +37 -12
  75. data/spec/adapters/mysql_spec.rb +39 -75
  76. data/spec/adapters/oracle_spec.rb +11 -11
  77. data/spec/adapters/postgres_spec.rb +414 -237
  78. data/spec/adapters/spec_helper.rb +1 -1
  79. data/spec/adapters/sqlite_spec.rb +14 -14
  80. data/spec/core/database_spec.rb +6 -6
  81. data/spec/core/dataset_spec.rb +169 -205
  82. data/spec/core/expression_filters_spec.rb +182 -295
  83. data/spec/core/object_graph_spec.rb +6 -6
  84. data/spec/core/schema_spec.rb +14 -14
  85. data/spec/core/spec_helper.rb +1 -0
  86. data/spec/{extensions/core_extensions_spec.rb → core_extensions_spec.rb} +208 -14
  87. data/spec/extensions/columns_introspection_spec.rb +5 -5
  88. data/spec/extensions/hook_class_methods_spec.rb +28 -36
  89. data/spec/extensions/many_through_many_spec.rb +4 -4
  90. data/spec/extensions/pg_array_ops_spec.rb +15 -7
  91. data/spec/extensions/pg_array_spec.rb +81 -48
  92. data/spec/extensions/pg_auto_parameterize_spec.rb +2 -2
  93. data/spec/extensions/pg_hstore_ops_spec.rb +13 -9
  94. data/spec/extensions/pg_hstore_spec.rb +66 -65
  95. data/spec/extensions/pg_inet_spec.rb +2 -4
  96. data/spec/extensions/pg_interval_spec.rb +2 -3
  97. data/spec/extensions/pg_json_spec.rb +20 -18
  98. data/spec/extensions/pg_range_ops_spec.rb +11 -4
  99. data/spec/extensions/pg_range_spec.rb +30 -7
  100. data/spec/extensions/pg_row_ops_spec.rb +48 -0
  101. data/spec/extensions/pg_row_plugin_spec.rb +45 -0
  102. data/spec/extensions/pg_row_spec.rb +323 -0
  103. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  104. data/spec/extensions/query_literals_spec.rb +11 -11
  105. data/spec/extensions/query_spec.rb +3 -3
  106. data/spec/extensions/schema_dumper_spec.rb +20 -4
  107. data/spec/extensions/schema_spec.rb +18 -41
  108. data/spec/extensions/select_remove_spec.rb +4 -4
  109. data/spec/extensions/spec_helper.rb +4 -8
  110. data/spec/extensions/to_dot_spec.rb +5 -5
  111. data/spec/extensions/validation_class_methods_spec.rb +28 -16
  112. data/spec/integration/associations_test.rb +20 -20
  113. data/spec/integration/dataset_test.rb +98 -98
  114. data/spec/integration/eager_loader_test.rb +13 -27
  115. data/spec/integration/plugin_test.rb +5 -5
  116. data/spec/integration/prepared_statement_test.rb +22 -13
  117. data/spec/integration/schema_test.rb +28 -18
  118. data/spec/integration/spec_helper.rb +1 -1
  119. data/spec/integration/timezone_test.rb +2 -2
  120. data/spec/integration/type_test.rb +15 -6
  121. data/spec/model/association_reflection_spec.rb +1 -1
  122. data/spec/model/associations_spec.rb +4 -4
  123. data/spec/model/base_spec.rb +5 -5
  124. data/spec/model/eager_loading_spec.rb +15 -15
  125. data/spec/model/model_spec.rb +32 -32
  126. data/spec/model/record_spec.rb +16 -0
  127. data/spec/model/spec_helper.rb +2 -6
  128. data/spec/model/validations_spec.rb +1 -1
  129. metadata +16 -4
@@ -5,6 +5,17 @@ module Sequel
5
5
  # Database and Dataset instance methods for JTDS specific
6
6
  # support via JDBC.
7
7
  module JTDS
8
+ module DatabaseMethods
9
+ include Sequel::JDBC::MSSQL::DatabaseMethods
10
+
11
+ private
12
+
13
+ # Handle nil values by using setNull with the correct parameter type.
14
+ def set_ps_arg_nil(cps, i)
15
+ cps.setNull(i, cps.getParameterMetaData.getParameterType(i))
16
+ end
17
+ end
18
+
8
19
  # Dataset class for JTDS datasets accessed via JDBC.
9
20
  class Dataset < JDBC::Dataset
10
21
  include Sequel::MSSQL::DatasetMethods
@@ -15,18 +15,15 @@ module Sequel
15
15
  # Add the primary_keys and primary_key_sequences instance variables,
16
16
  # so we can get the correct return values for inserted rows.
17
17
  def self.extended(db)
18
- db.instance_eval do
19
- @primary_keys = {}
20
- @primary_key_sequences = {}
21
- end
18
+ db.send(:initialize_postgres_adapter)
22
19
  end
23
20
 
24
21
  private
25
22
 
26
23
  # Use setNull for nil arguments as the default behavior of setString
27
24
  # with nil doesn't appear to work correctly on PostgreSQL.
28
- def set_ps_arg(cps, arg, i)
29
- arg.nil? ? cps.setNull(i, JavaSQL::Types::NULL) : super
25
+ def set_ps_arg_nil(cps, i)
26
+ cps.setNull(i, JavaSQL::Types::NULL)
30
27
  end
31
28
 
32
29
  # Execute the connection configuration SQL queries on the connection.
@@ -50,12 +50,17 @@ module Sequel
50
50
  'postgres' => lambda do |db|
51
51
  db.instance_eval do
52
52
  @server_version = 90103
53
- @primary_keys = {}
54
- @primary_key_sequences = {}
53
+ initialize_postgres_adapter
54
+ end
55
+ db.extend(Module.new do
56
+ def bound_variable_arg(arg, conn)
57
+ arg
58
+ end
59
+
55
60
  def primary_key(table)
56
61
  :id
57
62
  end
58
- end
63
+ end)
59
64
  end
60
65
  }
61
66
 
@@ -127,6 +132,7 @@ module Sequel
127
132
  def initialize(opts={})
128
133
  super
129
134
  opts = @opts
135
+ @sqls = opts[:sqls] || []
130
136
  if mod_name = SHARED_ADAPTERS[opts[:host]]
131
137
  @shared_adapter = true
132
138
  require "sequel/adapters/shared/#{opts[:host]}"
@@ -141,7 +147,7 @@ module Sequel
141
147
  self.fetch = opts[:fetch]
142
148
  self.numrows = opts[:numrows]
143
149
  extend(opts[:extend]) if opts[:extend]
144
- @sqls = opts[:sqls] || []
150
+ sqls
145
151
  end
146
152
 
147
153
  # Return a related Connection option connecting to the given shard.
@@ -1,5 +1,4 @@
1
1
  Sequel.require 'adapters/shared/postgres'
2
- Sequel.require 'adapters/utils/pg_types'
3
2
 
4
3
  begin
5
4
  require 'pg'
@@ -157,10 +156,6 @@ module Sequel
157
156
 
158
157
  set_adapter_scheme :postgres
159
158
 
160
- # A hash of conversion procs, keyed by type integer (oid) and
161
- # having callable values for the conversion proc for that type.
162
- attr_reader :conversion_procs
163
-
164
159
  # Whether infinite timestamps should be converted on retrieval. By default, no
165
160
  # conversion is done, so an error is raised if you attempt to retrieve an infinite
166
161
  # timestamp. You can set this to :nil to convert to nil, :string to leave
@@ -172,8 +167,7 @@ module Sequel
172
167
  def initialize(*args)
173
168
  super
174
169
  @convert_infinite_timestamps = false
175
- @primary_keys = {}
176
- @primary_key_sequences = {}
170
+ initialize_postgres_adapter
177
171
  end
178
172
 
179
173
  # Convert given argument so that it can be used directly by pg. Currently, pg doesn't
@@ -232,7 +226,6 @@ module Sequel
232
226
  conn.instance_variable_set(:@db, self)
233
227
  conn.instance_variable_set(:@prepared_statements, {}) if SEQUEL_POSTGRES_USES_PG
234
228
  connection_configuration_sqls.each{|sql| conn.execute(sql)}
235
- @conversion_procs ||= get_conversion_procs(conn)
236
229
  conn
237
230
  end
238
231
 
@@ -354,12 +347,6 @@ module Sequel
354
347
  end
355
348
  end
356
349
 
357
- # Reset the database's conversion procs, requires a server query if there
358
- # any named types.
359
- def reset_conversion_procs
360
- synchronize{|conn| @conversion_procs = get_conversion_procs(conn)}
361
- end
362
-
363
350
  # If convert_infinite_timestamps is true and the value is infinite, return an appropriate
364
351
  # value based on the convert_infinite_timestamps setting.
365
352
  def to_application_timestamp(value)
@@ -447,20 +434,6 @@ module Sequel
447
434
  end
448
435
  end
449
436
 
450
- # Return the conversion procs hash to use for this database.
451
- def get_conversion_procs(conn)
452
- procs = PG_TYPES.dup
453
- procs[1184] = procs[1114] = method(:to_application_timestamp)
454
- unless (pgnt = PG_NAMED_TYPES).empty?
455
- conn.execute("SELECT oid, typname FROM pg_type where typtype = 'b' AND typname IN ('#{pgnt.keys.map{|type| conn.escape_string(type.to_s)}.join("', '")}')") do |res|
456
- res.ntuples.times do |i|
457
- procs[res.getvalue(i, 0).to_i] ||= pgnt[res.getvalue(i, 1).untaint.to_sym]
458
- end
459
- end
460
- end
461
- procs
462
- end
463
-
464
437
  # Return an appropriate value for the given infinite timestamp string.
465
438
  def infinite_timestamp_value(value)
466
439
  case convert_infinite_timestamps
@@ -93,9 +93,17 @@ module Sequel
93
93
  def views(opts={})
94
94
  information_schema_tables('VIEW', opts)
95
95
  end
96
-
96
+
97
97
  private
98
98
 
99
+ # Add dropping of the default constraint to the list of SQL queries.
100
+ # This is necessary before dropping the column or changing its type.
101
+ def add_drop_default_constraint_sql(sqls, table, column)
102
+ if constraint = default_constraint_name(table, column)
103
+ sqls << "ALTER TABLE #{quote_schema_table(table)} DROP CONSTRAINT #{constraint}"
104
+ end
105
+ end
106
+
99
107
  # MSSQL uses the IDENTITY(1,1) column for autoincrementing columns.
100
108
  def auto_increment_sql
101
109
  AUTO_INCREMENT
@@ -106,6 +114,10 @@ module Sequel
106
114
  case op[:op]
107
115
  when :add_column
108
116
  "ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op)}"
117
+ when :drop_column
118
+ sqls = []
119
+ add_drop_default_constraint_sql(sqls, table, op[:name])
120
+ sqls << super
109
121
  when :rename_column
110
122
  "sp_rename #{literal("#{quote_schema_table(table)}.#{quote_identifier(op[:name])}")}, #{literal(op[:new_name].to_s)}, 'COLUMN'"
111
123
  when :set_column_type
@@ -113,9 +125,7 @@ module Sequel
113
125
  if sch = schema(table)
114
126
  if cs = sch.each{|k, v| break v if k == op[:name]; nil}
115
127
  cs = cs.dup
116
- if constraint = default_constraint_name(table, op[:name])
117
- sqls << "ALTER TABLE #{quote_schema_table(table)} DROP CONSTRAINT #{constraint}"
118
- end
128
+ add_drop_default_constraint_sql(sqls, table, op[:name])
119
129
  cs[:default] = cs[:ruby_default]
120
130
  op = cs.merge!(op)
121
131
  default = op.delete(:default)
@@ -176,15 +186,15 @@ module Sequel
176
186
  end
177
187
 
178
188
  # The name of the constraint for setting the default value on the table and column.
179
- def default_constraint_name(table, column)
180
- from(:sysobjects___c_obj).
181
- join(:syscomments___com, :id=>:id).
182
- join(:sysobjects___t_obj, :id=>:c_obj__parent_obj).
183
- join(:sysconstraints___con, :constid=>:c_obj__id).
184
- join(:syscolumns___col, :id=>:t_obj__id, :colid=>:colid).
185
- where{{c_obj__uid=>user_id{}}}.
186
- where(:c_obj__xtype=>'D', :t_obj__name=>table.to_s, :col__name=>column.to_s).
187
- get(:c_obj__name)
189
+ # The SQL used to select default constraints utilizes MSSQL catalog views which were introduced in 2005.
190
+ # This method intentionally does not support MSSQL 2000.
191
+ def default_constraint_name(table, column_name)
192
+ if server_version >= 9000000
193
+ table_name = schema_and_table(table).compact.join('.')
194
+ self[:sys__default_constraints].
195
+ where{{:parent_object_id => object_id(table_name), col_name(:parent_object_id, :parent_column_id) => column_name.to_s}}.
196
+ get(:name)
197
+ end
188
198
  end
189
199
 
190
200
  # The SQL to drop an index for the table.
@@ -1,3 +1,5 @@
1
+ Sequel.require 'adapters/utils/pg_types'
2
+
1
3
  module Sequel
2
4
  # Top level module for holding all PostgreSQL-related modules and classes
3
5
  # for Sequel. There are a few module level accessors that are added via
@@ -146,6 +148,13 @@ module Sequel
146
148
  end_sql
147
149
  ).strip.gsub(/\s+/, ' ').freeze
148
150
 
151
+ # The Sequel extensions that require reseting of the conversion procs.
152
+ RESET_PROCS_EXTENSIONS = [:pg_array, :pg_hstore, :pg_inet, :pg_interval, :pg_json, :pg_range].freeze
153
+
154
+ # A hash of conversion procs, keyed by type integer (oid) and
155
+ # having callable values for the conversion proc for that type.
156
+ attr_reader :conversion_procs
157
+
149
158
  # Commit an existing prepared transaction with the given transaction
150
159
  # identifier string.
151
160
  def commit_prepared_transaction(transaction_id)
@@ -250,6 +259,17 @@ module Sequel
250
259
  self << drop_trigger_sql(table, name, opts)
251
260
  end
252
261
 
262
+ # If any of the extensions that require reseting the conversion procs
263
+ # is loaded, reset them. This is done here so that if you load
264
+ # multiple pg_* extensions in the same call, the conversion procs are
265
+ # only reset once instead of once for every extension.
266
+ def extension(*exts)
267
+ super
268
+ unless (RESET_PROCS_EXTENSIONS & exts).empty?
269
+ reset_conversion_procs
270
+ end
271
+ end
272
+
253
273
  # Return full foreign key information using the pg system tables, including
254
274
  # :name, :on_delete, :on_update, and :deferrable entries in the hashes.
255
275
  def foreign_key_list(table, opts={})
@@ -380,6 +400,12 @@ module Sequel
380
400
  end
381
401
  end
382
402
  end
403
+
404
+ # Reset the database's conversion procs, requires a server query if there
405
+ # any named types.
406
+ def reset_conversion_procs
407
+ @conversion_procs = get_conversion_procs
408
+ end
383
409
 
384
410
  # Reset the primary key sequence for the given table, baseing it on the
385
411
  # maximum current value of the table's primary key.
@@ -643,6 +669,18 @@ module Sequel
643
669
  end
644
670
  end
645
671
 
672
+ # Return a hash with oid keys and callable values, used for converting types.
673
+ def get_conversion_procs
674
+ procs = PG_TYPES.dup
675
+ procs[1184] = procs[1114] = method(:to_application_timestamp)
676
+ unless (pgnt = PG_NAMED_TYPES).empty?
677
+ from(:pg_type).where(:typtype=>'b', :typname=>pgnt.keys.map{|t| t.to_s}).select_map([:oid, :typname]).each do |oid, name|
678
+ procs[oid.to_i] ||= pgnt[name.untaint.to_sym]
679
+ end
680
+ end
681
+ procs
682
+ end
683
+
646
684
  # PostgreSQL folds unquoted identifiers to lowercase, so it shouldn't need to upcase identifiers on input.
647
685
  def identifier_input_method_default
648
686
  nil
@@ -676,6 +714,13 @@ module Sequel
676
714
  "CREATE #{unique}INDEX#{' CONCURRENTLY' if index[:concurrently]} #{quote_identifier(index_name)} ON #{quote_schema_table(table_name)} #{"USING #{index_type} " if index_type}#{expr}#{filter}"
677
715
  end
678
716
 
717
+ # Setup datastructures shared by all postgres adapters.
718
+ def initialize_postgres_adapter
719
+ @primary_keys = {}
720
+ @primary_key_sequences = {}
721
+ reset_conversion_procs
722
+ end
723
+
679
724
  # Backbone of the tables and views support.
680
725
  def pg_class_relname(type, opts)
681
726
  ds = metadata_dataset.from(:pg_class).filter(:relkind=>type).select(:relname).exclude(SQL::StringExpression.like(:relname, SYSTEM_TABLE_REGEXP)).server(opts[:server]).join(:pg_namespace, :oid=>:relnamespace)
@@ -716,6 +761,7 @@ module Sequel
716
761
  m = output_identifier_meth(opts[:dataset])
717
762
  m2 = input_identifier_meth(opts[:dataset])
718
763
  ds = metadata_dataset.select(:pg_attribute__attname___name,
764
+ SQL::Cast.new(:pg_attribute__atttypid, :integer).as(:oid),
719
765
  SQL::Function.new(:format_type, :pg_type__oid, :pg_attribute__atttypmod).as(:db_type),
720
766
  SQL::Function.new(:pg_get_expr, :pg_attrdef__adbin, :pg_class__oid).as(:default),
721
767
  SQL::BooleanExpression.new(:NOT, :pg_attribute__attnotnull).as(:allow_null),
@@ -1,11 +1,8 @@
1
- require 'swift'
2
-
3
1
  module Sequel
4
- # Module holding the Swift support for Sequel. Swift is a
5
- # ruby front-end for dbic++, a fast database access library
6
- # written in C++.
2
+ # Module holding the Swift DB support for Sequel. Swift DB is a
3
+ # collection of drivers used in Swift ORM.
7
4
  #
8
- # The Swift adapter currently supports PostgreSQL and MySQL:
5
+ # The Swift adapter currently supports PostgreSQL, MySQL and SQLite3
9
6
  #
10
7
  # Sequel.connect('swift://user:password@host/database?db_type=postgres')
11
8
  # Sequel.connect('swift://user:password@host/database?db_type=mysql')
@@ -60,7 +57,9 @@ module Sequel
60
57
 
61
58
  # Create an instance of swift_class for the given options.
62
59
  def connect(server)
63
- setup_connection(swift_class.new(server_opts(server)))
60
+ opts = server_opts(server)
61
+ opts[:pass] = opts[:password]
62
+ setup_connection(swift_class.new(opts))
64
63
  end
65
64
 
66
65
  # Execute the given SQL, yielding a Swift::Result if a block is given.
@@ -70,7 +69,7 @@ module Sequel
70
69
  res = log_yield(sql){conn.execute(sql)}
71
70
  yield res if block_given?
72
71
  nil
73
- rescue SwiftError => e
72
+ rescue ::Swift::Error => e
74
73
  raise_error(e)
75
74
  end
76
75
  end
@@ -81,8 +80,8 @@ module Sequel
81
80
  def execute_dui(sql, opts={})
82
81
  synchronize(opts[:server]) do |conn|
83
82
  begin
84
- log_yield(sql){conn.execute(sql).rows}
85
- rescue SwiftError => e
83
+ log_yield(sql){conn.execute(sql).affected_rows}
84
+ rescue ::Swift::Error => e
86
85
  raise_error(e)
87
86
  end
88
87
  end
@@ -94,7 +93,7 @@ module Sequel
94
93
  synchronize(opts[:server]) do |conn|
95
94
  begin
96
95
  log_yield(sql){conn.execute(sql).insert_id}
97
- rescue SwiftError => e
96
+ rescue ::Swift::Error => e
98
97
  raise_error(e)
99
98
  end
100
99
  end
@@ -138,8 +137,17 @@ module Sequel
138
137
  # Set the columns and yield the hashes to the block.
139
138
  def fetch_rows(sql)
140
139
  execute(sql) do |res|
141
- @columns = res.fields
142
- res.each{|h| yield h}
140
+ col_map = {}
141
+ @columns = res.fields.map do |c|
142
+ col_map[c] = output_identifier(c)
143
+ end
144
+ res.each do |r|
145
+ h = {}
146
+ r.each do |k, v|
147
+ h[col_map[k]] = v.is_a?(StringIO) ? SQL::Blob.new(v.read) : v
148
+ end
149
+ yield h
150
+ end
143
151
  end
144
152
  self
145
153
  end
@@ -1,3 +1,4 @@
1
+ require 'swift/db/mysql'
1
2
  Sequel.require 'adapters/shared/mysql'
2
3
 
3
4
  module Sequel
@@ -1,7 +1,8 @@
1
+ require 'swift/db/postgres'
1
2
  Sequel.require 'adapters/shared/postgres'
2
3
 
3
4
  module Sequel
4
- Postgres::CONVERTED_EXCEPTIONS << ::SwiftError
5
+ Postgres::CONVERTED_EXCEPTIONS << ::Swift::Error
5
6
 
6
7
  module Swift
7
8
  # Adapter, Database, and Dataset support for accessing a PostgreSQL
@@ -14,10 +15,7 @@ module Sequel
14
15
  # Add the primary_keys and primary_key_sequences instance variables,
15
16
  # so we can get the correct return values for inserted rows.
16
17
  def self.extended(db)
17
- db.instance_eval do
18
- @primary_keys = {}
19
- @primary_key_sequences = {}
20
- end
18
+ db.send(:initialize_postgres_adapter)
21
19
  end
22
20
 
23
21
  private
@@ -35,6 +33,7 @@ module Sequel
35
33
  # Extend the adapter with the Swift PostgreSQL AdapterMethods.
36
34
  def setup_connection(conn)
37
35
  conn = super(conn)
36
+ conn.native_bind_format = true
38
37
  connection_configuration_sqls.each{|sql| log_yield(sql){conn.execute(sql)}}
39
38
  conn
40
39
  end
@@ -1,3 +1,4 @@
1
+ require 'swift/db/sqlite3'
1
2
  Sequel.require 'adapters/shared/sqlite'
2
3
 
3
4
  module Sequel
@@ -25,7 +26,7 @@ module Sequel
25
26
 
26
27
  # Use Swift's escape method for quoting.
27
28
  def literal_string_append(sql, s)
28
- sql << db.synchronize{|c| c.escape(s)}
29
+ sql << APOS << db.synchronize{|c| c.escape(s)} << APOS
29
30
  end
30
31
  end
31
32
  end
@@ -6,13 +6,25 @@ module Sequel
6
6
  class Database < Sequel::Database
7
7
  include Sequel::MSSQL::DatabaseMethods
8
8
  set_adapter_scheme :tinytds
9
+
10
+ # Choose whether to use unicode strings on initialization
11
+ def initialize(*)
12
+ super
13
+ set_mssql_unicode_strings
14
+ end
9
15
 
10
16
  # Transfer the :user option to the :username option.
11
17
  def connect(server)
12
18
  opts = server_opts(server)
13
19
  opts[:username] = opts[:user]
14
- set_mssql_unicode_strings
15
- TinyTds::Client.new(opts)
20
+ c = TinyTds::Client.new(opts)
21
+
22
+ if (ts = opts[:textsize])
23
+ sql = "SET TEXTSIZE #{typecast_value_integer(ts)}"
24
+ log_yield(sql){c.execute(sql)}
25
+ end
26
+
27
+ c
16
28
  end
17
29
 
18
30
  # Execute the given +sql+ on the server. If the :return option