sequel 3.46.0 → 3.47.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.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +96 -0
  3. data/Rakefile +7 -1
  4. data/bin/sequel +6 -4
  5. data/doc/active_record.rdoc +1 -1
  6. data/doc/advanced_associations.rdoc +14 -35
  7. data/doc/association_basics.rdoc +66 -4
  8. data/doc/migration.rdoc +4 -0
  9. data/doc/opening_databases.rdoc +6 -0
  10. data/doc/postgresql.rdoc +302 -0
  11. data/doc/release_notes/3.47.0.txt +270 -0
  12. data/doc/security.rdoc +6 -0
  13. data/lib/sequel/adapters/ibmdb.rb +9 -9
  14. data/lib/sequel/adapters/jdbc.rb +22 -7
  15. data/lib/sequel/adapters/jdbc/postgresql.rb +7 -2
  16. data/lib/sequel/adapters/mock.rb +2 -0
  17. data/lib/sequel/adapters/postgres.rb +44 -13
  18. data/lib/sequel/adapters/shared/mssql.rb +1 -1
  19. data/lib/sequel/adapters/shared/mysql.rb +2 -2
  20. data/lib/sequel/adapters/shared/postgres.rb +94 -55
  21. data/lib/sequel/adapters/shared/sqlite.rb +3 -1
  22. data/lib/sequel/adapters/sqlite.rb +2 -2
  23. data/lib/sequel/adapters/utils/pg_types.rb +1 -14
  24. data/lib/sequel/adapters/utils/split_alter_table.rb +3 -3
  25. data/lib/sequel/connection_pool/threaded.rb +1 -1
  26. data/lib/sequel/core.rb +1 -1
  27. data/lib/sequel/database/connecting.rb +2 -2
  28. data/lib/sequel/database/features.rb +5 -0
  29. data/lib/sequel/database/misc.rb +47 -5
  30. data/lib/sequel/database/query.rb +2 -2
  31. data/lib/sequel/dataset/actions.rb +4 -2
  32. data/lib/sequel/dataset/misc.rb +1 -1
  33. data/lib/sequel/dataset/prepared_statements.rb +1 -1
  34. data/lib/sequel/dataset/query.rb +8 -6
  35. data/lib/sequel/dataset/sql.rb +8 -6
  36. data/lib/sequel/extensions/constraint_validations.rb +5 -2
  37. data/lib/sequel/extensions/migration.rb +10 -8
  38. data/lib/sequel/extensions/pagination.rb +3 -0
  39. data/lib/sequel/extensions/pg_array.rb +85 -25
  40. data/lib/sequel/extensions/pg_hstore.rb +8 -1
  41. data/lib/sequel/extensions/pg_hstore_ops.rb +4 -1
  42. data/lib/sequel/extensions/pg_inet.rb +16 -13
  43. data/lib/sequel/extensions/pg_interval.rb +6 -2
  44. data/lib/sequel/extensions/pg_json.rb +18 -11
  45. data/lib/sequel/extensions/pg_range.rb +17 -2
  46. data/lib/sequel/extensions/pg_range_ops.rb +7 -5
  47. data/lib/sequel/extensions/pg_row.rb +29 -12
  48. data/lib/sequel/extensions/pretty_table.rb +3 -0
  49. data/lib/sequel/extensions/query.rb +3 -0
  50. data/lib/sequel/extensions/schema_caching.rb +2 -0
  51. data/lib/sequel/extensions/schema_dumper.rb +3 -1
  52. data/lib/sequel/extensions/select_remove.rb +3 -0
  53. data/lib/sequel/model.rb +8 -2
  54. data/lib/sequel/model/associations.rb +39 -27
  55. data/lib/sequel/model/base.rb +99 -38
  56. data/lib/sequel/model/plugins.rb +25 -0
  57. data/lib/sequel/plugins/association_autoreloading.rb +27 -22
  58. data/lib/sequel/plugins/association_dependencies.rb +1 -7
  59. data/lib/sequel/plugins/auto_validations.rb +110 -0
  60. data/lib/sequel/plugins/boolean_readers.rb +1 -6
  61. data/lib/sequel/plugins/caching.rb +6 -13
  62. data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
  63. data/lib/sequel/plugins/composition.rb +14 -7
  64. data/lib/sequel/plugins/constraint_validations.rb +2 -13
  65. data/lib/sequel/plugins/defaults_setter.rb +1 -6
  66. data/lib/sequel/plugins/dirty.rb +8 -0
  67. data/lib/sequel/plugins/error_splitter.rb +54 -0
  68. data/lib/sequel/plugins/force_encoding.rb +1 -5
  69. data/lib/sequel/plugins/hook_class_methods.rb +1 -6
  70. data/lib/sequel/plugins/input_transformer.rb +79 -0
  71. data/lib/sequel/plugins/instance_filters.rb +7 -1
  72. data/lib/sequel/plugins/instance_hooks.rb +7 -1
  73. data/lib/sequel/plugins/json_serializer.rb +5 -10
  74. data/lib/sequel/plugins/lazy_attributes.rb +20 -7
  75. data/lib/sequel/plugins/list.rb +1 -6
  76. data/lib/sequel/plugins/many_through_many.rb +1 -2
  77. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +23 -39
  78. data/lib/sequel/plugins/optimistic_locking.rb +1 -5
  79. data/lib/sequel/plugins/pg_row.rb +4 -2
  80. data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -7
  81. data/lib/sequel/plugins/prepared_statements.rb +1 -5
  82. data/lib/sequel/plugins/prepared_statements_safe.rb +2 -11
  83. data/lib/sequel/plugins/rcte_tree.rb +2 -2
  84. data/lib/sequel/plugins/serialization.rb +11 -13
  85. data/lib/sequel/plugins/serialization_modification_detection.rb +13 -1
  86. data/lib/sequel/plugins/single_table_inheritance.rb +4 -4
  87. data/lib/sequel/plugins/static_cache.rb +67 -19
  88. data/lib/sequel/plugins/string_stripper.rb +7 -27
  89. data/lib/sequel/plugins/subclasses.rb +3 -5
  90. data/lib/sequel/plugins/tactical_eager_loading.rb +2 -2
  91. data/lib/sequel/plugins/timestamps.rb +2 -7
  92. data/lib/sequel/plugins/touch.rb +5 -8
  93. data/lib/sequel/plugins/tree.rb +1 -6
  94. data/lib/sequel/plugins/typecast_on_load.rb +1 -5
  95. data/lib/sequel/plugins/update_primary_key.rb +26 -14
  96. data/lib/sequel/plugins/validation_class_methods.rb +31 -16
  97. data/lib/sequel/plugins/validation_helpers.rb +50 -26
  98. data/lib/sequel/plugins/xml_serializer.rb +3 -6
  99. data/lib/sequel/sql.rb +1 -1
  100. data/lib/sequel/version.rb +1 -1
  101. data/spec/adapters/postgres_spec.rb +131 -15
  102. data/spec/adapters/sqlite_spec.rb +1 -1
  103. data/spec/core/connection_pool_spec.rb +16 -17
  104. data/spec/core/database_spec.rb +111 -40
  105. data/spec/core/dataset_spec.rb +65 -74
  106. data/spec/core/expression_filters_spec.rb +6 -5
  107. data/spec/core/object_graph_spec.rb +0 -1
  108. data/spec/core/schema_spec.rb +23 -23
  109. data/spec/core/spec_helper.rb +5 -1
  110. data/spec/extensions/association_dependencies_spec.rb +1 -1
  111. data/spec/extensions/association_proxies_spec.rb +1 -1
  112. data/spec/extensions/auto_validations_spec.rb +90 -0
  113. data/spec/extensions/caching_spec.rb +6 -0
  114. data/spec/extensions/class_table_inheritance_spec.rb +8 -1
  115. data/spec/extensions/composition_spec.rb +12 -5
  116. data/spec/extensions/constraint_validations_spec.rb +4 -4
  117. data/spec/extensions/core_refinements_spec.rb +29 -79
  118. data/spec/extensions/dirty_spec.rb +14 -0
  119. data/spec/extensions/error_splitter_spec.rb +18 -0
  120. data/spec/extensions/identity_map_spec.rb +0 -1
  121. data/spec/extensions/input_transformer_spec.rb +54 -0
  122. data/spec/extensions/instance_filters_spec.rb +6 -0
  123. data/spec/extensions/instance_hooks_spec.rb +12 -1
  124. data/spec/extensions/json_serializer_spec.rb +0 -1
  125. data/spec/extensions/lazy_attributes_spec.rb +64 -55
  126. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  127. data/spec/extensions/many_through_many_spec.rb +3 -4
  128. data/spec/extensions/many_to_one_pk_lookup_spec.rb +53 -15
  129. data/spec/extensions/migration_spec.rb +16 -0
  130. data/spec/extensions/null_dataset_spec.rb +1 -1
  131. data/spec/extensions/pg_array_spec.rb +48 -1
  132. data/spec/extensions/pg_hstore_ops_spec.rb +10 -2
  133. data/spec/extensions/pg_hstore_spec.rb +5 -0
  134. data/spec/extensions/pg_inet_spec.rb +5 -0
  135. data/spec/extensions/pg_interval_spec.rb +7 -3
  136. data/spec/extensions/pg_json_spec.rb +6 -1
  137. data/spec/extensions/pg_range_ops_spec.rb +4 -1
  138. data/spec/extensions/pg_range_spec.rb +5 -0
  139. data/spec/extensions/pg_row_plugin_spec.rb +13 -0
  140. data/spec/extensions/pg_row_spec.rb +28 -19
  141. data/spec/extensions/pg_typecast_on_load_spec.rb +6 -1
  142. data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
  143. data/spec/extensions/query_literals_spec.rb +1 -1
  144. data/spec/extensions/rcte_tree_spec.rb +2 -2
  145. data/spec/extensions/schema_spec.rb +2 -2
  146. data/spec/extensions/serialization_modification_detection_spec.rb +8 -0
  147. data/spec/extensions/serialization_spec.rb +15 -1
  148. data/spec/extensions/sharding_spec.rb +1 -1
  149. data/spec/extensions/single_table_inheritance_spec.rb +1 -1
  150. data/spec/extensions/static_cache_spec.rb +59 -9
  151. data/spec/extensions/tactical_eager_loading_spec.rb +19 -4
  152. data/spec/extensions/update_primary_key_spec.rb +17 -1
  153. data/spec/extensions/validation_class_methods_spec.rb +25 -0
  154. data/spec/extensions/validation_helpers_spec.rb +59 -3
  155. data/spec/integration/associations_test.rb +5 -5
  156. data/spec/integration/eager_loader_test.rb +32 -63
  157. data/spec/integration/model_test.rb +2 -2
  158. data/spec/integration/plugin_test.rb +88 -56
  159. data/spec/integration/prepared_statement_test.rb +1 -1
  160. data/spec/integration/schema_test.rb +1 -1
  161. data/spec/integration/timezone_test.rb +0 -1
  162. data/spec/integration/transaction_test.rb +0 -1
  163. data/spec/model/association_reflection_spec.rb +1 -1
  164. data/spec/model/associations_spec.rb +106 -84
  165. data/spec/model/base_spec.rb +4 -4
  166. data/spec/model/eager_loading_spec.rb +8 -8
  167. data/spec/model/model_spec.rb +27 -9
  168. data/spec/model/plugins_spec.rb +71 -0
  169. data/spec/model/record_spec.rb +99 -13
  170. metadata +12 -2
@@ -151,6 +151,8 @@ module Sequel
151
151
  if pr = SHARED_ADAPTER_SETUP[opts[:host]]
152
152
  pr.call(self)
153
153
  end
154
+ else
155
+ @shared_adapter = false
154
156
  end
155
157
  self.autoid = opts[:autoid]
156
158
  self.columns = opts[:columns]
@@ -96,6 +96,15 @@ module Sequel
96
96
  def bytea(s) ::Sequel::SQL::Blob.new(Adapter.unescape_bytea(s)) end
97
97
  end.new.method(:bytea)
98
98
 
99
+ @use_iso_date_format = true
100
+
101
+ class << self
102
+ # As an optimization, Sequel sets the date style to ISO, so that PostgreSQL provides
103
+ # the date in a known format that Sequel can parse faster. This can be turned off
104
+ # if you require a date style other than ISO.
105
+ attr_accessor :use_iso_date_format
106
+ end
107
+
99
108
  # PGconn subclass for connection specific methods used with the
100
109
  # pg, postgres, or postgres-pr driver.
101
110
  class Adapter < ::PGconn
@@ -160,18 +169,20 @@ module Sequel
160
169
 
161
170
  set_adapter_scheme :postgres
162
171
 
163
- # Whether infinite timestamps should be converted on retrieval. By default, no
172
+ # Whether infinite timestamps/dates should be converted on retrieval. By default, no
164
173
  # conversion is done, so an error is raised if you attempt to retrieve an infinite
165
- # timestamp. You can set this to :nil to convert to nil, :string to leave
174
+ # timestamp/date. You can set this to :nil to convert to nil, :string to leave
166
175
  # as a string, or :float to convert to an infinite float.
167
176
  attr_reader :convert_infinite_timestamps
168
-
177
+
169
178
  # Add the primary_keys and primary_key_sequences instance variables,
170
179
  # so we can get the correct return values for inserted rows.
171
180
  def initialize(*args)
172
181
  super
173
- @convert_infinite_timestamps = false
182
+ @use_iso_date_format = typecast_value_boolean(@opts.fetch(:use_iso_date_format, Postgres.use_iso_date_format))
174
183
  initialize_postgres_adapter
184
+ conversion_procs[1082] = TYPE_TRANSLATOR.method(:date) if @use_iso_date_format
185
+ self.convert_infinite_timestamps = @opts[:convert_infinite_timestamps]
175
186
  end
176
187
 
177
188
  # Convert given argument so that it can be used directly by pg. Currently, pg doesn't
@@ -233,16 +244,32 @@ module Sequel
233
244
  conn
234
245
  end
235
246
 
247
+ # Set whether to allow infinite timestamps/dates. Make sure the
248
+ # conversion proc for date reflects that setting.
236
249
  def convert_infinite_timestamps=(v)
237
- @convert_infinite_timestamps = v
238
- pr = old_pr = Postgres.use_iso_date_format ? TYPE_TRANSLATOR.method(:date) : Sequel.method(:string_to_date)
250
+ @convert_infinite_timestamps = case v
251
+ when Symbol
252
+ v
253
+ when 'nil'
254
+ :nil
255
+ when 'string'
256
+ :string
257
+ when 'float'
258
+ :float
259
+ when String
260
+ typecast_value_boolean(v)
261
+ else
262
+ false
263
+ end
264
+
265
+ pr = old_pr = @use_iso_date_format ? TYPE_TRANSLATOR.method(:date) : Sequel.method(:string_to_date)
239
266
  if v
240
- pr = lambda do |v|
241
- case v
267
+ pr = lambda do |val|
268
+ case val
242
269
  when *INFINITE_TIMESTAMP_STRINGS
243
- infinite_timestamp_value(v)
270
+ infinite_timestamp_value(val)
244
271
  else
245
- old_pr.call(v)
272
+ old_pr.call(val)
246
273
  end
247
274
  end
248
275
  end
@@ -345,7 +372,7 @@ module Sequel
345
372
  conn.put_copy_data(buf)
346
373
  end
347
374
  else
348
- data.each{|buf| conn.put_copy_data(buf)}
375
+ data.each{|buff| conn.put_copy_data(buff)}
349
376
  end
350
377
  rescue Exception => e
351
378
  conn.put_copy_end("ruby exception occurred while copying data into PostgreSQL")
@@ -385,7 +412,11 @@ module Sequel
385
412
  synchronize(opts[:server]) do |conn|
386
413
  begin
387
414
  channels = Array(channels)
388
- channels.each{|channel| conn.execute("LISTEN #{dataset.send(:table_ref, channel)}")}
415
+ channels.each do |channel|
416
+ sql = "LISTEN "
417
+ dataset.send(:identifier_append, sql, channel)
418
+ conn.execute(sql)
419
+ end
389
420
  opts[:after_listen].call(conn) if opts[:after_listen]
390
421
  timeout = opts[:timeout] ? [opts[:timeout]] : []
391
422
  if l = opts[:loop]
@@ -452,7 +483,7 @@ module Sequel
452
483
  # Set the DateStyle to ISO if configured, for faster date parsing.
453
484
  def connection_configuration_sqls
454
485
  sqls = super
455
- sqls << "SET DateStyle = 'ISO'" if Postgres.use_iso_date_format
486
+ sqls << "SET DateStyle = 'ISO'" if @use_iso_date_format
456
487
  sqls
457
488
  end
458
489
 
@@ -1,4 +1,4 @@
1
- Sequel.require %w'emulate_offset_with_row_number split_alter_table', 'adapters/utils/'
1
+ Sequel.require %w'emulate_offset_with_row_number split_alter_table', 'adapters/utils'
2
2
 
3
3
  module Sequel
4
4
  Dataset::NON_SQL_OPTIONS << :disable_insert_output
@@ -203,7 +203,7 @@ module Sequel
203
203
  opts.delete(:auto_increment) if op[:auto_increment] == false
204
204
  "CHANGE COLUMN #{quote_identifier(op[:name])} #{column_definition_sql(opts)}"
205
205
  when :drop_constraint
206
- type = case op[:type]
206
+ case op[:type]
207
207
  when :primary_key
208
208
  "DROP PRIMARY KEY"
209
209
  when :foreign_key
@@ -881,7 +881,7 @@ module Sequel
881
881
  def limit_sql(sql)
882
882
  if l = @opts[:limit]
883
883
  sql << LIMIT
884
- literal_append(sql, @opts[:limit])
884
+ literal_append(sql, l)
885
885
  end
886
886
  end
887
887
  alias delete_limit_sql limit_sql
@@ -11,25 +11,17 @@ module Sequel
11
11
  # a per instance basis via the :client_min_messages option.
12
12
  # force_standard_strings :: Set to false to not force the use of standard strings. Overridable
13
13
  # on a per instance basis via the :force_standard_strings option.
14
- # use_iso_date_format :: (only available when using the native adapter)
15
- # Set to false to not change the date format to
16
- # ISO. This disables one of Sequel's optimizations.
17
14
  #
18
- # Changes in these settings only affect future connections. To make
19
- # sure that they are applied, they should generally be called right
20
- # after the Database object is instantiated and before a connection
21
- # is actually made. For example, to use whatever the server defaults are:
15
+ # It is not recommened you use these module-level accessors. Instead,
16
+ # use the database option to make the setting per-Database.
22
17
  #
23
- # DB = Sequel.postgres(...)
24
- # Sequel::Postgres.client_min_messages = nil
25
- # Sequel::Postgres.force_standard_strings = false
26
- # Sequel::Postgres.use_iso_date_format = false
27
- # # A connection to the server is not made until here
28
- # DB[:t].all
18
+ # All adapters that connect to PostgreSQL support the following option in
19
+ # addition to those mentioned above:
29
20
  #
30
- # The reason they can't be done earlier is that the Sequel::Postgres
31
- # module is not loaded until a Database object which uses PostgreSQL
32
- # is created.
21
+ # :search_path :: Set the schema search_path for this Database's connections.
22
+ # Allows to to set which schemas do not need explicit
23
+ # qualification, and in which order to check the schemas when
24
+ # an unqualified object is referenced.
33
25
  module Postgres
34
26
  # Array of exceptions that need to be converted. JDBC
35
27
  # uses NativeExceptions, the native adapter uses PGError.
@@ -155,9 +147,6 @@ module Sequel
155
147
  end_sql
156
148
  ).strip.gsub(/\s+/, ' ').freeze
157
149
 
158
- # The Sequel extensions that require reseting of the conversion procs.
159
- RESET_PROCS_EXTENSIONS = [:pg_array, :pg_hstore, :pg_inet, :pg_interval, :pg_json, :pg_range].freeze
160
-
161
150
  # A hash of conversion procs, keyed by type integer (oid) and
162
151
  # having callable values for the conversion proc for that type.
163
152
  attr_reader :conversion_procs
@@ -276,17 +265,6 @@ module Sequel
276
265
  self << drop_trigger_sql(table, name, opts)
277
266
  end
278
267
 
279
- # If any of the extensions that require reseting the conversion procs
280
- # is loaded, reset them. This is done here so that if you load
281
- # multiple pg_* extensions in the same call, the conversion procs are
282
- # only reset once instead of once for every extension.
283
- def extension(*exts)
284
- super
285
- unless (RESET_PROCS_EXTENSIONS & exts).empty?
286
- reset_conversion_procs
287
- end
288
- end
289
-
290
268
  # Return full foreign key information using the pg system tables, including
291
269
  # :name, :on_delete, :on_update, and :deferrable entries in the hashes.
292
270
  def foreign_key_list(table, opts={})
@@ -379,7 +357,13 @@ module Sequel
379
357
  # :server :: The server to which to send the NOTIFY statement, if the sharding support
380
358
  # is being used.
381
359
  def notify(channel, opts={})
382
- execute_ddl("NOTIFY #{dataset.send(:table_ref, channel)}#{", #{literal(opts[:payload].to_s)}" if opts[:payload]}", opts)
360
+ sql = "NOTIFY "
361
+ dataset.send(:identifier_append, sql, channel)
362
+ if payload = opts[:payload]
363
+ sql << ", "
364
+ dataset.literal_append(sql, payload.to_s)
365
+ end
366
+ execute_ddl(sql, opts)
383
367
  end
384
368
 
385
369
  # Return primary key for the given table.
@@ -530,6 +514,16 @@ module Sequel
530
514
 
531
515
  private
532
516
 
517
+ # Do a type name-to-oid lookup using the database and update the procs
518
+ # with the related proc if the database supports the type.
519
+ def add_named_conversion_procs(procs, named_procs)
520
+ unless (named_procs).empty?
521
+ convert_named_procs_to_procs(named_procs).each do |oid, pr|
522
+ procs[oid] ||= pr
523
+ end
524
+ end
525
+ end
526
+
533
527
  # Use a PostgreSQL-specific alter table generator
534
528
  def alter_table_generator_class
535
529
  Postgres::AlterTableGenerator
@@ -596,13 +590,29 @@ module Sequel
596
590
  (super || op[:op] == :validate_constraint) && op[:op] != :rename_column
597
591
  end
598
592
 
593
+ VALID_CLIENT_MIN_MESSAGES = %w'DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 LOG NOTICE WARNING ERROR FATAL PANIC'.freeze
599
594
  # The SQL queries to execute when starting a new connection.
600
595
  def connection_configuration_sqls
601
596
  sqls = []
597
+
602
598
  sqls << "SET standard_conforming_strings = ON" if typecast_value_boolean(@opts.fetch(:force_standard_strings, Postgres.force_standard_strings))
599
+
603
600
  if (cmm = @opts.fetch(:client_min_messages, Postgres.client_min_messages)) && !cmm.to_s.empty?
604
601
  sqls << "SET client_min_messages = '#{cmm.to_s.upcase}'"
605
602
  end
603
+
604
+ if search_path = @opts[:search_path]
605
+ case search_path
606
+ when String
607
+ search_path = search_path.split(",").map{|s| s.strip}
608
+ when Array
609
+ # nil
610
+ else
611
+ raise Error, "unrecognized value for :search_path option: #{search_path.inspect}"
612
+ end
613
+ sqls << "SET search_path = #{search_path.map{|s| "\"#{s.gsub('"', '""')}\""}.join(',')}"
614
+ end
615
+
606
616
  sqls
607
617
  end
608
618
 
@@ -623,6 +633,24 @@ module Sequel
623
633
  end
624
634
  end
625
635
 
636
+ # Convert the hash of named conversion procs into a hash a oid conversion procs.
637
+ def convert_named_procs_to_procs(named_procs)
638
+ h = {}
639
+ from(:pg_type).where(:typtype=>'b', :typname=>named_procs.keys.map{|t| t.to_s}).select_map([:oid, :typname]).each do |oid, name|
640
+ h[oid.to_i] = named_procs[name.untaint.to_sym]
641
+ end
642
+ h
643
+ end
644
+
645
+ # Copy the conversion procs related to the given oids from PG_TYPES into
646
+ # the conversion procs for this instance.
647
+ def copy_conversion_procs(oids)
648
+ procs = conversion_procs
649
+ oids.each do |oid|
650
+ procs[oid] = PG_TYPES[oid]
651
+ end
652
+ end
653
+
626
654
  EXCLUSION_CONSTRAINT_SQL_STATE = '23P01'.freeze
627
655
  def database_specific_error_class_from_sqlstate(sqlstate)
628
656
  if sqlstate == EXCLUSION_CONSTRAINT_SQL_STATE
@@ -665,23 +693,23 @@ module Sequel
665
693
 
666
694
  # SQL for doing fast table output to stdout.
667
695
  def copy_table_sql(table, opts)
668
- if table.is_a?(String)
669
- return table
670
- else
671
- if opts[:options] || opts[:format]
672
- options = " ("
673
- options << "FORMAT #{opts[:format]}" if opts[:format]
674
- options << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
675
- options << ')'
676
- end
677
- table = if table.is_a?(::Sequel::Dataset)
678
- "(#{table.sql})"
679
- else
680
- literal(table)
681
- end
682
- return "COPY #{table} TO STDOUT#{options}"
683
- end
684
- end
696
+ if table.is_a?(String)
697
+ table
698
+ else
699
+ if opts[:options] || opts[:format]
700
+ options = " ("
701
+ options << "FORMAT #{opts[:format]}" if opts[:format]
702
+ options << "#{', ' if opts[:format]}#{opts[:options]}" if opts[:options]
703
+ options << ')'
704
+ end
705
+ table = if table.is_a?(::Sequel::Dataset)
706
+ "(#{table.sql})"
707
+ else
708
+ literal(table)
709
+ end
710
+ "COPY #{table} TO STDOUT#{options}"
711
+ end
712
+ end
685
713
 
686
714
  # SQL statement to create database function.
687
715
  def create_function_sql(name, definition, opts={})
@@ -786,11 +814,7 @@ module Sequel
786
814
  def get_conversion_procs
787
815
  procs = PG_TYPES.dup
788
816
  procs[1184] = procs[1114] = method(:to_application_timestamp)
789
- unless (pgnt = PG_NAMED_TYPES).empty?
790
- from(:pg_type).where(:typtype=>'b', :typname=>pgnt.keys.map{|t| t.to_s}).select_map([:oid, :typname]).each do |oid, name|
791
- procs[oid.to_i] ||= pgnt[name.untaint.to_sym]
792
- end
793
- end
817
+ add_named_conversion_procs(procs, PG_NAMED_TYPES)
794
818
  procs
795
819
  end
796
820
 
@@ -915,6 +939,8 @@ module Sequel
915
939
  m = output_identifier_meth(opts[:dataset])
916
940
  ds = metadata_dataset.select(:pg_attribute__attname___name,
917
941
  SQL::Cast.new(:pg_attribute__atttypid, :integer).as(:oid),
942
+ SQL::Cast.new(:basetype__oid, :integer).as(:base_oid),
943
+ SQL::Function.new(:format_type, :basetype__oid, :pg_type__typtypmod).as(:db_base_type),
918
944
  SQL::Function.new(:format_type, :pg_type__oid, :pg_attribute__atttypmod).as(:db_type),
919
945
  SQL::Function.new(:pg_get_expr, :pg_attrdef__adbin, :pg_class__oid).as(:default),
920
946
  SQL::BooleanExpression.new(:NOT, :pg_attribute__attnotnull).as(:allow_null),
@@ -922,6 +948,7 @@ module Sequel
922
948
  from(:pg_class).
923
949
  join(:pg_attribute, :attrelid=>:oid).
924
950
  join(:pg_type, :oid=>:atttypid).
951
+ left_outer_join(:pg_type___basetype, :oid=>:typbasetype).
925
952
  left_outer_join(:pg_attrdef, :adrelid=>:pg_class__oid, :adnum=>:pg_attribute__attnum).
926
953
  left_outer_join(:pg_index, :indrelid=>:pg_class__oid, :indisprimary=>true).
927
954
  filter(:pg_attribute__attisdropped=>false).
@@ -930,6 +957,15 @@ module Sequel
930
957
  order(:pg_attribute__attnum)
931
958
  ds.map do |row|
932
959
  row[:default] = nil if blank_object?(row[:default])
960
+ if row[:base_oid]
961
+ row[:domain_oid] = row[:oid]
962
+ row[:oid] = row.delete(:base_oid)
963
+ row[:db_domain_type] = row[:db_type]
964
+ row[:db_type] = row.delete(:db_base_type)
965
+ else
966
+ row.delete(:base_oid)
967
+ row.delete(:db_base_type)
968
+ end
933
969
  row[:type] = schema_column_type(row[:db_type])
934
970
  [m.call(row.delete(:name)), row]
935
971
  end
@@ -1009,7 +1045,6 @@ module Sequel
1009
1045
  FOR_SHARE = ' FOR SHARE'.freeze
1010
1046
  INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'insert into columns values returning')
1011
1047
  INSERT_CLAUSE_METHODS_91 = Dataset.clause_methods(:insert, %w'with insert into columns values returning')
1012
- LOCK = 'LOCK TABLE %s IN %s MODE'.freeze
1013
1048
  NULL = LiteralString.new('NULL').freeze
1014
1049
  PG_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze
1015
1050
  QUERY_PLAN = 'QUERY PLAN'.to_sym
@@ -1039,6 +1074,7 @@ module Sequel
1039
1074
  BLOB_RE = /[\000-\037\047\134\177-\377]/n.freeze
1040
1075
  WINDOW = " WINDOW ".freeze
1041
1076
  EMPTY_STRING = ''.freeze
1077
+ LOCK_MODES = ['ACCESS SHARE', 'ROW SHARE', 'ROW EXCLUSIVE', 'SHARE UPDATE EXCLUSIVE', 'SHARE', 'SHARE ROW EXCLUSIVE', 'EXCLUSIVE', 'ACCESS EXCLUSIVE'].each{|s| s.freeze}
1042
1078
 
1043
1079
  # Shared methods for prepared statements when used with PostgreSQL databases.
1044
1080
  module PreparedStatementMethods
@@ -1140,7 +1176,10 @@ module Sequel
1140
1176
  if block_given? # perform locking inside a transaction and yield to block
1141
1177
  @db.transaction(opts){lock(mode, opts); yield}
1142
1178
  else
1143
- @db.execute(LOCK % [source_list(@opts[:from]), mode], opts) # lock without a transaction
1179
+ sql = 'LOCK TABLE '
1180
+ source_list_append(sql, @opts[:from])
1181
+ sql << " IN #{mode} MODE"
1182
+ @db.execute(sql, opts) # lock without a transaction
1144
1183
  end
1145
1184
  nil
1146
1185
  end
@@ -661,7 +661,9 @@ module Sequel
661
661
  SELECT_CLAUSE_METHODS
662
662
  end
663
663
 
664
- # Support FOR SHARE locking when using the :share lock style.
664
+ # SQLite does not support FOR UPDATE, but silently ignore it
665
+ # instead of raising an error for compatibility with other
666
+ # databases.
665
667
  def select_lock_sql(sql)
666
668
  super unless @opts[:lock] == :update
667
669
  end
@@ -356,8 +356,8 @@ module Sequel
356
356
  @columns = cols.map{|c| c.first}
357
357
  result.each do |values|
358
358
  row = {}
359
- cols.each do |name,i,type_proc|
360
- v = values[i]
359
+ cols.each do |name,id,type_proc|
360
+ v = values[id]
361
361
  if type_proc && v
362
362
  v = type_proc.call(v)
363
363
  end
@@ -59,23 +59,10 @@ module Sequel
59
59
  [700, 701] => tt.method(:float),
60
60
  [1700] => ::BigDecimal.method(:new),
61
61
  [1083, 1266] => ::Sequel.method(:string_to_time),
62
+ [1082] => ::Sequel.method(:string_to_date),
62
63
  [1184, 1114] => ::Sequel.method(:database_to_application_timestamp),
63
64
  }.each do |k,v|
64
65
  k.each{|n| PG_TYPES[n] = v}
65
66
  end
66
-
67
- class << self
68
- # As an optimization, Sequel sets the date style to ISO, so that PostgreSQL provides
69
- # the date in a known format that Sequel can parse faster. This can be turned off
70
- # if you require a date style other than ISO.
71
- attr_reader :use_iso_date_format
72
- end
73
-
74
- # Modify the type translator for the date type depending on the value given.
75
- def self.use_iso_date_format=(v)
76
- PG_TYPES[1082] = v ? TYPE_TRANSLATOR.method(:date) : Sequel.method(:string_to_date)
77
- @use_iso_date_format = v
78
- end
79
- self.use_iso_date_format = true
80
67
  end
81
68
  end