activerecord-cockroachdb-adapter 6.1.0beta1 → 6.1.2
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 +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +12 -3
- data/activerecord-cockroachdb-adapter.gemspec +1 -1
- data/build/config.teamcity.yml +3 -0
- data/lib/active_record/connection_adapters/cockroachdb/oid/type_map_initializer.rb +26 -0
- data/lib/active_record/connection_adapters/cockroachdb_adapter.rb +129 -6
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d0c9c46ba26129c6660d4c7dcc7fab97e62e6544cf97be3de59876df04b8b49
|
4
|
+
data.tar.gz: 35952dc2b491d58a1550a8466a0010ce1530465f7e5c17d3cb1863de9d17c304
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1d62e4dc3ef136ebb472b4439f0a500cd64e4c16a1d7f6f1f75d7426ddfd85dc871eb26889b3d617dc80816c3d47533c6d46b9dce6fbc42df8049d76f680cf8
|
7
|
+
data.tar.gz: 02b1e634681a6e2d25d88d2d78dd0c658bf4125decbce637fa5fa672e3651c099106ee79de86ffa2037ceb3f6fc13e80e8e870b6154e4dbd96f5405b3829003d
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## 6.1.2 - 2021-05-20
|
4
|
+
|
5
|
+
- Fix a bug where starting the driver can result in a ConnectionNotEstablished error.
|
6
|
+
|
7
|
+
## 6.1.1 - 2021-05-14
|
8
|
+
|
9
|
+
- Fix a bug where starting the driver can result in a NoDatabaseError.
|
10
|
+
|
11
|
+
## 6.1.0 - 2021-04-26
|
12
|
+
|
13
|
+
- Add a telemetry query on start-up. This helps the Cockroach Labs team
|
14
|
+
prioritize support for the adapter. It can be disabled by setting the
|
15
|
+
`disable_cockroachdb_telemetry` configuration option to false.
|
16
|
+
|
17
|
+
## 6.1.0-beta.3 - 2021-04-02
|
18
|
+
|
19
|
+
- Added a configuration option named `use_follower_reads_for_type_introspection`.
|
20
|
+
If true, it improves the speed of type introspection by allowing potentially stale
|
21
|
+
type metadata to be read. Defaults to false.
|
22
|
+
|
23
|
+
## 6.1.0-beta.2 - 2021-03-06
|
24
|
+
|
25
|
+
- Improved connection performance by refactoring an introspection
|
26
|
+
that loads types.
|
27
|
+
- Changed version numbers to semver.
|
28
|
+
|
29
|
+
## 6.1.0beta1
|
30
|
+
|
31
|
+
- Initial support for Rails 6.1.
|
32
|
+
- Support for spatial functionality.
|
data/README.md
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
# ActiveRecord CockroachDB Adapter
|
2
2
|
|
3
|
-
CockroachDB adapter for ActiveRecord
|
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', '~>
|
10
|
+
gem 'activerecord-cockroachdb-adapter', '~> 6.1.0'
|
11
11
|
```
|
12
12
|
|
13
|
-
If you're using Rails
|
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
|
|
@@ -22,6 +24,13 @@ development:
|
|
22
24
|
user: <username>
|
23
25
|
```
|
24
26
|
|
27
|
+
## Configuration
|
28
|
+
|
29
|
+
In addition to the standard adapter settings, CockroachDB also supports the following:
|
30
|
+
|
31
|
+
- `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.
|
32
|
+
- `disable_cockroachdb_telemetry`: Determines if a telemetry call is made to the database when the connection pool is initialized. Setting this to `true` will prevent the call from being made.
|
33
|
+
|
25
34
|
## Working with Spatial Data
|
26
35
|
|
27
36
|
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).
|
@@ -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.1.
|
7
|
+
spec.version = "6.1.2"
|
8
8
|
spec.licenses = ["Apache-2.0"]
|
9
9
|
spec.authors = ["Cockroach Labs"]
|
10
10
|
spec.email = ["cockroach-db@googlegroups.com"]
|
data/build/config.teamcity.yml
CHANGED
@@ -11,6 +11,7 @@ connections:
|
|
11
11
|
user: root
|
12
12
|
requiressl: disable
|
13
13
|
min_messages: warning
|
14
|
+
disable_cockroachdb_telemetry: true
|
14
15
|
arunit_without_prepared_statements:
|
15
16
|
database: activerecord_unittest
|
16
17
|
host: localhost
|
@@ -19,6 +20,7 @@ connections:
|
|
19
20
|
requiressl: disable
|
20
21
|
min_messages: warning
|
21
22
|
prepared_statements: false
|
23
|
+
disable_cockroachdb_telemetry: true
|
22
24
|
arunit2:
|
23
25
|
database: activerecord_unittest2
|
24
26
|
host: localhost
|
@@ -26,3 +28,4 @@ connections:
|
|
26
28
|
user: root
|
27
29
|
requiressl: disable
|
28
30
|
min_messages: warning
|
31
|
+
disable_cockroachdb_telemetry: true
|
@@ -0,0 +1,26 @@
|
|
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
|
@@ -13,6 +13,7 @@ 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"
|
16
17
|
require "active_record/connection_adapters/cockroachdb/oid/spatial"
|
17
18
|
require "active_record/connection_adapters/cockroachdb/oid/interval"
|
18
19
|
require "active_record/connection_adapters/cockroachdb/arel_tosql"
|
@@ -55,6 +56,35 @@ end
|
|
55
56
|
|
56
57
|
module ActiveRecord
|
57
58
|
module ConnectionAdapters
|
59
|
+
module CockroachDBConnectionPool
|
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]
|
64
|
+
return if disable_telemetry || adapter != "cockroachdb"
|
65
|
+
|
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
|
79
|
+
end
|
80
|
+
end
|
81
|
+
rescue StandardError
|
82
|
+
# Prevent failures on db creation and parallel testing.
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
ConnectionPool.prepend(CockroachDBConnectionPool)
|
87
|
+
|
58
88
|
class CockroachDBAdapter < PostgreSQLAdapter
|
59
89
|
ADAPTER_NAME = "CockroachDB".freeze
|
60
90
|
DEFAULT_PRIMARY_KEY = "rowid"
|
@@ -73,7 +103,7 @@ module ActiveRecord
|
|
73
103
|
st_polygon: {},
|
74
104
|
}
|
75
105
|
|
76
|
-
# http://postgis.17.x6.nabble.com/Default-SRID-td5001115.html
|
106
|
+
# http://postgis.17.x6.nabble.com/Default-SRID-td5001115.html
|
77
107
|
DEFAULT_SRID = 0
|
78
108
|
|
79
109
|
include CockroachDB::SchemaStatements
|
@@ -172,6 +202,10 @@ module ActiveRecord
|
|
172
202
|
@crdb_version >= 202
|
173
203
|
end
|
174
204
|
|
205
|
+
def supports_partitioned_indexes?
|
206
|
+
false
|
207
|
+
end
|
208
|
+
|
175
209
|
# This is hardcoded to 63 (as previously was in ActiveRecord 5.0) to aid in
|
176
210
|
# migration from PostgreSQL to CockroachDB. In practice, this limitation
|
177
211
|
# is arbitrary since CockroachDB supports index name lengths and table alias
|
@@ -189,6 +223,7 @@ module ActiveRecord
|
|
189
223
|
|
190
224
|
def initialize(connection, logger, conn_params, config)
|
191
225
|
super(connection, logger, conn_params, config)
|
226
|
+
|
192
227
|
crdb_version_string = query_value("SHOW crdb_version")
|
193
228
|
if crdb_version_string.include? "v1."
|
194
229
|
version_num = 1
|
@@ -242,12 +277,9 @@ module ActiveRecord
|
|
242
277
|
precision = extract_precision(sql_type)
|
243
278
|
scale = extract_scale(sql_type)
|
244
279
|
|
245
|
-
# TODO(#178) this should never use DecimalWithoutScale since scale
|
246
|
-
# is assumed to be 0 if it is not explicitly defined.
|
247
|
-
#
|
248
280
|
# If fmod is -1, that means that precision is defined but not
|
249
281
|
# scale, or neither is defined.
|
250
|
-
if fmod && fmod == -1
|
282
|
+
if fmod && fmod == -1 && !precision.nil?
|
251
283
|
# Below comment is from ActiveRecord
|
252
284
|
# FIXME: Remove this class, and the second argument to
|
253
285
|
# lookups on PG
|
@@ -360,7 +392,7 @@ module ActiveRecord
|
|
360
392
|
# In general, it is hard to parse that, but it is easy to handle the common
|
361
393
|
# case of an empty array.
|
362
394
|
def extract_empty_array_from_default(default)
|
363
|
-
return unless supports_string_to_array_coercion?
|
395
|
+
return unless supports_string_to_array_coercion?
|
364
396
|
return unless default =~ /\AARRAY\[\]\z/
|
365
397
|
return "{}"
|
366
398
|
end
|
@@ -439,6 +471,97 @@ module ActiveRecord
|
|
439
471
|
false
|
440
472
|
end
|
441
473
|
|
474
|
+
# override
|
475
|
+
# This method loads info about data types from the database to
|
476
|
+
# populate the TypeMap.
|
477
|
+
#
|
478
|
+
# Currently, querying from the pg_type catalog can be slow due to geo-partitioning
|
479
|
+
# so this modified query uses AS OF SYSTEM TIME '-10s' to read historical data.
|
480
|
+
def load_additional_types(oids = nil)
|
481
|
+
if @config[:use_follower_reads_for_type_introspection]
|
482
|
+
initializer = OID::TypeMapInitializer.new(type_map)
|
483
|
+
|
484
|
+
query = <<~SQL
|
485
|
+
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
486
|
+
FROM pg_type as t
|
487
|
+
LEFT JOIN pg_range as r ON oid = rngtypid AS OF SYSTEM TIME '-10s'
|
488
|
+
SQL
|
489
|
+
|
490
|
+
if oids
|
491
|
+
query += "WHERE t.oid IN (%s)" % oids.join(", ")
|
492
|
+
else
|
493
|
+
query += initializer.query_conditions_for_initial_load
|
494
|
+
end
|
495
|
+
|
496
|
+
execute_and_clear(query, "SCHEMA", []) do |records|
|
497
|
+
initializer.run(records)
|
498
|
+
end
|
499
|
+
else
|
500
|
+
super
|
501
|
+
end
|
502
|
+
rescue ActiveRecord::StatementInvalid => e
|
503
|
+
raise e unless e.cause.is_a? PG::InvalidCatalogName
|
504
|
+
# use original if database is younger than 10s
|
505
|
+
super
|
506
|
+
end
|
507
|
+
|
508
|
+
# override
|
509
|
+
# This method maps data types to their proper decoder.
|
510
|
+
#
|
511
|
+
# Currently, querying from the pg_type catalog can be slow due to geo-partitioning
|
512
|
+
# so this modified query uses AS OF SYSTEM TIME '-10s' to read historical data.
|
513
|
+
def add_pg_decoders
|
514
|
+
if @config[:use_follower_reads_for_type_introspection]
|
515
|
+
@default_timezone = nil
|
516
|
+
@timestamp_decoder = nil
|
517
|
+
|
518
|
+
coders_by_name = {
|
519
|
+
"int2" => PG::TextDecoder::Integer,
|
520
|
+
"int4" => PG::TextDecoder::Integer,
|
521
|
+
"int8" => PG::TextDecoder::Integer,
|
522
|
+
"oid" => PG::TextDecoder::Integer,
|
523
|
+
"float4" => PG::TextDecoder::Float,
|
524
|
+
"float8" => PG::TextDecoder::Float,
|
525
|
+
"numeric" => PG::TextDecoder::Numeric,
|
526
|
+
"bool" => PG::TextDecoder::Boolean,
|
527
|
+
"timestamp" => PG::TextDecoder::TimestampUtc,
|
528
|
+
"timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
|
529
|
+
}
|
530
|
+
|
531
|
+
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
532
|
+
query = <<~SQL % known_coder_types.join(", ")
|
533
|
+
SELECT t.oid, t.typname
|
534
|
+
FROM pg_type as t AS OF SYSTEM TIME '-10s'
|
535
|
+
WHERE t.typname IN (%s)
|
536
|
+
SQL
|
537
|
+
|
538
|
+
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
539
|
+
result
|
540
|
+
.map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
541
|
+
.compact
|
542
|
+
end
|
543
|
+
|
544
|
+
map = PG::TypeMapByOid.new
|
545
|
+
coders.each { |coder| map.add_coder(coder) }
|
546
|
+
@connection.type_map_for_results = map
|
547
|
+
|
548
|
+
@type_map_for_results = PG::TypeMapByOid.new
|
549
|
+
@type_map_for_results.default_type_map = map
|
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"))
|
552
|
+
|
553
|
+
# extract timestamp decoder for use in update_typemap_for_default_timezone
|
554
|
+
@timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
|
555
|
+
update_typemap_for_default_timezone
|
556
|
+
else
|
557
|
+
super
|
558
|
+
end
|
559
|
+
rescue ActiveRecord::StatementInvalid => e
|
560
|
+
raise e unless e.cause.is_a? PG::InvalidCatalogName
|
561
|
+
# use original if database is younger than 10s
|
562
|
+
super
|
563
|
+
end
|
564
|
+
|
442
565
|
def arel_visitor
|
443
566
|
Arel::Visitors::CockroachDB.new(self)
|
444
567
|
end
|
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.1.
|
4
|
+
version: 6.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cockroach Labs
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -62,6 +62,7 @@ extra_rdoc_files: []
|
|
62
62
|
files:
|
63
63
|
- ".gitignore"
|
64
64
|
- ".gitmodules"
|
65
|
+
- CHANGELOG.md
|
65
66
|
- CONTRIBUTING.md
|
66
67
|
- Gemfile
|
67
68
|
- LICENSE
|
@@ -83,6 +84,7 @@ files:
|
|
83
84
|
- lib/active_record/connection_adapters/cockroachdb/database_tasks.rb
|
84
85
|
- lib/active_record/connection_adapters/cockroachdb/oid/interval.rb
|
85
86
|
- lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb
|
87
|
+
- lib/active_record/connection_adapters/cockroachdb/oid/type_map_initializer.rb
|
86
88
|
- lib/active_record/connection_adapters/cockroachdb/quoting.rb
|
87
89
|
- lib/active_record/connection_adapters/cockroachdb/referential_integrity.rb
|
88
90
|
- lib/active_record/connection_adapters/cockroachdb/schema_statements.rb
|
@@ -109,9 +111,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
111
|
version: '0'
|
110
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
113
|
requirements:
|
112
|
-
- - "
|
114
|
+
- - ">="
|
113
115
|
- !ruby/object:Gem::Version
|
114
|
-
version:
|
116
|
+
version: '0'
|
115
117
|
requirements: []
|
116
118
|
rubygems_version: 3.0.3
|
117
119
|
signing_key:
|