You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Oracle Database accepts the DEFERRABLE INITIALLY {DEFERRED | IMMEDIATE} / NOT DEFERRABLE clause on CHECK constraints (verified directly: ALTER TABLE t ADD CONSTRAINT c CHECK (...) DEFERRABLE INITIALLY DEFERRED). The state is persisted in all_constraints (deferrable, deferred columns) just like for FK and UNIQUE constraints.
This is an Oracle-specific extension — PostgreSQL explicitly disallows DEFERRABLE on CHECK constraints, MySQL and SQLite do not have the concept. Active Record core therefore does not expose deferrable: on add_check_constraint, and the existing CHECK-constraint integration added in #2717 does not surface it on the Oracle adapter either.
For Oracle-only applications, deferrable CHECK constraints are useful in the same scenarios deferrable FK / UNIQUE constraints are: bulk loading or migrations where intermediate states violate the predicate but the final state is consistent.
Scope
Mirror the FK and UNIQUE deferrable handling already in oracle-enhanced (since #2594 / #2701):
add_check_constraint :t, "expr", deferrable: :deferred, name: "..." accepts the option.
assert_valid_deferrable(deferrable) is reused to validate :deferred / :immediate / false / nil.
OracleEnhanced::SchemaCreation#visit_CheckConstraintDefinition overrides the Rails-abstract visitor (which emits just CONSTRAINT n CHECK (expr)) to append DEFERRABLE INITIALLY ... after the expression, parallel to how visit_ForeignKeyDefinition and visit_UniqueConstraintDefinition already do.
OracleEnhanced::SchemaStatements#check_constraints(table_name) reader extends the SQL to also select c.deferrable, c.deferred, and populates options[:deferrable] via the existing extract_foreign_key_deferrable helper.
OracleEnhanced::StructureDump#structure_dump_check_constraints extends the emitted DDL with the DEFERRABLE INITIALLY ... clause when applicable, so the SQL structure dump round-trips faithfully too.
check_constraints(table_name) returns the deferrable state.
db/schema.rb round-trips the option.
structure_dump emits the DEFERRABLE INITIALLY ... clause.
Out of scope
A general deferrable: option on the upstream Rails add_check_constraint. That would be a Rails-core change, not an oracle-enhanced one.
Interaction with validate: false — separate concern (tracked in the validate_constraint issue / follow-up PR).
Why now
#2717 just landed CHECK constraint support. The feature parity with FK / UC deferrable handling is the natural next step, and adding it now (while the check_constraints reader and visitor are fresh) keeps the change small.
Acceptance criteria
add_check_constraint :t, "expr", deferrable: :deferred emits CHECK (expr) DEFERRABLE INITIALLY DEFERRED and round-trips through check_constraints(table_name).
Background
Oracle Database accepts the
DEFERRABLE INITIALLY {DEFERRED | IMMEDIATE}/NOT DEFERRABLEclause on CHECK constraints (verified directly:ALTER TABLE t ADD CONSTRAINT c CHECK (...) DEFERRABLE INITIALLY DEFERRED). The state is persisted inall_constraints(deferrable,deferredcolumns) just like for FK and UNIQUE constraints.This is an Oracle-specific extension — PostgreSQL explicitly disallows DEFERRABLE on CHECK constraints, MySQL and SQLite do not have the concept. Active Record core therefore does not expose
deferrable:onadd_check_constraint, and the existing CHECK-constraint integration added in #2717 does not surface it on the Oracle adapter either.For Oracle-only applications, deferrable CHECK constraints are useful in the same scenarios deferrable FK / UNIQUE constraints are: bulk loading or migrations where intermediate states violate the predicate but the final state is consistent.
Scope
Mirror the FK and UNIQUE deferrable handling already in oracle-enhanced (since #2594 / #2701):
add_check_constraint :t, "expr", deferrable: :deferred, name: "..."accepts the option.assert_valid_deferrable(deferrable)is reused to validate:deferred/:immediate/false/nil.OracleEnhanced::SchemaCreation#visit_CheckConstraintDefinitionoverrides the Rails-abstract visitor (which emits justCONSTRAINT n CHECK (expr)) to appendDEFERRABLE INITIALLY ...after the expression, parallel to howvisit_ForeignKeyDefinitionandvisit_UniqueConstraintDefinitionalready do.OracleEnhanced::SchemaStatements#check_constraints(table_name)reader extends the SQL to also selectc.deferrable, c.deferred, and populatesoptions[:deferrable]via the existingextract_foreign_key_deferrablehelper.OracleEnhanced::StructureDump#structure_dump_check_constraintsextends the emitted DDL with theDEFERRABLE INITIALLY ...clause when applicable, so the SQL structure dump round-trips faithfully too.OracleEnhanced::SchemaDumperalready callscheck_constraints_in_create(since Wire up CHECK constraint DSL: add_check_constraint, t.check_constraint, dump round-trip #2717), and the abstract dumper'scheck_partswill pick updeferrable:automatically once the reader exposes it — but verify, and adjust ifcheck_partsfilters Oracle-specific options.Specs cover:
add_check_constraintwith each ofdeferrable: :deferred,:immediate, omitted (defaultfalse).add_check_constraintwithdeferrable: trueraisesArgumentError(matches FK/UC behaviour from Add deferrable foreign key support #2594 / Add unique constraint DSL matching PostgreSQL adapter #2701).check_constraints(table_name)returns the deferrable state.db/schema.rbround-trips the option.structure_dumpemits theDEFERRABLE INITIALLY ...clause.Out of scope
deferrable:option on the upstream Railsadd_check_constraint. That would be a Rails-core change, not an oracle-enhanced one.validate: false— separate concern (tracked in the validate_constraint issue / follow-up PR).Why now
#2717 just landed CHECK constraint support. The feature parity with FK / UC deferrable handling is the natural next step, and adding it now (while the
check_constraintsreader and visitor are fresh) keeps the change small.Acceptance criteria
add_check_constraint :t, "expr", deferrable: :deferredemitsCHECK (expr) DEFERRABLE INITIALLY DEFERREDand round-trips throughcheck_constraints(table_name).add_check_constraint :t, "expr", deferrable: :immediateemitsDEFERRABLE INITIALLY IMMEDIATEand round-trips.add_check_constraint :t, "expr"(no:deferrable) emits noDEFERRABLEclause andcc.deferrable == false.Depends on: #2716 (PR #2717) landing.