activerecord-cockroachdb-adapter 6.0.0beta2 → 6.1.0.pre.beta.3
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 +18 -0
- data/CONTRIBUTING.md +20 -0
- data/README.md +297 -0
- data/Rakefile +20 -0
- data/activerecord-cockroachdb-adapter.gemspec +4 -3
- data/build/teamcity-test.sh +1 -1
- data/lib/active_record/connection_adapters/cockroachdb/arel_tosql.rb +27 -0
- data/lib/active_record/connection_adapters/cockroachdb/column.rb +78 -1
- data/lib/active_record/connection_adapters/cockroachdb/column_methods.rb +53 -0
- data/lib/active_record/connection_adapters/cockroachdb/oid/interval.rb +126 -0
- data/lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb +121 -0
- data/lib/active_record/connection_adapters/cockroachdb/oid/type_map_initializer.rb +26 -0
- data/lib/active_record/connection_adapters/cockroachdb/quoting.rb +10 -2
- data/lib/active_record/connection_adapters/cockroachdb/schema_statements.rb +66 -1
- data/lib/active_record/connection_adapters/cockroachdb/setup.rb +19 -0
- data/lib/active_record/connection_adapters/cockroachdb/spatial_column_info.rb +44 -0
- data/lib/active_record/connection_adapters/cockroachdb/table_definition.rb +56 -0
- 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 +277 -19
- metadata +31 -8
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord # :nodoc:
|
4
|
+
module ConnectionAdapters # :nodoc:
|
5
|
+
module CockroachDB # :nodoc:
|
6
|
+
def self.initial_setup
|
7
|
+
::ActiveRecord::SchemaDumper.ignore_tables |= %w[
|
8
|
+
geography_columns
|
9
|
+
geometry_columns
|
10
|
+
layer
|
11
|
+
raster_columns
|
12
|
+
raster_overviews
|
13
|
+
spatial_ref_sys
|
14
|
+
topology
|
15
|
+
]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module CockroachDB
|
4
|
+
class SpatialColumnInfo
|
5
|
+
def initialize(adapter, table_name)
|
6
|
+
@adapter = adapter
|
7
|
+
@table_name = table_name
|
8
|
+
end
|
9
|
+
|
10
|
+
def all
|
11
|
+
info = @adapter.query(
|
12
|
+
"SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='#{@table_name}'"
|
13
|
+
)
|
14
|
+
result = {}
|
15
|
+
info.each do |row|
|
16
|
+
name = row[0]
|
17
|
+
type = row[3]
|
18
|
+
dimension = row[1].to_i
|
19
|
+
has_m = !!(type =~ /m$/i)
|
20
|
+
type.sub!(/m$/, '')
|
21
|
+
has_z = dimension > 3 || dimension == 3 && !has_m
|
22
|
+
result[name] = {
|
23
|
+
dimension: dimension,
|
24
|
+
has_m: has_m,
|
25
|
+
has_z: has_z,
|
26
|
+
name: name,
|
27
|
+
srid: row[2].to_i,
|
28
|
+
type: type
|
29
|
+
}
|
30
|
+
end
|
31
|
+
result
|
32
|
+
end
|
33
|
+
|
34
|
+
# do not query the database for non-spatial columns/tables
|
35
|
+
def get(column_name, type)
|
36
|
+
return unless CockroachDBAdapter.spatial_column_options(type.to_sym)
|
37
|
+
|
38
|
+
@spatial_column_info ||= all
|
39
|
+
@spatial_column_info[column_name]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord # :nodoc:
|
4
|
+
module ConnectionAdapters # :nodoc:
|
5
|
+
module CockroachDB # :nodoc:
|
6
|
+
class TableDefinition < PostgreSQL::TableDefinition # :nodoc:
|
7
|
+
include ColumnMethods
|
8
|
+
|
9
|
+
# Support for spatial columns in tables
|
10
|
+
# super: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
|
11
|
+
def new_column_definition(name, type, **options)
|
12
|
+
if (info = CockroachDBAdapter.spatial_column_options(type.to_sym))
|
13
|
+
if (limit = options.delete(:limit)) && limit.is_a?(::Hash)
|
14
|
+
options.merge!(limit)
|
15
|
+
end
|
16
|
+
|
17
|
+
geo_type = ColumnDefinitionUtils.geo_type(options[:type] || type || info[:type])
|
18
|
+
base_type = info[:type] || (options[:geographic] ? :geography : :geometry)
|
19
|
+
|
20
|
+
options[:limit] = ColumnDefinitionUtils.limit_from_options(geo_type, options)
|
21
|
+
options[:spatial_type] = geo_type
|
22
|
+
column = super(name, base_type, **options)
|
23
|
+
else
|
24
|
+
column = super(name, type, **options)
|
25
|
+
end
|
26
|
+
|
27
|
+
column
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module ColumnDefinitionUtils
|
32
|
+
class << self
|
33
|
+
def geo_type(type = 'GEOMETRY')
|
34
|
+
g_type = type.to_s.delete('_').upcase
|
35
|
+
return 'POINT' if g_type == 'STPOINT'
|
36
|
+
return 'POLYGON' if g_type == 'STPOLYGON'
|
37
|
+
|
38
|
+
g_type
|
39
|
+
end
|
40
|
+
|
41
|
+
def limit_from_options(type, options = {})
|
42
|
+
spatial_type = geo_type(type)
|
43
|
+
spatial_type << 'Z' if options[:has_z]
|
44
|
+
spatial_type << 'M' if options[:has_m]
|
45
|
+
spatial_type << ",#{options[:srid] || default_srid(options)}"
|
46
|
+
spatial_type
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_srid(options)
|
50
|
+
options[:geographic] ? 4326 : CockroachDBAdapter::DEFAULT_SRID
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -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,36 +1,54 @@
|
|
1
|
-
require
|
1
|
+
require "rgeo/active_record"
|
2
|
+
|
3
|
+
require "active_record/connection_adapters/postgresql_adapter"
|
4
|
+
require "active_record/connection_adapters/cockroachdb/column_methods"
|
2
5
|
require "active_record/connection_adapters/cockroachdb/schema_statements"
|
3
6
|
require "active_record/connection_adapters/cockroachdb/referential_integrity"
|
4
7
|
require "active_record/connection_adapters/cockroachdb/transaction_manager"
|
5
|
-
require "active_record/connection_adapters/cockroachdb/column"
|
6
8
|
require "active_record/connection_adapters/cockroachdb/database_statements"
|
9
|
+
require "active_record/connection_adapters/cockroachdb/table_definition"
|
7
10
|
require "active_record/connection_adapters/cockroachdb/quoting"
|
8
11
|
require "active_record/connection_adapters/cockroachdb/type"
|
9
12
|
require "active_record/connection_adapters/cockroachdb/attribute_methods"
|
13
|
+
require "active_record/connection_adapters/cockroachdb/column"
|
14
|
+
require "active_record/connection_adapters/cockroachdb/spatial_column_info"
|
15
|
+
require "active_record/connection_adapters/cockroachdb/setup"
|
16
|
+
require "active_record/connection_adapters/cockroachdb/oid/type_map_initializer"
|
17
|
+
require "active_record/connection_adapters/cockroachdb/oid/spatial"
|
18
|
+
require "active_record/connection_adapters/cockroachdb/oid/interval"
|
19
|
+
require "active_record/connection_adapters/cockroachdb/arel_tosql"
|
20
|
+
|
21
|
+
# Run to ignore spatial tables that will break schemna dumper.
|
22
|
+
# Defined in ./setup.rb
|
23
|
+
ActiveRecord::ConnectionAdapters::CockroachDB.initial_setup
|
10
24
|
|
11
25
|
module ActiveRecord
|
12
26
|
module ConnectionHandling
|
13
27
|
def cockroachdb_connection(config)
|
14
28
|
# This is copied from the PostgreSQL adapter.
|
15
|
-
conn_params = config.symbolize_keys
|
16
|
-
|
17
|
-
conn_params.delete_if { |_, v| v.nil? }
|
29
|
+
conn_params = config.symbolize_keys.compact
|
18
30
|
|
19
31
|
# Map ActiveRecords param names to PGs.
|
20
32
|
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
|
21
33
|
conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
|
22
34
|
|
23
35
|
# Forward only valid config params to PG::Connection.connect.
|
24
|
-
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:
|
36
|
+
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
25
37
|
conn_params.slice!(*valid_conn_param_keys)
|
26
38
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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])
|
31
49
|
raise ActiveRecord::NoDatabaseError
|
32
50
|
else
|
33
|
-
raise
|
51
|
+
raise ActiveRecord::ConnectionNotEstablished, error.message
|
34
52
|
end
|
35
53
|
end
|
36
54
|
end
|
@@ -42,11 +60,49 @@ module ActiveRecord
|
|
42
60
|
ADAPTER_NAME = "CockroachDB".freeze
|
43
61
|
DEFAULT_PRIMARY_KEY = "rowid"
|
44
62
|
|
63
|
+
SPATIAL_COLUMN_OPTIONS =
|
64
|
+
{
|
65
|
+
geography: { geographic: true },
|
66
|
+
geometry: {},
|
67
|
+
geometry_collection: {},
|
68
|
+
line_string: {},
|
69
|
+
multi_line_string: {},
|
70
|
+
multi_point: {},
|
71
|
+
multi_polygon: {},
|
72
|
+
spatial: {},
|
73
|
+
st_point: {},
|
74
|
+
st_polygon: {},
|
75
|
+
}
|
76
|
+
|
77
|
+
# http://postgis.17.x6.nabble.com/Default-SRID-td5001115.html
|
78
|
+
DEFAULT_SRID = 0
|
79
|
+
|
45
80
|
include CockroachDB::SchemaStatements
|
46
81
|
include CockroachDB::ReferentialIntegrity
|
47
82
|
include CockroachDB::DatabaseStatements
|
48
83
|
include CockroachDB::Quoting
|
49
84
|
|
85
|
+
def self.spatial_column_options(key)
|
86
|
+
SPATIAL_COLUMN_OPTIONS[key]
|
87
|
+
end
|
88
|
+
|
89
|
+
def postgis_lib_version
|
90
|
+
@postgis_lib_version ||= select_value("SELECT PostGIS_Lib_Version()")
|
91
|
+
end
|
92
|
+
|
93
|
+
def default_srid
|
94
|
+
DEFAULT_SRID
|
95
|
+
end
|
96
|
+
|
97
|
+
def srs_database_columns
|
98
|
+
{
|
99
|
+
auth_name_column: "auth_name",
|
100
|
+
auth_srid_column: "auth_srid",
|
101
|
+
proj4text_column: "proj4text",
|
102
|
+
srtext_column: "srtext",
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
50
106
|
def debugging?
|
51
107
|
!!ENV["DEBUG_COCKROACHDB_ADAPTER"]
|
52
108
|
end
|
@@ -117,6 +173,10 @@ module ActiveRecord
|
|
117
173
|
@crdb_version >= 202
|
118
174
|
end
|
119
175
|
|
176
|
+
def supports_partitioned_indexes?
|
177
|
+
false
|
178
|
+
end
|
179
|
+
|
120
180
|
# This is hardcoded to 63 (as previously was in ActiveRecord 5.0) to aid in
|
121
181
|
# migration from PostgreSQL to CockroachDB. In practice, this limitation
|
122
182
|
# is arbitrary since CockroachDB supports index name lengths and table alias
|
@@ -160,17 +220,46 @@ module ActiveRecord
|
|
160
220
|
private
|
161
221
|
|
162
222
|
def initialize_type_map(m = type_map)
|
223
|
+
%w(
|
224
|
+
geography
|
225
|
+
geometry
|
226
|
+
geometry_collection
|
227
|
+
line_string
|
228
|
+
multi_line_string
|
229
|
+
multi_point
|
230
|
+
multi_polygon
|
231
|
+
st_point
|
232
|
+
st_polygon
|
233
|
+
).each do |geo_type|
|
234
|
+
m.register_type(geo_type) do |oid, _, sql_type|
|
235
|
+
CockroachDB::OID::Spatial.new(oid, sql_type)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Belongs after other types are defined because of issues described
|
240
|
+
# in this https://github.com/rails/rails/pull/38571
|
241
|
+
# Once that PR is merged, we can call super at the top.
|
163
242
|
super(m)
|
164
|
-
|
165
|
-
#
|
166
|
-
#
|
167
|
-
|
168
|
-
m.register_type "interval" do |_, _, sql_type|
|
243
|
+
|
244
|
+
# Override numeric type. This is almost identical to the default,
|
245
|
+
# except that the conditional based on the fmod is changed.
|
246
|
+
m.register_type "numeric" do |_, fmod, sql_type|
|
169
247
|
precision = extract_precision(sql_type)
|
170
|
-
|
171
|
-
|
248
|
+
scale = extract_scale(sql_type)
|
249
|
+
|
250
|
+
# TODO(#178) this should never use DecimalWithoutScale since scale
|
251
|
+
# is assumed to be 0 if it is not explicitly defined.
|
252
|
+
#
|
253
|
+
# If fmod is -1, that means that precision is defined but not
|
254
|
+
# scale, or neither is defined.
|
255
|
+
if fmod && fmod == -1
|
256
|
+
# Below comment is from ActiveRecord
|
257
|
+
# FIXME: Remove this class, and the second argument to
|
258
|
+
# lookups on PG
|
259
|
+
Type::DecimalWithoutScale.new(precision: precision)
|
260
|
+
else
|
261
|
+
OID::Decimal.new(precision: precision, scale: scale)
|
172
262
|
end
|
173
|
-
OID::SpecializedString.new(:interval, precision: precision)
|
174
263
|
end
|
175
264
|
end
|
176
265
|
|
@@ -281,6 +370,175 @@ module ActiveRecord
|
|
281
370
|
return "{}"
|
282
371
|
end
|
283
372
|
|
373
|
+
# override
|
374
|
+
# This method makes a query to gather information about columns
|
375
|
+
# in a table. It returns an array of arrays (one for each col) and
|
376
|
+
# passes each to the SchemaStatements#new_column_from_field method
|
377
|
+
# as the field parameter. This data is then used to format the column
|
378
|
+
# objects for the model and sent to the OID for data casting.
|
379
|
+
#
|
380
|
+
# Sometimes there are differences between how data is formatted
|
381
|
+
# in Postgres and CockroachDB, so additional queries for certain types
|
382
|
+
# may be necessary to properly form the column definition.
|
383
|
+
#
|
384
|
+
# @see: https://github.com/rails/rails/blob/8695b028261bdd244e254993255c6641bdbc17a5/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L829
|
385
|
+
def column_definitions(table_name)
|
386
|
+
fields = super
|
387
|
+
|
388
|
+
# Use regex comparison because if a type is an array it will
|
389
|
+
# have [] appended to the end of it.
|
390
|
+
target_types = [
|
391
|
+
/geometry/,
|
392
|
+
/geography/,
|
393
|
+
/interval/,
|
394
|
+
/numeric/
|
395
|
+
]
|
396
|
+
re = Regexp.union(target_types)
|
397
|
+
fields.map do |field|
|
398
|
+
dtype = field[1]
|
399
|
+
if re.match(dtype)
|
400
|
+
crdb_column_definition(field, table_name)
|
401
|
+
else
|
402
|
+
field
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
# Use the crdb_sql_type instead of the sql_type returned by
|
408
|
+
# column_definitions. This will include limit,
|
409
|
+
# precision, and scale information in the type.
|
410
|
+
# Ex. geometry -> geometry(point, 4326)
|
411
|
+
def crdb_column_definition(field, table_name)
|
412
|
+
col_name = field[0]
|
413
|
+
data_type = \
|
414
|
+
query(<<~SQL, "SCHEMA")
|
415
|
+
SELECT c.crdb_sql_type
|
416
|
+
FROM information_schema.columns c
|
417
|
+
WHERE c.table_name = #{quote(table_name)}
|
418
|
+
AND c.column_name = #{quote(col_name)}
|
419
|
+
SQL
|
420
|
+
field[1] = data_type[0][0].downcase
|
421
|
+
field
|
422
|
+
end
|
423
|
+
|
424
|
+
# override
|
425
|
+
# This method is used to determine if a
|
426
|
+
# FEATURE_NOT_SUPPORTED error from the PG gem should
|
427
|
+
# be an ActiveRecord::PreparedStatementCacheExpired
|
428
|
+
# error.
|
429
|
+
#
|
430
|
+
# ActiveRecord handles this by checking that the sql state matches the
|
431
|
+
# FEATURE_NOT_SUPPORTED code and that the source function
|
432
|
+
# is "RevalidateCachedQuery" since that is the only function
|
433
|
+
# in postgres that will create this error.
|
434
|
+
#
|
435
|
+
# That method will not work for CockroachDB because the error
|
436
|
+
# originates from the "runExecBuilder" function, so we need
|
437
|
+
# to modify the original to match the CockroachDB behavior.
|
438
|
+
def is_cached_plan_failure?(e)
|
439
|
+
pgerror = e.cause
|
440
|
+
|
441
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE) == FEATURE_NOT_SUPPORTED &&
|
442
|
+
pgerror.result.result_error_field(PG::PG_DIAG_SOURCE_FUNCTION) == "runExecBuilder"
|
443
|
+
rescue
|
444
|
+
false
|
445
|
+
end
|
446
|
+
|
447
|
+
# override
|
448
|
+
# This method loads info about data types from the database to
|
449
|
+
# populate the TypeMap.
|
450
|
+
#
|
451
|
+
# Currently, querying from the pg_type catalog can be slow due to geo-partitioning
|
452
|
+
# so this modified query uses AS OF SYSTEM TIME '-10s' to read historical data.
|
453
|
+
def load_additional_types(oids = nil)
|
454
|
+
if @config[:use_follower_reads_for_type_introspection]
|
455
|
+
initializer = OID::TypeMapInitializer.new(type_map)
|
456
|
+
|
457
|
+
query = <<~SQL
|
458
|
+
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
459
|
+
FROM pg_type as t
|
460
|
+
LEFT JOIN pg_range as r ON oid = rngtypid AS OF SYSTEM TIME '-10s'
|
461
|
+
SQL
|
462
|
+
|
463
|
+
if oids
|
464
|
+
query += "WHERE t.oid IN (%s)" % oids.join(", ")
|
465
|
+
else
|
466
|
+
query += initializer.query_conditions_for_initial_load
|
467
|
+
end
|
468
|
+
|
469
|
+
execute_and_clear(query, "SCHEMA", []) do |records|
|
470
|
+
initializer.run(records)
|
471
|
+
end
|
472
|
+
else
|
473
|
+
super
|
474
|
+
end
|
475
|
+
rescue ActiveRecord::StatementInvalid => e
|
476
|
+
raise e unless e.cause.is_a? PG::InvalidCatalogName
|
477
|
+
# use original if database is younger than 10s
|
478
|
+
super
|
479
|
+
end
|
480
|
+
|
481
|
+
# override
|
482
|
+
# This method maps data types to their proper decoder.
|
483
|
+
#
|
484
|
+
# Currently, querying from the pg_type catalog can be slow due to geo-partitioning
|
485
|
+
# so this modified query uses AS OF SYSTEM TIME '-10s' to read historical data.
|
486
|
+
def add_pg_decoders
|
487
|
+
if @config[:use_follower_reads_for_type_introspection]
|
488
|
+
@default_timezone = nil
|
489
|
+
@timestamp_decoder = nil
|
490
|
+
|
491
|
+
coders_by_name = {
|
492
|
+
"int2" => PG::TextDecoder::Integer,
|
493
|
+
"int4" => PG::TextDecoder::Integer,
|
494
|
+
"int8" => PG::TextDecoder::Integer,
|
495
|
+
"oid" => PG::TextDecoder::Integer,
|
496
|
+
"float4" => PG::TextDecoder::Float,
|
497
|
+
"float8" => PG::TextDecoder::Float,
|
498
|
+
"numeric" => PG::TextDecoder::Numeric,
|
499
|
+
"bool" => PG::TextDecoder::Boolean,
|
500
|
+
"timestamp" => PG::TextDecoder::TimestampUtc,
|
501
|
+
"timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
|
502
|
+
}
|
503
|
+
|
504
|
+
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
505
|
+
query = <<~SQL % known_coder_types.join(", ")
|
506
|
+
SELECT t.oid, t.typname
|
507
|
+
FROM pg_type as t AS OF SYSTEM TIME '-10s'
|
508
|
+
WHERE t.typname IN (%s)
|
509
|
+
SQL
|
510
|
+
|
511
|
+
coders = execute_and_clear(query, "SCHEMA", []) do |result|
|
512
|
+
result
|
513
|
+
.map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
|
514
|
+
.compact
|
515
|
+
end
|
516
|
+
|
517
|
+
map = PG::TypeMapByOid.new
|
518
|
+
coders.each { |coder| map.add_coder(coder) }
|
519
|
+
@connection.type_map_for_results = map
|
520
|
+
|
521
|
+
@type_map_for_results = PG::TypeMapByOid.new
|
522
|
+
@type_map_for_results.default_type_map = map
|
523
|
+
@type_map_for_results.add_coder(PG::TextDecoder::Bytea.new(oid: 17, name: "bytea"))
|
524
|
+
@type_map_for_results.add_coder(MoneyDecoder.new(oid: 790, name: "money"))
|
525
|
+
|
526
|
+
# extract timestamp decoder for use in update_typemap_for_default_timezone
|
527
|
+
@timestamp_decoder = coders.find { |coder| coder.name == "timestamp" }
|
528
|
+
update_typemap_for_default_timezone
|
529
|
+
else
|
530
|
+
super
|
531
|
+
end
|
532
|
+
rescue ActiveRecord::StatementInvalid => e
|
533
|
+
raise e unless e.cause.is_a? PG::InvalidCatalogName
|
534
|
+
# use original if database is younger than 10s
|
535
|
+
super
|
536
|
+
end
|
537
|
+
|
538
|
+
def arel_visitor
|
539
|
+
Arel::Visitors::CockroachDB.new(self)
|
540
|
+
end
|
541
|
+
|
284
542
|
# end private
|
285
543
|
end
|
286
544
|
end
|