activerecord-cockroachdb-adapter 7.1.0 → 7.2.0

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +22 -29
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +11 -2
  5. data/CONTRIBUTING.md +35 -90
  6. data/Gemfile +8 -4
  7. data/LICENSE +1 -2
  8. data/README.md +7 -5
  9. data/activerecord-cockroachdb-adapter.gemspec +2 -2
  10. data/bin/console +2 -2
  11. data/bin/start-cockroachdb +5 -20
  12. data/lib/active_record/connection_adapters/cockroachdb/arel_tosql.rb +14 -0
  13. data/lib/active_record/connection_adapters/cockroachdb/attribute_methods.rb +16 -0
  14. data/lib/active_record/connection_adapters/cockroachdb/column.rb +16 -0
  15. data/lib/active_record/connection_adapters/cockroachdb/column_methods.rb +14 -0
  16. data/lib/active_record/connection_adapters/cockroachdb/database_statements.rb +16 -0
  17. data/lib/active_record/connection_adapters/cockroachdb/database_tasks.rb +20 -3
  18. data/lib/active_record/connection_adapters/cockroachdb/oid/date_time.rb +14 -0
  19. data/lib/active_record/connection_adapters/cockroachdb/oid/interval.rb +16 -0
  20. data/lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb +14 -0
  21. data/lib/active_record/connection_adapters/cockroachdb/quoting.rb +16 -0
  22. data/lib/active_record/connection_adapters/cockroachdb/referential_integrity.rb +14 -0
  23. data/lib/active_record/connection_adapters/cockroachdb/schema_creation.rb +14 -1
  24. data/lib/active_record/connection_adapters/cockroachdb/schema_dumper.rb +14 -1
  25. data/lib/active_record/connection_adapters/cockroachdb/schema_statements.rb +102 -1
  26. data/lib/active_record/connection_adapters/cockroachdb/setup.rb +14 -0
  27. data/lib/active_record/connection_adapters/cockroachdb/spatial_column_info.rb +16 -0
  28. data/lib/active_record/connection_adapters/cockroachdb/table_definition.rb +14 -0
  29. data/lib/active_record/connection_adapters/cockroachdb/transaction_manager.rb +14 -0
  30. data/lib/active_record/connection_adapters/cockroachdb/type.rb +16 -0
  31. data/lib/active_record/connection_adapters/cockroachdb_adapter.rb +72 -126
  32. data/lib/active_record/migration/cockroachdb/compatibility.rb +16 -0
  33. data/lib/active_record/relation/query_methods_ext.rb +16 -3
  34. data/lib/activerecord-cockroachdb-adapter.rb +21 -0
  35. data/lib/arel/nodes/join_source_ext.rb +16 -0
  36. data/lib/version.rb +15 -1
  37. data/setup.sql +18 -0
  38. metadata +11 -12
  39. data/.ruby-version +0 -1
  40. data/lib/active_record/connection_adapters/cockroachdb/oid/type_map_initializer.rb +0 -26
@@ -1,3 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
1
17
  module ActiveRecord
2
18
  module ConnectionAdapters
3
19
  module CockroachDB
@@ -1,5 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
3
17
  # The PostgresSQL Adapter's ReferentialIntegrity module can disable and
4
18
  # re-enable foreign key constraints by disabling all table triggers. Since
5
19
  # triggers are not available in CockroachDB, we have to remove foreign keys and
@@ -1,5 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
3
17
  module ActiveRecord
4
18
  module ConnectionAdapters
5
19
  module CockroachDB
@@ -15,4 +29,3 @@ module ActiveRecord
15
29
  end
16
30
  end
17
31
  end
18
-
@@ -1,5 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
3
17
  module ActiveRecord
4
18
  module ConnectionAdapters
5
19
  module CockroachDB
@@ -16,4 +30,3 @@ module ActiveRecord
16
30
  end
17
31
  end
18
32
  end
19
-
@@ -1,9 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
1
17
  module ActiveRecord
2
18
  module ConnectionAdapters
3
19
  module CockroachDB
4
20
  module SchemaStatements
5
21
  include ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements
6
22
 
23
+ # OVERRIDE: We do not want to see the crdb_internal schema in the names.
24
+ #
25
+ # Returns an array of schema names.
26
+ def schema_names
27
+ super - ["crdb_internal"]
28
+ end
29
+
7
30
  def add_index(table_name, column_name, **options)
8
31
  super
9
32
  rescue ActiveRecord::StatementInvalid => error
@@ -32,6 +55,84 @@ module ActiveRecord
32
55
  end
33
56
  end
34
57
 
58
+ # OVERRIDE: CockroachDB does not support deferrable constraints.
59
+ # See: https://go.crdb.dev/issue-v/31632/v23.1
60
+ def foreign_key_options(from_table, to_table, options)
61
+ options = super
62
+ options.delete(:deferrable) unless supports_deferrable_constraints?
63
+ options
64
+ end
65
+
66
+ # OVERRIDE: Added `unique_rowid` to the last line of the second query.
67
+ # This is a CockroachDB-specific function used for primary keys.
68
+ # Also make sure we don't consider `NOT VISIBLE` columns.
69
+ #
70
+ # Returns a table's primary key and belonging sequence.
71
+ def pk_and_sequence_for(table) # :nodoc:
72
+ # First try looking for a sequence with a dependency on the
73
+ # given table's primary key.
74
+ result = query(<<~SQL, "SCHEMA")[0]
75
+ SELECT attr.attname, nsp.nspname, seq.relname
76
+ FROM pg_class seq,
77
+ pg_attribute attr,
78
+ pg_depend dep,
79
+ pg_constraint cons,
80
+ pg_namespace nsp,
81
+ -- TODO: use the pg_catalog.pg_attribute(attishidden) column when
82
+ -- it is added instead of joining on crdb_internal.
83
+ -- See https://github.com/cockroachdb/cockroach/pull/126397
84
+ crdb_internal.table_columns tc
85
+ WHERE seq.oid = dep.objid
86
+ AND seq.relkind = 'S'
87
+ AND attr.attrelid = dep.refobjid
88
+ AND attr.attnum = dep.refobjsubid
89
+ AND attr.attrelid = cons.conrelid
90
+ AND attr.attnum = cons.conkey[1]
91
+ AND seq.relnamespace = nsp.oid
92
+ AND attr.attrelid = tc.descriptor_id
93
+ AND attr.attname = tc.column_name
94
+ AND tc.hidden = false
95
+ AND cons.contype = 'p'
96
+ AND dep.classid = 'pg_class'::regclass
97
+ AND dep.refobjid = #{quote(quote_table_name(table))}::regclass
98
+ SQL
99
+
100
+ if result.nil? || result.empty?
101
+ result = query(<<~SQL, "SCHEMA")[0]
102
+ SELECT attr.attname, nsp.nspname,
103
+ CASE
104
+ WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
105
+ WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
106
+ substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
107
+ strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
108
+ ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
109
+ END
110
+ FROM pg_class t
111
+ JOIN pg_attribute attr ON (t.oid = attrelid)
112
+ JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
113
+ JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
114
+ JOIN pg_namespace nsp ON (t.relnamespace = nsp.oid)
115
+ -- TODO: use the pg_catalog.pg_attribute(attishidden) column when
116
+ -- it is added instead of joining on crdb_internal.
117
+ -- See https://github.com/cockroachdb/cockroach/pull/126397
118
+ JOIN crdb_internal.table_columns tc ON (attr.attrelid = tc.descriptor_id AND attr.attname = tc.column_name)
119
+ WHERE t.oid = #{quote(quote_table_name(table))}::regclass
120
+ AND tc.hidden = false
121
+ AND cons.contype = 'p'
122
+ AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate|gen_random_uuid|unique_rowid'
123
+ SQL
124
+ end
125
+
126
+ pk = result.shift
127
+ if result.last
128
+ [pk, PostgreSQL::Name.new(*result)]
129
+ else
130
+ [pk, nil]
131
+ end
132
+ rescue
133
+ nil
134
+ end
135
+
35
136
  # override
36
137
  # Modified version of the postgresql foreign_keys method.
37
138
  # Replaces t2.oid::regclass::text with t2.relname since this is
@@ -40,7 +141,7 @@ module ActiveRecord
40
141
  # so we append it manually.
41
142
  def foreign_keys(table_name)
42
143
  scope = quoted_scope(table_name)
43
- fk_info = exec_query(<<~SQL, "SCHEMA")
144
+ fk_info = internal_exec_query(<<~SQL, "SCHEMA")
44
145
  SELECT CASE
45
146
  WHEN n2.nspname = current_schema()
46
147
  THEN ''
@@ -1,5 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
3
17
  module ActiveRecord # :nodoc:
4
18
  module ConnectionAdapters # :nodoc:
5
19
  module CockroachDB # :nodoc:
@@ -1,3 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
1
17
  module ActiveRecord
2
18
  module ConnectionAdapters
3
19
  module CockroachDB
@@ -1,5 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
3
17
  module ActiveRecord # :nodoc:
4
18
  module ConnectionAdapters # :nodoc:
5
19
  module CockroachDB # :nodoc:
@@ -1,5 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
3
17
  module ActiveRecord
4
18
  module ConnectionAdapters
5
19
  module CockroachDB
@@ -1,3 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
1
17
  module ActiveRecord
2
18
  module Type
3
19
  module CRDBExt
@@ -1,3 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
1
17
  require "rgeo/active_record"
2
18
 
3
19
  require_relative "../../arel/nodes/join_source_ext"
@@ -16,7 +32,6 @@ require "active_record/connection_adapters/cockroachdb/type"
16
32
  require "active_record/connection_adapters/cockroachdb/column"
17
33
  require "active_record/connection_adapters/cockroachdb/spatial_column_info"
18
34
  require "active_record/connection_adapters/cockroachdb/setup"
19
- require "active_record/connection_adapters/cockroachdb/oid/type_map_initializer"
20
35
  require "active_record/connection_adapters/cockroachdb/oid/spatial"
21
36
  require "active_record/connection_adapters/cockroachdb/oid/interval"
22
37
  require "active_record/connection_adapters/cockroachdb/oid/date_time"
@@ -30,40 +45,6 @@ require_relative "../relation/query_methods_ext"
30
45
  # Defined in ./setup.rb
31
46
  ActiveRecord::ConnectionAdapters::CockroachDB.initial_setup
32
47
 
33
- module ActiveRecord
34
- module ConnectionHandling
35
- def cockroachdb_connection(config)
36
- # This is copied from the PostgreSQL adapter.
37
- conn_params = config.symbolize_keys.compact
38
-
39
- # Map ActiveRecords param names to PGs.
40
- conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
41
- conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
42
-
43
- # Forward only valid config params to PG::Connection.connect.
44
- valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
45
- conn_params.slice!(*valid_conn_param_keys)
46
-
47
- ConnectionAdapters::CockroachDBAdapter.new(
48
- ConnectionAdapters::CockroachDBAdapter.new_client(conn_params),
49
- logger,
50
- conn_params,
51
- config
52
- )
53
- # This rescue flow appears in new_client, but it is needed here as well
54
- # since Cockroach will sometimes not raise until a query is made.
55
- rescue ActiveRecord::StatementInvalid => error
56
- no_db_err_check1 = conn_params && conn_params[:dbname] && error.cause.message.include?(conn_params[:dbname])
57
- no_db_err_check2 = conn_params && conn_params[:dbname] && error.cause.message.include?("pg_type")
58
- if no_db_err_check1 || no_db_err_check2
59
- raise ActiveRecord::NoDatabaseError
60
- else
61
- raise ActiveRecord::ConnectionNotEstablished, error.message
62
- end
63
- end
64
- end
65
- end
66
-
67
48
  module ActiveRecord
68
49
  module ConnectionAdapters
69
50
  module CockroachDBConnectionPool
@@ -101,7 +82,7 @@ module ActiveRecord
101
82
  ConnectionPool.prepend(CockroachDBConnectionPool)
102
83
 
103
84
  class CockroachDBAdapter < PostgreSQLAdapter
104
- ADAPTER_NAME = "CockroachDB".freeze
85
+ ADAPTER_NAME = "CockroachDB"
105
86
  DEFAULT_PRIMARY_KEY = "rowid"
106
87
 
107
88
  SPATIAL_COLUMN_OPTIONS =
@@ -155,18 +136,29 @@ module ActiveRecord
155
136
  @max_transaction_retries ||= @config.fetch(:max_transaction_retries, 3)
156
137
  end
157
138
 
158
- # CockroachDB 20.1 can run queries that work against PostgreSQL 10+.
159
- def postgresql_version
160
- 100000
139
+ def get_database_version
140
+ with_raw_connection do |conn|
141
+ conn.async_exec("SHOW crdb_version") do |result|
142
+ major, minor, patch = result
143
+ .getvalue(0, 0)
144
+ .match(/v(\d+).(\d+).(\d+)/)
145
+ .captures
146
+ .map(&:to_i)
147
+ major * 100 * 100 + minor * 100 + patch
148
+ end
149
+ end
161
150
  end
151
+ undef :postgresql_version
152
+ alias :cockroachdb_version :database_version
162
153
 
163
- def supports_bulk_alter?
154
+ def supports_datetime_with_precision?
155
+ # https://github.com/cockroachdb/cockroach/pull/111400
164
156
  true
165
157
  end
166
158
 
167
- def supports_json?
168
- # FIXME(joey): Add a version check.
169
- true
159
+ def supports_nulls_not_distinct?
160
+ # https://github.com/cockroachdb/cockroach/issues/115836
161
+ false
170
162
  end
171
163
 
172
164
  def supports_ddl_transactions?
@@ -178,10 +170,6 @@ module ActiveRecord
178
170
  end
179
171
 
180
172
  def supports_materialized_views?
181
- false
182
- end
183
-
184
- def supports_partial_index?
185
173
  true
186
174
  end
187
175
 
@@ -200,14 +188,6 @@ module ActiveRecord
200
188
  false
201
189
  end
202
190
 
203
- def supports_datetime_with_precision?
204
- false
205
- end
206
-
207
- def supports_comments?
208
- true
209
- end
210
-
211
191
  def supports_comments_in_create?
212
192
  false
213
193
  end
@@ -229,53 +209,47 @@ module ActiveRecord
229
209
  end
230
210
 
231
211
  def supports_deferrable_constraints?
212
+ # https://go.crdb.dev/issue-v/31632/v23.1
232
213
  false
233
214
  end
234
215
 
235
- # This is hardcoded to 63 (as previously was in ActiveRecord 5.0) to aid in
236
- # migration from PostgreSQL to CockroachDB. In practice, this limitation
237
- # is arbitrary since CockroachDB supports index name lengths and table alias
238
- # lengths far greater than this value. For the time being though, we match
239
- # the original behavior for PostgreSQL to simplify migrations.
240
- #
241
- # Note that in the migration to ActiveRecord 5.1, this was changed in
242
- # PostgreSQLAdapter to use `SHOW max_identifier_length` (which does not
243
- # exist in CockroachDB). Therefore, we have to redefine this here.
244
- def max_identifier_length
245
- 63
216
+ def check_version # :nodoc:
217
+ # https://www.cockroachlabs.com/docs/releases/release-support-policy
218
+ if database_version < 23_01_12 # < 23.1.12
219
+ raise "Your version of CockroachDB (#{database_version}) is too old. Active Record supports CockroachDB >= 23.1.12."
220
+ end
246
221
  end
247
- alias index_name_length max_identifier_length
248
- alias table_alias_length max_identifier_length
249
222
 
250
- # NOTE: This commented bit of code allows to have access to crdb version,
251
- # which can be useful for feature detection. However, we currently don't
252
- # need, hence we avoid the extra queries.
223
+ def configure_connection(...)
224
+ super
225
+
226
+ # This rescue flow appears in new_client, but it is needed here as well
227
+ # since Cockroach will sometimes not raise until a query is made.
253
228
  #
254
- # def initialize(connection, logger, conn_params, config)
255
- # super(connection, logger, conn_params, config)
256
-
257
- # # crdb_version is the version of the binary running on the node. We
258
- # # really want to use `SHOW CLUSTER SETTING version` to get the cluster
259
- # # version, but that is only available to admins. Instead, we can use
260
- # # crdb_internal.is_at_least_version, but that's only available in 22.1.
261
- # crdb_version_string = query_value("SHOW crdb_version")
262
- # if crdb_version_string.include? "v22.1"
263
- # version_num = query_value(<<~SQL, "VERSION")
264
- # SELECT
265
- # CASE
266
- # WHEN crdb_internal.is_at_least_version('22.2') THEN 2220
267
- # WHEN crdb_internal.is_at_least_version('22.1') THEN 2210
268
- # ELSE 2120
269
- # END;
270
- # SQL
271
- # end
272
- # @crdb_version = version_num.to_i
273
- # end
274
-
275
- def self.database_exists?(config)
276
- !!ActiveRecord::Base.cockroachdb_connection(config)
277
- rescue ActiveRecord::NoDatabaseError
278
- false
229
+ # See https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/337#issuecomment-2328419453
230
+ #
231
+ # The error conditions used to differ from the ones in new_client, but
232
+ # the reasons why are no longer relevant. We keep this in sync with new_client
233
+ # even though some conditions might never be checked.
234
+ #
235
+ # See https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/229
236
+ #
237
+ # We have to rescue `ActiveRecord::StatementInvalid` instead of `::PG::Error`
238
+ # here as the error has already been casted (in `#with_raw_connection` as
239
+ # of Rails 7.2.1).
240
+ rescue ActiveRecord::StatementInvalid => error
241
+ conn_params = @connection_parameters
242
+ if conn_params && conn_params[:dbname] == "postgres"
243
+ raise ActiveRecord::ConnectionNotEstablished, error.message
244
+ elsif conn_params && conn_params[:dbname] && error.cause.message.include?(conn_params[:dbname])
245
+ raise ActiveRecord::NoDatabaseError.db_error(conn_params[:dbname])
246
+ elsif conn_params && conn_params[:user] && error.cause.message.include?(conn_params[:user])
247
+ raise ActiveRecord::DatabaseConnectionError.username_error(conn_params[:user])
248
+ elsif conn_params && conn_params[:host] && error.cause.message.include?(conn_params[:host])
249
+ raise ActiveRecord::DatabaseConnectionError.hostname_error(conn_params[:host])
250
+ else
251
+ raise ActiveRecord::ConnectionNotEstablished, error.message
252
+ end
279
253
  end
280
254
 
281
255
  # override
@@ -320,7 +294,6 @@ module ActiveRecord
320
294
  precision = extract_precision(sql_type)
321
295
  scale = extract_scale(sql_type)
322
296
 
323
-
324
297
  # The type for the numeric depends on the width of the field,
325
298
  # so we'll do something special here.
326
299
  #
@@ -351,7 +324,6 @@ module ActiveRecord
351
324
  def extract_value_from_default(default)
352
325
  super ||
353
326
  extract_escaped_string_from_default(default) ||
354
- extract_time_from_default(default) ||
355
327
  extract_empty_array_from_default(default) ||
356
328
  extract_decimal_from_default(default)
357
329
  end
@@ -369,32 +341,6 @@ module ActiveRecord
369
341
  "\"#{$1}\"".undump.gsub("\\'".freeze, "'".freeze)
370
342
  end
371
343
 
372
- # This method exists to extract the correct time and date defaults for a
373
- # couple of reasons.
374
- # 1) There's a bug in CockroachDB where the date type is missing from
375
- # the column info query.
376
- # https://github.com/cockroachdb/cockroach/issues/47285
377
- # 2) PostgreSQL's timestamp without time zone type maps to CockroachDB's
378
- # TIMESTAMP type. TIMESTAMP includes a UTC time zone while timestamp
379
- # without time zone doesn't.
380
- # https://www.cockroachlabs.com/docs/v19.2/timestamp.html#variants
381
- def extract_time_from_default(default)
382
- return unless default =~ /\A'(.*)'\z/
383
-
384
- # If default has a UTC time zone, we'll drop the time zone information
385
- # so it acts like PostgreSQL's timestamp without time zone. Then, try
386
- # to parse the resulting string to verify if it's a time.
387
- time = if default =~ /\A'(.*)(\+00:00)'\z/
388
- $1
389
- else
390
- default
391
- end
392
-
393
- Time.parse(time).to_s
394
- rescue
395
- nil
396
- end
397
-
398
344
  # CockroachDB stores default values for arrays in the `ARRAY[...]` format.
399
345
  # In general, it is hard to parse that, but it is easy to handle the common
400
346
  # case of an empty array.
@@ -566,7 +512,7 @@ module ActiveRecord
566
512
  # so this modified query uses AS OF SYSTEM TIME '-10s' to read historical data.
567
513
  def add_pg_decoders
568
514
  if @config[:use_follower_reads_for_type_introspection]
569
- @default_timezone = nil
515
+ @mapped_default_timezone = nil
570
516
  @timestamp_decoder = nil
571
517
 
572
518
  coders_by_name = {
@@ -581,6 +527,7 @@ module ActiveRecord
581
527
  "timestamp" => PG::TextDecoder::TimestampUtc,
582
528
  "timestamptz" => PG::TextDecoder::TimestampWithTimeZone,
583
529
  }
530
+ coders_by_name["date"] = PG::TextDecoder::Date if decode_dates
584
531
 
585
532
  known_coder_types = coders_by_name.keys.map { |n| quote(n) }
586
533
  query = <<~SQL % known_coder_types.join(", ")
@@ -588,7 +535,6 @@ module ActiveRecord
588
535
  FROM pg_type as t AS OF SYSTEM TIME '-10s'
589
536
  WHERE t.typname IN (%s)
590
537
  SQL
591
-
592
538
  coders = execute_and_clear(query, "SCHEMA", [], allow_retry: true, materialize_transactions: false) do |result|
593
539
  result.filter_map { |row| construct_coder(row, coders_by_name[row["typname"]]) }
594
540
  end
@@ -1,3 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
1
17
  require "active_record/migration"
2
18
  require "active_record/migration/compatibility"
3
19
 
@@ -1,5 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright 2024 The Cockroach Authors.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
3
17
  module ActiveRecord
4
18
  class Relation
5
19
  module QueryMethodsExt
@@ -76,10 +90,9 @@ module ActiveRecord
76
90
  self
77
91
  end
78
92
 
79
- # TODO: reset or no reset?
80
-
81
93
  def show_create
82
- connection.execute("show create table #{connection.quote_table_name self.table_name}").first["create_statement"]
94
+ quoted_table = connection.quote_table_name self.table_name
95
+ connection.select_one("show create table #{quoted_table}")["create_statement"]
83
96
  end
84
97
 
85
98
  private