activerecord-cockroachdb-adapter 8.0.3 → 8.1.1
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 +10 -0
- data/CONTRIBUTING.md +10 -17
- data/Gemfile +2 -1
- data/Rakefile +0 -19
- data/lib/active_record/connection_adapters/cockroachdb/column.rb +69 -24
- data/lib/active_record/connection_adapters/cockroachdb/database_statements.rb +13 -3
- data/lib/active_record/connection_adapters/cockroachdb/database_tasks.rb +1 -1
- data/lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb +34 -19
- data/lib/active_record/connection_adapters/cockroachdb/quoting.rb +19 -3
- data/lib/active_record/connection_adapters/cockroachdb/referential_integrity.rb +137 -51
- data/lib/active_record/connection_adapters/cockroachdb/schema_statements.rb +181 -102
- data/lib/active_record/connection_adapters/cockroachdb_adapter.rb +78 -34
- data/lib/version.rb +1 -1
- data/test/cases/adapter_test.rb +98 -0
- data/test/cases/adapters/cockroachdb/cached_plan_failure_test.rb +106 -0
- data/test/cases/adapters/cockroachdb/referential_integrity_test.rb +91 -0
- data/test/cases/adapters/postgresql/active_schema_test.rb +71 -0
- data/test/cases/adapters/postgresql/change_schema_test.rb +75 -0
- data/test/cases/adapters/postgresql/connection_test.rb +46 -0
- data/test/cases/adapters/postgresql/ddl_test.rb +326 -0
- data/test/cases/adapters/postgresql/interval_test.rb +131 -0
- data/test/cases/adapters/postgresql/nested_class_test.rb +22 -0
- data/test/cases/adapters/postgresql/numeric_test.rb +28 -0
- data/test/cases/adapters/postgresql/postgis_test.rb +199 -0
- data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +115 -0
- data/test/cases/adapters/postgresql/quoting_test.rb +30 -0
- data/test/cases/adapters/postgresql/schema_statements_test.rb +29 -0
- data/test/cases/adapters/postgresql/serial_test.rb +199 -0
- data/test/cases/adapters/postgresql/spatial_queries_test.rb +118 -0
- data/test/cases/adapters/postgresql/spatial_setup_test.rb +18 -0
- data/test/cases/adapters/postgresql/spatial_type_test.rb +41 -0
- data/test/cases/adapters/postgresql/timestamp_test.rb +58 -0
- data/test/cases/adapters/postgresql/virtual_column_test.rb +39 -0
- data/test/cases/associations/eager_load_nested_include_test.rb +111 -0
- data/test/cases/associations/left_outer_join_association_test.rb +30 -0
- data/test/cases/associations_test.rb +108 -0
- data/test/cases/base_test.rb +31 -0
- data/test/cases/comment_test.rb +75 -0
- data/test/cases/connection_adapters/type_test.rb +28 -0
- data/test/cases/database_configurations/resolver_test.rb +24 -0
- data/test/cases/defaults_test.rb +45 -0
- data/test/cases/dirty_test.rb +24 -0
- data/test/cases/fixtures_test.rb +541 -0
- data/test/cases/helper_cockroachdb.rb +232 -0
- data/test/cases/inheritance_test.rb +42 -0
- data/test/cases/invertible_migration_test.rb +73 -0
- data/test/cases/marshal_serialization_test.rb +45 -0
- data/test/cases/migration/change_schema_test.rb +140 -0
- data/test/cases/migration/check_constraint_test.rb +125 -0
- data/test/cases/migration/columns_test.rb +50 -0
- data/test/cases/migration/create_join_table_test.rb +66 -0
- data/test/cases/migration/foreign_key_test.rb +390 -0
- data/test/cases/migration/hidden_column_test.rb +70 -0
- data/test/cases/migration/references_foreign_key_test.rb +124 -0
- data/test/cases/migration_test.rb +120 -0
- data/test/cases/persistence_test.rb +33 -0
- data/test/cases/primary_keys_test.rb +134 -0
- data/test/cases/relation/aost_test.rb +57 -0
- data/test/cases/relation/or_test.rb +26 -0
- data/test/cases/relation/table_hints_test.rb +124 -0
- data/test/cases/relation_test.rb +26 -0
- data/test/cases/relations_test.rb +29 -0
- data/test/cases/schema_dumper_test.rb +221 -0
- data/test/cases/show_create_test.rb +14 -0
- data/test/cases/strict_loading_test.rb +34 -0
- data/test/cases/tasks/cockroachdb_rake_test.rb +113 -0
- data/test/cases/test_fixtures_test.rb +57 -0
- data/test/cases/transactions_test.rb +51 -0
- data/test/cases/unsafe_raw_sql_test.rb +22 -0
- data/test/config.yml +23 -0
- data/test/excludes/ActiveRecord/AdapterTest.rb +3 -0
- data/test/excludes/ActiveRecord/AdapterTestWithoutTransaction.rb +25 -0
- data/test/excludes/ActiveRecord/ConnectionAdapters/PoolConfig/ResolverTest.rb +1 -0
- data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/BindParameterTest.rb +15 -0
- data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/QuotingTest.rb +22 -0
- data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapterPreventWritesLegacyTest.rb +1 -0
- data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapterPreventWritesTest.rb +1 -0
- data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapterTest.rb +40 -0
- data/test/excludes/ActiveRecord/ConnectionAdapters/RegistrationIsolatedTest.rb +14 -0
- data/test/excludes/ActiveRecord/Encryption/EncryptionPerformanceTest.rb +1 -0
- data/test/excludes/ActiveRecord/Encryption/EnvelopeEncryptionPerformanceTest.rb +1 -0
- data/test/excludes/ActiveRecord/Encryption/ExtendedDeterministicQueriesPerformanceTest.rb +1 -0
- data/test/excludes/ActiveRecord/Encryption/StoragePerformanceTest.rb +2 -0
- data/test/excludes/ActiveRecord/InstrumentationTest.rb +16 -0
- data/test/excludes/ActiveRecord/InvertibleMigrationTest.rb +2 -0
- data/test/excludes/ActiveRecord/Migration/ChangeSchemaTest.rb +7 -0
- data/test/excludes/ActiveRecord/Migration/CheckConstraintTest.rb +6 -0
- data/test/excludes/ActiveRecord/Migration/ColumnsTest.rb +4 -0
- data/test/excludes/ActiveRecord/Migration/CompatibilityTest.rb +50 -0
- data/test/excludes/ActiveRecord/Migration/CompositeForeignKeyTest.rb +2 -0
- data/test/excludes/ActiveRecord/Migration/CreateJoinTableTest.rb +2 -0
- data/test/excludes/ActiveRecord/Migration/ForeignKeyInCreateTest.rb +1 -0
- data/test/excludes/ActiveRecord/Migration/ForeignKeyTest.rb +35 -0
- data/test/excludes/ActiveRecord/Migration/InvalidOptionsTest.rb +14 -0
- data/test/excludes/ActiveRecord/Migration/PGChangeSchemaTest.rb +8 -0
- data/test/excludes/ActiveRecord/Migration/ReferencesForeignKeyTest.rb +7 -0
- data/test/excludes/ActiveRecord/Migration/ReferencesIndexTest.rb +7 -0
- data/test/excludes/ActiveRecord/Migration/ReferencesStatementsTest.rb +3 -0
- data/test/excludes/ActiveRecord/MysqlDBCreateWithInvalidPermissionsTest.rb +1 -0
- data/test/excludes/ActiveRecord/OrTest.rb +1 -0
- data/test/excludes/ActiveRecord/PostgreSQLStructureDumpTest.rb +10 -0
- data/test/excludes/ActiveRecord/PostgresqlConnectionTest.rb +12 -0
- data/test/excludes/ActiveRecord/PostgresqlTransactionNestedTest.rb +14 -0
- data/test/excludes/ActiveRecord/PostgresqlTransactionTest.rb +4 -0
- data/test/excludes/ActiveRecord/RelationTest.rb +2 -0
- data/test/excludes/ActiveRecord/TooManyOrTest.rb +1 -0
- data/test/excludes/ActiveSupportSubclassWithFixturesTest.rb +1 -0
- data/test/excludes/AssociationDeprecationTest/NotifyModeTest.rb +2 -0
- data/test/excludes/AssociationDeprecationTest/RaiseBacktraceModeTest.rb +2 -0
- data/test/excludes/AssociationDeprecationTest/RaiseModeTest.rb +2 -0
- data/test/excludes/AssociationDeprecationTest/WarnBacktraceModeTest.rb +2 -0
- data/test/excludes/AssociationDeprecationTest/WarnModeTest.rb +2 -0
- data/test/excludes/AssociationDeprecationTest/fix_backtrace_cleaner.rb +10 -0
- data/test/excludes/BasicsTest.rb +1 -0
- data/test/excludes/BulkAlterTableMigrationsTest.rb +7 -0
- data/test/excludes/CalculationsTest.rb +4 -0
- data/test/excludes/CommentTest.rb +2 -0
- data/test/excludes/CoreTest.rb +1 -0
- data/test/excludes/CreateOrFindByWithinTransactions.rb +3 -0
- data/test/excludes/DefaultsUsingMultipleSchemasAndDomainTest.rb +7 -0
- data/test/excludes/DirtyTest.rb +3 -0
- data/test/excludes/EachTest.rb +8 -0
- data/test/excludes/EagerLoadPolyAssocsTest.rb +1 -0
- data/test/excludes/ExplicitlyNamedIndexMigrationTest.rb +1 -0
- data/test/excludes/FixturesResetPkSequenceTest.rb +3 -0
- data/test/excludes/FixturesTest.rb +21 -0
- data/test/excludes/FixturesWithForeignKeyViolationsTest.rb +2 -0
- data/test/excludes/ForeignTableTest.rb +10 -0
- data/test/excludes/InheritanceComputeTypeTest.rb +1 -0
- data/test/excludes/LeftOuterJoinAssociationTest.rb +2 -0
- data/test/excludes/LegacyPrimaryKeyTest/V4_2.rb +6 -0
- data/test/excludes/LegacyPrimaryKeyTest/V5_0.rb +6 -0
- data/test/excludes/MarshalSerializationTest.rb +4 -0
- data/test/excludes/MaterializedViewTest.rb +13 -0
- data/test/excludes/MigrationTest.rb +2 -0
- data/test/excludes/MultiDbMigratorTest.rb +2 -0
- data/test/excludes/NestedRelationScopingTest.rb +1 -0
- data/test/excludes/OrTest.rb +1 -0
- data/test/excludes/PersistenceTest.rb +3 -0
- data/test/excludes/PessimisticLockingTest.rb +1 -0
- data/test/excludes/PostgreSQLExplainTest.rb +7 -0
- data/test/excludes/PostgreSQLGeometricLineTest.rb +3 -0
- data/test/excludes/PostgreSQLGeometricTypesTest.rb +7 -0
- data/test/excludes/PostgreSQLPartitionsTest.rb +1 -0
- data/test/excludes/PostgreSQLReferentialIntegrityTest.rb +14 -0
- data/test/excludes/PostgresqlArrayTest.rb +21 -0
- data/test/excludes/PostgresqlBigSerialTest.rb +7 -0
- data/test/excludes/PostgresqlBitStringTest.rb +2 -0
- data/test/excludes/PostgresqlByteaTest.rb +1 -0
- data/test/excludes/PostgresqlCitextTest.rb +7 -0
- data/test/excludes/PostgresqlCollationTest.rb +5 -0
- data/test/excludes/PostgresqlCompositeTest.rb +2 -0
- data/test/excludes/PostgresqlCompositeWithCustomOIDTest.rb +2 -0
- data/test/excludes/PostgresqlDataTypeTest.rb +9 -0
- data/test/excludes/PostgresqlDefaultExpressionTest.rb +1 -0
- data/test/excludes/PostgresqlDeferredConstraintsTest.rb +3 -0
- data/test/excludes/PostgresqlDomainTest.rb +2 -0
- data/test/excludes/PostgresqlExtensionMigrationTest.rb +5 -0
- data/test/excludes/PostgresqlFullTextTest.rb +3 -0
- data/test/excludes/PostgresqlGeometricTest.rb +4 -0
- data/test/excludes/PostgresqlHstoreTest.rb +45 -0
- data/test/excludes/PostgresqlInfinityTest.rb +5 -0
- data/test/excludes/PostgresqlIntervalTest.rb +1 -0
- data/test/excludes/PostgresqlJSONBTest.rb +27 -0
- data/test/excludes/PostgresqlJSONTest.rb +27 -0
- data/test/excludes/PostgresqlLtreeTest.rb +4 -0
- data/test/excludes/PostgresqlMoneyTest.rb +12 -0
- data/test/excludes/PostgresqlNetworkTest.rb +69 -0
- data/test/excludes/PostgresqlNumberTest.rb +1 -0
- data/test/excludes/PostgresqlPointTest.rb +15 -0
- data/test/excludes/PostgresqlRangeTest.rb +3 -0
- data/test/excludes/PostgresqlRenameTableTest.rb +2 -0
- data/test/excludes/PostgresqlSerialTest.rb +7 -0
- data/test/excludes/PostgresqlTimestampFixtureTest.rb +2 -0
- data/test/excludes/PostgresqlTimestampMigrationTest.rb +3 -0
- data/test/excludes/PostgresqlTypeLookupTest.rb +2 -0
- data/test/excludes/PostgresqlUUIDGenerationTest.rb +7 -0
- data/test/excludes/PostgresqlUUIDTest.rb +1 -0
- data/test/excludes/PostgresqlVirtualColumnTest.rb +17 -0
- data/test/excludes/PostgresqlXMLTest.rb +5 -0
- data/test/excludes/PrimaryKeyIntegerNilDefaultTest.rb +1 -0
- data/test/excludes/PrimaryKeyIntegerTest.rb +3 -0
- data/test/excludes/PrimaryKeysTest.rb +2 -0
- data/test/excludes/QueryCacheExpiryTest.rb +10 -0
- data/test/excludes/RelationMergingTest.rb +15 -0
- data/test/excludes/RelationTest.rb +3 -0
- data/test/excludes/ReservedWordsMigrationTest.rb +1 -0
- data/test/excludes/SameNameDifferentDatabaseFixturesTest.rb +1 -0
- data/test/excludes/SanitizeTest.rb +13 -0
- data/test/excludes/SchemaAuthorizationTest.rb +8 -0
- data/test/excludes/SchemaCreateTableOptionsTest.rb +2 -0
- data/test/excludes/SchemaDumperDefaultsTest.rb +1 -0
- data/test/excludes/SchemaDumperTest.rb +11 -0
- data/test/excludes/SchemaForeignKeyTest.rb +1 -0
- data/test/excludes/SchemaIndexNullsOrderTest.rb +2 -0
- data/test/excludes/SchemaIndexOpclassTest.rb +3 -0
- data/test/excludes/SchemaTest.rb +49 -0
- data/test/excludes/SequenceNameDetectionTestCases/CollidedSequenceNameTest.rb +1 -0
- data/test/excludes/SequenceNameDetectionTestCases/LongerSequenceNameDetectionTest.rb +1 -0
- data/test/excludes/StrictLoadingFixturesTest.rb +1 -0
- data/test/excludes/TestFixturesTest.rb +1 -0
- data/test/excludes/TransactionInstrumentationTest.rb +1 -0
- data/test/excludes/TransactionIsolationTest.rb +1 -0
- data/test/excludes/TypeTest.rb +1 -0
- data/test/excludes/UniquenessValidationTest.rb +2 -0
- data/test/excludes/UnloggedTablesTest.rb +3 -0
- data/test/excludes/UnsafeRawSqlTest.rb +2 -0
- data/test/excludes/UpdateableViewTest.rb +5 -0
- data/test/excludes/WithAnnotationsTest.rb +6 -0
- data/test/models/building.rb +4 -0
- data/test/models/spatial_model.rb +5 -0
- data/test/schema/cockroachdb_specific_schema.rb +218 -0
- data/test/support/copy_cat.rb +83 -0
- data/test/support/exclude_from_transactional_tests.rb +33 -0
- data/test/support/paths_cockroachdb.rb +46 -0
- data/test/support/rake_helpers.rb +37 -0
- data/test/support/sql_logger.rb +55 -0
- data/test/support/template_creator.rb +114 -0
- metadata +422 -30
- data/.editorconfig +0 -7
- data/.github/issue_template.md +0 -46
- data/.github/reproduction_scripts/migrations.rb +0 -60
- data/.github/reproduction_scripts/models_and_database.rb +0 -49
- data/.github/workflows/ci.yml +0 -96
- data/.github/workflows/docker.yml +0 -57
- data/.gitignore +0 -18
- data/.gitmodules +0 -0
- data/activerecord-cockroachdb-adapter.gemspec +0 -38
- data/bin/console +0 -36
- data/bin/console_schemas/default.rb +0 -11
- data/bin/console_schemas/schemas.rb +0 -23
- data/bin/setup +0 -8
- data/bin/start-cockroachdb +0 -33
- data/build/Dockerfile +0 -14
- data/build/config.teamcity.yml +0 -31
- data/build/local-test.sh +0 -32
- data/build/teamcity-test.sh +0 -76
- data/docker.sh +0 -35
- data/lib/active_record/connection_adapters/cockroachdb/spatial_column_info.rb +0 -60
- data/setup.sql +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3f8176b5dc25df91e28dc937133083fc0640d7485059e3a098300032e0cf7610
|
|
4
|
+
data.tar.gz: 10448b0a9437ca1b28a8ef104e5e838e2484d3a085668f3c5ef7630463af0b6b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 613aaf5e74fd644104aaf407894ab006ae2f46d0684920407820c83b3a7402879e90c907fd06a8d158204d66d3c7af5100e266cb2ff17979553c5fd94935c5d2
|
|
7
|
+
data.tar.gz: 96d18f7427ecec5820c579bf579bc8567178bc876c459822d8d68ce9d31dbabfd82a5a5f18b54dab79f2402ff15ea507182706eb62337d82f486c3886f81dc66
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Ongoing
|
|
4
4
|
|
|
5
|
+
## 8.1.1 - 2026-08-18
|
|
6
|
+
|
|
7
|
+
- Disabled `schema_locked` by default on connect for CockroachDB v25.3+ and unlocked tables around batched foreign key changes ([#404](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/404))
|
|
8
|
+
- Improved error classification by detecting cached plan failures from the error message instead of the source function ([#403](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/403))
|
|
9
|
+
- Stopped advertising support for restarting database transactions ([#398](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/398))
|
|
10
|
+
- Fixed enum columns being misdetected as spatial columns ([#396](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/396))
|
|
11
|
+
|
|
12
|
+
## 8.1.0 - 2025-11-25
|
|
13
|
+
- Add support for Rails 8.1 ([#386](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/386))
|
|
14
|
+
|
|
5
15
|
## 8.0.3 - 2025-08-19
|
|
6
16
|
|
|
7
17
|
- Fixed the handling of column comments that end in a single quote ([#382](https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/382))
|
data/CONTRIBUTING.md
CHANGED
|
@@ -61,23 +61,16 @@ Only do it if you know the schema was left in a correct state.
|
|
|
61
61
|
|
|
62
62
|
### Run Tests from a Backup
|
|
63
63
|
|
|
64
|
-
Loading the full test schema every time a test runs can take
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
To load from the template, use the `COCKROACH_LOAD_FROM_TEMPLATE` flag.
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
COCKROACH_LOAD_FROM_TEMPLATE=1 TEST_FILES="test/cases/adapters/postgresql/ddl_test.rb" bundle exec rake test
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
And the `activerecord_unittest` database will use the `RESTORE` command to load the schema from the template database.
|
|
64
|
+
Loading the full test schema every time a test runs can take
|
|
65
|
+
a while, so for cases where loading the schema sequentially
|
|
66
|
+
is unimportant, it is possible to use a backup to set up the
|
|
67
|
+
database. This is significantly faster than the standard
|
|
68
|
+
method and is provided to run individual tests faster, but
|
|
69
|
+
should not be used to validate a build.
|
|
70
|
+
|
|
71
|
+
To do so, just set the env variable `COCKROACH_LOAD_FROM_TEMPLATE`.
|
|
72
|
+
First run will generate and cache a template, latter runs will use
|
|
73
|
+
it.
|
|
81
74
|
|
|
82
75
|
# Improvements
|
|
83
76
|
|
data/Gemfile
CHANGED
|
@@ -52,10 +52,11 @@ group :development, :test do
|
|
|
52
52
|
gem "msgpack", ">= 1.7.0"
|
|
53
53
|
gem "mutex_m", "~> 0.2.0"
|
|
54
54
|
|
|
55
|
+
gem "tracer"
|
|
55
56
|
gem "rake"
|
|
56
57
|
gem "debug"
|
|
58
|
+
gem "minitest-bisect", github: "BuonOmo/minitest-bisect", branch: "main"
|
|
57
59
|
gem "minitest-excludes", "~> 2.0.1"
|
|
58
|
-
gem "minitest-github_action_reporter", github: "BuonOmo/minitest-github_action_reporter", require: "minitest/github_action_reporter_plugin"
|
|
59
60
|
gem "ostruct", "~> 0.6"
|
|
60
61
|
|
|
61
62
|
# Gems used for tests meta-programming.
|
data/Rakefile
CHANGED
|
@@ -2,28 +2,9 @@ require "bundler/gem_tasks"
|
|
|
2
2
|
require "rake/testtask"
|
|
3
3
|
require_relative 'test/support/paths_cockroachdb'
|
|
4
4
|
require_relative 'test/support/rake_helpers'
|
|
5
|
-
require_relative 'test/support/template_creator'
|
|
6
5
|
|
|
7
6
|
task default: [:test]
|
|
8
7
|
|
|
9
|
-
namespace :db do
|
|
10
|
-
task "create_test_template" do
|
|
11
|
-
ENV['DEBUG_COCKROACHDB_ADAPTER'] = "1"
|
|
12
|
-
ENV['COCKROACH_SKIP_LOAD_SCHEMA'] = "1"
|
|
13
|
-
|
|
14
|
-
TemplateCreator.connect
|
|
15
|
-
require_relative 'test/cases/helper'
|
|
16
|
-
|
|
17
|
-
# TODO: look into this more, but for some reason the blob alias
|
|
18
|
-
# is not defined while running this task.
|
|
19
|
-
ActiveRecord::ConnectionAdapters::CockroachDB::TableDefinition.class_eval do
|
|
20
|
-
alias :blob :binary
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
TemplateCreator.create_test_template
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
8
|
Rake::TestTask.new do |t|
|
|
28
9
|
t.libs = ARTest::CockroachDB.test_load_paths
|
|
29
10
|
t.test_files = RakeHelpers.test_files
|
|
@@ -20,33 +20,32 @@ module ActiveRecord
|
|
|
20
20
|
class Column < PostgreSQL::Column
|
|
21
21
|
# most functions taken from activerecord-postgis-adapter spatial_column
|
|
22
22
|
# https://github.com/rgeo/activerecord-postgis-adapter/blob/master/lib/active_record/connection_adapters/postgis/spatial_column.rb
|
|
23
|
-
def initialize(name, default, sql_type_metadata = nil, null = true,
|
|
23
|
+
def initialize(name, cast_type, default, sql_type_metadata = nil, null = true,
|
|
24
24
|
default_function = nil, collation: nil, comment: nil, identity: nil,
|
|
25
|
-
serial: nil,
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
serial: nil, generated: nil, hidden: nil)
|
|
26
|
+
|
|
27
|
+
super(name, cast_type, default, sql_type_metadata, null, default_function,
|
|
28
|
+
collation: collation, comment: comment, serial: serial, generated: generated, identity: identity)
|
|
29
|
+
|
|
28
30
|
@hidden = hidden
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@has_m = !!spatial[:has_m]
|
|
36
|
-
elsif @geographic
|
|
32
|
+
return unless spatial?
|
|
33
|
+
|
|
34
|
+
@geographic = sql_type_metadata.sql_type.match?(/geography\(/i)
|
|
35
|
+
|
|
36
|
+
if @geographic
|
|
37
37
|
# Geographic type information is embedded in the SQL type
|
|
38
38
|
@srid = 4326
|
|
39
39
|
@has_z = @has_m = false
|
|
40
40
|
build_from_sql_type(sql_type_metadata.sql_type)
|
|
41
|
-
elsif sql_type
|
|
41
|
+
elsif sql_type.match?(/geography|geometry|point|linestring|polygon/i)
|
|
42
42
|
build_from_sql_type(sql_type_metadata.sql_type)
|
|
43
|
-
elsif sql_type_metadata.sql_type
|
|
43
|
+
elsif sql_type_metadata.sql_type.match?(/geography|geometry|point|linestring|polygon/i)
|
|
44
44
|
# A geometry column with no geometry_columns entry.
|
|
45
45
|
# @geometric_type = geo_type_from_sql_type(sql_type)
|
|
46
46
|
build_from_sql_type(sql_type_metadata.sql_type)
|
|
47
47
|
end
|
|
48
|
-
|
|
49
|
-
collation: collation, comment: comment, serial: serial, generated: generated, identity: identity)
|
|
48
|
+
|
|
50
49
|
if spatial? && @srid
|
|
51
50
|
@limit = { srid: @srid, type: to_type_name(geometric_type) }
|
|
52
51
|
@limit[:has_z] = true if @has_z
|
|
@@ -59,20 +58,18 @@ module ActiveRecord
|
|
|
59
58
|
:geometric_type,
|
|
60
59
|
:has_m,
|
|
61
60
|
:has_z,
|
|
62
|
-
:srid
|
|
61
|
+
:srid,
|
|
62
|
+
:hidden
|
|
63
63
|
|
|
64
64
|
alias geographic? geographic
|
|
65
65
|
alias has_z? has_z
|
|
66
66
|
alias has_m? has_m
|
|
67
|
+
alias hidden? hidden
|
|
67
68
|
|
|
68
69
|
def limit
|
|
69
70
|
spatial? ? @limit : super
|
|
70
71
|
end
|
|
71
72
|
|
|
72
|
-
def hidden?
|
|
73
|
-
@hidden
|
|
74
|
-
end
|
|
75
|
-
|
|
76
73
|
def spatial?
|
|
77
74
|
%i[geometry geography].include?(@sql_type_metadata.type)
|
|
78
75
|
end
|
|
@@ -81,15 +78,63 @@ module ActiveRecord
|
|
|
81
78
|
default_function == 'unique_rowid()'
|
|
82
79
|
end
|
|
83
80
|
|
|
84
|
-
|
|
81
|
+
# TODO: add tests (see #390)
|
|
82
|
+
def init_with(coder)
|
|
83
|
+
@geographic = coder["geographic"]
|
|
84
|
+
@geometric_type = coder["geometric_type"]
|
|
85
|
+
@has_m = coder["has_m"]
|
|
86
|
+
@has_z = coder["has_z"]
|
|
87
|
+
@srid = coder["srid"]
|
|
88
|
+
@hidden = coder["hidden"]
|
|
89
|
+
@limit = coder["limit"]
|
|
90
|
+
super
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# TODO: add tests (see #390)
|
|
94
|
+
def encode_with(coder)
|
|
95
|
+
coder["geographic"] = @geographic
|
|
96
|
+
coder["geometric_type"] = @geometric_type
|
|
97
|
+
coder["has_m"] = @has_m
|
|
98
|
+
coder["has_z"] = @has_z
|
|
99
|
+
coder["srid"] = @srid
|
|
100
|
+
coder["hidden"] = @hidden
|
|
101
|
+
coder["limit"] = @limit
|
|
102
|
+
super
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# TODO: add tests (see #390)
|
|
106
|
+
def ==(other)
|
|
107
|
+
other.is_a?(Column) &&
|
|
108
|
+
super &&
|
|
109
|
+
other.geographic == geographic &&
|
|
110
|
+
other.geometric_type == geometric_type &&
|
|
111
|
+
other.has_m == has_m &&
|
|
112
|
+
other.has_z == has_z &&
|
|
113
|
+
other.srid == srid &&
|
|
114
|
+
other.hidden == hidden &&
|
|
115
|
+
other.limit == limit
|
|
85
116
|
|
|
86
|
-
def set_geometric_type_from_name(name)
|
|
87
|
-
@geometric_type = RGeo::ActiveRecord.geometric_type_from_name(name) || RGeo::Feature::Geometry
|
|
88
117
|
end
|
|
118
|
+
alias :eql? :==
|
|
119
|
+
|
|
120
|
+
# TODO: add tests (see #390)
|
|
121
|
+
def hash
|
|
122
|
+
Column.hash ^
|
|
123
|
+
super.hash ^
|
|
124
|
+
geographic.hash ^
|
|
125
|
+
geometric_type.hash ^
|
|
126
|
+
has_m.hash ^
|
|
127
|
+
has_z.hash ^
|
|
128
|
+
srid.hash ^
|
|
129
|
+
hidden.hash ^
|
|
130
|
+
limit.hash
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
private
|
|
89
134
|
|
|
90
135
|
def build_from_sql_type(sql_type)
|
|
91
136
|
geo_type, @srid, @has_z, @has_m = OID::Spatial.parse_sql_type(sql_type)
|
|
92
|
-
|
|
137
|
+
@geometric_type = RGeo::ActiveRecord.geometric_type_from_name(geo_type) || RGeo::Feature::Geometry
|
|
93
138
|
end
|
|
94
139
|
|
|
95
140
|
def to_type_name(geometric_type)
|
|
@@ -22,15 +22,25 @@ module ActiveRecord
|
|
|
22
22
|
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
|
23
23
|
fixture_inserts = build_fixture_statements(fixture_set)
|
|
24
24
|
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
|
|
25
|
-
statements = table_deletes + fixture_inserts
|
|
25
|
+
statements = (table_deletes + fixture_inserts).join(";")
|
|
26
26
|
|
|
27
|
+
# Since [rails pull request #52428][1], `#execute_batch` does not
|
|
28
|
+
# trigger a cache clear anymore. However, `#insert_fixtures_set`
|
|
29
|
+
# relies on that clear to ensure consistency. In the postgresql
|
|
30
|
+
# adapter, this is ensured by a call to `#execute` rather than
|
|
31
|
+
# `#execute_batch` in `#disable_referential_integrity`. Since
|
|
32
|
+
# we are not always calling `#disable_referential_integrity`,
|
|
33
|
+
# we need to ensure that the cache is cleared when running
|
|
34
|
+
# our statements by calling `#execute` instead of `#execute_batch`.
|
|
35
|
+
#
|
|
36
|
+
# [1]: https://github.com/rails/rails/pull/52428
|
|
27
37
|
begin # much faster without disabling referential integrity, worth trying.
|
|
28
38
|
transaction(requires_new: true) do
|
|
29
|
-
|
|
39
|
+
execute(statements, "Fixtures Load")
|
|
30
40
|
end
|
|
31
41
|
rescue
|
|
32
42
|
disable_referential_integrity do
|
|
33
|
-
|
|
43
|
+
execute(statements, "Fixtures Load")
|
|
34
44
|
end
|
|
35
45
|
end
|
|
36
46
|
end
|
|
@@ -74,7 +74,7 @@ module ActiveRecord
|
|
|
74
74
|
"https://github.com/cockroachdb/activerecord-cockroachdb-adapter/issues/new"
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
run_cmd("cockroach",
|
|
77
|
+
run_cmd("cockroach", "sql", "--set", "errexit=false", "--file", filename)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
private
|
|
@@ -26,9 +26,22 @@ module ActiveRecord
|
|
|
26
26
|
# "geometry(Polygon,4326) NOT NULL"
|
|
27
27
|
# "geometry(Geography,4326)"
|
|
28
28
|
def initialize(oid, sql_type)
|
|
29
|
-
|
|
30
|
-
@
|
|
29
|
+
super()
|
|
30
|
+
@sql_type = sql_type.freeze
|
|
31
|
+
@factory_attrs = self.class
|
|
32
|
+
.parse_sql_type(sql_type)
|
|
33
|
+
.then { |geo_type, srid, has_z, has_m|
|
|
34
|
+
{
|
|
35
|
+
geo_type: geo_type.underscore.freeze,
|
|
36
|
+
srid: srid.freeze,
|
|
37
|
+
has_z: has_z.freeze,
|
|
38
|
+
has_m: has_m.freeze,
|
|
39
|
+
sql_type: type.to_s.freeze
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
.freeze
|
|
31
43
|
end
|
|
44
|
+
protected attr_reader :sql_type, :factory_attrs
|
|
32
45
|
|
|
33
46
|
# sql_type: geometry, geometry(Point), geometry(Point,4326), ...
|
|
34
47
|
#
|
|
@@ -59,15 +72,8 @@ module ActiveRecord
|
|
|
59
72
|
[geo_type, srid, has_z, has_m]
|
|
60
73
|
end
|
|
61
74
|
|
|
62
|
-
def spatial_factory
|
|
63
|
-
@spatial_factory ||=
|
|
64
|
-
RGeo::ActiveRecord::SpatialFactoryStore.instance.factory(
|
|
65
|
-
factory_attrs
|
|
66
|
-
)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
75
|
def geographic?
|
|
70
|
-
@sql_type
|
|
76
|
+
@sql_type.start_with?("geography")
|
|
71
77
|
end
|
|
72
78
|
|
|
73
79
|
def spatial?
|
|
@@ -92,6 +98,19 @@ module ActiveRecord
|
|
|
92
98
|
.generate(geo_value)
|
|
93
99
|
end
|
|
94
100
|
|
|
101
|
+
# TODO: add tests (see #390)
|
|
102
|
+
def ==(other)
|
|
103
|
+
super &&
|
|
104
|
+
@sql_type == other.sql_type &&
|
|
105
|
+
@factory_attrs == other.factory_attrs
|
|
106
|
+
end
|
|
107
|
+
alias eql? ==
|
|
108
|
+
|
|
109
|
+
# TODO: add tests (see #390)
|
|
110
|
+
def hash
|
|
111
|
+
super ^ [@sql_type, @factory_attrs].hash
|
|
112
|
+
end
|
|
113
|
+
|
|
95
114
|
private
|
|
96
115
|
|
|
97
116
|
def cast_value(value)
|
|
@@ -108,7 +127,7 @@ module ActiveRecord
|
|
|
108
127
|
end
|
|
109
128
|
|
|
110
129
|
def binary_string?(string)
|
|
111
|
-
string[0] == "\x00" || string[0] == "\x01" || string[0, 4]
|
|
130
|
+
string[0] == "\x00" || string[0] == "\x01" || string[0, 4].match?(/[0-9a-fA-F]{4}/)
|
|
112
131
|
end
|
|
113
132
|
|
|
114
133
|
def wkt_parser(string)
|
|
@@ -119,14 +138,10 @@ module ActiveRecord
|
|
|
119
138
|
end
|
|
120
139
|
end
|
|
121
140
|
|
|
122
|
-
def
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
has_z: @has_z,
|
|
127
|
-
srid: @srid,
|
|
128
|
-
sql_type: type.to_s
|
|
129
|
-
}
|
|
141
|
+
def spatial_factory
|
|
142
|
+
RGeo::ActiveRecord::SpatialFactoryStore.instance.factory(
|
|
143
|
+
factory_attrs
|
|
144
|
+
)
|
|
130
145
|
end
|
|
131
146
|
end
|
|
132
147
|
end
|
|
@@ -34,7 +34,8 @@ module ActiveRecord
|
|
|
34
34
|
# but when creating objects, using RGeo features is more convenient than
|
|
35
35
|
# converting to WKB, so this does it automatically.
|
|
36
36
|
def quote(value)
|
|
37
|
-
|
|
37
|
+
case value
|
|
38
|
+
when Numeric
|
|
38
39
|
# NOTE: The fact that integers are quoted is important and helps
|
|
39
40
|
# mitigate a potential vulnerability.
|
|
40
41
|
#
|
|
@@ -42,9 +43,9 @@ module ActiveRecord
|
|
|
42
43
|
# - https://nvd.nist.gov/vuln/detail/CVE-2022-44566
|
|
43
44
|
# - https://github.com/cockroachdb/activerecord-cockroachdb-adapter/pull/280#discussion_r1288692977
|
|
44
45
|
"'#{quote_string(value.to_s)}'"
|
|
45
|
-
|
|
46
|
+
when RGeo::Feature::Geometry
|
|
46
47
|
"'#{RGeo::WKRep::WKBGenerator.new(hex_format: true, type_format: :ewkb, emit_ewkb_srid: true).generate(value)}'"
|
|
47
|
-
|
|
48
|
+
when RGeo::Cartesian::BoundingBox
|
|
48
49
|
"'#{value.min_x},#{value.min_y},#{value.max_x},#{value.max_y}'::box"
|
|
49
50
|
else
|
|
50
51
|
super
|
|
@@ -58,6 +59,21 @@ module ActiveRecord
|
|
|
58
59
|
# This is tested by `BasicsTest#test_default_in_local_time`.
|
|
59
60
|
super + value.strftime("%z")
|
|
60
61
|
end
|
|
62
|
+
|
|
63
|
+
# NOTE: This method should be private in future rails versions.
|
|
64
|
+
# Hence we should also make it private then.
|
|
65
|
+
#
|
|
66
|
+
# See https://github.com/rails/rails/blob/v8.1.1/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb#L190
|
|
67
|
+
def lookup_cast_type(sql_type)
|
|
68
|
+
type_map.lookup(
|
|
69
|
+
# oid
|
|
70
|
+
query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i,
|
|
71
|
+
# fmod, not needed.
|
|
72
|
+
nil,
|
|
73
|
+
# details needed for `..::CockroachDB::OID::Spatial` (e.g. `geometry(point,3857)`)
|
|
74
|
+
sql_type
|
|
75
|
+
)
|
|
76
|
+
end
|
|
61
77
|
end
|
|
62
78
|
end
|
|
63
79
|
end
|
|
@@ -34,8 +34,47 @@ module ActiveRecord
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def disable_referential_integrity
|
|
37
|
-
|
|
37
|
+
if transaction_open? && query_value("SHOW autocommit_before_ddl") == "off"
|
|
38
|
+
begin
|
|
39
|
+
yield
|
|
40
|
+
rescue ActiveRecord::InvalidForeignKey => e
|
|
41
|
+
warn <<-WARNING
|
|
42
|
+
WARNING: Rails was not able to disable referential integrity.
|
|
43
|
+
|
|
44
|
+
This is due to CockroachDB's need of committing transactions
|
|
45
|
+
before a schema change occurs. To bypass this, you can set
|
|
46
|
+
`autocommit_before_ddl: "on"` in your database configuration.
|
|
47
|
+
WARNING
|
|
48
|
+
raise e
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
foreign_keys = all_foreign_keys
|
|
52
|
+
|
|
53
|
+
remove_foreign_keys(foreign_keys)
|
|
54
|
+
|
|
55
|
+
# Prefixes and suffixes are added in add_foreign_key
|
|
56
|
+
# in AR7+ so we need to temporarily disable them here,
|
|
57
|
+
# otherwise prefixes/suffixes will be erroneously added.
|
|
58
|
+
old_prefix = ActiveRecord::Base.table_name_prefix
|
|
59
|
+
old_suffix = ActiveRecord::Base.table_name_suffix
|
|
60
|
+
|
|
61
|
+
begin
|
|
62
|
+
yield
|
|
63
|
+
ensure
|
|
64
|
+
ActiveRecord::Base.table_name_prefix = ""
|
|
65
|
+
ActiveRecord::Base.table_name_suffix = ""
|
|
38
66
|
|
|
67
|
+
add_foreign_keys(foreign_keys) # Never raises.
|
|
68
|
+
|
|
69
|
+
ActiveRecord::Base.table_name_prefix = old_prefix if defined?(old_prefix)
|
|
70
|
+
ActiveRecord::Base.table_name_suffix = old_suffix if defined?(old_suffix)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def remove_foreign_keys(foreign_keys)
|
|
39
78
|
statements = foreign_keys.map do |foreign_key|
|
|
40
79
|
# We do not use the `#remove_foreign_key` method here because it
|
|
41
80
|
# checks for foreign keys existance in the schema cache. This method
|
|
@@ -45,48 +84,85 @@ module ActiveRecord
|
|
|
45
84
|
|
|
46
85
|
schema_creation.accept(at)
|
|
47
86
|
end
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
87
|
+
with_schema_unlocked(foreign_keys.flat_map { |fk| [fk.from_table, fk.to_table] }) do
|
|
88
|
+
execute_batch(statements, "Disable referential integrity -> remove foreign keys")
|
|
89
|
+
end
|
|
90
|
+
end
|
|
51
91
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
92
|
+
# NOTE: This method should never raise, otherwise we risk polluting table name
|
|
93
|
+
# prefixes and suffixes. The good thing is: if this happens, tests will crash
|
|
94
|
+
# hard, no way we miss it.
|
|
95
|
+
def add_foreign_keys(foreign_keys)
|
|
96
|
+
# We avoid using `foreign_key_exists?` here because it checks the schema cache
|
|
97
|
+
# for every key. This method is performance critical for the test suite, hence
|
|
98
|
+
# we use the `#all_foreign_keys` method that only make one query to the database.
|
|
99
|
+
already_inserted_foreign_keys = all_foreign_keys
|
|
100
|
+
foreign_keys_to_add = foreign_keys.reject do |foreign_key|
|
|
101
|
+
already_inserted_foreign_keys.any? { |fk| fk.from_table == foreign_key.from_table && fk.options[:name] == foreign_key.options[:name] }
|
|
102
|
+
end
|
|
103
|
+
statements = foreign_keys_to_add.map do |foreign_key|
|
|
104
|
+
options = foreign_key_options(foreign_key.from_table, foreign_key.to_table, foreign_key.options)
|
|
105
|
+
at = create_alter_table foreign_key.from_table
|
|
106
|
+
at.add_foreign_key foreign_key.to_table, options
|
|
57
107
|
|
|
58
|
-
|
|
59
|
-
|
|
108
|
+
schema_creation.accept(at)
|
|
109
|
+
end
|
|
110
|
+
with_schema_unlocked(foreign_keys_to_add.flat_map { |fk| [fk.from_table, fk.to_table] }) do
|
|
111
|
+
execute_batch(statements, "Disable referential integrity -> add foreign keys")
|
|
112
|
+
end
|
|
113
|
+
end
|
|
60
114
|
|
|
115
|
+
# Starting in CockroachDB v26.x, tables are created with the
|
|
116
|
+
# `schema_locked` storage parameter enabled by default (it improves
|
|
117
|
+
# changefeed performance). CockroachDB transparently unlocks a table to
|
|
118
|
+
# run a single-statement DDL, but it cannot do so for the multi-statement
|
|
119
|
+
# batches used to drop and re-add foreign keys above: it raises instead
|
|
120
|
+
# of unlocking automatically. So we unlock the affected tables ourselves,
|
|
121
|
+
# run the batch, then restore their locked state. Adding a foreign key
|
|
122
|
+
# also writes a back-reference into the referenced table, so callers must
|
|
123
|
+
# pass both the referencing and referenced tables.
|
|
124
|
+
#
|
|
125
|
+
# See https://www.cockroachlabs.com/docs/stable/schema-locked
|
|
126
|
+
def with_schema_unlocked(tables)
|
|
127
|
+
locked = schema_locked_tables(tables.uniq)
|
|
128
|
+
return yield if locked.empty?
|
|
129
|
+
|
|
130
|
+
set_schema_locked(locked, false)
|
|
61
131
|
begin
|
|
62
|
-
|
|
63
|
-
# TODO: verify that there is no cache issue related to running this (e.g: fk
|
|
64
|
-
# still in cache but not in db)
|
|
65
|
-
#
|
|
66
|
-
# We avoid using `foreign_key_exists?` here because it checks the schema cache
|
|
67
|
-
# for every key. This method is performance critical for the test suite, hence
|
|
68
|
-
# we use the `#all_foreign_keys` method that only make one query to the database.
|
|
69
|
-
already_inserted_foreign_keys = all_foreign_keys
|
|
70
|
-
statements = foreign_keys.map do |foreign_key|
|
|
71
|
-
next if already_inserted_foreign_keys.any? { |fk| fk.from_table == foreign_key.from_table && fk.options[:name] == foreign_key.options[:name] }
|
|
72
|
-
|
|
73
|
-
options = foreign_key_options(foreign_key.from_table, foreign_key.to_table, foreign_key.options)
|
|
74
|
-
at = create_alter_table foreign_key.from_table
|
|
75
|
-
at.add_foreign_key foreign_key.to_table, options
|
|
76
|
-
|
|
77
|
-
schema_creation.accept(at)
|
|
78
|
-
end
|
|
79
|
-
execute_batch(statements.compact, "Disable referential integrity -> add foreign keys")
|
|
132
|
+
yield
|
|
80
133
|
ensure
|
|
81
|
-
|
|
82
|
-
ActiveRecord::Base.table_name_suffix = old_suffix
|
|
134
|
+
set_schema_locked(locked, true)
|
|
83
135
|
end
|
|
84
136
|
end
|
|
85
137
|
|
|
86
|
-
|
|
138
|
+
# Returns the subset of +tables+ whose `schema_locked` storage parameter
|
|
139
|
+
# is currently enabled. CockroachDB exposes storage parameters through
|
|
140
|
+
# `pg_class.reloptions`. On versions (or configurations) that do not lock
|
|
141
|
+
# tables this returns an empty array, so callers stay on the fast path.
|
|
142
|
+
def schema_locked_tables(tables)
|
|
143
|
+
return [] if tables.empty?
|
|
144
|
+
|
|
145
|
+
locked = query_values(<<~SQL, "SCHEMA")
|
|
146
|
+
SELECT (CASE WHEN n.nspname = current_schema() THEN '' ELSE n.nspname || '.' END) || c.relname
|
|
147
|
+
FROM pg_class c
|
|
148
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
149
|
+
WHERE c.relkind = 'r' AND 'schema_locked=true' = ANY (c.reloptions)
|
|
150
|
+
SQL
|
|
151
|
+
tables & locked
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Toggles the `schema_locked` storage parameter for the given tables.
|
|
155
|
+
# CockroachDB only allows changing `schema_locked` in a single-statement
|
|
156
|
+
# implicit transaction, so unlike the foreign key statements above these
|
|
157
|
+
# cannot be batched together.
|
|
158
|
+
def set_schema_locked(tables, value)
|
|
159
|
+
tables.each do |table|
|
|
160
|
+
execute("ALTER TABLE #{quote_table_name(table)} SET (schema_locked = #{value})", "Toggle schema_locked")
|
|
161
|
+
end
|
|
162
|
+
end
|
|
87
163
|
|
|
88
|
-
# Copy/paste of the `#foreign_keys(table)` method adapted
|
|
89
|
-
# foreign key in the database.
|
|
164
|
+
# NOTE: Copy/paste of the `#foreign_keys(table)` method adapted
|
|
165
|
+
# to return every single foreign key in the database.
|
|
90
166
|
def all_foreign_keys
|
|
91
167
|
fk_info = internal_exec_query(<<~SQL, "SCHEMA")
|
|
92
168
|
SELECT CASE
|
|
@@ -99,14 +175,30 @@ module ActiveRecord
|
|
|
99
175
|
THEN ''
|
|
100
176
|
ELSE n2.nspname || '.'
|
|
101
177
|
END || t2.relname AS to_table,
|
|
102
|
-
|
|
103
|
-
|
|
178
|
+
c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid, c.condeferrable AS deferrable, c.condeferred AS deferred, c.conrelid, c.confrelid,
|
|
179
|
+
(
|
|
180
|
+
SELECT array_agg(a.attname ORDER BY idx)
|
|
181
|
+
FROM (
|
|
182
|
+
SELECT idx, c.conkey[idx] AS conkey_elem
|
|
183
|
+
FROM generate_subscripts(c.conkey, 1) AS idx
|
|
184
|
+
) indexed_conkeys
|
|
185
|
+
JOIN pg_attribute a ON a.attrelid = t1.oid
|
|
186
|
+
AND a.attnum = indexed_conkeys.conkey_elem
|
|
187
|
+
AND NOT a.attishidden
|
|
188
|
+
) AS conkey_names,
|
|
189
|
+
(
|
|
190
|
+
SELECT array_agg(a.attname ORDER BY idx)
|
|
191
|
+
FROM (
|
|
192
|
+
SELECT idx, c.confkey[idx] AS confkey_elem
|
|
193
|
+
FROM generate_subscripts(c.confkey, 1) AS idx
|
|
194
|
+
) indexed_confkeys
|
|
195
|
+
JOIN pg_attribute a ON a.attrelid = t2.oid
|
|
196
|
+
AND a.attnum = indexed_confkeys.confkey_elem
|
|
197
|
+
AND NOT a.attishidden
|
|
198
|
+
) AS confkey_names
|
|
104
199
|
FROM pg_constraint c
|
|
105
200
|
JOIN pg_class t1 ON c.conrelid = t1.oid
|
|
106
201
|
JOIN pg_class t2 ON c.confrelid = t2.oid
|
|
107
|
-
JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
|
|
108
|
-
JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
|
|
109
|
-
JOIN pg_namespace t3 ON c.connamespace = t3.oid
|
|
110
202
|
JOIN pg_namespace n1 ON t1.relnamespace = n1.oid
|
|
111
203
|
JOIN pg_namespace n2 ON t2.relnamespace = n2.oid
|
|
112
204
|
WHERE c.contype = 'f'
|
|
@@ -116,22 +208,16 @@ module ActiveRecord
|
|
|
116
208
|
fk_info.map do |row|
|
|
117
209
|
from_table = PostgreSQL::Utils.unquote_identifier(row["from_table"])
|
|
118
210
|
to_table = PostgreSQL::Utils.unquote_identifier(row["to_table"])
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if conkey.size > 1
|
|
123
|
-
column = column_names_from_column_numbers(row["conrelid"], conkey)
|
|
124
|
-
primary_key = column_names_from_column_numbers(row["confrelid"], confkey)
|
|
125
|
-
else
|
|
126
|
-
column = PostgreSQL::Utils.unquote_identifier(row["column"])
|
|
127
|
-
primary_key = row["primary_key"]
|
|
128
|
-
end
|
|
211
|
+
|
|
212
|
+
column = decode_string_array(row["conkey_names"])
|
|
213
|
+
primary_key = decode_string_array(row["confkey_names"])
|
|
129
214
|
|
|
130
215
|
options = {
|
|
131
|
-
column: column,
|
|
216
|
+
column: column.size == 1 ? column.first : column,
|
|
132
217
|
name: row["name"],
|
|
133
|
-
primary_key: primary_key
|
|
218
|
+
primary_key: primary_key.size == 1 ? primary_key.first : primary_key
|
|
134
219
|
}
|
|
220
|
+
|
|
135
221
|
options[:on_delete] = extract_foreign_key_action(row["on_delete"])
|
|
136
222
|
options[:on_update] = extract_foreign_key_action(row["on_update"])
|
|
137
223
|
options[:deferrable] = extract_constraint_deferrable(row["deferrable"], row["deferred"])
|