Module: ActiveRecord::ConnectionAdapters::CockroachDB::SchemaStatements

Includes:
PostgreSQL::SchemaStatements
Included in:
ActiveRecord::ConnectionAdapters::CockroachDBAdapter
Defined in:
lib/active_record/connection_adapters/cockroachdb/schema_statements.rb

Instance Method Summary collapse

Instance Method Details

#add_index(table_name, column_name, options = {}) ⇒ Object



7
8
9
10
11
12
13
14
15
# File 'lib/active_record/connection_adapters/cockroachdb/schema_statements.rb', line 7

def add_index(table_name, column_name, options = {})
  super
rescue ActiveRecord::StatementInvalid => error
  if debugging? && error.cause.class == PG::FeatureNotSupported
    warn "#{error}\n\nThis error will be ignored and the index will not be created.\n\n"
  else
    raise error
  end
end

#create_table_definition(*args, **kwargs) ⇒ Object

override



145
146
147
# File 'lib/active_record/connection_adapters/cockroachdb/schema_statements.rb', line 145

def create_table_definition(*args, **kwargs)
  CockroachDB::TableDefinition.new(self, *args, **kwargs)
end

#default_sequence_name(table_name, pk = "id") ⇒ Object

CockroachDB uses unique_rowid() for primary keys, not sequences. It’s possible to force a table to use sequences, but since it’s not the default behavior we’ll always return nil for default_sequence_name.



38
39
40
# File 'lib/active_record/connection_adapters/cockroachdb/schema_statements.rb', line 38

def default_sequence_name(table_name, pk = "id")
  nil
end

#native_database_typesObject

override



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/active_record/connection_adapters/cockroachdb/schema_statements.rb', line 128

def native_database_types
  # Add spatial types
  super.merge(
    geography:           { name: "geography" },
    geometry:            { name: "geometry" },
    geometry_collection: { name: "geometry_collection" },
    line_string:         { name: "line_string" },
    multi_line_string:   { name: "multi_line_string" },
    multi_point:         { name: "multi_point" },
    multi_polygon:       { name: "multi_polygon" },
    spatial:             { name: "geometry" },
    st_point:            { name: "st_point" },
    st_polygon:          { name: "st_polygon" }
  )
end

#new_column_from_field(table_name, field) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/active_record/connection_adapters/cockroachdb/schema_statements.rb', line 44

def new_column_from_field(table_name, field)
  column_name, type, default, notnull, oid, fmod, collation, comment = field
   = (column_name, type, oid.to_i, fmod.to_i)
  default_value = extract_value_from_default(default)
  default_function = extract_default_function(default_value, default)

  serial =
    if (match = default_function&.match(/\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z/))
      sequence_name_from_parts(table_name, column_name, match[:suffix]) == match[:sequence_name]
    end

  # {:dimension=>2, :has_m=>false, :has_z=>false, :name=>"latlon", :srid=>0, :type=>"GEOMETRY"}
  spatial = spatial_column_info(table_name).get(column_name, .sql_type)

  PostgreSQL::Column.new(
    column_name,
    default_value,
    ,
    !notnull,
    default_function,
    collation: collation,
    comment: comment.presence,
    serial: serial,
    spatial: spatial
  )
end

#primary_key(table_name) ⇒ Object

ActiveRecord allows for tables to exist without primary keys. Databases like PostgreSQL support this behavior, but CockroachDB does not. If a table is created without a primary key, CockroachDB will add a rowid column to serve as its primary key. This breaks a lot of ActiveRecord’s assumptions so we’ll treat tables with rowid primary keys as if they didn’t have primary keys at all. www.cockroachlabs.com/docs/v19.2/create-table.html#create-a-table api.rubyonrails.org/v5.2.4/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_table



25
26
27
28
29
30
31
32
33
# File 'lib/active_record/connection_adapters/cockroachdb/schema_statements.rb', line 25

def primary_key(table_name)
  pk = super

  if pk == CockroachDBAdapter::DEFAULT_PRIMARY_KEY
    nil
  else
    pk
  end
end

#reset_pk_sequence!(table, pk = nil, sequence = nil) ⇒ Object

This overrides the method from PostegreSQL adapter Resets the sequence of a table’s primary key to the maximum value.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/active_record/connection_adapters/cockroachdb/schema_statements.rb', line 104

def reset_pk_sequence!(table, pk = nil, sequence = nil)
  unless pk && sequence
    default_pk, default_sequence = pk_and_sequence_for(table)

    pk ||= default_pk
    sequence ||= default_sequence
  end

  if @logger && pk && !sequence
    @logger.warn "#{table} has primary key #{pk} with no default sequence."
  end

  if pk && sequence
    quoted_sequence = quote_table_name(sequence)
    max_pk = query_value("SELECT MAX(#{quote_column_name pk}) FROM #{quote_table_name(table)}", "SCHEMA")
    if max_pk.nil?
      minvalue = query_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass", "SCHEMA")
    end

    query_value("SELECT setval(#{quote(quoted_sequence)}, #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})", "SCHEMA")
  end
end

#spatial_column_info(table_name) ⇒ Object

memoize hash of column infos for tables



150
151
152
153
# File 'lib/active_record/connection_adapters/cockroachdb/schema_statements.rb', line 150

def spatial_column_info(table_name)
  @spatial_column_info ||= {}
  @spatial_column_info[table_name.to_sym] ||= SpatialColumnInfo.new(self, table_name.to_s)
end

#type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil) ⇒ Object

CockroachDB will use INT8 if the SQL type is INTEGER, so we make it use INT4 explicitly when needed.

For spatial columns, include the limit to properly format the column name since type alone is not enough to format the column. Ex. type_to_sql(:geography, limit: “Point,4326”)

> “geography(Point,4326)”



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/active_record/connection_adapters/cockroachdb/schema_statements.rb', line 79

def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **) # :nodoc:
  sql = \
    case type.to_s
    when "integer"
      case limit
      when nil; "int"
      when 1, 2; "int2"
      when 3, 4; "int4"
      when 5..8; "int8"
      else super
      end
    when "geometry", "geography"
      "#{type}(#{limit})"
    else
      super
    end
  # The call to super might have appeneded [] already.
  if array && type != :primary_key && !sql.end_with?("[]")
    sql = "#{sql}[]"
  end
  sql
end