activerecord-cockroachdb-adapter 6.0.0 → 6.1.1

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
  SHA256:
3
- metadata.gz: 4d570f0cc045c61b9fb3fd82bfa64462f34aa086295dff104b559f52e4b6b5ef
4
- data.tar.gz: 9995b9883f98e7eba7f429f977eadc8001d3d4e91aa6b7e3eb4d8976f9e78ff1
3
+ metadata.gz: e12a061e79d389fd1c698456bf368bb8a2971d3c8e1580242aadb669bfa30809
4
+ data.tar.gz: e12b269976f47ff593b3ece0f7848e56b76dda1d6a797dc826c483d301dc3082
5
5
  SHA512:
6
- metadata.gz: 6c2ec381be5f87497c1dd10521956475ebe8ed57b013e89296d29afc1b30764ef18952cafa7127b02df0dba6c8eb97315819e42d658235f41bccf5c86fd2b46c
7
- data.tar.gz: 675854788950b2182be1e44864f2a2b03ef768ace4346660f2075437de4ee90dc28717e48d7346d23cece34b9aabb8c493cfa6d93fce494c02b396ad19f3a002
6
+ metadata.gz: 52a6c9404a44dac790e2e7c61548d703d53f27c9654d492e9e58ba2b0f20cd7d93f9c92d26391038eccb590695b71c90d15872d44e299fd7a4e6e3f1185a2986
7
+ data.tar.gz: fff215842d13491523a7001273df0abec8a95b31294c71b6873f1c604e77f3b43d98beac514bca747ef8bd55aec9160e2ff47cfb7181eac1e230a8a9d16ec6a7
data/CHANGELOG.md CHANGED
@@ -1,31 +1,24 @@
1
1
  # Changelog
2
2
 
3
- ## 6.0.0 - 2021-04-26
3
+ ## 6.1.0 - 2021-04-26
4
4
 
5
5
  - Add a telemetry query on start-up. This helps the Cockroach Labs team
6
6
  prioritize support for the adapter. It can be disabled by setting the
7
7
  `disable_cockroachdb_telemetry` configuration option to false.
8
8
 
9
- ## 6.0.0-beta.5 - 2021-04-02
9
+ ## 6.1.0-beta.3 - 2021-04-02
10
10
 
11
11
  - Added a configuration option named `use_follower_reads_for_type_introspection`.
12
12
  If true, it improves the speed of type introspection by allowing potentially stale
13
13
  type metadata to be read. Defaults to false.
14
14
 
15
- ## 6.0.0-beta.4 - 2021-03-06
15
+ ## 6.1.0-beta.2 - 2021-03-06
16
16
 
17
17
  - Improved connection performance by refactoring an introspection
18
18
  that loads types.
19
19
  - Changed version numbers to semver.
20
20
 
21
- ## 6.0.0beta3
21
+ ## 6.1.0beta1
22
22
 
23
- - Added support for spatial features.
24
-
25
- ## 6.0.0beta2
26
-
27
- - Updated transaction retry logic to work with Rails 6.
28
-
29
- ## 6.0.0beta1
30
-
31
- - Initial support for Rails 6.
23
+ - Initial support for Rails 6.1.
24
+ - Support for spatial functionality.
data/CONTRIBUTING.md CHANGED
@@ -78,6 +78,26 @@ RAILS_SOURCE="path/to/local_copy" bundle exec rake test
78
78
 
79
79
  `test/config.yml` assumes CockroachDB will be running at localhost:26257 with a root user. Make changes to `test/config.yml` as needed.
80
80
 
81
+ ### Run Tests from a Backup
82
+
83
+ Loading the full test schema every time a test runs can take a while, so for cases where loading the schema sequentially is unimportant, it is possible to use a backup to set up the database. This is significantly faster than the standard method and is provided to run individual tests faster, but should not be used to validate a build.
84
+
85
+ First create the template database.
86
+
87
+ ```bash
88
+ bundle exec rake db:create_test_template
89
+ ```
90
+
91
+ This will create a template database for the current version (ex. `activerecord_test_template611` for version 6.1.1) and create a `BACKUP` in the `nodelocal://self/activerecord-crdb-adapter/#{activerecord_version}` directory.
92
+
93
+ To load from the template, use the `COCKROACH_LOAD_FROM_TEMPLATE` flag.
94
+
95
+ ```bash
96
+ COCKROACH_LOAD_FROM_TEMPLATE=1 TEST_FILES="test/cases/adapters/postgresql/ddl_test.rb" bundle exec rake test
97
+ ```
98
+
99
+ And the `activerecord_unittest` database will use the `RESTORE` command to load the schema from the template database.
100
+
81
101
  # Improvements
82
102
 
83
103
 
data/README.md CHANGED
@@ -1,16 +1,18 @@
1
1
  # ActiveRecord CockroachDB Adapter
2
2
 
3
- CockroachDB adapter for ActiveRecord 4 and 5. This is a lightweight extension of the PostgreSQL adapter that establishes compatibility with [CockroachDB](https://github.com/cockroachdb/cockroach).
3
+ CockroachDB adapter for ActiveRecord 5 and 6. This is a lightweight extension of the PostgreSQL adapter that establishes compatibility with [CockroachDB](https://github.com/cockroachdb/cockroach).
4
4
 
5
5
  ## Installation
6
6
 
7
7
  Add this line to your project's Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'activerecord-cockroachdb-adapter', '~> 5.2.0'
10
+ gem 'activerecord-cockroachdb-adapter', '~> 6.1.0'
11
11
  ```
12
12
 
13
- If you're using Rails 4.x, use the `0.1.x` versions of this gem.
13
+ If you're using Rails 5.2, use the `5.2.x` versions of this gem.
14
+
15
+ If you're using Rails 6.0, use the `6.0.x` versions of this gem.
14
16
 
15
17
  In `database.yml`, use the following adapter setting:
16
18
 
data/Rakefile CHANGED
@@ -2,10 +2,30 @@ require "bundler/gem_tasks"
2
2
  require "rake/testtask"
3
3
  require_relative 'test/support/paths_cockroachdb'
4
4
  require_relative 'test/support/rake_helpers'
5
+ require_relative 'test/support/template_creator'
5
6
 
6
7
  task test: ["test:cockroachdb"]
7
8
  task default: [:test]
8
9
 
10
+ namespace :db do
11
+ task "create_test_template" do
12
+ ENV['DEBUG_COCKROACHDB_ADAPTER'] = "1"
13
+ ENV['COCKROACH_SKIP_LOAD_SCHEMA'] = "1"
14
+ ENV["ARCONN"] = "cockroachdb"
15
+
16
+ TemplateCreator.connect
17
+ require_relative 'test/cases/helper'
18
+
19
+ # TODO: look into this more, but for some reason the blob alias
20
+ # is not defined while running this task.
21
+ ActiveRecord::ConnectionAdapters::CockroachDB::TableDefinition.class_eval do
22
+ alias :blob :binary
23
+ end
24
+
25
+ TemplateCreator.create_test_template
26
+ end
27
+ end
28
+
9
29
  namespace :test do
10
30
  Rake::TestTask.new("cockroachdb") do |t|
11
31
  t.libs = ARTest::CockroachDB.test_load_paths
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "activerecord-cockroachdb-adapter"
7
- spec.version = "6.0.0"
7
+ spec.version = "6.1.1"
8
8
  spec.licenses = ["Apache-2.0"]
9
9
  spec.authors = ["Cockroach Labs"]
10
10
  spec.email = ["cockroach-db@googlegroups.com"]
@@ -13,8 +13,8 @@ Gem::Specification.new do |spec|
13
13
  spec.description = "Allows the use of CockroachDB as a backend for ActiveRecord and Rails apps."
14
14
  spec.homepage = "https://github.com/cockroachdb/activerecord-cockroachdb-adapter"
15
15
 
16
- spec.add_dependency "activerecord", "~> 6.0.3"
17
- spec.add_dependency "pg", ">= 0.20"
16
+ spec.add_dependency "activerecord", "~> 6.1"
17
+ spec.add_dependency "pg", "~> 1.2"
18
18
  spec.add_dependency "rgeo-activerecord", "~> 7.0.0"
19
19
 
20
20
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
@@ -0,0 +1,126 @@
1
+ # frozen-string-literal: true
2
+
3
+ require "active_support/duration"
4
+
5
+ module ActiveRecord
6
+ module ConnectionAdapters
7
+ module CockroachDB
8
+ module OID
9
+ module Interval # :nodoc:
10
+ DEFAULT_PRECISION = 6 # microseconds
11
+
12
+ def cast_value(value)
13
+ case value
14
+ when ::ActiveSupport::Duration
15
+ value
16
+ when ::String
17
+ begin
18
+ PostgresqlInterval::Parser.parse(value)
19
+ rescue PostgresqlInterval::ParseError
20
+ # Try ISO 8601
21
+ super
22
+ end
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ def serialize(value)
29
+ precision = self.precision || DEFAULT_PRECISION
30
+ case value
31
+ when ::ActiveSupport::Duration
32
+ serialize_duration(value, precision)
33
+ when ::Numeric
34
+ serialize_duration(value.seconds, precision)
35
+ else
36
+ super
37
+ end
38
+ end
39
+
40
+ def type_cast_for_schema(value)
41
+ serialize(value).inspect
42
+ end
43
+
44
+ private
45
+
46
+ # Convert an ActiveSupport::Duration to
47
+ # the postgres interval style
48
+ # ex. 1 year 2 mons 3 days 4 hours 5 minutes 6 seconds
49
+ def serialize_duration(value, precision)
50
+ yrs = value.parts.fetch(:years, 0)
51
+ mons = value.parts.fetch(:months, 0)
52
+ days = value.parts.fetch(:days, 0)
53
+ hrs = value.parts.fetch(:hours, 0)
54
+ mins = value.parts.fetch(:minutes, 0)
55
+ secs = value.parts.fetch(:seconds, 0).round(precision)
56
+
57
+ "#{yrs} years #{mons} mons #{days} days #{hrs} hours #{mins} minutes #{secs} seconds"
58
+ end
59
+ end
60
+
61
+ PostgreSQL::OID::Interval.prepend(Interval)
62
+ end
63
+
64
+ module PostgresqlInterval
65
+ class Parser
66
+ PARTS = ActiveSupport::Duration::PARTS
67
+ PARTS_IN_SECONDS = ActiveSupport::Duration::PARTS_IN_SECONDS
68
+
69
+ # modified regex from https://github.com/jeremyevans/sequel/blob/master/lib/sequel/extensions/pg_interval.rb#L86
70
+ REGEX = /\A([+-]?\d+ years?\s?)?([+-]?\d+ mons?\s?)?([+-]?\d+ days?\s?)?(?:([+-])?(\d{2,10}):(\d\d):(\d\d(\.\d+)?))?\z/
71
+
72
+ def self.parse(string)
73
+ matches = REGEX.match(string)
74
+ raise(ParseError) unless matches
75
+
76
+ # 1 => years, 2 => months, 3 => days, 4 => nil, 5 => hours,
77
+ # 6 => minutes, 7 => seconds with fraction digits, 8 => fractional portion of 7
78
+ duration = 0
79
+ parts = {}
80
+
81
+ if matches[1]
82
+ val = matches[1].to_i
83
+ duration += val * PARTS_IN_SECONDS[:years]
84
+ parts[:years] = val
85
+ end
86
+
87
+ if matches[2]
88
+ val = matches[2].to_i
89
+ duration += val * PARTS_IN_SECONDS[:months]
90
+ parts[:months] = val
91
+ end
92
+
93
+ if matches[3]
94
+ val = matches[3].to_i
95
+ duration += val * PARTS_IN_SECONDS[:days]
96
+ parts[:days] = val
97
+ end
98
+
99
+ if matches[5]
100
+ val = matches[5].to_i
101
+ duration += val * PARTS_IN_SECONDS[:hours]
102
+ parts[:hours] = val
103
+ end
104
+
105
+ if matches[6]
106
+ val = matches[6].to_i
107
+ duration += val * PARTS_IN_SECONDS[:minutes]
108
+ parts[:minutes] = val
109
+ end
110
+
111
+ if matches[7]
112
+ val = matches[7].to_f
113
+ duration += val * PARTS_IN_SECONDS[:seconds]
114
+ parts[:seconds] = val
115
+ end
116
+
117
+ ActiveSupport::Duration.new(duration, parts)
118
+ end
119
+ end
120
+
121
+ class ParseError < StandardError
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  module SchemaStatements
5
5
  include ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements
6
6
 
7
- def add_index(table_name, column_name, options = {})
7
+ def add_index(table_name, column_name, **options)
8
8
  super
9
9
  rescue ActiveRecord::StatementInvalid => error
10
10
  if debugging? && error.cause.class == PG::FeatureNotSupported
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  # transactions will be retried until they pass or the max retry limit is
10
10
  # exceeded.
11
11
  def within_new_transaction(isolation: nil, joinable: true, attempts: 0)
12
- super
12
+ super(isolation: isolation, joinable: joinable)
13
13
  rescue ActiveRecord::StatementInvalid => error
14
14
  raise unless retryable? error
15
15
  raise if attempts >= @connection.max_transaction_retries
@@ -1,12 +1,10 @@
1
1
  module ActiveRecord
2
2
  module Type
3
3
  class << self
4
- private
5
-
6
4
  # Return :postgresql instead of :cockroachdb for current_adapter_name so
7
5
  # we can continue using the ActiveRecord::Types defined in
8
6
  # PostgreSQLAdapter.
9
- def current_adapter_name
7
+ def adapter_name_from(_model)
10
8
  :postgresql
11
9
  end
12
10
  end
@@ -1,6 +1,6 @@
1
1
  require "rgeo/active_record"
2
2
 
3
- require 'active_record/connection_adapters/postgresql_adapter'
3
+ require "active_record/connection_adapters/postgresql_adapter"
4
4
  require "active_record/connection_adapters/cockroachdb/column_methods"
5
5
  require "active_record/connection_adapters/cockroachdb/schema_statements"
6
6
  require "active_record/connection_adapters/cockroachdb/referential_integrity"
@@ -15,6 +15,7 @@ require "active_record/connection_adapters/cockroachdb/spatial_column_info"
15
15
  require "active_record/connection_adapters/cockroachdb/setup"
16
16
  require "active_record/connection_adapters/cockroachdb/oid/type_map_initializer"
17
17
  require "active_record/connection_adapters/cockroachdb/oid/spatial"
18
+ require "active_record/connection_adapters/cockroachdb/oid/interval"
18
19
  require "active_record/connection_adapters/cockroachdb/arel_tosql"
19
20
 
20
21
  # Run to ignore spatial tables that will break schemna dumper.
@@ -25,25 +26,29 @@ module ActiveRecord
25
26
  module ConnectionHandling
26
27
  def cockroachdb_connection(config)
27
28
  # This is copied from the PostgreSQL adapter.
28
- conn_params = config.symbolize_keys
29
-
30
- conn_params.delete_if { |_, v| v.nil? }
29
+ conn_params = config.symbolize_keys.compact
31
30
 
32
31
  # Map ActiveRecords param names to PGs.
33
32
  conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
34
33
  conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
35
34
 
36
35
  # Forward only valid config params to PG::Connection.connect.
37
- valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:sslmode, :application_name]
36
+ valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
38
37
  conn_params.slice!(*valid_conn_param_keys)
39
38
 
40
- conn = PG.connect(conn_params)
41
- ConnectionAdapters::CockroachDBAdapter.new(conn, logger, conn_params, config)
42
- rescue ::PG::Error, ActiveRecord::ActiveRecordError => error
43
- if error.message.include?("does not exist")
39
+ ConnectionAdapters::CockroachDBAdapter.new(
40
+ ConnectionAdapters::CockroachDBAdapter.new_client(conn_params),
41
+ logger,
42
+ conn_params,
43
+ config
44
+ )
45
+ # This rescue flow appears in new_client, but it is needed here as well
46
+ # since Cockroach will sometimes not raise until a query is made.
47
+ rescue ActiveRecord::StatementInvalid => error
48
+ if conn_params && conn_params[:dbname] && error.cause.message.include?(conn_params[:dbname])
44
49
  raise ActiveRecord::NoDatabaseError
45
50
  else
46
- raise
51
+ raise ActiveRecord::ConnectionNotEstablished, error.message
47
52
  end
48
53
  end
49
54
  end
@@ -52,24 +57,29 @@ end
52
57
  module ActiveRecord
53
58
  module ConnectionAdapters
54
59
  module CockroachDBConnectionPool
55
- def initialize(spec)
56
- super(spec)
57
- disable_telemetry = spec.config[:disable_cockroachdb_telemetry]
58
- adapter = spec.config[:adapter]
60
+ def initialize(pool_config)
61
+ super(pool_config)
62
+ disable_telemetry = pool_config.db_config.configuration_hash[:disable_cockroachdb_telemetry]
63
+ adapter = pool_config.db_config.configuration_hash[:adapter]
59
64
  return if disable_telemetry || adapter != "cockroachdb"
60
65
 
61
- with_connection do |conn|
62
- if conn.active?
63
- begin
64
- query = "SELECT crdb_internal.increment_feature_counter('ActiveRecord %d.%d')"
65
- conn.execute(query % [ActiveRecord::VERSION::MAJOR, ActiveRecord::VERSION::MINOR])
66
- rescue ActiveRecord::StatementInvalid
67
- # The increment_feature_counter built-in is not supported on this
68
- # CockroachDB version. Ignore.
69
- rescue StandardError => e
70
- conn.logger.warn "Unexpected error when incrementing feature counter: #{e}"
66
+
67
+ begin
68
+ with_connection do |conn|
69
+ if conn.active?
70
+ begin
71
+ query = "SELECT crdb_internal.increment_feature_counter('ActiveRecord %d.%d')"
72
+ conn.execute(query % [ActiveRecord::VERSION::MAJOR, ActiveRecord::VERSION::MINOR])
73
+ rescue ActiveRecord::StatementInvalid
74
+ # The increment_feature_counter built-in is not supported on this
75
+ # CockroachDB version. Ignore.
76
+ rescue StandardError => e
77
+ conn.logger.warn "Unexpected error when incrementing feature counter: #{e}"
78
+ end
71
79
  end
72
80
  end
81
+ rescue ActiveRecord::NoDatabaseError
82
+ # Prevent failures on db creation and parallel testing.
73
83
  end
74
84
  end
75
85
  end
@@ -93,7 +103,7 @@ module ActiveRecord
93
103
  st_polygon: {},
94
104
  }
95
105
 
96
- # http://postgis.17.x6.nabble.com/Default-SRID-td5001115.html
106
+ # http://postgis.17.x6.nabble.com/Default-SRID-td5001115.html
97
107
  DEFAULT_SRID = 0
98
108
 
99
109
  include CockroachDB::SchemaStatements
@@ -101,56 +111,6 @@ module ActiveRecord
101
111
  include CockroachDB::DatabaseStatements
102
112
  include CockroachDB::Quoting
103
113
 
104
- # override
105
- # This method makes a sql query to gather information about columns
106
- # in a table. It returns an array of arrays (one for each col) and
107
- # passes each to the SchemaStatements#new_column_from_field method
108
- # as the field parameter. This data is then used to format the column
109
- # objects for the model and sent to the OID for data casting.
110
- #
111
- # The issue with the default method is that the sql_type field is
112
- # retrieved with the `format_type` function, but this is implemented
113
- # differently in CockroachDB than PostGIS, so geometry/geography
114
- # types are missing information which makes parsing them impossible.
115
- # Below is an example of what `format_type` returns for a geometry
116
- # column.
117
- #
118
- # column_type: geometry(POINT, 4326)
119
- # Expected: geometry(POINT, 4326)
120
- # Actual: geometry
121
- #
122
- # The solution is to make the default query with super, then
123
- # iterate through the columns and if it is a spatial type,
124
- # access the proper column_type with the information_schema.columns
125
- # table.
126
- #
127
- # @see: https://github.com/rails/rails/blob/8695b028261bdd244e254993255c6641bdbc17a5/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L829
128
- def column_definitions(table_name)
129
- fields = super
130
- # iterate through and identify all spatial fields based on format_type
131
- # being geometry or geography, then query for the information_schema.column
132
- # column_type because that contains the necessary information.
133
- fields.map do |field|
134
- dtype = field[1]
135
- if dtype == 'geometry' || dtype == 'geography'
136
- col_name = field[0]
137
- data_type = \
138
- query(<<~SQL, "SCHEMA")
139
- SELECT c.data_type
140
- FROM information_schema.columns c
141
- WHERE c.table_name = #{quote(table_name)}
142
- AND c.column_name = #{quote(col_name)}
143
- SQL
144
- field[1] = data_type[0][0]
145
- end
146
- field
147
- end
148
- end
149
-
150
- def arel_visitor
151
- Arel::Visitors::CockroachDB.new(self)
152
- end
153
-
154
114
  def self.spatial_column_options(key)
155
115
  SPATIAL_COLUMN_OPTIONS[key]
156
116
  end
@@ -306,19 +266,28 @@ module ActiveRecord
306
266
  end
307
267
  end
308
268
 
309
- # NOTE(joey): PostgreSQL intervals have a precision.
310
- # CockroachDB intervals do not, so overide the type
311
- # definition. Returning a ArgumentError may not be correct.
312
- # This needs to be tested.
313
- m.register_type "interval" do |_, _, sql_type|
269
+ # Belongs after other types are defined because of issues described
270
+ # in this https://github.com/rails/rails/pull/38571
271
+ # Once that PR is merged, we can call super at the top.
272
+ super(m)
273
+
274
+ # Override numeric type. This is almost identical to the default,
275
+ # except that the conditional based on the fmod is changed.
276
+ m.register_type "numeric" do |_, fmod, sql_type|
314
277
  precision = extract_precision(sql_type)
315
- if precision
316
- raise(ArgumentError, "CockroachDB does not support precision on intervals, but got precision: #{precision}")
278
+ scale = extract_scale(sql_type)
279
+
280
+ # If fmod is -1, that means that precision is defined but not
281
+ # scale, or neither is defined.
282
+ if fmod && fmod == -1 && !precision.nil?
283
+ # Below comment is from ActiveRecord
284
+ # FIXME: Remove this class, and the second argument to
285
+ # lookups on PG
286
+ Type::DecimalWithoutScale.new(precision: precision)
287
+ else
288
+ OID::Decimal.new(precision: precision, scale: scale)
317
289
  end
318
- OID::SpecializedString.new(:interval, precision: precision)
319
290
  end
320
-
321
- super(m)
322
291
  end
323
292
 
324
293
  # Configures the encoding, verbosity, schema search path, and time zone of the connection.
@@ -423,11 +392,85 @@ module ActiveRecord
423
392
  # In general, it is hard to parse that, but it is easy to handle the common
424
393
  # case of an empty array.
425
394
  def extract_empty_array_from_default(default)
426
- return unless supports_string_to_array_coercion?
395
+ return unless supports_string_to_array_coercion?
427
396
  return unless default =~ /\AARRAY\[\]\z/
428
397
  return "{}"
429
398
  end
430
399
 
400
+ # override
401
+ # This method makes a query to gather information about columns
402
+ # in a table. It returns an array of arrays (one for each col) and
403
+ # passes each to the SchemaStatements#new_column_from_field method
404
+ # as the field parameter. This data is then used to format the column
405
+ # objects for the model and sent to the OID for data casting.
406
+ #
407
+ # Sometimes there are differences between how data is formatted
408
+ # in Postgres and CockroachDB, so additional queries for certain types
409
+ # may be necessary to properly form the column definition.
410
+ #
411
+ # @see: https://github.com/rails/rails/blob/8695b028261bdd244e254993255c6641bdbc17a5/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L829
412
+ def column_definitions(table_name)
413
+ fields = super
414
+
415
+ # Use regex comparison because if a type is an array it will
416
+ # have [] appended to the end of it.
417
+ target_types = [
418
+ /geometry/,
419
+ /geography/,
420
+ /interval/,
421
+ /numeric/
422
+ ]
423
+ re = Regexp.union(target_types)
424
+ fields.map do |field|
425
+ dtype = field[1]
426
+ if re.match(dtype)
427
+ crdb_column_definition(field, table_name)
428
+ else
429
+ field
430
+ end
431
+ end
432
+ end
433
+
434
+ # Use the crdb_sql_type instead of the sql_type returned by
435
+ # column_definitions. This will include limit,
436
+ # precision, and scale information in the type.
437
+ # Ex. geometry -> geometry(point, 4326)
438
+ def crdb_column_definition(field, table_name)
439
+ col_name = field[0]
440
+ data_type = \
441
+ query(<<~SQL, "SCHEMA")
442
+ SELECT c.crdb_sql_type
443
+ FROM information_schema.columns c
444
+ WHERE c.table_name = #{quote(table_name)}
445
+ AND c.column_name = #{quote(col_name)}
446
+ SQL
447
+ field[1] = data_type[0][0].downcase
448
+ field
449
+ end
450
+
451
+ # override
452
+ # This method is used to determine if a
453
+ # FEATURE_NOT_SUPPORTED error from the PG gem should
454
+ # be an ActiveRecord::PreparedStatementCacheExpired
455
+ # error.
456
+ #
457
+ # ActiveRecord handles this by checking that the sql state matches the
458
+ # FEATURE_NOT_SUPPORTED code and that the source function
459
+ # is "RevalidateCachedQuery" since that is the only function
460
+ # in postgres that will create this error.
461
+ #
462
+ # That method will not work for CockroachDB because the error
463
+ # originates from the "runExecBuilder" function, so we need
464
+ # to modify the original to match the CockroachDB behavior.
465
+ def is_cached_plan_failure?(e)
466
+ pgerror = e.cause
467
+
468
+ pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
469
+ pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "runExecBuilder"
470
+ rescue
471
+ false
472
+ end
473
+
431
474
  # override
432
475
  # This method loads info about data types from the database to
433
476
  # populate the TypeMap.
@@ -505,6 +548,7 @@ module ActiveRecord
505
548
  @type_map_for_results = PG::TypeMapByOid.new
506
549
  @type_map_for_results.default_type_map = map
507
550
  @type_map_for_results.add_coder(PG::TextDecoder::Bytea.new(oid: 17, name: "bytea"))
551
+ @type_map_for_results.add_coder(MoneyDecoder.new(oid: 790, name: "money"))
508
552
 
509
553
  # extract timestamp decoder for use in update_typemap_for_default_timezone
510
554
  @timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-cockroachdb-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0
4
+ version: 6.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cockroach Labs
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-28 00:00:00.000000000 Z
11
+ date: 2021-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.3
19
+ version: '6.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 6.0.3
26
+ version: '6.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pg
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.20'
33
+ version: '1.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.20'
40
+ version: '1.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rgeo-activerecord
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -82,6 +82,7 @@ files:
82
82
  - lib/active_record/connection_adapters/cockroachdb/column_methods.rb
83
83
  - lib/active_record/connection_adapters/cockroachdb/database_statements.rb
84
84
  - lib/active_record/connection_adapters/cockroachdb/database_tasks.rb
85
+ - lib/active_record/connection_adapters/cockroachdb/oid/interval.rb
85
86
  - lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb
86
87
  - lib/active_record/connection_adapters/cockroachdb/oid/type_map_initializer.rb
87
88
  - lib/active_record/connection_adapters/cockroachdb/quoting.rb
@@ -99,7 +100,7 @@ licenses:
99
100
  - Apache-2.0
100
101
  metadata:
101
102
  allowed_push_host: https://rubygems.org
102
- post_install_message:
103
+ post_install_message:
103
104
  rdoc_options: []
104
105
  require_paths:
105
106
  - lib
@@ -114,8 +115,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
115
  - !ruby/object:Gem::Version
115
116
  version: '0'
116
117
  requirements: []
117
- rubygems_version: 3.1.4
118
- signing_key:
118
+ rubygems_version: 3.0.3
119
+ signing_key:
119
120
  specification_version: 4
120
121
  summary: CockroachDB adapter for ActiveRecord.
121
122
  test_files: []