Class: ActiveRecord::ConnectionAdapters::CockroachDBAdapter

Inherits:
PostgreSQLAdapter
  • Object
show all
Includes:
ActiveRecord::ConnectionAdapters::CockroachDB::DatabaseStatements, ActiveRecord::ConnectionAdapters::CockroachDB::Quoting, ActiveRecord::ConnectionAdapters::CockroachDB::ReferentialIntegrity, ActiveRecord::ConnectionAdapters::CockroachDB::SchemaStatements
Defined in:
lib/active_record/connection_adapters/cockroachdb_adapter.rb

Constant Summary collapse

ADAPTER_NAME =
"CockroachDB".freeze
DEFAULT_PRIMARY_KEY =
"rowid"
SPATIAL_COLUMN_OPTIONS =
{
  geography:           { geographic: true },
  geometry:            {},
  geometry_collection: {},
  line_string:         {},
  multi_line_string:   {},
  multi_point:         {},
  multi_polygon:       {},
  spatial:             {},
  st_point:            {},
  st_polygon:          {},
}
DEFAULT_SRID =
0

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ActiveRecord::ConnectionAdapters::CockroachDB::Quoting

#quote

Methods included from ActiveRecord::ConnectionAdapters::CockroachDB::DatabaseStatements

#insert_fixtures_set, #transaction_isolation_levels

Methods included from ActiveRecord::ConnectionAdapters::CockroachDB::ReferentialIntegrity

#disable_referential_integrity

Methods included from ActiveRecord::ConnectionAdapters::CockroachDB::SchemaStatements

#add_index, #create_schema_dumper, #create_table_definition, #default_sequence_name, #foreign_keys, #native_database_types, #new_column_from_field, #primary_key, #reset_pk_sequence!, #schema_creation, #spatial_column_info, #type_to_sql

Constructor Details

#initialize(connection, logger, conn_params, config) ⇒ CockroachDBAdapter

Returns a new instance of CockroachDBAdapter.



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 239

def initialize(connection, logger, conn_params, config)
  super(connection, logger, conn_params, config)

  # crdb_version is the version of the binary running on the node. We
  # really want to use `SHOW CLUSTER SETTING version` to get the cluster
  # version, but that is only available to admins. Instead, we can use
  # crdb_internal.is_at_least_version, but that's only available in 22.1.
  crdb_version_string = query_value("SHOW crdb_version")
  if crdb_version_string.include? "v22.1"
    version_num = query_value(<<~SQL, "VERSION")
      SELECT
        CASE
        WHEN crdb_internal.is_at_least_version('22.2') THEN 2220
        WHEN crdb_internal.is_at_least_version('22.1') THEN 2210
        ELSE 2120
        END;
    SQL
  else
    # This branch can be removed once the dialect stops supporting v21.2
    # and earlier.
    if crdb_version_string.include? "v1."
      version_num = 1
    elsif crdb_version_string.include? "v2."
      version_num 2
    elsif crdb_version_string.include? "v19.1."
      version_num = 1910
    elsif crdb_version_string.include? "v19.2."
      version_num = 1920
    elsif crdb_version_string.include? "v20.1."
      version_num = 2010
    elsif crdb_version_string.include? "v20.2."
      version_num = 2020
    elsif crdb_version_string.include? "v21.1."
      version_num = 2110
    else
      version_num = 2120
    end
  end
  @crdb_version = version_num.to_i

  # NOTE: this is normally in configure_connection, but that is run
  # before crdb_version is determined. Once all supported versions
  # of CockroachDB support SET intervalstyle it can safely be moved
  # back.
  # Set interval output format to ISO 8601 for ease of parsing by ActiveSupport::Duration.parse
  if @crdb_version >= 2120
    begin
      execute("SET intervalstyle_enabled = true", "SCHEMA")
      execute("SET intervalstyle = iso_8601", "SCHEMA")
    rescue
      # Ignore any error. This can happen with a cluster that has
      # not yet finalized the v21.2 upgrade. v21.2 does not have
      # a way to tell if the upgrade was finalized (see comment above).
    end
  end
end

Class Method Details

.database_exists?(config) ⇒ Boolean

Returns:

  • (Boolean)


296
297
298
299
300
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 296

def self.database_exists?(config)
  !!ActiveRecord::Base.cockroachdb_connection(config)
rescue ActiveRecord::NoDatabaseError
  false
end

.initialize_type_map(m = type_map) ⇒ Object



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 316

def initialize_type_map(m = type_map)
  %w(
    geography
    geometry
    geometry_collection
    line_string
    multi_line_string
    multi_point
    multi_polygon
    st_point
    st_polygon
  ).each do |geo_type|
    m.register_type(geo_type) do |oid, _, sql_type|
      CockroachDB::OID::Spatial.new(oid, sql_type)
    end
  end

  # Belongs after other types are defined because of issues described
  # in this https://github.com/rails/rails/pull/38571
  # Once that PR is merged, we can call super at the top.
  super(m)

  # Override numeric type. This is almost identical to the default,
  # except that the conditional based on the fmod is changed.
  m.register_type "numeric" do |_, fmod, sql_type|
    precision = extract_precision(sql_type)
    scale = extract_scale(sql_type)


    # The type for the numeric depends on the width of the field,
    # so we'll do something special here.
    #
    # When dealing with decimal columns:
    #
    # places after decimal  = fmod - 4 & 0xffff
    # places before decimal = (fmod - 4) >> 16 & 0xffff
    #
    # For older versions of CockroachDB (<v22.1), fmod is -1 for 0 width.
    # If fmod is -1, that means that precision is defined but not
    # scale, or neither is defined.
    if fmod && ((fmod == -1 && !precision.nil?) || (fmod - 4 & 0xffff).zero?)
      # Below comment is from ActiveRecord
      # FIXME: Remove this class, and the second argument to
      # lookups on PG
      Type::DecimalWithoutScale.new(precision: precision)
    else
      ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Decimal.new(precision: precision, scale: scale)
    end
  end
end

.spatial_column_options(key) ⇒ Object



126
127
128
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 126

def self.spatial_column_options(key)
  SPATIAL_COLUMN_OPTIONS[key]
end

Instance Method Details

#create_enum(name, values) ⇒ Object

override The PostgreSQLAdapter uses syntax for an anonymous function (DO $$) that CockroachDB does not support.

Given a name and an array of values, creates an enum type.



307
308
309
310
311
312
313
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 307

def create_enum(name, values)
  sql_values = values.map { |s| "'#{s}'" }.join(", ")
  query = <<~SQL
    CREATE TYPE IF NOT EXISTS \"#{name}\" AS ENUM (#{sql_values});
  SQL
  exec_query(query)
end

#debugging?Boolean

Returns:

  • (Boolean)


147
148
149
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 147

def debugging?
  !!ENV["DEBUG_COCKROACHDB_ADAPTER"]
end

#default_sridObject



134
135
136
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 134

def default_srid
  DEFAULT_SRID
end

#max_identifier_lengthObject Also known as: index_name_length, table_alias_length

This is hardcoded to 63 (as previously was in ActiveRecord 5.0) to aid in migration from PostgreSQL to CockroachDB. In practice, this limitation is arbitrary since CockroachDB supports index name lengths and table alias lengths far greater than this value. For the time being though, we match the original behavior for PostgreSQL to simplify migrations.

Note that in the migration to ActiveRecord 5.1, this was changed in PostgreSQLAdapter to use ‘SHOW max_identifier_length` (which does not exist in CockroachDB). Therefore, we have to redefine this here.



233
234
235
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 233

def max_identifier_length
  63
end

#max_transaction_retriesObject



151
152
153
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 151

def max_transaction_retries
  @max_transaction_retries ||= @config.fetch(:max_transaction_retries, 3)
end

#postgis_lib_versionObject



130
131
132
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 130

def postgis_lib_version
  @postgis_lib_version ||= select_value("SELECT PostGIS_Lib_Version()")
end

#postgresql_versionObject

CockroachDB 20.1 can run queries that work against PostgreSQL 10+.



156
157
158
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 156

def postgresql_version
  100000
end

#srs_database_columnsObject



138
139
140
141
142
143
144
145
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 138

def srs_database_columns
  {
    auth_name_column: "auth_name",
    auth_srid_column: "auth_srid",
    proj4text_column: "proj4text",
    srtext_column:    "srtext",
  }
end

#supports_advisory_locks?Boolean

Returns:

  • (Boolean)


204
205
206
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 204

def supports_advisory_locks?
  false
end

#supports_bulk_alter?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 160

def supports_bulk_alter?
  false
end

#supports_comments?Boolean

Returns:

  • (Boolean)


196
197
198
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 196

def supports_comments?
  @crdb_version >= 2010
end

#supports_comments_in_create?Boolean

Returns:

  • (Boolean)


200
201
202
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 200

def supports_comments_in_create?
  false
end

#supports_datetime_with_precision?Boolean

Returns:

  • (Boolean)


192
193
194
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 192

def supports_datetime_with_precision?
  false
end

#supports_ddl_transactions?Boolean

Returns:

  • (Boolean)


169
170
171
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 169

def supports_ddl_transactions?
  false
end

#supports_deferrable_constraints?Boolean

Returns:

  • (Boolean)


220
221
222
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 220

def supports_deferrable_constraints?
  false
end

#supports_expression_index?Boolean

Returns:

  • (Boolean)


185
186
187
188
189
190
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 185

def supports_expression_index?
  # Expression indexes are partially supported by CockroachDB v21.2,
  # but activerecord requires "ON CONFLICT expression" support.
  # See https://github.com/cockroachdb/cockroach/issues/67893
  false
end

#supports_extensions?Boolean

Returns:

  • (Boolean)


173
174
175
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 173

def supports_extensions?
  false
end

#supports_json?Boolean

Returns:

  • (Boolean)


164
165
166
167
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 164

def supports_json?
  # FIXME(joey): Add a version check.
  true
end

#supports_materialized_views?Boolean

Returns:

  • (Boolean)


177
178
179
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 177

def supports_materialized_views?
  false
end

#supports_partial_index?Boolean

Returns:

  • (Boolean)


181
182
183
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 181

def supports_partial_index?
  @crdb_version >= 2020
end

#supports_partitioned_indexes?Boolean

Returns:

  • (Boolean)


216
217
218
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 216

def supports_partitioned_indexes?
  false
end

#supports_string_to_array_coercion?Boolean

Returns:

  • (Boolean)


212
213
214
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 212

def supports_string_to_array_coercion?
  @crdb_version >= 2020
end

#supports_virtual_columns?Boolean

Returns:

  • (Boolean)


208
209
210
# File 'lib/active_record/connection_adapters/cockroachdb_adapter.rb', line 208

def supports_virtual_columns?
  @crdb_version >= 2110
end