activerecord-cockroachdb-adapter 7.1.0 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
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