activerecord-cockroachdb-adapter 6.0.0beta3 → 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 +4 -4
- data/CONTRIBUTING.md +20 -0
- data/Rakefile +20 -0
- data/activerecord-cockroachdb-adapter.gemspec +3 -3
- data/lib/active_record/connection_adapters/cockroachdb/oid/interval.rb +126 -0
- data/lib/active_record/connection_adapters/cockroachdb/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/cockroachdb/transaction_manager.rb +1 -1
- data/lib/active_record/connection_adapters/cockroachdb/type.rb +1 -3
- data/lib/active_record/connection_adapters/cockroachdb_adapter.rb +115 -70
- metadata +9 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5d0954fd425d90342f04c1b6559b78e398be9e523e67779476d81f925a1aa611
|
|
4
|
+
data.tar.gz: 1f990c34784394bafa77933eb0d49965a0eac81151f2468c92a66c1bc9beb78a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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/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.
|
|
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.
|
|
17
|
-
spec.add_dependency "pg", "
|
|
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
|
|
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
|
|
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"
|
|
@@ -14,6 +14,7 @@ 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
16
|
require "active_record/connection_adapters/cockroachdb/oid/spatial"
|
|
17
|
+
require "active_record/connection_adapters/cockroachdb/oid/interval"
|
|
17
18
|
require "active_record/connection_adapters/cockroachdb/arel_tosql"
|
|
18
19
|
|
|
19
20
|
# Run to ignore spatial tables that will break schemna dumper.
|
|
@@ -24,25 +25,29 @@ module ActiveRecord
|
|
|
24
25
|
module ConnectionHandling
|
|
25
26
|
def cockroachdb_connection(config)
|
|
26
27
|
# This is copied from the PostgreSQL adapter.
|
|
27
|
-
conn_params = config.symbolize_keys
|
|
28
|
-
|
|
29
|
-
conn_params.delete_if { |_, v| v.nil? }
|
|
28
|
+
conn_params = config.symbolize_keys.compact
|
|
30
29
|
|
|
31
30
|
# Map ActiveRecords param names to PGs.
|
|
32
31
|
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
|
|
33
32
|
conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
|
|
34
33
|
|
|
35
34
|
# Forward only valid config params to PG::Connection.connect.
|
|
36
|
-
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:
|
|
35
|
+
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
|
37
36
|
conn_params.slice!(*valid_conn_param_keys)
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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])
|
|
43
48
|
raise ActiveRecord::NoDatabaseError
|
|
44
49
|
else
|
|
45
|
-
raise
|
|
50
|
+
raise ActiveRecord::ConnectionNotEstablished, error.message
|
|
46
51
|
end
|
|
47
52
|
end
|
|
48
53
|
end
|
|
@@ -76,56 +81,6 @@ module ActiveRecord
|
|
|
76
81
|
include CockroachDB::DatabaseStatements
|
|
77
82
|
include CockroachDB::Quoting
|
|
78
83
|
|
|
79
|
-
# override
|
|
80
|
-
# This method makes a sql query to gather information about columns
|
|
81
|
-
# in a table. It returns an array of arrays (one for each col) and
|
|
82
|
-
# passes each to the SchemaStatements#new_column_from_field method
|
|
83
|
-
# as the field parameter. This data is then used to format the column
|
|
84
|
-
# objects for the model and sent to the OID for data casting.
|
|
85
|
-
#
|
|
86
|
-
# The issue with the default method is that the sql_type field is
|
|
87
|
-
# retrieved with the `format_type` function, but this is implemented
|
|
88
|
-
# differently in CockroachDB than PostGIS, so geometry/geography
|
|
89
|
-
# types are missing information which makes parsing them impossible.
|
|
90
|
-
# Below is an example of what `format_type` returns for a geometry
|
|
91
|
-
# column.
|
|
92
|
-
#
|
|
93
|
-
# column_type: geometry(POINT, 4326)
|
|
94
|
-
# Expected: geometry(POINT, 4326)
|
|
95
|
-
# Actual: geometry
|
|
96
|
-
#
|
|
97
|
-
# The solution is to make the default query with super, then
|
|
98
|
-
# iterate through the columns and if it is a spatial type,
|
|
99
|
-
# access the proper column_type with the information_schema.columns
|
|
100
|
-
# table.
|
|
101
|
-
#
|
|
102
|
-
# @see: https://github.com/rails/rails/blob/8695b028261bdd244e254993255c6641bdbc17a5/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L829
|
|
103
|
-
def column_definitions(table_name)
|
|
104
|
-
fields = super
|
|
105
|
-
# iterate through and identify all spatial fields based on format_type
|
|
106
|
-
# being geometry or geography, then query for the information_schema.column
|
|
107
|
-
# column_type because that contains the necessary information.
|
|
108
|
-
fields.map do |field|
|
|
109
|
-
dtype = field[1]
|
|
110
|
-
if dtype == 'geometry' || dtype == 'geography'
|
|
111
|
-
col_name = field[0]
|
|
112
|
-
data_type = \
|
|
113
|
-
query(<<~SQL, "SCHEMA")
|
|
114
|
-
SELECT c.data_type
|
|
115
|
-
FROM information_schema.columns c
|
|
116
|
-
WHERE c.table_name = #{quote(table_name)}
|
|
117
|
-
AND c.column_name = #{quote(col_name)}
|
|
118
|
-
SQL
|
|
119
|
-
field[1] = data_type[0][0]
|
|
120
|
-
end
|
|
121
|
-
field
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def arel_visitor
|
|
126
|
-
Arel::Visitors::CockroachDB.new(self)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
84
|
def self.spatial_column_options(key)
|
|
130
85
|
SPATIAL_COLUMN_OPTIONS[key]
|
|
131
86
|
end
|
|
@@ -276,19 +231,31 @@ module ActiveRecord
|
|
|
276
231
|
end
|
|
277
232
|
end
|
|
278
233
|
|
|
279
|
-
#
|
|
280
|
-
#
|
|
281
|
-
#
|
|
282
|
-
|
|
283
|
-
|
|
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|
|
|
284
242
|
precision = extract_precision(sql_type)
|
|
285
|
-
|
|
286
|
-
|
|
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)
|
|
287
257
|
end
|
|
288
|
-
OID::SpecializedString.new(:interval, precision: precision)
|
|
289
258
|
end
|
|
290
|
-
|
|
291
|
-
super(m)
|
|
292
259
|
end
|
|
293
260
|
|
|
294
261
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
|
@@ -398,6 +365,84 @@ module ActiveRecord
|
|
|
398
365
|
return "{}"
|
|
399
366
|
end
|
|
400
367
|
|
|
368
|
+
# override
|
|
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.
|
|
378
|
+
#
|
|
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)
|
|
396
|
+
else
|
|
397
|
+
field
|
|
398
|
+
end
|
|
399
|
+
end
|
|
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
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# override
|
|
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.
|
|
424
|
+
#
|
|
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
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def arel_visitor
|
|
443
|
+
Arel::Visitors::CockroachDB.new(self)
|
|
444
|
+
end
|
|
445
|
+
|
|
401
446
|
# end private
|
|
402
447
|
end
|
|
403
448
|
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.
|
|
4
|
+
version: 6.1.0beta1
|
|
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-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.
|
|
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.
|
|
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: '
|
|
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: '
|
|
40
|
+
version: '1.2'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rgeo-activerecord
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -81,6 +81,7 @@ files:
|
|
|
81
81
|
- lib/active_record/connection_adapters/cockroachdb/column_methods.rb
|
|
82
82
|
- lib/active_record/connection_adapters/cockroachdb/database_statements.rb
|
|
83
83
|
- lib/active_record/connection_adapters/cockroachdb/database_tasks.rb
|
|
84
|
+
- lib/active_record/connection_adapters/cockroachdb/oid/interval.rb
|
|
84
85
|
- lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb
|
|
85
86
|
- lib/active_record/connection_adapters/cockroachdb/quoting.rb
|
|
86
87
|
- lib/active_record/connection_adapters/cockroachdb/referential_integrity.rb
|