activerecord-cockroachdb-adapter 6.0.0.pre.beta.5 → 6.1.0beta1

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: e242232ac6fcfc87b6bddc17eeb852099a959d3a024064ed3a32e85bd80ad786
4
- data.tar.gz: 5ab114df9f5fee7fb5c18c5cf0eb0dfdc822f7513f19d79312f65e0b55e1e459
3
+ metadata.gz: 5d0954fd425d90342f04c1b6559b78e398be9e523e67779476d81f925a1aa611
4
+ data.tar.gz: 1f990c34784394bafa77933eb0d49965a0eac81151f2468c92a66c1bc9beb78a
5
5
  SHA512:
6
- metadata.gz: a2de1e036b53ebeb11185eaeb10bd465f9a1103a34307354bc4bbbe94b8beb4c5a2313938e01703db8b68f5a689ee6b9b778b8282bceac3bb852b6569340351b
7
- data.tar.gz: 4138ea2ccad0bac070c277adb9ec4aa837be440900f72fe8f2728bac78d58a96d96ed7df9a830841b3389e5f51678dba9377e0598b3aa96d682d36c609dcedfb
6
+ metadata.gz: 3074426e81a83bb4ae2e50047c6db97dc75d9b8a822c3fd1153fb3403457bb56e7f36acb42802e5dd777c056dd0864db7dc26e875e7a644cb158f0a1c8001f3a
7
+ data.tar.gz: 8ff7c637812c1b262452ca1ef6ad8308a3f620a47e3798c6ef7b93096fedb362ce52372f6c0b870af1b475a31cf83f670f4e6d65498c231f5759a475820568af
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
@@ -22,12 +22,6 @@ development:
22
22
  user: <username>
23
23
  ```
24
24
 
25
- ## Configuration
26
-
27
- In addition to the standard adapter settings, CockroachDB also supports the following:
28
-
29
- - `use_follower_reads_for_type_introspection`: Use follower reads on queries to the `pg_type` catalog when set to `true`. This helps to speed up initialization by reading historical data, but may not find recently created user-defined types.
30
-
31
25
  ## Working with Spatial Data
32
26
 
33
27
  The adapter uses [RGeo](https://github.com/rgeo/rgeo) and [RGeo-ActiveRecord](https://github.com/rgeo/rgeo-activerecord) to represent geometric and geographic data as Ruby objects and easily interface them with the adapter. The following is a brief introduction to RGeo and tips to help setup your spatial application. More documentation about RGeo can be found in the [YARD Docs](https://rubydoc.info/github/rgeo/rgeo) and [wiki](https://github.com/rgeo/rgeo/wiki).
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-beta.5"
7
+ spec.version = "6.1.0beta1"
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"
@@ -13,8 +13,8 @@ require "active_record/connection_adapters/cockroachdb/attribute_methods"
13
13
  require "active_record/connection_adapters/cockroachdb/column"
14
14
  require "active_record/connection_adapters/cockroachdb/spatial_column_info"
15
15
  require "active_record/connection_adapters/cockroachdb/setup"
16
- require "active_record/connection_adapters/cockroachdb/oid/type_map_initializer"
17
16
  require "active_record/connection_adapters/cockroachdb/oid/spatial"
17
+ require "active_record/connection_adapters/cockroachdb/oid/interval"
18
18
  require "active_record/connection_adapters/cockroachdb/arel_tosql"
19
19
 
20
20
  # Run to ignore spatial tables that will break schemna dumper.
@@ -25,25 +25,29 @@ module ActiveRecord
25
25
  module ConnectionHandling
26
26
  def cockroachdb_connection(config)
27
27
  # This is copied from the PostgreSQL adapter.
28
- conn_params = config.symbolize_keys
29
-
30
- conn_params.delete_if { |_, v| v.nil? }
28
+ conn_params = config.symbolize_keys.compact
31
29
 
32
30
  # Map ActiveRecords param names to PGs.
33
31
  conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
34
32
  conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
35
33
 
36
34
  # Forward only valid config params to PG::Connection.connect.
37
- valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:sslmode, :application_name]
35
+ valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
38
36
  conn_params.slice!(*valid_conn_param_keys)
39
37
 
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")
38
+ ConnectionAdapters::CockroachDBAdapter.new(
39
+ ConnectionAdapters::CockroachDBAdapter.new_client(conn_params),
40
+ logger,
41
+ conn_params,
42
+ config
43
+ )
44
+ # This rescue flow appears in new_client, but it is needed here as well
45
+ # since Cockroach will sometimes not raise until a query is made.
46
+ rescue ActiveRecord::StatementInvalid => error
47
+ if conn_params && conn_params[:dbname] && error.cause.message.include?(conn_params[:dbname])
44
48
  raise ActiveRecord::NoDatabaseError
45
49
  else
46
- raise
50
+ raise ActiveRecord::ConnectionNotEstablished, error.message
47
51
  end
48
52
  end
49
53
  end
@@ -77,56 +81,6 @@ module ActiveRecord
77
81
  include CockroachDB::DatabaseStatements
78
82
  include CockroachDB::Quoting
79
83
 
80
- # override
81
- # This method makes a sql query to gather information about columns
82
- # in a table. It returns an array of arrays (one for each col) and
83
- # passes each to the SchemaStatements#new_column_from_field method
84
- # as the field parameter. This data is then used to format the column
85
- # objects for the model and sent to the OID for data casting.
86
- #
87
- # The issue with the default method is that the sql_type field is
88
- # retrieved with the `format_type` function, but this is implemented
89
- # differently in CockroachDB than PostGIS, so geometry/geography
90
- # types are missing information which makes parsing them impossible.
91
- # Below is an example of what `format_type` returns for a geometry
92
- # column.
93
- #
94
- # column_type: geometry(POINT, 4326)
95
- # Expected: geometry(POINT, 4326)
96
- # Actual: geometry
97
- #
98
- # The solution is to make the default query with super, then
99
- # iterate through the columns and if it is a spatial type,
100
- # access the proper column_type with the information_schema.columns
101
- # table.
102
- #
103
- # @see: https://github.com/rails/rails/blob/8695b028261bdd244e254993255c6641bdbc17a5/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L829
104
- def column_definitions(table_name)
105
- fields = super
106
- # iterate through and identify all spatial fields based on format_type
107
- # being geometry or geography, then query for the information_schema.column
108
- # column_type because that contains the necessary information.
109
- fields.map do |field|
110
- dtype = field[1]
111
- if dtype == 'geometry' || dtype == 'geography'
112
- col_name = field[0]
113
- data_type = \
114
- query(<<~SQL, "SCHEMA")
115
- SELECT c.data_type
116
- FROM information_schema.columns c
117
- WHERE c.table_name = #{quote(table_name)}
118
- AND c.column_name = #{quote(col_name)}
119
- SQL
120
- field[1] = data_type[0][0]
121
- end
122
- field
123
- end
124
- end
125
-
126
- def arel_visitor
127
- Arel::Visitors::CockroachDB.new(self)
128
- end
129
-
130
84
  def self.spatial_column_options(key)
131
85
  SPATIAL_COLUMN_OPTIONS[key]
132
86
  end
@@ -218,10 +172,6 @@ module ActiveRecord
218
172
  @crdb_version >= 202
219
173
  end
220
174
 
221
- def supports_partitioned_indexes?
222
- false
223
- end
224
-
225
175
  # This is hardcoded to 63 (as previously was in ActiveRecord 5.0) to aid in
226
176
  # migration from PostgreSQL to CockroachDB. In practice, this limitation
227
177
  # is arbitrary since CockroachDB supports index name lengths and table alias
@@ -281,19 +231,31 @@ module ActiveRecord
281
231
  end
282
232
  end
283
233
 
284
- # NOTE(joey): PostgreSQL intervals have a precision.
285
- # CockroachDB intervals do not, so overide the type
286
- # definition. Returning a ArgumentError may not be correct.
287
- # This needs to be tested.
288
- m.register_type "interval" do |_, _, sql_type|
234
+ # Belongs after other types are defined because of issues described
235
+ # in this https://github.com/rails/rails/pull/38571
236
+ # Once that PR is merged, we can call super at the top.
237
+ super(m)
238
+
239
+ # Override numeric type. This is almost identical to the default,
240
+ # except that the conditional based on the fmod is changed.
241
+ m.register_type "numeric" do |_, fmod, sql_type|
289
242
  precision = extract_precision(sql_type)
290
- if precision
291
- raise(ArgumentError, "CockroachDB does not support precision on intervals, but got precision: #{precision}")
243
+ scale = extract_scale(sql_type)
244
+
245
+ # TODO(#178) this should never use DecimalWithoutScale since scale
246
+ # is assumed to be 0 if it is not explicitly defined.
247
+ #
248
+ # If fmod is -1, that means that precision is defined but not
249
+ # scale, or neither is defined.
250
+ if fmod && fmod == -1
251
+ # Below comment is from ActiveRecord
252
+ # FIXME: Remove this class, and the second argument to
253
+ # lookups on PG
254
+ Type::DecimalWithoutScale.new(precision: precision)
255
+ else
256
+ OID::Decimal.new(precision: precision, scale: scale)
292
257
  end
293
- OID::SpecializedString.new(:interval, precision: precision)
294
258
  end
295
-
296
- super(m)
297
259
  end
298
260
 
299
261
  # Configures the encoding, verbosity, schema search path, and time zone of the connection.
@@ -404,93 +366,77 @@ module ActiveRecord
404
366
  end
405
367
 
406
368
  # override
407
- # This method loads info about data types from the database to
408
- # populate the TypeMap.
369
+ # This method makes a query to gather information about columns
370
+ # in a table. It returns an array of arrays (one for each col) and
371
+ # passes each to the SchemaStatements#new_column_from_field method
372
+ # as the field parameter. This data is then used to format the column
373
+ # objects for the model and sent to the OID for data casting.
374
+ #
375
+ # Sometimes there are differences between how data is formatted
376
+ # in Postgres and CockroachDB, so additional queries for certain types
377
+ # may be necessary to properly form the column definition.
409
378
  #
410
- # Currently, querying from the pg_type catalog can be slow due to geo-partitioning
411
- # so this modified query uses AS OF SYSTEM TIME '-10s' to read historical data.
412
- def load_additional_types(oids = nil)
413
- if @config[:use_follower_reads_for_type_introspection]
414
- initializer = OID::TypeMapInitializer.new(type_map)
415
-
416
- query = <<~SQL
417
- SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
418
- FROM pg_type as t
419
- LEFT JOIN pg_range as r ON oid = rngtypid AS OF SYSTEM TIME '-10s'
420
- SQL
421
-
422
- if oids
423
- query += "WHERE t.oid IN (%s)" % oids.join(", ")
379
+ # @see: https://github.com/rails/rails/blob/8695b028261bdd244e254993255c6641bdbc17a5/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L829
380
+ def column_definitions(table_name)
381
+ fields = super
382
+
383
+ # Use regex comparison because if a type is an array it will
384
+ # have [] appended to the end of it.
385
+ target_types = [
386
+ /geometry/,
387
+ /geography/,
388
+ /interval/,
389
+ /numeric/
390
+ ]
391
+ re = Regexp.union(target_types)
392
+ fields.map do |field|
393
+ dtype = field[1]
394
+ if re.match(dtype)
395
+ crdb_column_definition(field, table_name)
424
396
  else
425
- query += initializer.query_conditions_for_initial_load
426
- end
427
-
428
- execute_and_clear(query, "SCHEMA", []) do |records|
429
- initializer.run(records)
397
+ field
430
398
  end
431
- else
432
- super
433
399
  end
434
- rescue ActiveRecord::StatementInvalid => e
435
- raise e unless e.cause.is_a? PG::InvalidCatalogName
436
- # use original if database is younger than 10s
437
- super
400
+ end
401
+
402
+ # Use the crdb_sql_type instead of the sql_type returned by
403
+ # column_definitions. This will include limit,
404
+ # precision, and scale information in the type.
405
+ # Ex. geometry -> geometry(point, 4326)
406
+ def crdb_column_definition(field, table_name)
407
+ col_name = field[0]
408
+ data_type = \
409
+ query(<<~SQL, "SCHEMA")
410
+ SELECT c.crdb_sql_type
411
+ FROM information_schema.columns c
412
+ WHERE c.table_name = #{quote(table_name)}
413
+ AND c.column_name = #{quote(col_name)}
414
+ SQL
415
+ field[1] = data_type[0][0].downcase
416
+ field
438
417
  end
439
418
 
440
419
  # override
441
- # This method maps data types to their proper decoder.
420
+ # This method is used to determine if a
421
+ # FEATURE_NOT_SUPPORTED error from the PG gem should
422
+ # be an ActiveRecord::PreparedStatementCacheExpired
423
+ # error.
442
424
  #
443
- # Currently, querying from the pg_type catalog can be slow due to geo-partitioning
444
- # so this modified query uses AS OF SYSTEM TIME '-10s' to read historical data.
445
- def add_pg_decoders
446
- if @config[:use_follower_reads_for_type_introspection]
447
- @default_timezone = nil
448
- @timestamp_decoder = nil
449
-
450
- coders_by_name = {
451
- "int2" => PG::TextDecoder::Integer,
452
- "int4" => PG::TextDecoder::Integer,
453
- "int8" => PG::TextDecoder::Integer,
454
- "oid" => PG::TextDecoder::Integer,
455
- "float4" => PG::TextDecoder::Float,
456
- "float8" => PG::TextDecoder::Float,
457
- "numeric" => PG::TextDecoder::Numeric,
458
- "bool" => PG::TextDecoder::Boolean,
459
- "timestamp" => PG::TextDecoder::TimestampUtc,
460
- "timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
461
- }
462
-
463
- known_coder_types = coders_by_name.keys.map { |n| quote(n) }
464
- query = <<~SQL % known_coder_types.join(", ")
465
- SELECT t.oid, t.typname
466
- FROM pg_type as t AS OF SYSTEM TIME '-10s'
467
- WHERE t.typname IN (%s)
468
- SQL
469
-
470
- coders = execute_and_clear(query, "SCHEMA", []) do |result|
471
- result
472
- .map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
473
- .compact
474
- end
475
-
476
- map = PG::TypeMapByOid.new
477
- coders.each { |coder| map.add_coder(coder) }
478
- @connection.type_map_for_results = map
479
-
480
- @type_map_for_results = PG::TypeMapByOid.new
481
- @type_map_for_results.default_type_map = map
482
- @type_map_for_results.add_coder(PG::TextDecoder::Bytea.new(oid: 17, name: "bytea"))
483
-
484
- # extract timestamp decoder for use in update_typemap_for_default_timezone
485
- @timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
486
- update_typemap_for_default_timezone
487
- else
488
- super
489
- end
490
- rescue ActiveRecord::StatementInvalid => e
491
- raise e unless e.cause.is_a? PG::InvalidCatalogName
492
- # use original if database is younger than 10s
493
- super
425
+ # ActiveRecord handles this by checking that the sql state matches the
426
+ # FEATURE_NOT_SUPPORTED code and that the source function
427
+ # is "RevalidateCachedQuery" since that is the only function
428
+ # in postgres that will create this error.
429
+ #
430
+ # That method will not work for CockroachDB because the error
431
+ # originates from the "runExecBuilder" function, so we need
432
+ # to modify the original to match the CockroachDB behavior.
433
+ def is_cached_plan_failure?(e)
434
+ pgerror = e.cause
435
+
436
+ pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
437
+ pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "runExecBuilder"
438
+ rescue
439
+ false
494
440
  end
495
441
 
496
442
  def arel_visitor
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.pre.beta.5
4
+ version: 6.1.0beta1
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-05 00:00:00.000000000 Z
11
+ date: 2021-02-10 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
@@ -62,7 +62,6 @@ extra_rdoc_files: []
62
62
  files:
63
63
  - ".gitignore"
64
64
  - ".gitmodules"
65
- - CHANGELOG.md
66
65
  - CONTRIBUTING.md
67
66
  - Gemfile
68
67
  - LICENSE
@@ -82,8 +81,8 @@ files:
82
81
  - lib/active_record/connection_adapters/cockroachdb/column_methods.rb
83
82
  - lib/active_record/connection_adapters/cockroachdb/database_statements.rb
84
83
  - lib/active_record/connection_adapters/cockroachdb/database_tasks.rb
84
+ - lib/active_record/connection_adapters/cockroachdb/oid/interval.rb
85
85
  - lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb
86
- - lib/active_record/connection_adapters/cockroachdb/oid/type_map_initializer.rb
87
86
  - lib/active_record/connection_adapters/cockroachdb/quoting.rb
88
87
  - lib/active_record/connection_adapters/cockroachdb/referential_integrity.rb
89
88
  - lib/active_record/connection_adapters/cockroachdb/schema_statements.rb
@@ -99,7 +98,7 @@ licenses:
99
98
  - Apache-2.0
100
99
  metadata:
101
100
  allowed_push_host: https://rubygems.org
102
- post_install_message:
101
+ post_install_message:
103
102
  rdoc_options: []
104
103
  require_paths:
105
104
  - lib
@@ -114,8 +113,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
113
  - !ruby/object:Gem::Version
115
114
  version: 1.3.1
116
115
  requirements: []
117
- rubygems_version: 3.1.4
118
- signing_key:
116
+ rubygems_version: 3.0.3
117
+ signing_key:
119
118
  specification_version: 4
120
119
  summary: CockroachDB adapter for ActiveRecord.
121
120
  test_files: []
data/CHANGELOG.md DELETED
@@ -1,25 +0,0 @@
1
- # Changelog
2
-
3
- ## 6.0.0-beta.5 - 2021-04-02
4
-
5
- - Added a configuration option named `use_follower_reads_for_type_introspection`.
6
- If true, it improves the speed of type introspection by allowing potentially stale
7
- type metadata to be read. Defaults to false.
8
-
9
- ## 6.0.0-beta.4 - 2021-03-06
10
-
11
- - Improved connection performance by refactoring an introspection
12
- that loads types.
13
- - Changed version numbers to semver.
14
-
15
- ## 6.0.0beta3
16
-
17
- - Added support for spatial features.
18
-
19
- ## 6.0.0beta2
20
-
21
- - Updated transaction retry logic to work with Rails 6.
22
-
23
- ## 6.0.0beta1
24
-
25
- - Initial support for Rails 6.
@@ -1,26 +0,0 @@
1
- module ActiveRecord
2
- module ConnectionAdapters
3
- module CockroachDB
4
- module OID
5
- module TypeMapInitializer
6
- # override
7
- # Replaces the query with a faster version that doesn't rely on the
8
- # use of 'array_in(cstring,oid,integer)'::regprocedure.
9
- def query_conditions_for_initial_load
10
- known_type_names = @store.keys.map { |n| "'#{n}'" }
11
- known_type_types = %w('r' 'e' 'd')
12
- <<~SQL % [known_type_names.join(", "), known_type_types.join(", ")]
13
- WHERE
14
- t.typname IN (%s)
15
- OR t.typtype IN (%s)
16
- OR (t.typarray = 0 AND t.typcategory='A')
17
- OR t.typelem != 0
18
- SQL
19
- end
20
- end
21
-
22
- PostgreSQL::OID::TypeMapInitializer.prepend(TypeMapInitializer)
23
- end
24
- end
25
- end
26
- end