activerecord-jdbc-adapter 1.3.15 → 1.3.16

Sign up to get free protection for your applications and to get access to all the features.
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