activerecord-jdbc-adapter 1.3.15 → 1.3.16

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4739f3c7b3060fa31587fc71df2cc0694e01b112
4
- data.tar.gz: a2eb0b13a9c4e91ec04114dfa3b6ccf4837c1caf
3
+ metadata.gz: 7cf55d725c96e138c32eea755df27374aa764038
4
+ data.tar.gz: 9f5e8cf34fc6099b8958ef3de9bacffaf746dc6b
5
5
  SHA512:
6
- metadata.gz: 5c7a8e8d16adaa14b6ff45722f50ac83284b9cfb7e1fd01656369ed863b09a0174f5e3d5da082f39ce531417bcdbdc84259bc6683e2ee024d07bc0f03f4d1efa
7
- data.tar.gz: 31745bff9b3d93c76adcfe18a6073e48115aa2f0de2b923ec5c396f3ce855357d36c29b174ef003d421cc92cccc903469bd0d53dea5aa4c664b7ea7a60f8e6f3
6
+ metadata.gz: d75af524f18547b955e6a5b00964536223b382d052b69a7fbce062ba142a5bcb85ccf7ba3918838653756c0e582cbf62852568f3239399b7e00efe749ec7a8b7
7
+ data.tar.gz: 4f2e9693c5d1eb81f69741e0b1e8d06911d05273564a67910a77da073141609d5c81d1b751c715c2de7adb79956622b36e216493bcb40649bb2157bebcee3d8a
data/History.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 1.3.16 (04/13/15)
2
+
3
+ - [h2] allow jdbch2 adapter to use jdbc-h2 1.4 (#639)
4
+ - [postgres] quote and type_cast should not be overriden on 4.2
5
+ - [postgres] fix table column resolution (slightly align it to our needs) on 4.2
6
+ - [postgres] re-arrange Column internals as some helpers end-up on Adapter in 4.2
7
+ - [mysql] change_column table is redefined on AR 4.2 so that it uses _sql version
8
+ - [mysql] more tuning/compatibility backports for AR 4.2 (working booleans #626)
9
+ - [mysql] type-map support copy-pasta from AR 4.2 (closer to full compat) (#617)
10
+ - [postgres] improved support for Amazon Redshift (based on user feedback #403)
11
+ - fixed problem with create table statements with references in MySQL (#629)
12
+ - fix RecordNotUnique reference in ArJdbc::SQlite3 (#634)
13
+ - [postgres] add support for jsonb column type (#633 #635 #637)
14
+
1
15
  ## 1.3.15 (03/09/15)
2
16
 
3
17
  - [informix] adapter undefined method 'column_types' with Rails 4.x (#622)
@@ -7,7 +7,9 @@ module ArJdbc
7
7
  module MySQL
8
8
 
9
9
  # @private
10
- AR42 = ActiveRecord::VERSION::STRING >= '4.2'
10
+ AR40 = ::ActiveRecord::VERSION::MAJOR > 3
11
+ # @private
12
+ AR42 = ::ActiveRecord::VERSION::STRING >= '4.2'
11
13
 
12
14
  require 'arjdbc/mysql/column'
13
15
  require 'arjdbc/mysql/bulk_change_table'
@@ -16,6 +18,9 @@ module ArJdbc
16
18
 
17
19
  include BulkChangeTable if const_defined? :BulkChangeTable
18
20
 
21
+ # @private
22
+ ActiveRecordError = ::ActiveRecord::ActiveRecordError
23
+
19
24
  # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
20
25
  def self.jdbc_connection_class
21
26
  ::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
@@ -77,10 +82,10 @@ module ArJdbc
77
82
  execute("SET #{encoding} #{variable_assignments}", :skip_logging)
78
83
  end
79
84
 
80
- def strict_mode? # strict_mode is default since AR 4.0
85
+ def strict_mode?
81
86
  config.key?(:strict) ?
82
87
  self.class.type_cast_config_to_boolean(config[:strict]) :
83
- ::ActiveRecord::VERSION::MAJOR > 3
88
+ AR40 # strict_mode is default since AR 4.0
84
89
  end
85
90
 
86
91
  # @private
@@ -166,7 +171,7 @@ module ArJdbc
166
171
  else
167
172
  ActiveRecord::SchemaMigration.create_table
168
173
  end
169
- end if ::ActiveRecord::VERSION::MAJOR > 3
174
+ end if AR40
170
175
 
171
176
  # HELPER METHODS ===========================================
172
177
 
@@ -200,7 +205,16 @@ module ArJdbc
200
205
  else
201
206
  super
202
207
  end
203
- end
208
+ end unless AR42
209
+
210
+ # @private since AR 4.2
211
+ def _quote(value)
212
+ if value.is_a?(Type::Binary::Data)
213
+ "x'#{value.hex}'"
214
+ else
215
+ super
216
+ end
217
+ end if AR42
204
218
 
205
219
  # @override
206
220
  def quote_column_name(name)
@@ -229,6 +243,11 @@ module ArJdbc
229
243
  true
230
244
  end
231
245
 
246
+ # @override
247
+ def supports_indexes_in_create?
248
+ true
249
+ end
250
+
232
251
  # @override
233
252
  def supports_transaction_isolation?
234
253
  # MySQL 4 technically support transaction isolation, but it is affected by
@@ -247,6 +266,10 @@ module ArJdbc
247
266
  (version[0] == 5 && version[1] >= 7) || version[0] >= 6
248
267
  end
249
268
 
269
+ def index_algorithms
270
+ { :default => 'ALGORITHM = DEFAULT', :copy => 'ALGORITHM = COPY', :inplace => 'ALGORITHM = INPLACE' }
271
+ end if AR42
272
+
250
273
  # @override
251
274
  def supports_transaction_isolation?(level = nil)
252
275
  version[0] && version[0] >= 5 # MySQL 5+
@@ -335,12 +358,8 @@ module ArJdbc
335
358
  # @private
336
359
  IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
337
360
 
338
- if ::ActiveRecord::VERSION::MAJOR > 3
339
-
340
- INDEX_TYPES = [ :fulltext, :spatial ]
341
- INDEX_USINGS = [ :btree, :hash ]
342
-
343
- end
361
+ INDEX_TYPES = [ :fulltext, :spatial ] if AR40
362
+ INDEX_USINGS = [ :btree, :hash ] if AR40
344
363
 
345
364
  # Returns an array of indexes for the given table.
346
365
  # @override
@@ -373,7 +392,7 @@ module ArJdbc
373
392
  # Returns an array of `Column` objects for the table specified.
374
393
  # @override
375
394
  def columns(table_name, name = nil)
376
- sql = "SHOW FULL COLUMNS FROM #{quote_table_name(table_name)}"
395
+ sql = "SHOW FULL #{AR40 ? 'FIELDS' : 'COLUMNS'} FROM #{quote_table_name(table_name)}"
377
396
  columns = execute(sql, name || 'SCHEMA')
378
397
  strict = strict_mode?
379
398
  pass_cast_type = respond_to?(:lookup_cast_type)
@@ -561,6 +580,11 @@ module ArJdbc
561
580
  execute(change_column_sql)
562
581
  end
563
582
 
583
+ # @private
584
+ def change_column(table_name, column_name, type, options = {})
585
+ execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_sql(table_name, column_name, type, options)}")
586
+ end if AR42
587
+
564
588
  # @override
565
589
  def rename_column(table_name, column_name, new_column_name)
566
590
  options = {}
@@ -570,7 +594,7 @@ module ArJdbc
570
594
  options[:default] = column.default if type != :text && type != :binary
571
595
  options[:null] = column.null
572
596
  else
573
- raise ActiveRecord::ActiveRecordError, "No such column: #{table_name}.#{column_name}"
597
+ raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
574
598
  end
575
599
 
576
600
  current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"]
@@ -646,7 +670,7 @@ module ArJdbc
646
670
  when 0..0xfff; "varbinary(#{limit})"
647
671
  when nil; "blob"
648
672
  when 0x1000..0xffffffff; "blob(#{limit})"
649
- else raise ActiveRecord::ActiveRecordError, "No binary type has character length #{limit}"
673
+ else raise ActiveRecordError, "No binary type has character length #{limit}"
650
674
  end
651
675
  when 'integer'
652
676
  case limit
@@ -655,7 +679,7 @@ module ArJdbc
655
679
  when 3; 'mediumint'
656
680
  when nil, 4, 11; 'int(11)' # compatibility with MySQL default
657
681
  when 5..8; 'bigint'
658
- else raise ActiveRecord::ActiveRecordError, "No integer type has byte size #{limit}"
682
+ else raise ActiveRecordError, "No integer type has byte size #{limit}"
659
683
  end
660
684
  when 'text'
661
685
  case limit
@@ -663,7 +687,7 @@ module ArJdbc
663
687
  when nil, 0x100..0xffff; 'text'
664
688
  when 0x10000..0xffffff; 'mediumtext'
665
689
  when 0x1000000..0xffffffff; 'longtext'
666
- else raise ActiveRecord::ActiveRecordError, "No text type has character length #{limit}"
690
+ else raise ActiveRecordError, "No text type has character length #{limit}"
667
691
  end
668
692
  else
669
693
  super
@@ -675,8 +699,91 @@ module ArJdbc
675
699
  "VALUES ()"
676
700
  end
677
701
 
702
+ # @note since AR 4.2
703
+ def valid_type?(type)
704
+ ! native_database_types[type].nil?
705
+ end
706
+
707
+ def clear_cache!
708
+ super
709
+ reload_type_map
710
+ end if AR42
711
+
712
+ # @private since AR 4.2
713
+ def prepare_column_options(column, types)
714
+ spec = super
715
+ spec.delete(:limit) if column.type == :boolean
716
+ spec
717
+ end if AR42
718
+
719
+ # @private
720
+ Type = ActiveRecord::Type if AR42
721
+
678
722
  protected
679
723
 
724
+ # @private
725
+ def initialize_type_map(m)
726
+ super
727
+
728
+ register_class_with_limit m, %r(char)i, MysqlString
729
+
730
+ m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
731
+ m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
732
+ m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
733
+ m.register_type %r(blob)i, Type::Binary.new(limit: 2**16 - 1)
734
+ m.register_type %r(mediumtext)i, Type::Text.new(limit: 2**24 - 1)
735
+ m.register_type %r(mediumblob)i, Type::Binary.new(limit: 2**24 - 1)
736
+ m.register_type %r(longtext)i, Type::Text.new(limit: 2**32 - 1)
737
+ m.register_type %r(longblob)i, Type::Binary.new(limit: 2**32 - 1)
738
+ m.register_type %r(^float)i, Type::Float.new(limit: 24)
739
+ m.register_type %r(^double)i, Type::Float.new(limit: 53)
740
+
741
+ register_integer_type m, %r(^bigint)i, limit: 8
742
+ register_integer_type m, %r(^int)i, limit: 4
743
+ register_integer_type m, %r(^mediumint)i, limit: 3
744
+ register_integer_type m, %r(^smallint)i, limit: 2
745
+ register_integer_type m, %r(^tinyint)i, limit: 1
746
+
747
+ m.alias_type %r(tinyint\(1\))i, 'boolean' if emulate_booleans
748
+ m.alias_type %r(set)i, 'varchar'
749
+ m.alias_type %r(year)i, 'integer'
750
+ m.alias_type %r(bit)i, 'binary'
751
+
752
+ m.register_type(%r(datetime)i) do |sql_type|
753
+ precision = extract_precision(sql_type)
754
+ MysqlDateTime.new(precision: precision)
755
+ end
756
+
757
+ m.register_type(%r(enum)i) do |sql_type|
758
+ limit = sql_type[/^enum\((.+)\)/i, 1]
759
+ .split(',').map{|enum| enum.strip.length - 2}.max
760
+ MysqlString.new(limit: limit)
761
+ end
762
+ end if AR42
763
+
764
+ # @private
765
+ def register_integer_type(mapping, key, options)
766
+ mapping.register_type(key) do |sql_type|
767
+ if /unsigned/i =~ sql_type
768
+ Type::UnsignedInteger.new(options)
769
+ else
770
+ Type::Integer.new(options)
771
+ end
772
+ end
773
+ end if AR42
774
+
775
+ # MySQL is too stupid to create a temporary table for use subquery, so we have
776
+ # to give it some prompting in the form of a subsubquery. Ugh!
777
+ # @note since AR 4.2
778
+ def subquery_for(key, select)
779
+ subsubselect = select.clone
780
+ subsubselect.projections = [key]
781
+
782
+ subselect = Arel::SelectManager.new(select.engine)
783
+ subselect.project Arel.sql(key.name)
784
+ subselect.from subsubselect.as('__active_record_temp')
785
+ end if AR42
786
+
680
787
  def quoted_columns_for_index(column_names, options = {})
681
788
  length = options[:length] if options.is_a?(Hash)
682
789
 
@@ -741,6 +848,40 @@ module ArJdbc
741
848
  end
742
849
  end
743
850
 
851
+ # @private
852
+ def emulate_booleans; ::ArJdbc::MySQL.emulate_booleans?; end # due AR 4.2
853
+ public :emulate_booleans
854
+
855
+ # @private
856
+ class MysqlDateTime < Type::DateTime
857
+ private
858
+
859
+ def has_precision?
860
+ precision || 0
861
+ end
862
+ end if AR42
863
+
864
+ # @private
865
+ class MysqlString < Type::String
866
+ def type_cast_for_database(value)
867
+ case value
868
+ when true then "1"
869
+ when false then "0"
870
+ else super
871
+ end
872
+ end
873
+
874
+ private
875
+
876
+ def cast_value(value)
877
+ case value
878
+ when true then "1"
879
+ when false then "0"
880
+ else super
881
+ end
882
+ end
883
+ end if AR42
884
+
744
885
  end
745
886
  end
746
887
 
@@ -772,9 +913,9 @@ module ActiveRecord
772
913
 
773
914
  end
774
915
 
775
- def initialize(*args)
776
- super # configure_connection happens in super
777
- end
916
+ #def initialize(*args)
917
+ # super # configure_connection happens in super
918
+ #end
778
919
 
779
920
  def jdbc_connection_class(spec)
780
921
  ::ArJdbc::MySQL.jdbc_connection_class
@@ -3,10 +3,13 @@ module ArJdbc
3
3
  module BulkChangeTable
4
4
 
5
5
  # @private
6
- AR41 = ActiveRecord::VERSION::STRING >= '4.1'
6
+ AR41 = ::ActiveRecord::VERSION::STRING >= '4.1'
7
7
 
8
8
  # @private
9
- ChangeColumnDefinition = ActiveRecord::ConnectionAdapters::ChangeColumnDefinition if AR41
9
+ #ActiveRecordError = ActiveRecord::ActiveRecordError
10
+
11
+ # @private
12
+ ChangeColumnDefinition = ::ActiveRecord::ConnectionAdapters::ChangeColumnDefinition if AR41
10
13
 
11
14
  # @override
12
15
  def supports_bulk_alter?; true end
@@ -106,12 +109,12 @@ module ArJdbc
106
109
  schema_creation.accept ChangeColumnDefinition.new column, current_type, options
107
110
  end if AR41
108
111
 
109
- def remove_column_sql(table_name, column_name, type = nil, options = {})
112
+ def remove_column_sql(table_name, column_name, type = nil, options = nil)
110
113
  "DROP #{quote_column_name(column_name)}"
111
114
  end
112
115
 
113
116
  def remove_columns_sql(table_name, *column_names)
114
- column_names.map {|column_name| remove_column_sql(table_name, column_name) }
117
+ column_names.map { |column_name| remove_column_sql(table_name, column_name) }
115
118
  end
116
119
 
117
120
  def add_index_sql(table_name, column_name, options = {})
@@ -16,6 +16,12 @@ module ArJdbc
16
16
  require 'arjdbc/postgresql/explain_support'
17
17
  require 'arjdbc/postgresql/schema_creation' # AR 4.x
18
18
 
19
+ # @private
20
+ IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
21
+
22
+ # @private
23
+ Type = ::ActiveRecord::Type if AR42_COMPAT
24
+
19
25
  # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
20
26
  def self.jdbc_connection_class
21
27
  ::ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection
@@ -54,8 +60,8 @@ module ArJdbc
54
60
  def postgresql_version
55
61
  @postgresql_version ||=
56
62
  begin
57
- value = select_value('SELECT version()')
58
- if value =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
63
+ version = select_version
64
+ if version =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
59
65
  ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
60
66
  else
61
67
  0
@@ -63,6 +69,21 @@ module ArJdbc
63
69
  end
64
70
  end
65
71
 
72
+ def select_version
73
+ @_version ||= select_value('SELECT version()')
74
+ end
75
+ private :select_version
76
+
77
+ def redshift?
78
+ # SELECT version() :
79
+ # PostgreSQL 8.0.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3), Redshift 1.0.647
80
+ if ( redshift = config[:redshift] ).nil?
81
+ redshift = !! (select_version || '').index('Redshift')
82
+ end
83
+ redshift
84
+ end
85
+ private :redshift?
86
+
66
87
  def use_insert_returning?
67
88
  if @use_insert_returning.nil?
68
89
  @use_insert_returning = supports_insert_with_returning?
@@ -97,16 +118,16 @@ module ArJdbc
97
118
  execute("SET time zone 'UTC'", 'SCHEMA')
98
119
  elsif tz = local_tz
99
120
  execute("SET time zone '#{tz}'", 'SCHEMA')
100
- end # if defined? ActiveRecord::Base.default_timezone
121
+ end unless redshift?
101
122
 
102
123
  # SET statements from :variables config hash
103
124
  # http://www.postgresql.org/docs/8.3/static/sql-set.html
104
125
  (config[:variables] || {}).map do |k, v|
105
126
  if v == ':default' || v == :default
106
127
  # Sets the value to the global or compile default
107
- execute("SET SESSION #{k.to_s} TO DEFAULT", 'SCHEMA')
128
+ execute("SET SESSION #{k} TO DEFAULT", 'SCHEMA')
108
129
  elsif ! v.nil?
109
- execute("SET SESSION #{k.to_s} TO #{quote(v)}", 'SCHEMA')
130
+ execute("SET SESSION #{k} TO #{quote(v)}", 'SCHEMA')
110
131
  end
111
132
  end
112
133
  end
@@ -163,7 +184,7 @@ module ArJdbc
163
184
  case column.sql_type
164
185
  when 'point'
165
186
  jdbc_column_class.point_to_string(value)
166
- when 'json'
187
+ when 'json', 'jsonb'
167
188
  jdbc_column_class.json_to_string(value)
168
189
  else
169
190
  return super(value, column) unless column.array?
@@ -181,7 +202,7 @@ module ArJdbc
181
202
  case column.sql_type
182
203
  when 'hstore'
183
204
  jdbc_column_class.hstore_to_string(value)
184
- when 'json'
205
+ when 'json', 'jsonb'
185
206
  jdbc_column_class.json_to_string(value)
186
207
  else super(value, column)
187
208
  end
@@ -194,7 +215,23 @@ module ArJdbc
194
215
  else
195
216
  super(value, column)
196
217
  end
197
- end if AR4_COMPAT
218
+ end if AR4_COMPAT && ! AR42_COMPAT
219
+
220
+ # @private
221
+ def _type_cast(value)
222
+ case value
223
+ when Type::Binary::Data
224
+ # Return a bind param hash with format as binary.
225
+ # See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc
226
+ # for more information
227
+ { value: value.to_s, format: 1 }
228
+ when OID::Xml::Data, OID::Bit::Data
229
+ value.to_s
230
+ else
231
+ super
232
+ end
233
+ end if AR42_COMPAT
234
+ private :_type_cast if AR42_COMPAT
198
235
 
199
236
  NATIVE_DATABASE_TYPES = {
200
237
  :primary_key => "serial primary key",
@@ -227,6 +264,7 @@ module ArJdbc
227
264
  :macaddr => { :name => "macaddr" },
228
265
  :uuid => { :name => "uuid" },
229
266
  :json => { :name => "json" },
267
+ :jsonb => { :name => "jsonb" },
230
268
  :ltree => { :name => "ltree" },
231
269
  # ranges :
232
270
  :daterange => { :name => "daterange" },
@@ -249,6 +287,7 @@ module ArJdbc
249
287
  end
250
288
 
251
289
  # Adds `:array` option to the default set provided by the `AbstractAdapter`.
290
+ # @override
252
291
  def prepare_column_options(column, types)
253
292
  spec = super
254
293
  spec[:array] = 'true' if column.respond_to?(:array) && column.array
@@ -257,6 +296,7 @@ module ArJdbc
257
296
  end if AR4_COMPAT
258
297
 
259
298
  # Adds `:array` as a valid migration key.
299
+ # @override
260
300
  def migration_keys
261
301
  super + [:array]
262
302
  end if AR4_COMPAT
@@ -744,11 +784,15 @@ module ArJdbc
744
784
 
745
785
  # Returns the current client message level.
746
786
  def client_min_messages
787
+ return nil if redshift? # not supported on Redshift
747
788
  select_value('SHOW client_min_messages', 'SCHEMA')
748
789
  end
749
790
 
750
791
  # Set the client message level.
751
792
  def client_min_messages=(level)
793
+ # NOTE: for now simply ignore the writer (no warn on Redshift) so that
794
+ # the AR copy-pasted PpstgreSQL parts stay the same as much as possible
795
+ return nil if redshift? # not supported on Redshift
752
796
  execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
753
797
  end
754
798
 
@@ -834,6 +878,8 @@ module ArJdbc
834
878
  "'#{jdbc_column_class.array_to_string(value, column, self).gsub(/'/, "''")}'"
835
879
  elsif column.type == :json # only in AR-4.0
836
880
  super(jdbc_column_class.json_to_string(value), column)
881
+ elsif column.type == :jsonb # only in AR-4.0
882
+ super(jdbc_column_class.json_to_string(value), column)
837
883
  elsif column.type == :point # only in AR-4.0
838
884
  super(jdbc_column_class.point_to_string(value), column)
839
885
  else super
@@ -843,6 +889,8 @@ module ArJdbc
843
889
  super(jdbc_column_class.hstore_to_string(value), column)
844
890
  elsif column.type == :json # only in AR-4.0
845
891
  super(jdbc_column_class.json_to_string(value), column)
892
+ elsif column.type == :jsonb # only in AR-4.0
893
+ super(jdbc_column_class.json_to_string(value), column)
846
894
  else super
847
895
  end
848
896
  when Range
@@ -862,13 +910,22 @@ module ArJdbc
862
910
  end
863
911
  end unless AR42_COMPAT
864
912
 
865
- def quote(value, column = nil)
866
- return super unless column
867
-
913
+ # @private
914
+ def _quote(value)
868
915
  case value
916
+ when Type::Binary::Data
917
+ "'#{escape_bytea(value.to_s)}'"
918
+ when OID::Xml::Data
919
+ "xml '#{quote_string(value.to_s)}'"
920
+ when OID::Bit::Data
921
+ if value.binary?
922
+ "B'#{value}'"
923
+ elsif value.hex?
924
+ "X'#{value}'"
925
+ end
869
926
  when Float
870
927
  if value.infinite? || value.nan?
871
- "'#{value.to_s}'"
928
+ "'#{value}'"
872
929
  else
873
930
  super
874
931
  end
@@ -876,6 +933,7 @@ module ArJdbc
876
933
  super
877
934
  end
878
935
  end if AR42_COMPAT
936
+ private :_quote if AR42_COMPAT
879
937
 
880
938
  # Quotes a string, escaping any ' (single quote) and \ (backslash) chars.
881
939
  # @return [String]
@@ -932,7 +990,7 @@ module ArJdbc
932
990
  # @override
933
991
  def quote_table_name_for_assignment(table, attr)
934
992
  quote_column_name(attr)
935
- end if ::ActiveRecord::VERSION::MAJOR >= 4
993
+ end if AR4_COMPAT
936
994
 
937
995
  # @override
938
996
  def quote_column_name(name)
@@ -1088,9 +1146,8 @@ module ArJdbc
1088
1146
  # Returns the list of all column definitions for a table.
1089
1147
  def columns(table_name, name = nil)
1090
1148
  column = jdbc_column_class
1091
- pass_cast_type = respond_to?(:lookup_cast_type)
1092
- column_definitions(table_name).map do |row|
1093
- # name, type, default, notnull, oid, fmod
1149
+ column_definitions(table_name).map! do |row|
1150
+ # |name, type, default, notnull, oid, fmod|
1094
1151
  name = row[0]; type = row[1]; default = row[2]
1095
1152
  notnull = row[3]; oid = row[4]; fmod = row[5]
1096
1153
  # oid = OID::TYPE_MAP.fetch(oid.to_i, fmod.to_i) { OID::Identity.new }
@@ -1102,18 +1159,41 @@ module ArJdbc
1102
1159
  elsif default =~ /^\(([-+]?[\d\.]+)\)$/ # e.g. "(-1)" for a negative default
1103
1160
  default = $1
1104
1161
  end
1105
- if pass_cast_type
1106
- cast_type = lookup_cast_type(type)
1107
- column.new(name, default, cast_type, type, ! notnull, fmod, self)
1108
- else
1109
- column.new(name, default, oid, type, ! notnull, fmod, self)
1110
- end
1162
+
1163
+ column.new(name, default, oid, type, ! notnull, fmod, self)
1111
1164
  end
1112
1165
  end
1113
1166
 
1167
+ # @private documented above
1168
+ def columns(table_name)
1169
+ column = jdbc_column_class
1170
+ # Limit, precision, and scale are all handled by the superclass.
1171
+ column_definitions(table_name).map! do |row|
1172
+ # |name, type, default, notnull, oid, fmod|
1173
+ name = row[0]; type = row[1]; default = row[2]
1174
+ notnull = row[3]; oid = row[4]; fmod = row[5]
1175
+ notnull = notnull == 't' if notnull.is_a?(String) # JDBC gets true/false
1176
+
1177
+ oid_type = get_oid_type(oid.to_i, fmod.to_i, name, type)
1178
+ default_value = extract_value_from_default(oid, default)
1179
+ default_function = extract_default_function(default_value, default)
1180
+
1181
+ column.new(name, default_value, oid_type, type, ! notnull, default_function, oid, self)
1182
+ end
1183
+ end if AR42_COMPAT
1184
+
1185
+ # @private only for API compatibility
1186
+ def new_column(name, default, cast_type, sql_type = nil, null = true, default_function = nil)
1187
+ jdbc_column_class.new(name, default, cast_type, sql_type, null, default_function)
1188
+ end if AR42_COMPAT
1189
+
1114
1190
  # @private
1115
1191
  def column_for(table_name, column_name)
1116
- columns(table_name).detect { |c| c.name == column_name.to_s }
1192
+ column_name = column_name.to_s
1193
+ for column in columns(table_name)
1194
+ return column if column.name == column_name
1195
+ end
1196
+ nil
1117
1197
  end
1118
1198
 
1119
1199
  # Returns the list of a table's column names, data types, and default values.
@@ -1188,9 +1268,6 @@ module ArJdbc
1188
1268
  SQL
1189
1269
  end if AR42_COMPAT
1190
1270
 
1191
- # @private
1192
- IndexDefinition = ::ActiveRecord::ConnectionAdapters::IndexDefinition
1193
-
1194
1271
  # Returns an array of indexes for the given table.
1195
1272
  def indexes(table_name, name = nil)
1196
1273
  # NOTE: maybe it's better to leave things of to the JDBC API ?!
@@ -1304,33 +1381,6 @@ module ActiveRecord::ConnectionAdapters
1304
1381
 
1305
1382
  class PostgreSQLColumn < JdbcColumn
1306
1383
  include ::ArJdbc::PostgreSQL::Column
1307
-
1308
- def initialize(name, default, oid_type = nil, sql_type = nil, null = true,
1309
- fmod = nil, adapter = nil) # added due resolving #oid_type
1310
- if oid_type.is_a?(Integer) # the "main" if branch (on AR 4.x)
1311
- @oid = oid_type; @fmod = fmod; @adapter = adapter # see Column#oid_type
1312
- elsif oid_type.respond_to?(:type_cast) # MRI compatibility
1313
- @oid_type = oid_type; # @fmod = fmod; @adapter = adapter
1314
- else # NOTE: AR <= 3.2 : (name, default, sql_type = nil, null = true)
1315
- null, sql_type, oid_type = !! sql_type, oid_type, nil
1316
- end
1317
- if sql_type.to_s[-2, 2] == '[]' && ArJdbc::PostgreSQL::AR4_COMPAT
1318
- @array = true if respond_to?(:array)
1319
- super(name, default, sql_type[0..-3], null)
1320
- else
1321
- @array = false if respond_to?(:array)
1322
- super(name, default, sql_type, null)
1323
- end
1324
-
1325
- @default_function = default if has_default_function?(@default, default)
1326
- end
1327
-
1328
- private
1329
-
1330
- def has_default_function?(default_value, default)
1331
- ! default_value && ( %r{\w+\(.*\)} === default )
1332
- end
1333
-
1334
1384
  end
1335
1385
 
1336
1386
  # NOTE: seems needed on 4.x due loading of '.../postgresql/oid' which
@@ -1341,8 +1391,9 @@ module ActiveRecord::ConnectionAdapters
1341
1391
  include ::ArJdbc::PostgreSQL
1342
1392
  include ::ArJdbc::PostgreSQL::ExplainSupport
1343
1393
 
1344
- require 'arjdbc/postgresql/oid_types' if ::ArJdbc::PostgreSQL::AR4_COMPAT
1394
+ require 'arjdbc/postgresql/oid_types' if AR4_COMPAT
1345
1395
  include ::ArJdbc::PostgreSQL::OIDTypes if ::ArJdbc::PostgreSQL.const_defined?(:OIDTypes)
1396
+ include ::ArJdbc::PostgreSQL::ColumnHelpers if AR42_COMPAT
1346
1397
 
1347
1398
  include ::ArJdbc::Util::QuotedCache
1348
1399
 
@@ -1354,6 +1405,8 @@ module ActiveRecord::ConnectionAdapters
1354
1405
 
1355
1406
  @table_alias_length = nil
1356
1407
 
1408
+ initialize_type_map(@type_map = Type::HashLookupTypeMap.new) if AR42_COMPAT
1409
+
1357
1410
  @use_insert_returning = @config.key?(:insert_returning) ?
1358
1411
  self.class.type_cast_config_to_boolean(@config[:insert_returning]) : nil
1359
1412
  end
@@ -275,6 +275,25 @@ module ActiveRecord
275
275
  end
276
276
  end
277
277
 
278
+ class Jsonb < Type
279
+ def type_cast_for_write(value)
280
+ # roundtrip to ensure uniform uniform types
281
+ # TODO: This is not an efficient solution.
282
+ stringified = ConnectionAdapters::PostgreSQLColumn.json_to_string(value)
283
+ type_cast(stringified)
284
+ end
285
+
286
+ def type_cast(value)
287
+ return if value.nil?
288
+
289
+ ConnectionAdapters::PostgreSQLColumn.string_to_json value
290
+ end
291
+
292
+ def accessor
293
+ ActiveRecord::Store::StringKeyedHashAccessor
294
+ end
295
+ end
296
+
278
297
  class TypeMap
279
298
  def initialize
280
299
  @mapping = {}
@@ -382,6 +401,7 @@ module ActiveRecord
382
401
  register_type 'circle', OID::Identity.new
383
402
  register_type 'hstore', OID::Hstore.new
384
403
  register_type 'json', OID::Json.new
404
+ register_type 'jsonb', OID::Jsonb.new
385
405
  register_type 'ltree', OID::Identity.new
386
406
 
387
407
  register_type 'cidr', OID::Cidr.new
@@ -389,4 +409,4 @@ module ActiveRecord
389
409
  end
390
410
  end
391
411
  end
392
- end
412
+ end
@@ -6,46 +6,134 @@ module ArJdbc
6
6
  [ /postgre/i, lambda { |cfg, column| column.extend(Column) } ]
7
7
  end
8
8
 
9
+ # @private these are defined on the Adapter class since 4.2
10
+ module ColumnHelpers
11
+
12
+ def extract_limit(sql_type) # :nodoc:
13
+ case sql_type
14
+ when /^bigint/i, /^int8/i then 8
15
+ when /^smallint/i then 2
16
+ when /^timestamp/i then nil
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ # Extracts the value from a PostgreSQL column default definition.
23
+ def extract_value_from_default(oid, default) # :nodoc:
24
+ case default
25
+ # Quoted types
26
+ when /\A[\(B]?'(.*)'::/m
27
+ $1.gsub(/''/, "'")
28
+ # Boolean types
29
+ when 'true', 'false'
30
+ default
31
+ # Numeric types
32
+ when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
33
+ $1
34
+ # Object identifier types
35
+ when /\A-?\d+\z/
36
+ $1
37
+ else
38
+ # Anything else is blank, some user type, or some function
39
+ # and we can't know the value of that, so return nil.
40
+ nil
41
+ end
42
+ end
43
+
44
+ def extract_default_function(default_value, default) # :nodoc:
45
+ default if ! default_value && ( %r{\w+\(.*\)} === default )
46
+ end
47
+
48
+ end
49
+
9
50
  # Column behavior based on PostgreSQL adapter in Rails.
10
51
  # @see ActiveRecord::ConnectionAdapters::JdbcColumn
11
52
  module Column
12
53
 
54
+ attr_accessor :array
55
+
56
+ def initialize(name, default, cast_type, sql_type = nil, null = true, default_function = nil,
57
+ oid = nil, adapter = nil) # added arguments
58
+ if sql_type.to_s[-2, 2] == '[]'
59
+ @array = true
60
+ super(name, default, cast_type, sql_type[0..-3], null)
61
+ else
62
+ @array = false
63
+ super(name, default, cast_type, sql_type, null)
64
+ end
65
+
66
+ @oid = oid # used on Java side - expects @oid on Column instances
67
+ #@adapter = adapter
68
+
69
+ @default_function = default_function
70
+ end
71
+
72
+ end if AR42_COMPAT
73
+
74
+ # @private (AR < 4.2 version) documented above
75
+ module Column
76
+
77
+ def initialize(name, default, oid_type = nil, sql_type = nil, null = true,
78
+ fmod = nil, adapter = nil) # added due resolving #oid_type
79
+ if oid_type.is_a?(Integer) # the "main" if branch (on AR 4.x)
80
+ @oid = oid_type; @fmod = fmod; @adapter = adapter # see Column#oid_type
81
+ elsif oid_type.respond_to?(:type_cast) # MRI compatibility
82
+ @oid_type = oid_type; # @fmod = fmod; @adapter = adapter
83
+ else # NOTE: AR <= 3.2 : (name, default, sql_type = nil, null = true)
84
+ null, sql_type, oid_type = !! sql_type, oid_type, nil
85
+ end
86
+ if sql_type.to_s[-2, 2] == '[]' && ArJdbc::PostgreSQL::AR4_COMPAT
87
+ @array = true if respond_to?(:array)
88
+ super(name, default, sql_type[0..-3], null)
89
+ else
90
+ @array = false if respond_to?(:array)
91
+ super(name, default, sql_type, null)
92
+ end
93
+
94
+ @default_function = extract_default_function(@default, default)
95
+ end
96
+
13
97
  def self.included(base)
14
98
  # NOTE: assumes a standalone PostgreSQLColumn class
15
- class << base
16
-
17
- attr_accessor :money_precision
18
-
19
- # Loads pg_array_parser if available. String parsing can be
20
- # performed quicker by a native extension, which will not create
21
- # a large amount of Ruby objects that will need to be garbage
22
- # collected. pg_array_parser has a C and Java extension
23
- begin
24
- require 'pg_array_parser'
25
- include PgArrayParser
26
- rescue LoadError
27
- if AR42_COMPAT
28
- require 'active_record/connection_adapters/postgresql/array_parser'
29
- else
30
- require 'arjdbc/postgresql/base/array_parser'
31
- end
32
- include ActiveRecord::ConnectionAdapters::PostgreSQL::ArrayParser
33
- end if AR4_COMPAT
99
+ base_meta = class << base; self end
100
+ base_meta.send :attr_accessor, :money_precision
101
+
102
+ # Loads pg_array_parser if available. String parsing can be
103
+ # performed quicker by a native extension, which will not create
104
+ # a large amount of Ruby objects that will need to be garbage
105
+ # collected. pg_array_parser has a C and Java extension
106
+ begin
107
+ require 'pg_array_parser'
108
+ base_meta.send :include, PgArrayParser
109
+ rescue LoadError
110
+ if AR42_COMPAT
111
+ require 'active_record/connection_adapters/postgresql/array_parser'
112
+ else
113
+ require 'arjdbc/postgresql/base/array_parser'
114
+ end
115
+ base_meta.send :include, ActiveRecord::ConnectionAdapters::PostgreSQL::ArrayParser
116
+ end if AR4_COMPAT
34
117
 
35
- include Cast
118
+ base_meta.send :include, Cast
36
119
 
37
- end
120
+ base.send :include, ColumnHelpers
38
121
  end
39
122
 
123
+ if AR4_COMPAT && ! AR42_COMPAT
124
+
40
125
  # @private
41
126
  def oid_type
42
127
  @oid_type ||= begin
43
128
  raise "oid not defined" unless oid = (@oid ||= nil)
44
129
  @adapter.get_oid_type(oid.to_i, @fmod.to_i, name)
45
130
  end
46
- end if AR4_COMPAT
131
+ end
132
+
133
+ # @private
134
+ def accessor; oid_type.accessor end
47
135
 
48
- def accessor; oid_type.accessor end if AR4_COMPAT
136
+ end
49
137
 
50
138
  ( attr_accessor :array; def array?; array; end ) if AR4_COMPAT
51
139
 
@@ -110,6 +198,9 @@ module ArJdbc
110
198
  # JSON
111
199
  when /\A'(.*)'::json\z/
112
200
  $1
201
+ # JSONB
202
+ when /\A'(.*)'::jsonb\z/
203
+ $1
113
204
  # Object identifier types
114
205
  when /\A-?\d+\z/
115
206
  $1
@@ -146,6 +237,7 @@ module ArJdbc
146
237
  case type ||= self.type
147
238
  when :hstore then self.class.string_to_hstore value
148
239
  when :json then self.class.string_to_json value
240
+ when :jsonb then self.class.string_to_json value
149
241
  when :cidr, :inet then self.class.string_to_cidr value
150
242
  when :macaddr then value
151
243
  when :tsvector then value
@@ -198,15 +290,6 @@ module ArJdbc
198
290
 
199
291
  private
200
292
 
201
- def extract_limit(sql_type)
202
- case sql_type
203
- when /^bigint/i; 8
204
- when /^smallint/i; 2
205
- when /^timestamp/i; nil
206
- else super
207
- end
208
- end
209
-
210
293
  # Extracts the scale from PostgreSQL-specific data types.
211
294
  def extract_scale(sql_type)
212
295
  # Money type has a fixed scale of 2.
@@ -302,6 +385,7 @@ module ArJdbc
302
385
  when 'uuid' then :uuid
303
386
  # JSON type
304
387
  when 'json' then :json
388
+ when 'jsonb' then :jsonb
305
389
  # Small and big integer types
306
390
  when /^(?:small|big)int$/ then :integer
307
391
  when /(num|date|tstz|ts|int4|int8)range$/
@@ -550,6 +634,6 @@ module ArJdbc
550
634
 
551
635
  end
552
636
 
553
- end
637
+ end unless AR42_COMPAT
554
638
  end
555
639
  end
@@ -10,11 +10,10 @@ module ArJdbc
10
10
  end
11
11
 
12
12
  # @private
13
- module OIDTypes
14
-
15
- OID = ActiveRecord::ConnectionAdapters::PostgreSQL::OID
13
+ OID = ::ActiveRecord::ConnectionAdapters::PostgreSQL::OID
16
14
 
17
- Type = ActiveRecord::Type if AR42_COMPAT
15
+ # @private
16
+ module OIDTypes
18
17
 
19
18
  # @override
20
19
  def enable_extension(name)
@@ -44,7 +43,7 @@ module ArJdbc
44
43
  }
45
44
  end unless AR42_COMPAT
46
45
 
47
- def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc:
46
+ def get_oid_type(oid, fmod, column_name, sql_type = '')
48
47
  if !type_map.key?(oid)
49
48
  load_additional_types(type_map, [oid])
50
49
  end
@@ -79,7 +78,8 @@ module ArJdbc
79
78
  end
80
79
 
81
80
  def type_map
82
- # NOTE: our type_map is lazy since it's only used for `adapter.accessor`
81
+ # NOTE: our type_map is lazy (on AR < 4.2)
82
+ # ... since it's only used for `adapter.accessor`
83
83
  @type_map ||= begin
84
84
  if type_map = @@type_map_cache[ type_cache_key ]
85
85
  type_map.dup
@@ -150,10 +150,10 @@ module ArJdbc
150
150
  end
151
151
  end unless AR42_COMPAT
152
152
 
153
- def initialize_type_map(m) # :nodoc:
153
+ def initialize_type_map(m)
154
154
  register_class_with_limit m, 'int2', OID::Integer
155
- m.alias_type 'int4', 'int2'
156
- m.alias_type 'int8', 'int2'
155
+ register_class_with_limit m, 'int4', OID::Integer
156
+ register_class_with_limit m, 'int8', OID::Integer
157
157
  m.alias_type 'oid', 'int2'
158
158
  m.register_type 'float4', OID::Float.new
159
159
  m.alias_type 'float8', 'float4'
@@ -221,7 +221,7 @@ module ArJdbc
221
221
  load_additional_types(m)
222
222
  end if AR42_COMPAT
223
223
 
224
- def load_additional_types(type_map, oids = nil) # :nodoc:
224
+ def load_additional_types(type_map, oids = nil)
225
225
  if supports_ranges?
226
226
  query = <<-SQL
227
227
  SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
@@ -235,11 +235,16 @@ module ArJdbc
235
235
  SQL
236
236
  end
237
237
 
238
+ initializer = OID::TypeMapInitializer.new(type_map)
239
+
238
240
  if oids
239
- query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
241
+ query << "WHERE t.oid::integer IN (%s)" % oids.join(", ")
242
+ else
243
+ if initializer.respond_to?(:query_conditions_for_initial_load)
244
+ query << initializer.query_conditions_for_initial_load(type_map)
245
+ end
240
246
  end
241
247
 
242
- initializer = OID::TypeMapInitializer.new(type_map)
243
248
  records = execute(query, 'SCHEMA')
244
249
  initializer.run(records)
245
250
  end if AR42_COMPAT
@@ -534,7 +534,7 @@ module ArJdbc
534
534
  # column *column_name* is not unique
535
535
  if msg.index('UNIQUE constraint failed: ') ||
536
536
  msg =~ /column(s)? .* (is|are) not unique/
537
- return RecordNotUnique.new(message, exception)
537
+ return ::ActiveRecord::RecordNotUnique.new(message, exception)
538
538
  end
539
539
  end
540
540
  super
@@ -1,5 +1,5 @@
1
1
  module ArJdbc
2
- VERSION = "1.3.15"
2
+ VERSION = "1.3.16"
3
3
  # @deprecated
4
4
  module Version
5
5
  # @private 1.2.x compatibility
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-jdbc-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.15
4
+ version: 1.3.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sieger, Ola Bini, Karol Bucek and JRuby contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-09 00:00:00.000000000 Z
11
+ date: 2015-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord