sequel 4.47.0 → 4.48.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +134 -0
  3. data/Rakefile +1 -1
  4. data/doc/release_notes/4.48.0.txt +293 -0
  5. data/lib/sequel/adapters/ado/access.rb +2 -1
  6. data/lib/sequel/adapters/do/postgres.rb +5 -2
  7. data/lib/sequel/adapters/ibmdb.rb +24 -7
  8. data/lib/sequel/adapters/jdbc.rb +36 -22
  9. data/lib/sequel/adapters/jdbc/db2.rb +12 -3
  10. data/lib/sequel/adapters/jdbc/derby.rb +4 -5
  11. data/lib/sequel/adapters/jdbc/oracle.rb +16 -2
  12. data/lib/sequel/adapters/jdbc/postgresql.rb +43 -18
  13. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +9 -7
  14. data/lib/sequel/adapters/jdbc/sqlserver.rb +11 -4
  15. data/lib/sequel/adapters/mock.rb +24 -19
  16. data/lib/sequel/adapters/mysql.rb +17 -16
  17. data/lib/sequel/adapters/mysql2.rb +4 -5
  18. data/lib/sequel/adapters/oracle.rb +5 -9
  19. data/lib/sequel/adapters/postgres.rb +89 -102
  20. data/lib/sequel/adapters/shared/db2.rb +22 -6
  21. data/lib/sequel/adapters/shared/mssql.rb +5 -4
  22. data/lib/sequel/adapters/shared/mysql.rb +75 -24
  23. data/lib/sequel/adapters/shared/postgres.rb +196 -94
  24. data/lib/sequel/adapters/shared/sqlanywhere.rb +23 -10
  25. data/lib/sequel/adapters/shared/sqlite.rb +72 -82
  26. data/lib/sequel/adapters/sqlanywhere.rb +4 -1
  27. data/lib/sequel/adapters/sqlite.rb +5 -3
  28. data/lib/sequel/adapters/swift/postgres.rb +5 -2
  29. data/lib/sequel/adapters/tinytds.rb +0 -5
  30. data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -1
  31. data/lib/sequel/adapters/utils/pg_types.rb +2 -76
  32. data/lib/sequel/core.rb +2 -2
  33. data/lib/sequel/database/connecting.rb +5 -5
  34. data/lib/sequel/database/dataset.rb +6 -3
  35. data/lib/sequel/database/misc.rb +1 -1
  36. data/lib/sequel/database/query.rb +3 -0
  37. data/lib/sequel/database/schema_methods.rb +1 -1
  38. data/lib/sequel/dataset/actions.rb +18 -10
  39. data/lib/sequel/dataset/graph.rb +1 -1
  40. data/lib/sequel/dataset/misc.rb +1 -0
  41. data/lib/sequel/dataset/prepared_statements.rb +3 -3
  42. data/lib/sequel/dataset/query.rb +19 -8
  43. data/lib/sequel/extensions/core_extensions.rb +4 -1
  44. data/lib/sequel/extensions/duplicate_columns_handler.rb +1 -1
  45. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +3 -0
  46. data/lib/sequel/extensions/filter_having.rb +2 -0
  47. data/lib/sequel/extensions/freeze_datasets.rb +2 -0
  48. data/lib/sequel/extensions/from_block.rb +1 -1
  49. data/lib/sequel/extensions/graph_each.rb +2 -2
  50. data/lib/sequel/extensions/hash_aliases.rb +2 -0
  51. data/lib/sequel/extensions/identifier_mangling.rb +0 -7
  52. data/lib/sequel/extensions/meta_def.rb +2 -0
  53. data/lib/sequel/extensions/migration.rb +6 -6
  54. data/lib/sequel/extensions/no_auto_literal_strings.rb +1 -1
  55. data/lib/sequel/extensions/pagination.rb +1 -1
  56. data/lib/sequel/extensions/pg_array.rb +207 -130
  57. data/lib/sequel/extensions/pg_hstore.rb +38 -20
  58. data/lib/sequel/extensions/pg_inet.rb +18 -6
  59. data/lib/sequel/extensions/pg_interval.rb +19 -12
  60. data/lib/sequel/extensions/pg_json.rb +25 -14
  61. data/lib/sequel/extensions/pg_json_ops.rb +2 -2
  62. data/lib/sequel/extensions/pg_range.rb +133 -100
  63. data/lib/sequel/extensions/pg_range_ops.rb +4 -3
  64. data/lib/sequel/extensions/pg_row.rb +68 -39
  65. data/lib/sequel/extensions/pg_row_ops.rb +11 -5
  66. data/lib/sequel/extensions/query_literals.rb +2 -0
  67. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +2 -0
  68. data/lib/sequel/extensions/s.rb +1 -1
  69. data/lib/sequel/extensions/schema_dumper.rb +24 -24
  70. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +3 -1
  71. data/lib/sequel/extensions/sequel_4_dataset_methods.rb +83 -0
  72. data/lib/sequel/extensions/set_overrides.rb +2 -2
  73. data/lib/sequel/extensions/string_agg.rb +0 -1
  74. data/lib/sequel/extensions/symbol_aref.rb +0 -4
  75. data/lib/sequel/model.rb +25 -57
  76. data/lib/sequel/model/associations.rb +14 -5
  77. data/lib/sequel/model/base.rb +96 -32
  78. data/lib/sequel/plugins/association_pks.rb +73 -46
  79. data/lib/sequel/plugins/association_proxies.rb +1 -1
  80. data/lib/sequel/plugins/auto_validations.rb +6 -2
  81. data/lib/sequel/plugins/boolean_readers.rb +1 -1
  82. data/lib/sequel/plugins/caching.rb +19 -13
  83. data/lib/sequel/plugins/class_table_inheritance.rb +19 -10
  84. data/lib/sequel/plugins/column_conflicts.rb +7 -2
  85. data/lib/sequel/plugins/column_select.rb +1 -1
  86. data/lib/sequel/plugins/csv_serializer.rb +8 -8
  87. data/lib/sequel/plugins/defaults_setter.rb +10 -0
  88. data/lib/sequel/plugins/eager_each.rb +1 -1
  89. data/lib/sequel/plugins/force_encoding.rb +2 -2
  90. data/lib/sequel/plugins/hook_class_methods.rb +9 -12
  91. data/lib/sequel/plugins/identifier_columns.rb +2 -0
  92. data/lib/sequel/plugins/instance_filters.rb +3 -1
  93. data/lib/sequel/plugins/instance_hooks.rb +17 -9
  94. data/lib/sequel/plugins/json_serializer.rb +17 -10
  95. data/lib/sequel/plugins/lazy_attributes.rb +8 -7
  96. data/lib/sequel/plugins/modification_detection.rb +3 -0
  97. data/lib/sequel/plugins/nested_attributes.rb +5 -1
  98. data/lib/sequel/plugins/pg_array_associations.rb +5 -0
  99. data/lib/sequel/plugins/prepared_statements.rb +1 -0
  100. data/lib/sequel/plugins/rcte_tree.rb +4 -4
  101. data/lib/sequel/plugins/serialization.rb +3 -10
  102. data/lib/sequel/plugins/single_table_inheritance.rb +2 -2
  103. data/lib/sequel/plugins/split_values.rb +6 -5
  104. data/lib/sequel/plugins/static_cache.rb +31 -25
  105. data/lib/sequel/plugins/subset_conditions.rb +3 -1
  106. data/lib/sequel/plugins/table_select.rb +1 -1
  107. data/lib/sequel/plugins/touch.rb +2 -1
  108. data/lib/sequel/plugins/validation_class_methods.rb +5 -6
  109. data/lib/sequel/plugins/validation_helpers.rb +2 -4
  110. data/lib/sequel/plugins/xml_serializer.rb +4 -4
  111. data/lib/sequel/sql.rb +2 -2
  112. data/lib/sequel/version.rb +1 -1
  113. data/spec/adapters/db2_spec.rb +115 -14
  114. data/spec/adapters/mysql_spec.rb +78 -28
  115. data/spec/adapters/oracle_spec.rb +24 -24
  116. data/spec/adapters/postgres_spec.rb +38 -24
  117. data/spec/adapters/sqlanywhere_spec.rb +88 -86
  118. data/spec/adapters/sqlite_spec.rb +29 -24
  119. data/spec/core/connection_pool_spec.rb +17 -0
  120. data/spec/core/database_spec.rb +6 -0
  121. data/spec/core/dataset_spec.rb +46 -36
  122. data/spec/core/schema_spec.rb +16 -0
  123. data/spec/core/spec_helper.rb +1 -0
  124. data/spec/core_extensions_spec.rb +6 -2
  125. data/spec/extensions/active_model_spec.rb +1 -1
  126. data/spec/extensions/arbitrary_servers_spec.rb +1 -1
  127. data/spec/extensions/association_pks_spec.rb +34 -2
  128. data/spec/extensions/auto_literal_strings_spec.rb +5 -1
  129. data/spec/extensions/auto_validations_spec.rb +2 -0
  130. data/spec/extensions/boolean_readers_spec.rb +1 -1
  131. data/spec/extensions/boolean_subsets_spec.rb +1 -1
  132. data/spec/extensions/class_table_inheritance_spec.rb +48 -2
  133. data/spec/extensions/column_conflicts_spec.rb +11 -0
  134. data/spec/extensions/connection_validator_spec.rb +1 -1
  135. data/spec/extensions/dataset_associations_spec.rb +8 -8
  136. data/spec/extensions/defaults_setter_spec.rb +1 -1
  137. data/spec/extensions/filter_having_spec.rb +5 -3
  138. data/spec/extensions/hash_aliases_spec.rb +3 -1
  139. data/spec/extensions/identifier_columns_spec.rb +3 -1
  140. data/spec/extensions/implicit_subquery_spec.rb +4 -2
  141. data/spec/extensions/json_serializer_spec.rb +18 -0
  142. data/spec/extensions/lazy_attributes_spec.rb +3 -3
  143. data/spec/extensions/meta_def_spec.rb +9 -0
  144. data/spec/extensions/migration_spec.rb +3 -3
  145. data/spec/extensions/nested_attributes_spec.rb +14 -3
  146. data/spec/extensions/no_auto_literal_strings_spec.rb +8 -4
  147. data/spec/extensions/pg_array_associations_spec.rb +29 -18
  148. data/spec/extensions/pg_array_spec.rb +44 -25
  149. data/spec/extensions/pg_hstore_spec.rb +10 -0
  150. data/spec/extensions/pg_inet_spec.rb +26 -0
  151. data/spec/extensions/pg_interval_spec.rb +20 -0
  152. data/spec/extensions/pg_json_spec.rb +24 -0
  153. data/spec/extensions/pg_range_spec.rb +98 -14
  154. data/spec/extensions/pg_row_spec.rb +14 -4
  155. data/spec/extensions/prepared_statements_safe_spec.rb +1 -1
  156. data/spec/extensions/query_literals_spec.rb +3 -1
  157. data/spec/extensions/schema_dumper_spec.rb +96 -98
  158. data/spec/extensions/sequel_3_dataset_methods_spec.rb +10 -6
  159. data/spec/extensions/sequel_4_dataset_methods_spec.rb +121 -0
  160. data/spec/extensions/single_table_inheritance_spec.rb +1 -1
  161. data/spec/extensions/spec_helper.rb +7 -1
  162. data/spec/extensions/static_cache_spec.rb +75 -24
  163. data/spec/extensions/string_agg_spec.rb +1 -1
  164. data/spec/extensions/touch_spec.rb +9 -0
  165. data/spec/extensions/validation_helpers_spec.rb +9 -3
  166. data/spec/extensions/whitelist_security_spec.rb +26 -0
  167. data/spec/integration/dataset_test.rb +45 -44
  168. data/spec/integration/plugin_test.rb +20 -0
  169. data/spec/integration/prepared_statement_test.rb +3 -0
  170. data/spec/integration/schema_test.rb +21 -1
  171. data/spec/integration/transaction_test.rb +40 -40
  172. data/spec/model/class_dataset_methods_spec.rb +14 -4
  173. data/spec/model/dataset_methods_spec.rb +12 -3
  174. data/spec/model/model_spec.rb +8 -0
  175. metadata +6 -4
  176. data/spec/adapters/firebird_spec.rb +0 -405
  177. data/spec/adapters/informix_spec.rb +0 -100
@@ -335,19 +335,19 @@ module Sequel
335
335
  #
336
336
  # For example, to migrate the database to the latest version:
337
337
  #
338
- # Sequel::Migrator.apply(DB, '.')
338
+ # Sequel::Migrator.run(DB, '.')
339
339
  #
340
340
  # For example, to migrate the database all the way down:
341
341
  #
342
- # Sequel::Migrator.apply(DB, '.', 0)
342
+ # Sequel::Migrator.run(DB, '.', :target=>0)
343
343
  #
344
344
  # For example, to migrate the database to version 4:
345
345
  #
346
- # Sequel::Migrator.apply(DB, '.', 4)
346
+ # Sequel::Migrator.run(DB, '.', :target=>4)
347
347
  #
348
348
  # To migrate the database from version 1 to version 5:
349
349
  #
350
- # Sequel::Migrator.apply(DB, '.', 5, 1)
350
+ # Sequel::Migrator.run(DB, '.', :target=>5, :current=>1)
351
351
  #
352
352
  # Part of the +migration+ extension.
353
353
  class Migrator
@@ -490,7 +490,7 @@ module Sequel
490
490
  def remove_migration_classes
491
491
  # Remove class definitions
492
492
  Migration.descendants.each do |c|
493
- Object.send(:remove_const, c.to_s) rescue nil
493
+ Object.send(:remove_const, c.name) if c.is_a?(Class) && !c.name.to_s.empty? && Object.const_defined?(c.name)
494
494
  end
495
495
  Migration.descendants.clear # remove any defined migration classes
496
496
  end
@@ -634,7 +634,7 @@ module Sequel
634
634
  ds
635
635
  end
636
636
 
637
- # Sets the current migration version stored in the database.
637
+ # Sets the current migration version stored in the database.
638
638
  def set_migration_version(version)
639
639
  ds.update(column=>version)
640
640
  end
@@ -83,4 +83,4 @@ module Sequel
83
83
  end
84
84
  end
85
85
 
86
- # SEQUEL5: Make extension empty
86
+ # Sequel::Dataset.register_extension(:no_auto_literal_strings){} # SEQUEL5
@@ -139,7 +139,7 @@ module Sequel
139
139
  # SEQUEL5: Remove
140
140
  # :nocov:
141
141
  def set_pagination_info(page_no, page_size, record_count)
142
- Sequel::Deprecation.deprecate("Dataset#set_pagination_info", "It should no longer be necessary to call this method.")
142
+ Sequel::Deprecation.deprecate("Dataset#set_pagination_info", "It should no longer be necessary to call this method")
143
143
  self.current_page = page_no
144
144
  self.page_size = page_size
145
145
  self.pagination_record_count = record_count
@@ -45,12 +45,10 @@
45
45
  # all scalar types that the native postgres adapter handles. It
46
46
  # also makes it easy to add support for other array types. In
47
47
  # general, you just need to make sure that the scalar type is
48
- # handled and has the appropriate converter installed in
49
- # Sequel::Postgres::PG_TYPES or the Database instance's
50
- # conversion_procs usingthe appropriate type OID. For user defined
48
+ # handled and has the appropriate converter installed. For user defined
51
49
  # types, you can do this via:
52
50
  #
53
- # DB.conversion_procs[scalar_type_oid] = lambda{|string| }
51
+ # DB.add_conversion_proc(scalar_type_oid){|string| }
54
52
  #
55
53
  # Then you can call
56
54
  # Sequel::Postgres::PGArray::DatabaseMethods#register_array_type
@@ -60,18 +58,6 @@
60
58
  #
61
59
  # DB.register_array_type('foo')
62
60
  #
63
- # You can also register array types on a global basis using
64
- # Sequel::Postgres::PGArray.register. In this case, you'll have
65
- # to specify the type oids:
66
- #
67
- # Sequel::Postgres::PG_TYPES[1234] = lambda{|string| }
68
- # Sequel::Postgres::PGArray.register('foo', :oid=>4321, :scalar_oid=>1234)
69
- #
70
- # Both Sequel::Postgres::PGArray::DatabaseMethods#register_array_type
71
- # and Sequel::Postgres::PGArray.register support many options to
72
- # customize the array type handling. See the Sequel::Postgres::PGArray.register
73
- # method documentation.
74
- #
75
61
  # While this extension can parse PostgreSQL arrays with explicit bounds, it
76
62
  # currently ignores explicit bounds, so such values do not round
77
63
  # trip.
@@ -85,7 +71,7 @@
85
71
 
86
72
  require 'delegate'
87
73
  require 'strscan'
88
- Sequel.require 'adapters/utils/pg_types'
74
+ Sequel.require 'adapters/shared/postgres'
89
75
 
90
76
  module Sequel
91
77
  module Postgres
@@ -94,59 +80,42 @@ module Sequel
94
80
  include Sequel::SQL::AliasMethods
95
81
 
96
82
  ARRAY = "ARRAY".freeze
83
+ Sequel::Deprecation.deprecate_constant(self, :ARRAY)
97
84
  DOUBLE_COLON = '::'.freeze
85
+ Sequel::Deprecation.deprecate_constant(self, :DOUBLE_COLON)
98
86
  EMPTY_ARRAY = "'{}'".freeze
87
+ Sequel::Deprecation.deprecate_constant(self, :EMPTY_ARRAY)
99
88
  EMPTY_BRACKET = '[]'.freeze
89
+ Sequel::Deprecation.deprecate_constant(self, :EMPTY_BRACKET)
100
90
  OPEN_BRACKET = '['.freeze
91
+ Sequel::Deprecation.deprecate_constant(self, :OPEN_BRACKET)
101
92
  CLOSE_BRACKET = ']'.freeze
93
+ Sequel::Deprecation.deprecate_constant(self, :CLOSE_BRACKET)
102
94
  COMMA = ','.freeze
95
+ Sequel::Deprecation.deprecate_constant(self, :COMMA)
103
96
  BACKSLASH = '\\'.freeze
97
+ Sequel::Deprecation.deprecate_constant(self, :BACKSLASH)
104
98
  EMPTY_STRING = ''.freeze
99
+ Sequel::Deprecation.deprecate_constant(self, :EMPTY_STRING)
105
100
  OPEN_BRACE = '{'.freeze
101
+ Sequel::Deprecation.deprecate_constant(self, :OPEN_BRACE)
106
102
  CLOSE_BRACE = '}'.freeze
103
+ Sequel::Deprecation.deprecate_constant(self, :CLOSE_BRACE)
107
104
  NULL = 'NULL'.freeze
105
+ Sequel::Deprecation.deprecate_constant(self, :NULL)
108
106
  QUOTE = '"'.freeze
107
+ Sequel::Deprecation.deprecate_constant(self, :QUOTE)
109
108
 
110
- # Global hash of database array type name strings to symbols (e.g. 'double precision' => :float),
111
- # used by the schema parsing for array types registered globally.
109
+ # SEQUEL5: Remove
112
110
  ARRAY_TYPES = {}
113
111
 
114
- # Registers an array type that the extension should handle. Makes a Database instance that
115
- # has been extended with DatabaseMethods recognize the array type given and set up the
116
- # appropriate typecasting. Also sets up automatic typecasting for the native postgres
117
- # adapter, so that on retrieval, the values are automatically converted to PGArray instances.
118
- # The db_type argument should be the exact database type used (as returned by the PostgreSQL
119
- # format_type database function). Accepts the following options:
120
- #
121
- # :array_type :: The type to automatically cast the array to when literalizing the array.
122
- # Usually the same as db_type.
123
- # :converter :: A callable object (e.g. Proc), that is called with each element of the array
124
- # (usually a string), and should return the appropriate typecasted object.
125
- # :oid :: The PostgreSQL OID for the array type. This is used by the Sequel postgres adapter
126
- # to set up automatic type conversion on retrieval from the database.
127
- # :scalar_oid :: Should be the PostgreSQL OID for the scalar version of this array type. If given,
128
- # automatically sets the :converter option by looking for scalar conversion
129
- # proc.
130
- # :scalar_typecast :: Should be a symbol indicating the typecast method that should be called on
131
- # each element of the array, when a plain array is passed into a database
132
- # typecast method. For example, for an array of integers, this could be set to
133
- # :integer, so that the typecast_value_integer method is called on all of the
134
- # array elements. Defaults to :type_symbol option.
135
- # :type_procs :: A hash mapping oids to conversion procs, used for looking up the :scalar_oid and
136
- # value and setting the :oid value. Defaults to the global Sequel::Postgres::PG_TYPES.
137
- # :type_symbol :: The base of the schema type symbol for this type. For example, if you provide
138
- # :integer, Sequel will recognize this type as :integer_array during schema parsing.
139
- # Defaults to the db_type argument.
140
- # :typecast_method_map :: The map in which to place the database type string to type symbol mapping.
141
- # Defaults to ARRAY_TYPES.
142
- # :typecast_methods_module :: If given, a module object to add the typecasting method to. Defaults
143
- # to DatabaseMethods.
144
- #
145
- # If a block is given, it is treated as the :converter option.
112
+ # SEQUEL5: Remove
146
113
  def self.register(db_type, opts=OPTS, &block)
114
+ Sequel::Deprecation.deprecate("Sequel::Postgres::PGArray.register", "Use Database#register_array_type on a Database instance using the pg_array extension") unless opts[:skip_deprecation_warning]
115
+
147
116
  db_type = db_type.to_s
148
117
  type = (opts[:type_symbol] || db_type).to_sym
149
- type_procs = opts[:type_procs] || PG_TYPES
118
+ type_procs = opts[:type_procs] || PG__TYPES
150
119
  mod = opts[:typecast_methods_module] || DatabaseMethods
151
120
  typecast_method_map = opts[:typecast_method_map] || ARRAY_TYPES
152
121
 
@@ -169,14 +138,19 @@ module Sequel
169
138
  define_array_typecast_method(mod, type, creator, opts.fetch(:scalar_typecast, type))
170
139
 
171
140
  if oid = opts[:oid]
141
+ if opts[:skip_deprecation_warning]
142
+ def creator.call(s)
143
+ Sequel::Deprecation.deprecate("Conversion proc for #{type}[] added globally by pg_array or other pg_* extension", "Load the appropriate pg_* extension(s) into the Database instance")
144
+ super
145
+ end
146
+ end
172
147
  type_procs[oid] = creator
173
148
  end
174
149
 
175
150
  nil
176
151
  end
177
152
 
178
- # Define a private array typecasting method in the given module for the given type that uses
179
- # the creator argument to do the type conversion.
153
+ # SEQUEL5: Remove
180
154
  def self.define_array_typecast_method(mod, type, creator, scalar_typecast)
181
155
  mod.class_eval do
182
156
  meth = :"typecast_value_#{type}_array"
@@ -189,9 +163,14 @@ module Sequel
189
163
 
190
164
  module DatabaseMethods
191
165
  APOS = "'".freeze
166
+ Sequel::Deprecation.deprecate_constant(self, :APOS)
192
167
  DOUBLE_APOS = "''".freeze
168
+ Sequel::Deprecation.deprecate_constant(self, :DOUBLE_APOS)
193
169
  ESCAPE_RE = /("|\\)/.freeze
170
+ Sequel::Deprecation.deprecate_constant(self, :ESCAPE_RE)
194
171
  ESCAPE_REPLACEMENT = '\\\\\1'.freeze
172
+ Sequel::Deprecation.deprecate_constant(self, :ESCAPE_REPLACEMENT)
173
+
195
174
  BLOB_RANGE = 1...-1
196
175
 
197
176
  # Create the local hash of database type strings to schema type symbols,
@@ -200,9 +179,41 @@ module Sequel
200
179
  db.instance_eval do
201
180
  @pg_array_schema_types ||= {}
202
181
  procs = conversion_procs
203
- procs[1115] = Creator.new("timestamp without time zone", procs[1114])
204
- procs[1185] = Creator.new("timestamp with time zone", procs[1184])
205
- copy_conversion_procs([143, 791, 1000, 1001, 1003, 1005, 1006, 1007, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1021, 1022, 1028, 1182, 1183, 1231, 1270, 1561, 1563, 2951])
182
+ add_conversion_proc(1115, Creator.new("timestamp without time zone", procs[1114]))
183
+ add_conversion_proc(1185, Creator.new("timestamp with time zone", procs[1184]))
184
+
185
+ register_array_type('text', :oid=>1009, :scalar_oid=>25, :type_symbol=>:string)
186
+ register_array_type('integer', :oid=>1007, :scalar_oid=>23)
187
+ register_array_type('bigint', :oid=>1016, :scalar_oid=>20, :scalar_typecast=>:integer)
188
+ register_array_type('numeric', :oid=>1231, :scalar_oid=>1700, :type_symbol=>:decimal)
189
+ register_array_type('double precision', :oid=>1022, :scalar_oid=>701, :type_symbol=>:float)
190
+
191
+ register_array_type('boolean', :oid=>1000, :scalar_oid=>16)
192
+ register_array_type('bytea', :oid=>1001, :scalar_oid=>17, :type_symbol=>:blob)
193
+ register_array_type('date', :oid=>1182, :scalar_oid=>1082)
194
+ register_array_type('time without time zone', :oid=>1183, :scalar_oid=>1083, :type_symbol=>:time)
195
+ register_array_type('time with time zone', :oid=>1270, :scalar_oid=>1083, :type_symbol=>:time_timezone, :scalar_typecast=>:time)
196
+
197
+ register_array_type('smallint', :oid=>1005, :scalar_oid=>21, :scalar_typecast=>:integer)
198
+ register_array_type('oid', :oid=>1028, :scalar_oid=>26, :scalar_typecast=>:integer)
199
+ register_array_type('real', :oid=>1021, :scalar_oid=>700, :scalar_typecast=>:float)
200
+ register_array_type('character', :oid=>1014, :converter=>nil, :array_type=>:text, :scalar_typecast=>:string)
201
+ register_array_type('character varying', :oid=>1015, :converter=>nil, :scalar_typecast=>:string, :type_symbol=>:varchar)
202
+
203
+ register_array_type('xml', :oid=>143, :scalar_oid=>142)
204
+ register_array_type('money', :oid=>791, :scalar_oid=>790)
205
+ register_array_type('bit', :oid=>1561, :scalar_oid=>1560)
206
+ register_array_type('bit varying', :oid=>1563, :scalar_oid=>1562, :type_symbol=>:varbit)
207
+ register_array_type('uuid', :oid=>2951, :scalar_oid=>2950)
208
+
209
+ register_array_type('xid', :oid=>1011, :scalar_oid=>28)
210
+ register_array_type('cid', :oid=>1012, :scalar_oid=>29)
211
+
212
+ register_array_type('name', :oid=>1003, :scalar_oid=>19)
213
+ register_array_type('tid', :oid=>1010, :scalar_oid=>27)
214
+ register_array_type('int2vector', :oid=>1006, :scalar_oid=>22)
215
+ register_array_type('oidvector', :oid=>1013, :scalar_oid=>30)
216
+
206
217
  [:string_array, :integer_array, :decimal_array, :float_array, :boolean_array, :blob_array, :date_array, :time_array, :datetime_array].each do |v|
207
218
  @schema_type_classes[v] = PGArray
208
219
  end
@@ -227,23 +238,77 @@ module Sequel
227
238
  super
228
239
  end
229
240
 
230
- # Register a database specific array type. This can be used to support
231
- # different array types per Database. Use of this method does not
232
- # affect global state, unlike PGArray.register. See PGArray.register for
233
- # possible options.
241
+ # Register a database specific array type. Options:
242
+ #
243
+ # :array_type :: The type to automatically cast the array to when literalizing the array.
244
+ # Usually the same as db_type.
245
+ # :converter :: A callable object (e.g. Proc), that is called with each element of the array
246
+ # (usually a string), and should return the appropriate typecasted object.
247
+ # :oid :: The PostgreSQL OID for the array type. This is used by the Sequel postgres adapter
248
+ # to set up automatic type conversion on retrieval from the database.
249
+ # :scalar_oid :: Should be the PostgreSQL OID for the scalar version of this array type. If given,
250
+ # automatically sets the :converter option by looking for scalar conversion
251
+ # proc.
252
+ # :scalar_typecast :: Should be a symbol indicating the typecast method that should be called on
253
+ # each element of the array, when a plain array is passed into a database
254
+ # typecast method. For example, for an array of integers, this could be set to
255
+ # :integer, so that the typecast_value_integer method is called on all of the
256
+ # array elements. Defaults to :type_symbol option.
257
+ # :type_symbol :: The base of the schema type symbol for this type. For example, if you provide
258
+ # :integer, Sequel will recognize this type as :integer_array during schema parsing.
259
+ # Defaults to the db_type argument.
260
+ #
261
+ # If a block is given, it is treated as the :converter option.
234
262
  def register_array_type(db_type, opts=OPTS, &block)
235
- opts = {:type_procs=>conversion_procs, :typecast_method_map=>@pg_array_schema_types, :typecast_methods_module=>(class << self; self; end)}.merge!(opts)
236
- unless (opts.has_key?(:scalar_oid) || block) && opts.has_key?(:oid)
263
+ # Only for convert_named_procs_to_procs usage
264
+ type_procs = opts[:type_procs] || conversion_procs # SEQUEL5: Remove
265
+
266
+ oid = opts[:oid]
267
+ soid = opts[:scalar_oid]
268
+
269
+ if has_converter = opts.has_key?(:converter)
270
+ raise Error, "can't provide both a block and :converter option to register_array_type" if block
271
+ converter = opts[:converter]
272
+ else
273
+ has_converter = true if block
274
+ converter = block
275
+ end
276
+
277
+ unless (soid || has_converter) && oid
237
278
  array_oid, scalar_oid = from(:pg_type).where(:typname=>db_type.to_s).get([:typarray, :oid])
238
- opts[:scalar_oid] = scalar_oid unless opts.has_key?(:scalar_oid) || block
239
- opts[:oid] = array_oid unless opts.has_key?(:oid)
279
+ soid ||= scalar_oid unless has_converter
280
+ oid ||= array_oid
281
+ end
282
+
283
+ db_type = db_type.to_s
284
+ type = (opts[:type_symbol] || db_type).to_sym
285
+ typecast_method_map = @pg_array_schema_types
286
+
287
+ if soid
288
+ raise Error, "can't provide both a converter and :scalar_oid option to register" if has_converter
289
+ converter = type_procs[soid] # SEQUEL5: conversion_procs[soid]
240
290
  end
241
- PGArray.register(db_type, opts, &block)
242
- @schema_type_classes[:"#{opts[:type_symbol] || db_type}_array"] = PGArray
243
- conversion_procs_updated
291
+
292
+ array_type = (opts[:array_type] || db_type).to_s.dup.freeze
293
+ creator = Creator.new(array_type, converter)
294
+ type_procs[oid] = creator # SEQUEL5: Remove
295
+ #add_conversion_proc(oid, creator) # SEQUEL5
296
+
297
+ typecast_method_map[db_type] = :"#{type}_array"
298
+
299
+ (class << self; self end).class_eval do # singleton_class.class_eval do # SEQUEL5
300
+ meth = :"typecast_value_#{type}_array"
301
+ scalar_typecast_method = :"typecast_value_#{opts.fetch(:scalar_typecast, type)}"
302
+ define_method(meth){|v| typecast_value_pg_array(v, creator, scalar_typecast_method)}
303
+ private meth
304
+ end
305
+
306
+ @schema_type_classes[:"#{type}_array"] = PGArray
307
+ conversion_procs_updated # SEQUEL5: Remove
308
+ nil
244
309
  end
245
310
 
246
- # Return PGArray if this type matches any supported array type.
311
+ # SEQUEL5: Remove
247
312
  def schema_type_class(type)
248
313
  super || (ARRAY_TYPES.each_value{|v| return PGArray if type == v}; nil)
249
314
  end
@@ -254,13 +319,13 @@ module Sequel
254
319
  def bound_variable_array(a)
255
320
  case a
256
321
  when Array
257
- "{#{a.map{|i| bound_variable_array(i)}.join(COMMA)}}"
322
+ "{#{a.map{|i| bound_variable_array(i)}.join(',')}}"
258
323
  when Sequel::SQL::Blob
259
- "\"#{literal(a)[BLOB_RANGE].gsub(DOUBLE_APOS, APOS).gsub(ESCAPE_RE, ESCAPE_REPLACEMENT)}\""
324
+ "\"#{literal(a)[BLOB_RANGE].gsub("''", "'").gsub(/("|\\)/, '\\\\\1')}\""
260
325
  when Sequel::LiteralString
261
326
  a
262
327
  when String
263
- "\"#{a.gsub(ESCAPE_RE, ESCAPE_REPLACEMENT)}\""
328
+ "\"#{a.gsub(/("|\\)/, '\\\\\1')}\""
264
329
  else
265
330
  literal(a)
266
331
  end
@@ -277,9 +342,7 @@ module Sequel
277
342
  h
278
343
  end
279
344
 
280
- # Manually override the typecasting for timestamp array types so that
281
- # they use the database's timezone instead of the global Sequel
282
- # timezone.
345
+ # SEQUEL5: Remove
283
346
  def get_conversion_procs
284
347
  procs = super
285
348
 
@@ -293,7 +356,7 @@ module Sequel
293
356
  # array schema types to get the type symbol for the given database type
294
357
  # string.
295
358
  def pg_array_schema_type(type)
296
- @pg_array_schema_types[type] || ARRAY_TYPES[type]
359
+ @pg_array_schema_types[type] || ARRAY_TYPES[type] # SEQUEL5: Remove || ARRAY_TYPES[type]
297
360
  end
298
361
 
299
362
  # Make the column type detection handle registered array types.
@@ -346,9 +409,13 @@ module Sequel
346
409
  # accept, and it will not raise an error for all forms of invalid input.
347
410
  class Parser < StringScanner
348
411
  UNQUOTED_RE = /[{}",]|[^{}",]+/
412
+ Sequel::Deprecation.deprecate_constant(self, :UNQUOTED_RE)
349
413
  QUOTED_RE = /["\\]|[^"\\]+/
414
+ Sequel::Deprecation.deprecate_constant(self, :QUOTED_RE)
350
415
  NULL_RE = /NULL",/
416
+ Sequel::Deprecation.deprecate_constant(self, :NULL_RE)
351
417
  OPEN_RE = /((\[\d+:\d+\])+=)?\{/
418
+ Sequel::Deprecation.deprecate_constant(self, :OPEN_RE)
352
419
 
353
420
  # Set the source for the input, and any converter callable
354
421
  # to call with objects to be created. For nested parsers
@@ -358,7 +425,8 @@ module Sequel
358
425
  super(source)
359
426
  @converter = converter
360
427
  @stack = [[]]
361
- @recorded = String.new
428
+ @recorded = new_entry_buffer
429
+ #@encoding = string.encoding # SEQUEL5
362
430
  end
363
431
 
364
432
  # Take the buffer of recorded characters and add it to the array
@@ -366,13 +434,13 @@ module Sequel
366
434
  def new_entry(include_empty=false)
367
435
  if !@recorded.empty? || include_empty
368
436
  entry = @recorded
369
- if entry == NULL && !include_empty
437
+ if entry == 'NULL' && !include_empty
370
438
  entry = nil
371
439
  elsif @converter
372
440
  entry = @converter.call(entry)
373
441
  end
374
442
  @stack.last.push(entry)
375
- @recorded = String.new
443
+ @recorded = new_entry_buffer
376
444
  end
377
445
  end
378
446
 
@@ -380,36 +448,36 @@ module Sequel
380
448
  # of parsed (and potentially converted) objects.
381
449
  def parse
382
450
  raise Sequel::Error, "invalid array, empty string" if eos?
383
- raise Sequel::Error, "invalid array, doesn't start with {" unless scan(OPEN_RE)
451
+ raise Sequel::Error, "invalid array, doesn't start with {" unless scan(/((\[\d+:\d+\])+=)?\{/)
384
452
 
385
453
  while !eos?
386
- char = scan(UNQUOTED_RE)
387
- if char == COMMA
454
+ char = scan(/[{}",]|[^{}",]+/)
455
+ if char == ','
388
456
  # Comma outside quoted string indicates end of current entry
389
457
  new_entry
390
- elsif char == QUOTE
458
+ elsif char == '"'
391
459
  raise Sequel::Error, "invalid array, opening quote with existing recorded data" unless @recorded.empty?
392
460
  while true
393
- char = scan(QUOTED_RE)
394
- if char == BACKSLASH
461
+ char = scan(/["\\]|[^"\\]+/)
462
+ if char == '\\'
395
463
  @recorded << getch
396
- elsif char == QUOTE
464
+ elsif char == '"'
397
465
  n = peek(1)
398
- raise Sequel::Error, "invalid array, closing quote not followed by comma or closing brace" unless n == COMMA || n == CLOSE_BRACE
466
+ raise Sequel::Error, "invalid array, closing quote not followed by comma or closing brace" unless n == ',' || n == '}'
399
467
  break
400
468
  else
401
469
  @recorded << char
402
470
  end
403
471
  end
404
472
  new_entry(true)
405
- elsif char == OPEN_BRACE
473
+ elsif char == '{'
406
474
  raise Sequel::Error, "invalid array, opening brace with existing recorded data" unless @recorded.empty?
407
475
 
408
476
  # Start of new array, add it to the stack
409
477
  new = []
410
478
  @stack.last << new
411
479
  @stack << new
412
- elsif char == CLOSE_BRACE
480
+ elsif char == '}'
413
481
  # End of current array, add current entry to the current array
414
482
  new_entry
415
483
 
@@ -431,6 +499,21 @@ module Sequel
431
499
 
432
500
  raise Sequel::Error, "array parsing finished with array unclosed"
433
501
  end
502
+
503
+ private
504
+
505
+ if RUBY_VERSION < '1.9.0'
506
+ # :nocov:
507
+ def new_entry_buffer
508
+ String.new
509
+ end
510
+ # :nocov:
511
+ else
512
+ def new_entry_buffer
513
+ String.new.force_encoding(string.encoding)
514
+ #String.new.force_encoding(@encoding) # SEQUEL5
515
+ end
516
+ end
434
517
  end unless Sequel::Postgres.respond_to?(:parse_pg_array)
435
518
 
436
519
  # Callable object that takes the input string and parses it using Parser.
@@ -483,13 +566,13 @@ module Sequel
483
566
  def sql_literal_append(ds, sql)
484
567
  at = array_type
485
568
  if empty? && at
486
- sql << EMPTY_ARRAY
569
+ sql << "'{}'"
487
570
  else
488
- sql << ARRAY
571
+ sql << "ARRAY"
489
572
  _literal_append(sql, ds, to_a)
490
573
  end
491
574
  if at
492
- sql << DOUBLE_COLON << at.to_s << EMPTY_BRACKET
575
+ sql << '::' << at.to_s << '[]'
493
576
  end
494
577
  end
495
578
 
@@ -499,9 +582,9 @@ module Sequel
499
582
  # arrays, surrounding each with [] and interspersing
500
583
  # entries with ,.
501
584
  def _literal_append(sql, ds, array)
502
- sql << OPEN_BRACKET
585
+ sql << '['
503
586
  comma = false
504
- commas = COMMA
587
+ commas = ','
505
588
  array.each do |i|
506
589
  sql << commas if comma
507
590
  if i.is_a?(Array)
@@ -511,44 +594,38 @@ module Sequel
511
594
  end
512
595
  comma = true
513
596
  end
514
- sql << CLOSE_BRACKET
597
+ sql << ']'
515
598
  end
516
599
 
517
- # Register all array types that this extension handles by default.
518
-
519
- register('text', :oid=>1009, :scalar_oid=>25, :type_symbol=>:string)
520
- register('integer', :oid=>1007, :scalar_oid=>23)
521
- register('bigint', :oid=>1016, :scalar_oid=>20, :scalar_typecast=>:integer)
522
- register('numeric', :oid=>1231, :scalar_oid=>1700, :type_symbol=>:decimal)
523
- register('double precision', :oid=>1022, :scalar_oid=>701, :type_symbol=>:float)
524
-
525
- register('boolean', :oid=>1000, :scalar_oid=>16)
526
- register('bytea', :oid=>1001, :scalar_oid=>17, :type_symbol=>:blob)
527
- register('date', :oid=>1182, :scalar_oid=>1082)
528
- register('time without time zone', :oid=>1183, :scalar_oid=>1083, :type_symbol=>:time)
529
- register('timestamp without time zone', :oid=>1115, :scalar_oid=>1114, :type_symbol=>:datetime)
530
- register('time with time zone', :oid=>1270, :scalar_oid=>1083, :type_symbol=>:time_timezone, :scalar_typecast=>:time)
531
- register('timestamp with time zone', :oid=>1185, :scalar_oid=>1184, :type_symbol=>:datetime_timezone, :scalar_typecast=>:datetime)
532
-
533
- register('smallint', :oid=>1005, :scalar_oid=>21, :scalar_typecast=>:integer)
534
- register('oid', :oid=>1028, :scalar_oid=>26, :scalar_typecast=>:integer)
535
- register('real', :oid=>1021, :scalar_oid=>700, :scalar_typecast=>:float)
536
- register('character', :oid=>1014, :array_type=>:text, :scalar_typecast=>:string)
537
- register('character varying', :oid=>1015, :scalar_typecast=>:string, :type_symbol=>:varchar)
538
-
539
- register('xml', :oid=>143, :scalar_oid=>142)
540
- register('money', :oid=>791, :scalar_oid=>790)
541
- register('bit', :oid=>1561, :scalar_oid=>1560)
542
- register('bit varying', :oid=>1563, :scalar_oid=>1562, :type_symbol=>:varbit)
543
- register('uuid', :oid=>2951, :scalar_oid=>2950)
544
-
545
- register('xid', :oid=>1011, :scalar_oid=>28)
546
- register('cid', :oid=>1012, :scalar_oid=>29)
547
-
548
- register('name', :oid=>1003, :scalar_oid=>19)
549
- register('tid', :oid=>1010, :scalar_oid=>27)
550
- register('int2vector', :oid=>1006, :scalar_oid=>22)
551
- register('oidvector', :oid=>1013, :scalar_oid=>30)
600
+ # SEQUEL5: Remove
601
+ register('text', :oid=>1009, :scalar_oid=>25, :type_symbol=>:string, :skip_deprecation_warning=>true)
602
+ register('integer', :oid=>1007, :scalar_oid=>23, :skip_deprecation_warning=>true)
603
+ register('bigint', :oid=>1016, :scalar_oid=>20, :scalar_typecast=>:integer, :skip_deprecation_warning=>true)
604
+ register('numeric', :oid=>1231, :scalar_oid=>1700, :type_symbol=>:decimal, :skip_deprecation_warning=>true)
605
+ register('double precision', :oid=>1022, :scalar_oid=>701, :type_symbol=>:float, :skip_deprecation_warning=>true)
606
+ register('boolean', :oid=>1000, :scalar_oid=>16, :skip_deprecation_warning=>true)
607
+ register('bytea', :oid=>1001, :scalar_oid=>17, :type_symbol=>:blob, :skip_deprecation_warning=>true)
608
+ register('date', :oid=>1182, :scalar_oid=>1082, :skip_deprecation_warning=>true)
609
+ register('time without time zone', :oid=>1183, :scalar_oid=>1083, :type_symbol=>:time, :skip_deprecation_warning=>true)
610
+ register('timestamp without time zone', :oid=>1115, :scalar_oid=>1114, :type_symbol=>:datetime, :skip_deprecation_warning=>true)
611
+ register('time with time zone', :oid=>1270, :scalar_oid=>1083, :type_symbol=>:time_timezone, :scalar_typecast=>:time, :skip_deprecation_warning=>true)
612
+ register('timestamp with time zone', :oid=>1185, :scalar_oid=>1184, :type_symbol=>:datetime_timezone, :scalar_typecast=>:datetime, :skip_deprecation_warning=>true)
613
+ register('smallint', :oid=>1005, :scalar_oid=>21, :scalar_typecast=>:integer, :skip_deprecation_warning=>true)
614
+ register('oid', :oid=>1028, :scalar_oid=>26, :scalar_typecast=>:integer, :skip_deprecation_warning=>true)
615
+ register('real', :oid=>1021, :scalar_oid=>700, :scalar_typecast=>:float, :skip_deprecation_warning=>true)
616
+ register('character', :oid=>1014, :array_type=>:text, :scalar_typecast=>:string, :skip_deprecation_warning=>true)
617
+ register('character varying', :oid=>1015, :scalar_typecast=>:string, :type_symbol=>:varchar, :skip_deprecation_warning=>true)
618
+ register('xml', :oid=>143, :scalar_oid=>142, :skip_deprecation_warning=>true)
619
+ register('money', :oid=>791, :scalar_oid=>790, :skip_deprecation_warning=>true)
620
+ register('bit', :oid=>1561, :scalar_oid=>1560, :skip_deprecation_warning=>true)
621
+ register('bit varying', :oid=>1563, :scalar_oid=>1562, :type_symbol=>:varbit, :skip_deprecation_warning=>true)
622
+ register('uuid', :oid=>2951, :scalar_oid=>2950, :skip_deprecation_warning=>true)
623
+ register('xid', :oid=>1011, :scalar_oid=>28, :skip_deprecation_warning=>true)
624
+ register('cid', :oid=>1012, :scalar_oid=>29, :skip_deprecation_warning=>true)
625
+ register('name', :oid=>1003, :scalar_oid=>19, :skip_deprecation_warning=>true)
626
+ register('tid', :oid=>1010, :scalar_oid=>27, :skip_deprecation_warning=>true)
627
+ register('int2vector', :oid=>1006, :scalar_oid=>22, :skip_deprecation_warning=>true)
628
+ register('oidvector', :oid=>1013, :scalar_oid=>30, :skip_deprecation_warning=>true)
552
629
  end
553
630
  end
554
631