WIP: Support constraint enable clause on CREATE statements.#1147
WIP: Support constraint enable clause on CREATE statements.#1147c2main wants to merge 6 commits intoIvorySQL:masterfrom
Conversation
📝 WalkthroughWalkthroughAdds Oracle-style constraint-attribute parsing and handling: new lexer keyword NOVALIDATE, grammar nonterminal OraConstraintAttributeElem, CAS_* attribute bitflags, parser transforms to map ENABLE/DISABLE/VALIDATE/NOVALIDATE into enforcement/validation flags (with error checks), enum additions, and extensive regression tests. Changes
Sequence Diagram(s)sequenceDiagram
participant Lexer as Lexer (scanner)
participant Parser as Parser (ora_gram)
participant Transform as Transform (parse_utilcmd.c)
participant Catalog as Catalog (constraint builder)
Lexer->>Parser: emit tokens (ENABLE / DISABLE / VALIDATE / NOVALIDATE)
Parser->>Parser: parse OraConstraintAttributeElem -> produce CAS_* bits / CONSTR_ATTR_*
Parser->>Transform: pass ConstraintAttributeSpec with attribute codes
Transform->>Transform: processCASbits & transformConstraintAttrs -> map to ENFORCED/NOT_ENFORCED, set skip_validation/initially_valid, or raise errors
Transform->>Catalog: populate constraint descriptor (enforced/validated flags)
Transform-->>Parser: report semantic errors (if any)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/backend/oracle_parser/ora_gram.y (1)
22157-22302: CAS_ENABLE handling inprocessCASbitswipes other constraint attributes (e.g., DEFERRABLE)In
processCASbits, forPRIMARY KEY/UNIQUE/NOT NULLyou do:if (cas_bits & CAS_ENABLE) { cas_bits = 0; ereport(LOG, ...); }If a user writes something like:
PRIMARY KEY DEFERRABLE ENABLE UNIQUE DEFERRABLE ENABLE NOT NULL DEFERRABLE ENABLE -- via table constraint formthe CAS mask will contain both
CAS_DEFERRABLEandCAS_ENABLE. The above block zeroes all bits, silently discardingCAS_DEFERRABLE(and anyINITIALLY_*flags). The constraint ends up non‑deferrable, which is a behavioral bug rather than merely treatingENABLEas noise.You probably want to strip just the
CAS_ENABLEbit while preserving others:if (cas_bits & CAS_ENABLE) { cas_bits &= ~CAS_ENABLE; ereport(LOG, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("%s ENABLE is the default.", constrType), errhint("Update your %s CONSTRAINT definition.", constrType), parser_errposition(location))); }Same consideration applies if more masking like this is added later; keep the non‑Oracle flags intact.
Also applies to: 141-155
🧹 Nitpick comments (5)
src/oracle_test/regress/sql/constraints.sql (1)
1044-1366: Comprehensive test coverage for constraint ENABLE/DISABLE syntax.The test suite thoroughly exercises all constraint types (PRIMARY KEY, UNIQUE, CHECK, NOT NULL) with all ENABLE/DISABLE and VALIDATE/NOVALIDATE combinations. The pattern of creating tables and querying pg_constraint to verify enforcement and validation flags is appropriate for regression testing.
Minor suggestion for clarity:
The comments "Not supported" and "Not supported - XXX NOT VALID supported on ALTER TABLE" could be more explicit about expected behavior. Consider clarifying whether these cases should:
- Produce an error with a HINT message
- Silently treat NOVALIDATE as unsupported
- Create the constraint with specific flag values
This would help future maintainers understand the intended behavior.
src/oracle_test/regress/expected/foreign_key.out (1)
3408-3625: fkpart14 FK ENABLE/DISABLE tests look correct and completeThe new fkpart14 block exercises foreign key
ENABLE/DISABLEwithVALIDATE/NOVALIDATEacross inline, column, and named FKs, and the expectedpg_constraintflags and error/HINT combinations all align with the documented mapping:
ENABLE/ENABLE VALIDATE→conenforced = t,convalidated = t.DISABLE/DISABLE NOVALIDATE→conenforced = f,convalidated = f.ENABLE NOVALIDATEandDISABLE VALIDATE→ explicit “FOREIGN KEY … is not supported” errors with a HINT and no leftover constraints.If you want even stronger coverage, you could optionally add a tiny DML snippet to confirm that a
DISABLE [NOVALIDATE]FK indeed allows inserting non-matching rows and thatENABLEstill enforces, but that’s already well-covered earlier in this file and not strictly necessary here.src/oracle_test/regress/expected/constraints.out (1)
1692-2311: CREATE TABLE ENABLE/DISABLE constraint tests are thorough and consistentThe
ivo_regress_enableblock does a good job of:
- Exercising
ENABLE/DISABLEwithVALIDATE/NOVALIDATEacross PRIMARY KEY, UNIQUE, CHECK, and NOT NULL, in both column and table-constraint forms.- Verifying that supported forms map to the intended
conenforced/convalidatedcombinations and that unsupported forms yield clear, type-specific “<TYPE> <STATE> is not supported.” errors with a HINT and no residual constraints inpg_constraint.- Including an explicit syntax error case (
id NUMBER ENABLE) plus cleanup viaDROP SCHEMA … CASCADEandRESET search_path;.One small optional polish: for cases like
PRIMARY KEY DISABLE NOVALIDATEandNOT NULL DISABLE NOVALIDATE, you might consider mentioningDISABLE NOVALIDATEexplicitly in the error text (rather than justDISABLE) to more directly reflect the user’s input, but the current behavior is functionally fine.src/backend/oracle_parser/ora_gram.y (2)
6644-6692: ENABLE/DISABLE grammar now applies to allConstraintAttributeSpecusers (ALTER, DOMAIN, TRIGGER)By:
- Extending
%typeto includeOraConstraintAttributeElem(line 615),- Adding
OraConstraintAttributeElemintoConstraintAttributeElemand as its own alternative inConstraintAttributeSpec(lines 6644–6683),- Introducing the
OraConstraintAttributeElemnonterminal andNOVALIDATEkeyword (lines 6685–6692, 781–782),the
{ ENABLE | DISABLE } [ VALIDATE | NOVALIDATE ]syntax is now accepted anywhereConstraintAttributeSpecis used, not just in CREATE-table/column constraints. That includes:
ALTER TABLE ... ALTER CONSTRAINT ... ConstraintAttributeSpecCREATE DOMAIN/ALTER DOMAINconstraintsCREATE CONSTRAINT TRIGGER ... ConstraintAttributeSpecThis is broader than the PR description (“currently applies only to CREATE statements; ALTER and DOMAIN are not supported”), and some of these combinations hit generic
processCASbitserrors like “%s constraints cannot be marked ENFORCED/NOT ENFORCED”, which may be surprising to users of the new syntax.If the intent is truly “CREATE only”, consider:
- Using a separate nonterminal (e.g.
OraConstraintAttributeSpec) wired only into the CREATE‑time constraint productions, or- Guarding unsupported call sites early (e.g. reject any CAS_ENABLE/CAS_DISABLE bits when
constrTypeis"TRIGGER"or invoked from ALTER/DOMAIN paths) with a clear Oracle‑style error/HINT.Otherwise, please update the PR docs/tests to explicitly call out that ALTER/DOMAIN also accept the syntax and verify the behavior you want at those sites.
Also applies to: 615-615, 781-782
4278-4482: Column-levelENABLE/DISABLE [NO]VALIDATEbehavior looks consistent, but a few edge cases need decisionsThe new
OraConstraintAttributeElemusages inColConstraintElem:
NOT NULL_P OraConstraintAttributeElemUNIQUE ... OraConstraintAttributeElemPRIMARY KEY ... OraConstraintAttributeElemCHECK (...) opt_no_inherit OraConstraintAttributeElemREFERENCES ... key_actions OraConstraintAttributeElemplus the updated
processCASbitsgive:
REFERENCES ... DISABLE NOVALIDATE→is_enforced = false,skip_validation = true,initially_valid = false(as desired for “not enforced, not validated”).CHECK ... DISABLE NOVALIDATE→ same pattern withis_enforced = falseandinitially_valid = false.PRIMARY KEY|UNIQUE|NOT NULL ... DISABLE[*]→ hard error (“... DISABLE is not supported”) as per the PR text.PRIMARY KEY|UNIQUE|NOT NULL ... ENABLE[*]→ treated as redundant, logged, and ignored.Two things to lock down:
Plain
DISABLEvsDISABLE NOVALIDATEfor CHECK/FK
Right now both map toCAS_DISABLE(i.e., treated as “NOT ENFORCED and NOT VALID”). If you intend to mirror Oracle’s distinction betweenDISABLE VALIDATEandDISABLE NOVALIDATE, you might at least want to:
- Continue erroring on
DISABLE VALIDATE(as you do now), and- Decide whether bare
DISABLEshould be an alias forDISABLE NOVALIDATE(current behavior) or be rejected as ambiguous.Column-level NOT NULL with ENABLE syntax
NOT NULL ENABLEis accepted but only logged atLOGlevel and treated identically to bareNOT NULL. If you want users to see that ENABLE is redundant/Oracle‑only, consider WARNING/NOTICE instead of LOG, or just silently ignore it and document as accepted Oracle noise.These are more semantics/UX than correctness issues, but clarifying them now will prevent surprising behavior once people start relying on the Oracle compatibility layer.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/backend/oracle_parser/ora_gram.ysrc/include/oracle_parser/ora_kwlist.hsrc/oracle_test/regress/expected/constraints.outsrc/oracle_test/regress/expected/foreign_key.outsrc/oracle_test/regress/sql/constraints.sqlsrc/oracle_test/regress/sql/foreign_key.sql
🧰 Additional context used
📓 Path-based instructions (2)
**/sql/*.sql
⚙️ CodeRabbit configuration file
**/sql/*.sql: Test SQL files. Ensure comprehensive coverage of features.
Files:
src/oracle_test/regress/sql/constraints.sqlsrc/oracle_test/regress/sql/foreign_key.sql
**/expected/*.out
⚙️ CodeRabbit configuration file
**/expected/*.out: These are expected test outputs from pg_regress. Review for:
- Correctness of query results
- Proper Oracle compatibility behavior
- Edge case coverage
- Consistency with corresponding .sql test files
Files:
src/oracle_test/regress/expected/constraints.outsrc/oracle_test/regress/expected/foreign_key.out
🔇 Additional comments (2)
src/include/oracle_parser/ora_kwlist.h (1)
357-357: LGTM! Keyword addition is correct.The NOVALIDATE keyword is properly added in alphabetical order with appropriate categorization (UNRESERVED_KEYWORD, BARE_LABEL), consistent with similar constraint-related keywords.
src/oracle_test/regress/sql/foreign_key.sql (1)
2390-2516: LGTM! Comprehensive foreign key constraint testing.The test suite provides thorough coverage of foreign key constraint syntax with ENABLE/DISABLE and VALIDATE/NOVALIDATE attributes across three different declaration forms:
- Inline REFERENCES
- FOREIGN KEY clause
- CONSTRAINT FOREIGN KEY clause
The systematic testing of all six combinations (ENABLE, ENABLE VALIDATE, ENABLE NOVALIDATE, DISABLE, DISABLE VALIDATE, DISABLE NOVALIDATE) for each form ensures consistent behavior. The verification pattern using pg_constraint queries is appropriate for validating the conenforced and convalidated flags.
As per coding guidelines, test SQL files should ensure comprehensive coverage of features—this test block achieves that goal for foreign key constraints.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/include/nodes/parsenodes.h (1)
332-339: OraParamRef node support infrastructure is missing critical functionsAdding
ParseLoc locationandchar *nametoOraParamRefrequires implementing support in all node infrastructure functions (copy, equal, read, write, and query-jumbling). Currently, there are no references to OraParamRef in any of these support files (copyfuncs.c, readfuncs.c, outfuncs.c, equalfuncs.c, queryjumblefuncs.c), which will cause parse trees containing Oracle parameters to fail serialization, comparison, and cloning operations.Ensure the code generator (gen_node_support.pl) properly processes OraParamRef and generates the necessary support functions, or add them manually to all node infrastructure files.
src/backend/oracle_parser/ora_gram.y (1)
2920-2942: ALTER CONSTRAINT with ENABLE/DISABLE doesn’t mark alterEnforceabilityIn:
if ($4 & (CAS_NOT_ENFORCED | CAS_ENFORCED)) c->alterEnforceability = true; ... processCASbits($4, @4, "FOREIGN KEY", &c->deferrable, &c->initdeferred, &c->is_enforced, NULL, &c->noinherit, yyscanner);
$4can now containCAS_ENABLE/CAS_DISABLE(fromOraConstraintAttributeElem), which are only converted toCAS_ENFORCED/CAS_NOT_ENFORCEDinsideprocessCASbits(). As a result:
ALTER TABLE .. ALTER CONSTRAINT .. ENABLE [VALIDATE|NOVALIDATE]ALTER TABLE .. ALTER CONSTRAINT .. DISABLE [VALIDATE|NOVALIDATE]will populate
c->is_enforcedviaprocessCASbits(), butc->alterEnforceabilityremainsfalse, so downstream code that keys offalterEnforceabilitymay ignore the enforcement change.You likely need to treat
CAS_ENABLE/CAS_DISABLEas enforcement-changing here, e.g.:- if ($4 & (CAS_NOT_ENFORCED | CAS_ENFORCED)) + if ($4 & (CAS_NOT_ENFORCED | CAS_ENFORCED | CAS_ENABLE | CAS_DISABLE)) c->alterEnforceability = true;Without this, the new Oracle-style
ENABLE/DISABLEsyntax forALTER CONSTRAINTis parsed but may be a no-op at execution time.
🤖 Fix all issues with AI agents
In @src/backend/parser/parse_utilcmd.c:
- Around line 4304-4310: The error path that checks lastprimarycon and raises
ERROR for DISABLE on unsupported constraint types (the ereport(...) call
referencing lastprimarycon and con->location) is missing the helpful errhint;
modify that ereport to include an errhint() suggesting the user update the
constraint definition to remove the DISABLE clause (for example: "Update the
constraint definition without the DISABLE clause, e.g. ALTER TABLE ... ADD
CONSTRAINT ... (omit DISABLE)"). Ensure the errhint text matches the style used
in other DISABLE error paths.
- Around line 4241-4274: The ENABLE branch handling CONSTR_ATTR_ENABLE contains
an unreachable inner `if (con->skip_validation)` block because earlier it errors
when `con->skip_validation` is true; remove the dead block (the inner `if
(con->skip_validation)` that sets `lastprimarycon->skip_validation` and
`lastprimarycon->initially_valid`) from the CONSTR_ATTR_ENABLE case in
parse_utilcmd so the code no longer contains unreachable statements, or
alternatively, if ENABLE NOVALIDATE must be supported, restructure the earlier
guard that raises the error on `con->skip_validation` to allow controlled
handling here and adjust `con->contype`/`saw_enforced` logic accordingly.
🧹 Nitpick comments (9)
src/include/nodes/parsenodes.h (3)
1765-1776: MergeWhenClauseupdate_deletelinkageThe
update_deleteself-pointer onMergeWhenClauseis a reasonable way to represent Oracle-styleUPDATE ... DELETEcombinations. Just ensure this new field is included in copy/equal/read/write support forMergeWhenClauseso rules and stored queries round-trip correctly.
3250-3260: CreateSeqStmtseq_typesemantics should be documentedThe new
char seq_typeflag (“is oracle compatible type or original type”) is fine structurally, but it would benefit from a clearer comment describing the allowed values and their meaning (e.g., which char indicates Oracle-compatible behavior vs native). That will avoid future ambiguity when interpreting this field.
3611-3655: New DO / InlineCodeBlock / CALL fields: check lifecycle and node supportThe additions:
DoStmt.paramsmode/DoStmt.paramslenInlineCodeBlock.paramsCallStmt.hostvariableandCallStmt.callintoall look consistent with extending PL/SQL-style call/DO support. A few points to verify:
InlineCodeBlockandCallStmtare used outside parse trees at execution time; ensure ownership/lifetime ofParamListInfo paramsandOraParamRef *hostvariableis clear so there are no dangling pointers.- Confirm all three structs are updated in copy/equal/read/write helpers as appropriate (for
DoStmtandCallStmt, which are parse nodes;InlineCodeBlockis taggednodetag_onlybut still flows through some infrastructure).src/backend/commands/typecmds.c (1)
1032-1040: Domain constraint switch correctly rejects ENABLE/DISABLE attributesExtending the
DefineDomainconstraint-type switch to includeCONSTR_ATTR_ENABLEandCONSTR_ATTR_DISABLEalongsideCONSTR_ATTR_ENFORCED/CONSTR_ATTR_NOT_ENFORCEDensures that Oracle-styleENABLE/DISABLEattributes on domains are rejected consistently, which aligns with the stated “not supported for domains” behavior.If you want to be extra explicit for Oracle users, you might consider slightly broadening the error text (e.g., mention ENABLE/DISABLE in the message or HINT), but the current wording is functionally correct.
src/oracle_test/regress/sql/foreign_key.sql (1)
2390-2558: Consider adding DML operations to verify actual constraint behavior.The fkpart14 test block comprehensively tests the syntax and metadata storage for FK constraints with ENABLE/DISABLE/VALIDATE/NOVALIDATE clauses. However, it only queries
pg_constraintto verify the flags—it doesn't verify that the constraints actually enforce (or don't enforce) the expected behavior through INSERT/UPDATE/DELETE operations.💡 Suggested enhancement
Consider adding DML verification for at least a few representative cases. For example:
-- After creating ENABLE constraint INSERT INTO fk_r VALUES (1, 'test'); INSERT INTO fk_p1 VALUES (1, 'valid'); -- should succeed INSERT INTO fk_p1 VALUES (999, 'invalid'); -- should fail -- After creating DISABLE constraint INSERT INTO fk_p4 VALUES (999, 'invalid'); -- should succeed (not enforced) -- Clean up DELETE FROM fk_p1; DELETE FROM fk_p4; DELETE FROM fk_r;This would provide functional validation in addition to the metadata checks.
As per coding guidelines, these are SQL test files that should ensure comprehensive coverage of features.
src/backend/parser/parse_utilcmd.c (1)
4311-4316: Inconsistent error formatting for duplicate clause detection.The error for multiple ENABLE/DISABLE clauses includes an
errhintin the DISABLE case (line 4315-4316) but not in the ENABLE case (line 4264). For consistency, either both should have the hint or neither should.🔧 Proposed fix: Remove unnecessary hint for consistency
if (saw_enforced) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple ENABLE/DISABLE clauses not allowed"), - errhint("Update your CONSTRAINT definition."), parser_errposition(cxt->pstate, con->location)));src/backend/oracle_parser/ora_gram.y (3)
4568-4627: ENABLE/DISABLE [NO]VALIDATE ConstraintAttr semantics need downstream handlingThe new
ConstraintAttrvariants for:
ENABLE [VALIDATE|NOVALIDATE]DISABLE [VALIDATE|NOVALIDATE]populate
contype = CONSTR_ATTR_ENABLE/DISABLEplusskip_validationandinitially_valid. This is reasonable, but behavior depends on parse/analyze code actually interpreting these fields forCONSTR_ATTR_ENABLE/CONSTR_ATTR_DISABLE(e.g., inparse_utilcmd.c).If downstream still only looks at the legacy
CONSTR_ATTR_[NOT_]DEFERRABLE/...values, these new attributes may be silently ignored.Consider:
- Verifying that all
Constraint-attribute handling switch statements cover the newCONSTR_ATTR_ENABLE/CONSTR_ATTR_DISABLEvariants.- Adding a defensive
default:in such switches that errors if an unsupported attribute contype is seen, to avoid silent no-ops.Would you like me to generate a small
rg/ast-grepscript to scan forCONSTR_ATTR_usages and confirm all cases handle the new values?
6733-6750: OraConstraintAttributeElem → CAS_ mapping is fine but lacks conflict checks*Mapping:
ENABLE→CAS_ENABLEDISABLE→CAS_DISABLEVALIDATE→CAS_VALIDATE(no-op, default)NOVALIDATE→CAS_NOVALIDATEis straightforward and works with later
processCASbits()remapping. However,ConstraintAttributeSpec’s conflict checks only look atCAS_NOT_DEFERRABLE/DEFERRABLE,CAS_INITIALLY_*, andCAS_NOT_ENFORCED/ENFORCED, so combinations likeENABLE DISABLEorENFORCED DISABLEare not detected there and currently rely entirely onprocessCASbits()behavior.Given the PR description mentions future tests for “duplicate/opposite clauses”, it may be worth:
- Either adding explicit conflict checks for CAS_ENABLE/CAS_DISABLE and CAS_VALIDATE/CAS_NOVALIDATE in
ConstraintAttributeSpec, or- Documenting that these combinations are undefined for now so tests don’t accidentally rely on the current behavior.
22201-22345: processCASbits: ENABLE/DISABLE/[NO]VALIDATE mapping mostly correct, but be careful with unsupported callersThe updated
processCASbits():
- Maps:
CAS_ENABLE→CAS_ENFORCEDCAS_DISABLE→CAS_NOT_ENFORCEDCAS_NOVALIDATE→CAS_NOT_VALID- Issues Oracle-style errors/hints when:
NOVALIDATEorDISABLEare used on constraint types that don’t support NOT VALID or NOT ENFORCED.The main semantic points look good, but there are a couple of edge considerations:
- Callers that pass
NULLforis_enforcedornot_validnow rely on the newif (cas_bits & CAS_DISABLE)/if (cas_bits & CAS_NOVALIDATE)branches for error reporting. That’s fine, but it means any future caller added withNULLpointers will get Oracle-style error text by default, which might not always be desired.- There is no second-stage conflict check after
CAS_ENABLE/CAS_DISABLEare mapped toCAS_ENFORCED/CAS_NOT_ENFORCED, so combinations likeENABLE DISABLEorENFORCED DISABLEend up with both bits set but are not flagged here (only plainENFORCEDvsNOT ENFORCEDconflicts are blocked inConstraintAttributeSpec). If you care about rejecting such opposite combinations, you may want a small consistency check after the CAS_ENABLE/DISABLE remap.Overall the mapping is consistent, but it would be good to:
- Audit all
processCASbitscall sites to ensure that combinations ofENABLE/DISABLE/[NO]VALIDATEeither have supported pointer fields or get the desired error behavior.- Optionally add a post-remap assertion for
(CAS_ENFORCED | CAS_NOT_ENFORCED)being non-conflicting if you want to hard-fail on contradictory specs.Would you like a quick grep-based script to list all
processCASbits(call sites and summarize which boolean pointer arguments are NULL vs non-NULL?
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/backend/commands/typecmds.csrc/backend/oracle_parser/ora_gram.ysrc/backend/parser/parse_utilcmd.csrc/include/nodes/parsenodes.hsrc/oracle_test/regress/expected/constraints.outsrc/oracle_test/regress/expected/foreign_key.outsrc/oracle_test/regress/sql/constraints.sqlsrc/oracle_test/regress/sql/foreign_key.sql
🚧 Files skipped from review as they are similar to previous changes (2)
- src/oracle_test/regress/expected/foreign_key.out
- src/oracle_test/regress/sql/constraints.sql
🧰 Additional context used
📓 Path-based instructions (2)
**/sql/*.sql
⚙️ CodeRabbit configuration file
**/sql/*.sql: Test SQL files. Ensure comprehensive coverage of features.
Files:
src/oracle_test/regress/sql/foreign_key.sql
**/expected/*.out
⚙️ CodeRabbit configuration file
**/expected/*.out: These are expected test outputs from pg_regress. Review for:
- Correctness of query results
- Proper Oracle compatibility behavior
- Edge case coverage
- Consistency with corresponding .sql test files
Files:
src/oracle_test/regress/expected/constraints.out
🔇 Additional comments (12)
src/include/nodes/parsenodes.h (5)
765-790: ColumnDefis_invisiblefield placement looks fineAppending
bool is_invisibleafterlocationis consistent with the rest of the struct and matches the comment semantics for invisible columns. GivenmakeNode(ColumnDef)zero-initializes memory, the defaultfalsebehavior for existing callers is preserved.
2201-2229: SelectStmtvaluesIsrowflagThe new
bool valuesIsrowflag is a clean way to distinguish row-valuedVALUESforms. Since nodes are zeroed on allocation, existing code will seefalseby default. As with other new fields, please confirm it’s wired into outfuncs/readfuncs/equalfuncs forSelectStmt.
2512-2527: AlterTableCmdis_rowidextensionIntroducing
bool is_rowidonAlterTableCmdis structurally safe (zero-initialized, placed at the end). Behavior-wise, just confirm all construction sites that need this set it explicitly, and that node serialization/deserialization forAlterTableCmdwas updated where necessary.
2823-2844: ConstrType enum extension for ENABLE/DISABLE is consistentAdding
CONSTR_ATTR_ENABLEandCONSTR_ATTR_DISABLEat the end ofConstrTypepreserves existing numeric values and is an appropriate place for new constraint-attribute kinds. The corresponding handling inDefineDomain(in typecmds.c) routes these to the same error path as other enforceability attributes, which matches the stated behavior of rejecting ENABLE/DISABLE on domains.Please also ensure all other
switch (ConstrType ...)sites (e.g., in parser/transform and utility code, plus outfuncs/readfuncs) are updated to either handle or explicitly reject these new enum values.
4381-4474: FixACCESSOR_UNKNOWtypo toACCESSOR_UNKNOWNThe enum constant
ACCESSOR_UNKNOWat line 4388 is misspelled and should beACCESSOR_UNKNOWNbefore this becomes part of the stable API. If backward compatibility with the misspelling is needed, keep the misspelled name as a deprecated alias.Verify that the new node types (
AccessorItem,AccessibleByClause,CompileFunctionStmt,ColumnRefOrFuncCall,CreatePackageStmt,CreatePackageBodyStmt,AlterPackageStmt) are fully integrated into node infrastructure functions including copy, equal, read/write, and query-jumble support to ensure packages and accessibility clauses serialize correctly through views and stored rules.src/oracle_test/regress/expected/constraints.out (2)
2449-2458: LGTM: Correct NOT VALID behavior for ALTER TABLE ADD.The test correctly shows that
ALTER TABLE ADD CHECK ... ENABLE NOVALIDATEcreates an enforced but not-validated constraint (conenforced = t, convalidated = f). This aligns with PostgreSQL's support for adding NOT VALID constraints via ALTER TABLE, which allows existing data to violate the constraint while preventing new violations.This differs from the CREATE TABLE behavior (line 2021) where
ENABLE NOVALIDATEcreates a fully validated constraint, which is appropriate since there's no existing data at table creation time.Based on coding guidelines for test expected outputs, this correctly demonstrates proper Oracle compatibility behavior.
1991-2121: The inconsistency between CONSTRAINT CHECK and inline CHECK behavior is real but appears intentional.The test output correctly reflects the current implementation where:
- CONSTRAINT CHECK accepts
ENABLE NOVALIDATEandDISABLE VALIDATE(succeeds, creates constraint)- Inline CHECK rejects both with "not supported" errors
Per the commit message for this WIP (1516fdb), this is acknowledged as a "hack" while reworking ENABLE/DISABLE handling. The constraint attribute handling differs between named and inline constraints by design during this refactoring phase. The test expectations are accurate for the current behavior, and the error messages properly guide users.
Consider whether this inconsistency should be unified in the final implementation or documented as a temporary limitation while the rework is in progress.
src/backend/parser/parse_utilcmd.c (2)
1105-1108: LGTM!The fallthrough cases for
CONSTR_ATTR_ENABLEandCONSTR_ATTR_DISABLEcorrectly follow the established pattern for other constraint attributes that are preprocessed bytransformConstraintAttrs.
1248-1252: LGTM!Correctly errors out when
CONSTR_ATTR_ENABLEorCONSTR_ATTR_DISABLEappears as a standalone table constraint, consistent with handling of other constraint attributes.src/backend/oracle_parser/ora_gram.y (3)
141-156: CAS_ bitmask extension looks structurally sound*The new CAS_ENABLE/CAS_DISABLE/CAS_VALIDATE/CAS_NOVALIDATE bits extend the existing flag space cleanly (no overlap, still within an
int), and the comment separation (“extra syntax”) makes the intent clear. No issues here.
614-615: OraConstraintAttributeElem correctly wired into ConstraintAttributeSpecAdding
OraConstraintAttributeElemto the%typeand toConstraintAttributeSpeckeeps all attribute forms flowing through the same bitmask path, which is whatprocessCASbits()expects. This is the right integration point.
780-781: NOVALIDATE keyword categorization is consistentRegistering
NOVALIDATEas anunreserved_keywordandbare_label_keywordallows it to be used in constraint-attribute positions while remaining available as an identifier where needed, consistent with how similar attribute words are treated. No parser-category conflicts are apparent.Also applies to: 20463-20465, 21163-21165
| case CONSTR_ATTR_ENABLE: | ||
| if (con->skip_validation) | ||
| ereport(ERROR, | ||
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | ||
| errmsg("ENABLE NOVALIDATE clause is not supported"), | ||
| errhint("Update your CONSTRAINT definition."), | ||
| parser_errposition(cxt->pstate, con->location))); | ||
|
|
||
| if (lastprimarycon == NULL || | ||
| (lastprimarycon->contype != CONSTR_PRIMARY && | ||
| lastprimarycon->contype != CONSTR_CHECK && | ||
| lastprimarycon->contype != CONSTR_UNIQUE && | ||
| lastprimarycon->contype != CONSTR_NOTNULL && | ||
| lastprimarycon->contype != CONSTR_FOREIGN)) | ||
| { | ||
| ereport(ERROR, | ||
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | ||
| errmsg("misplaced ENABLE clause"), | ||
| parser_errposition(cxt->pstate, con->location))); | ||
| } | ||
| if (saw_enforced) | ||
| ereport(ERROR, | ||
| (errcode(ERRCODE_SYNTAX_ERROR), | ||
| errmsg("multiple ENABLE/DISABLE clauses not allowed"), | ||
| parser_errposition(cxt->pstate, con->location))); | ||
| con->contype = CONSTR_ATTR_ENFORCED; | ||
| saw_enforced = true; | ||
| lastprimarycon->is_enforced = true; | ||
| if (con->skip_validation) | ||
| { | ||
| lastprimarycon->skip_validation = true; | ||
| lastprimarycon->initially_valid = false; | ||
| } | ||
| break; |
There was a problem hiding this comment.
Dead code: the skip_validation block at lines 4269-4273 is unreachable.
The check at line 4242 already errors out if con->skip_validation is true (for "ENABLE NOVALIDATE"). Therefore, when execution reaches line 4269, con->skip_validation is guaranteed to be false, making the entire block dead code.
Either:
- Remove the dead code block (lines 4269-4273), or
- If ENABLE NOVALIDATE should be supported in certain cases, the logic needs restructuring
🔧 Proposed fix: Remove dead code
con->contype = CONSTR_ATTR_ENFORCED;
saw_enforced = true;
lastprimarycon->is_enforced = true;
- if (con->skip_validation)
- {
- lastprimarycon->skip_validation = true;
- lastprimarycon->initially_valid = false;
- }
break;🤖 Prompt for AI Agents
In @src/backend/parser/parse_utilcmd.c around lines 4241 - 4274, The ENABLE
branch handling CONSTR_ATTR_ENABLE contains an unreachable inner `if
(con->skip_validation)` block because earlier it errors when
`con->skip_validation` is true; remove the dead block (the inner `if
(con->skip_validation)` that sets `lastprimarycon->skip_validation` and
`lastprimarycon->initially_valid`) from the CONSTR_ATTR_ENABLE case in
parse_utilcmd so the code no longer contains unreachable statements, or
alternatively, if ENABLE NOVALIDATE must be supported, restructure the earlier
guard that raises the error on `con->skip_validation` to allow controlled
handling here and adjust `con->contype`/`saw_enforced` logic accordingly.
There was a problem hiding this comment.
@c2main
Hi, Cederic, I agree with codeRabbit about the dead code here. They should be removed.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
There was a problem hiding this comment.
to be revisited, depends on how strong we want to allow NOVALIDATE on CREATE statements.
| if (lastprimarycon == NULL || | ||
| (lastprimarycon->contype != CONSTR_CHECK && | ||
| lastprimarycon->contype != CONSTR_FOREIGN)) | ||
| ereport(ERROR, | ||
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | ||
| errmsg("DISABLE clause is not supported"), | ||
| parser_errposition(cxt->pstate, con->location))); |
There was a problem hiding this comment.
Missing HINT for unsupported constraint types with DISABLE.
Per the PR objectives, PRIMARY KEY ... DISABLE should "return an error and HINT to update the constraint definition." However, the current error message for DISABLE on unsupported constraint types (PRIMARY, UNIQUE, NOTNULL) lacks the errhint() that other error paths include.
🔧 Proposed fix: Add helpful hint
if (lastprimarycon == NULL ||
(lastprimarycon->contype != CONSTR_CHECK &&
lastprimarycon->contype != CONSTR_FOREIGN))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("DISABLE clause is not supported"),
+ errmsg("DISABLE clause is not supported for this constraint type"),
+ errhint("Update your CONSTRAINT definition to remove the DISABLE clause."),
parser_errposition(cxt->pstate, con->location)));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (lastprimarycon == NULL || | |
| (lastprimarycon->contype != CONSTR_CHECK && | |
| lastprimarycon->contype != CONSTR_FOREIGN)) | |
| ereport(ERROR, | |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | |
| errmsg("DISABLE clause is not supported"), | |
| parser_errposition(cxt->pstate, con->location))); | |
| if (lastprimarycon == NULL || | |
| (lastprimarycon->contype != CONSTR_CHECK && | |
| lastprimarycon->contype != CONSTR_FOREIGN)) | |
| ereport(ERROR, | |
| (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | |
| errmsg("DISABLE clause is not supported for this constraint type"), | |
| errhint("Update your CONSTRAINT definition to remove the DISABLE clause."), | |
| parser_errposition(cxt->pstate, con->location))); |
🤖 Prompt for AI Agents
In @src/backend/parser/parse_utilcmd.c around lines 4304 - 4310, The error path
that checks lastprimarycon and raises ERROR for DISABLE on unsupported
constraint types (the ereport(...) call referencing lastprimarycon and
con->location) is missing the helpful errhint; modify that ereport to include an
errhint() suggesting the user update the constraint definition to remove the
DISABLE clause (for example: "Update the constraint definition without the
DISABLE clause, e.g. ALTER TABLE ... ADD CONSTRAINT ... (omit DISABLE)"). Ensure
the errhint text matches the style used in other DISABLE error paths.
|
Hi, Cedric, I'm looking at this PR and will provide feedback. Thanks! |
| if (saw_enforced) | ||
| ereport(ERROR, | ||
| (errcode(ERRCODE_SYNTAX_ERROR), | ||
| errmsg("multiple ENABLE/DISABLE clauses not allowed"), |
There was a problem hiding this comment.
In the case of CONSTR_ATTR_ENFORCED, the saw_enforced is set as true.
So, if both ENABLE and ENFORCED appear in statement, the errmsg here "multiple ENABLE/DISABLE clauses not allowed" become misleading. Should we use a new flag to replace saw_enforced?
| (errcode(ERRCODE_SYNTAX_ERROR), | ||
| errmsg("multiple ENABLE/DISABLE clauses not allowed"), | ||
| parser_errposition(cxt->pstate, con->location))); | ||
| con->contype = CONSTR_ATTR_ENFORCED; |
There was a problem hiding this comment.
why is con->contype here not CONSTR_ATTR_ENABLE?
There was a problem hiding this comment.
it is when entering this case but it then looks easier to assume this CONST_ATTR_ENABLE is transient, only the time to assign CONSTR_ATTR_ENFORCED. It allowed me not to have to inspect other logic related to contype value.
1516fdb to
90691f2
Compare
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/backend/oracle_parser/ora_gram.y (2)
2928-2933:⚠️ Potential issue | 🟠 MajorALTER CONSTRAINT ENABLE/DISABLE won’t flip enforceability.
Line 2928 only checks
CAS_NOT_ENFORCED | CAS_ENFORCED, soENABLE/DISABLEwon’t setalterEnforceabilityand can be ignored downstream.🐛 Proposed fix
- if ($4 & (CAS_NOT_ENFORCED | CAS_ENFORCED)) + if ($4 & (CAS_NOT_ENFORCED | CAS_ENFORCED | CAS_ENABLE | CAS_DISABLE)) c->alterEnforceability = true;
6706-6725:⚠️ Potential issue | 🟠 MajorAdd conflict checks for ENABLE/DISABLE and VALIDATE/NOVALIDATE.
ConstraintAttributeSpeconly detects deferrable/enforced conflicts. WithOraConstraintAttributeElem, contradictory pairs (e.g.,ENABLE+DISABLE,ENABLE+NOT ENFORCED,VALIDATE+NOVALIDATE) can slip through and become “last wins.”🐛 Proposed fix
- int newspec = $1 | $2; + int newspec = $1 | $2; + int normspec = newspec; + + if (normspec & CAS_ENABLE) + normspec |= CAS_ENFORCED; + if (normspec & CAS_DISABLE) + normspec |= CAS_NOT_ENFORCED; + if (normspec & CAS_NOVALIDATE) + normspec |= CAS_NOT_VALID; /* special message for this case */ - if ((newspec & (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED)) == (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED)) + if ((normspec & (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED)) == (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"), parser_errposition(`@2`))); /* generic message for other conflicts */ - if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) || - (newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED) || - (newspec & (CAS_NOT_ENFORCED | CAS_ENFORCED)) == (CAS_NOT_ENFORCED | CAS_ENFORCED)) + if ((normspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) || + (normspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED) || + (normspec & (CAS_NOT_ENFORCED | CAS_ENFORCED)) == (CAS_NOT_ENFORCED | CAS_ENFORCED) || + (newspec & (CAS_VALIDATE | CAS_NOVALIDATE)) == (CAS_VALIDATE | CAS_NOVALIDATE)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting constraint properties"), parser_errposition(`@2`)));Also applies to: 6733-6749
🧹 Nitpick comments (1)
src/backend/parser/parse_utilcmd.c (1)
4255-4260: Inconsistent error code for "misplaced" error.The error uses
ERRCODE_FEATURE_NOT_SUPPORTEDwith message "misplaced ENABLE clause", but all other "misplaced" errors in this function (e.g., lines 4152, 4163, 4188, 4230) useERRCODE_SYNTAX_ERROR.For consistency, consider using
ERRCODE_SYNTAX_ERRORhere as well.🛠️ Proposed fix for consistency
{ ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + (errcode(ERRCODE_SYNTAX_ERROR), errmsg("misplaced ENABLE clause"), parser_errposition(cxt->pstate, con->location))); }
* Not covering ALTER and DOMAIN. * Add unit testing with catalog lookup to check VALID and ENFORCED status in pg_constraints. * Valid only starting with PostgreSQL 18 (which has been enhanced regarding supported options on CONSTRAINT).
Support for syntax and mapping to PostgreSQL policies (see CAS constants) HINTs to suggest updating the syntax when relevant. In `ora_gram.y`, extended the bitmask to cover more cases.
extending the test coverage
The previous patchset is a working PoC with few bugs. In this one I have updated parsenode for constrType, adding CONS_ATTR_ENABLE/DISABLE, which allows to manage the clause like it's done with ENFORCE/NOT ENFORCED. Only real "hack" is to accept ENABLE in CREATE TABLE, see bottom of processCASbits()
Adding checks in `ora_gram.y` and related unit test.
df98ef0 to
ca7c95f
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
src/oracle_test/regress/expected/constraints.out (1)
2585-2631: Consider ordering multi-row pg_constraint outputs to avoid nondeterminism.The multi-row queries (Lines 2585–2593 and 2625–2631) don’t specify an ORDER BY. This relies on heap/insert order and can be fragile if catalog changes reorder rows. Recommend adding
ORDER BY connamein the SQL and updating the expected output accordingly.
As per coding guidelines, “These are expected test outputs from pg_regress. Review for: Correctness of query results; Proper Oracle compatibility behavior; Edge case coverage; Consistency with corresponding .sql test files”.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/oracle_test/regress/expected/constraints.out` around lines 2585 - 2631, The SELECT queries against pg_constraint that return multiple rows (the statements starting "SELECT conname, contype, conenforced, convalidated FROM pg_constraint WHERE conrelid = 'enable_noconflict'::regclass;" and the similar ones for 'disable_noconflict' and 'novalidate_noconflict') are nondeterministic; add "ORDER BY conname" to each of those SELECTs to produce a stable ordering and then update the expected output blocks to match the new sorted ordering. Ensure you modify each multi-row SELECT that queries pg_constraint (referenced above) and regenerate the expected output so the test comparisons are deterministic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/backend/oracle_parser/ora_gram.y`:
- Around line 4568-4627: The grammar actions create Constraint nodes for
ENABLE_P / DISABLE_P alternatives but always set initially_valid = true; change
each alternative (the actions for ENABLE_P, ENABLE_P VALIDATE, ENABLE_P
NOVALIDATE, DISABLE_P, DISABLE_P NOVALIDATE, DISABLE_P VALIDATE in ora_gram.y)
so that after setting n->skip_validation you set n->initially_valid based on
that flag (e.g., n->initially_valid = !n->skip_validation) instead of hardcoding
true, keeping n->contype and n->location assignments intact.
In `@src/oracle_test/regress/expected/constraints.out`:
- Around line 1806-1836: The error output for unsupported DISABLE variants is
inconsistent: add the missing HINT lines to the failing cases so they match the
pk_disable_validate case; update the expected file entries for pk_disable and
pk_disable_novalidate in constraints.out to include the same "HINT: Update your
CONSTRAINT definition." line immediately after their ERROR blocks (keeping the
existing ERROR text, caret line and spacing) so pk_disable, pk_disable_validate
and pk_disable_novalidate all show the HINT consistently.
- Around line 2013-2088: The test shows inconsistent handling of "ENABLE
NOVALIDATE" between table-level CONSTRAINT (e.g.,
ccheck_check_enable_novalidate) which is accepted and recorded as convalidated =
t, and column-level CHECK (check_enable_novalidate) which currently errors; make
them consistent by changing the column-level parser/validator that handles CHECK
... ENABLE NOVALIDATE to either accept and map to the same internal state as
table-level constraints (so convalidated becomes true) or to explicitly reject
with the same error/HINT as the table-level path—update the code path that
processes column-level CHECK clauses (look for the function that builds column
constraints/flags for CHECK and the handler for ENABLE NOVALIDATE) and then
update the expected output in constraints.out to match the chosen behavior
(adjust the entry for check_enable_novalidate_id_check or the error text to
mirror the table-level case).
In `@src/oracle_test/regress/sql/constraints.sql`:
- Around line 1044-1058: Add migration tests that exercise ALTER TABLE ... ALTER
CONSTRAINT state transitions for the existing schema/tables: use
ivo_regress_enable and the constraints cpk_pk_enable and cpk_pk_enable_validate
to toggle through DISABLE NOVALIDATE → ENABLE VALIDATE and NOT VALID → VALIDATE
sequences; specifically, add ALTER TABLE ... ALTER CONSTRAINT statements (e.g.,
ALTER TABLE cpk_enable ALTER CONSTRAINT cpk_pk_enable DISABLE NOVALIDATE, then
ENABLE VALIDATE) followed by queries against pg_constraint (conname, contype,
conenforced, convalidated) to assert the expected state at each step so
transitions are covered for both cpk_pk_enable and cpk_pk_enable_validate.
In `@src/oracle_test/regress/sql/foreign_key.sql`:
- Around line 2391-2558: Add SQL regression cases that exercise ALTER-time
transitions and conflicting/duplicate clause combinations: add ALTER TABLE ...
ENABLE / DISABLE / VALIDATE / NOVALIDATE transitions for representative tables
(e.g., fk_p36, fk_p33, fk_p13) to test moves like NOT ENFORCED NOT VALID →
ENFORCED VALIDATE and vice versa, and add creation/alter statements with
conflicting clauses (e.g., CREATE/ALTER with both ENABLE and DISABLE, ENABLE
NOVALIDATE vs ENABLE VALIDATE, or duplicate ENABLE/ENABLE) for tables such as
fk_p1/fk_p4/fk_p16 and constraint names like fk_p13_fk_r_id_fkey or fk_fk_p23 to
validate parser/state handling and ensure SELECT checks against pg_constraint
(conenforced, convalidated) follow each transition.
---
Duplicate comments:
In `@src/backend/parser/parse_utilcmd.c`:
- Around line 4297-4310: The second error path for CONSTR_ATTR_DISABLE (the
check that verifies lastprimarycon and its contype against
CONSTR_CHECK/CONSTR_FOREIGN) is missing an errhint; modify the ereport(ERROR,
...) that reports "DISABLE clause is not supported" to include the same errhint
used above (e.g. errhint("Update your CONSTRAINT definition.")) and keep the
existing errcode and parser_errposition calls (reference symbols:
CONSTR_ATTR_DISABLE, lastprimarycon, lastprimarycon->contype, CONSTR_CHECK,
CONSTR_FOREIGN, parser_errposition(cxt->pstate, con->location)).
- Around line 4241-4274: The ENABLE NOVALIDATE branch inside the
CONSTR_ATTR_ENABLE case is unreachable because con->skip_validation is already
rejected earlier; either remove the dead block that sets
lastprimarycon->skip_validation and lastprimarycon->initially_valid, or if
ENABLE NOVALIDATE should be supported, relax/remove the earlier ereport that
errors on con->skip_validation and ensure proper validation by keeping the
assignments to lastprimarycon->skip_validation and
lastprimarycon->initially_valid in the CONSTR_ATTR_ENABLE handling (referencing
con->skip_validation, lastprimarycon, and lastprimarycon->is_enforced to locate
the code).
---
Nitpick comments:
In `@src/oracle_test/regress/expected/constraints.out`:
- Around line 2585-2631: The SELECT queries against pg_constraint that return
multiple rows (the statements starting "SELECT conname, contype, conenforced,
convalidated FROM pg_constraint WHERE conrelid = 'enable_noconflict'::regclass;"
and the similar ones for 'disable_noconflict' and 'novalidate_noconflict') are
nondeterministic; add "ORDER BY conname" to each of those SELECTs to produce a
stable ordering and then update the expected output blocks to match the new
sorted ordering. Ensure you modify each multi-row SELECT that queries
pg_constraint (referenced above) and regenerate the expected output so the test
comparisons are deterministic.
| | ENABLE_P | ||
| { | ||
| Constraint *n = makeNode(Constraint); | ||
|
|
||
| n->contype = CONSTR_ATTR_ENABLE; | ||
| n->location = @1; | ||
| n->skip_validation = false; | ||
| n->initially_valid = true; | ||
| $$ = (Node *) n; | ||
| } | ||
| | ENABLE_P VALIDATE | ||
| { | ||
| Constraint *n = makeNode(Constraint); | ||
|
|
||
| n->contype = CONSTR_ATTR_ENABLE; | ||
| n->location = @1; | ||
| n->skip_validation = false; | ||
| n->initially_valid = true; | ||
| $$ = (Node *) n; | ||
| } | ||
| | ENABLE_P NOVALIDATE | ||
| { | ||
| Constraint *n = makeNode(Constraint); | ||
|
|
||
| n->contype = CONSTR_ATTR_ENABLE; | ||
| n->location = @1; | ||
| n->skip_validation = true; | ||
| n->initially_valid = true; | ||
| $$ = (Node *) n; | ||
| } | ||
| | DISABLE_P | ||
| { | ||
| Constraint *n = makeNode(Constraint); | ||
|
|
||
| n->contype = CONSTR_ATTR_DISABLE; | ||
| n->location = @1; | ||
| n->skip_validation = true; | ||
| n->initially_valid = true; | ||
| $$ = (Node *) n; | ||
| } | ||
| | DISABLE_P NOVALIDATE | ||
| { | ||
| Constraint *n = makeNode(Constraint); | ||
|
|
||
| n->contype = CONSTR_ATTR_DISABLE; | ||
| n->location = @1; | ||
| n->skip_validation = true; | ||
| n->initially_valid = true; | ||
| $$ = (Node *) n; | ||
| } | ||
| | DISABLE_P VALIDATE | ||
| { | ||
| Constraint *n = makeNode(Constraint); | ||
|
|
||
| n->contype = CONSTR_ATTR_DISABLE; | ||
| n->location = @1; | ||
| n->skip_validation = false; | ||
| n->initially_valid = true; | ||
| $$ = (Node *) n; | ||
| } |
There was a problem hiding this comment.
NOVALIDATE is marked as initially valid.
skip_validation is set to true for NOVALIDATE/ DISABLE, but initially_valid is hardcoded to true, which makes NOVALIDATE constraints appear validated. This can break later VALIDATE transitions or status reporting. Set initially_valid based on skip_validation for all ENABLE/DISABLE branches.
✅ Proposed fix
- n->skip_validation = false;
- n->initially_valid = true;
+ n->skip_validation = false;
+ n->initially_valid = !n->skip_validation;
...
- n->skip_validation = true;
- n->initially_valid = true;
+ n->skip_validation = true;
+ n->initially_valid = !n->skip_validation;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/backend/oracle_parser/ora_gram.y` around lines 4568 - 4627, The grammar
actions create Constraint nodes for ENABLE_P / DISABLE_P alternatives but always
set initially_valid = true; change each alternative (the actions for ENABLE_P,
ENABLE_P VALIDATE, ENABLE_P NOVALIDATE, DISABLE_P, DISABLE_P NOVALIDATE,
DISABLE_P VALIDATE in ora_gram.y) so that after setting n->skip_validation you
set n->initially_valid based on that flag (e.g., n->initially_valid =
!n->skip_validation) instead of hardcoding true, keeping n->contype and
n->location assignments intact.
| -- Not supported: NOT ENFORCED | ||
| CREATE TABLE pk_disable (id NUMBER PRIMARY KEY DISABLE, name VARCHAR2(100)); | ||
| ERROR: DISABLE clause is not supported | ||
| LINE 1: CREATE TABLE pk_disable (id NUMBER PRIMARY KEY DISABLE, name... | ||
| ^ | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'pk_disable_pkey'; | ||
| conname | contype | conenforced | convalidated | ||
| ---------+---------+-------------+-------------- | ||
| (0 rows) | ||
|
|
||
| -- Not supported: VALIDATE .. NOT ENFORCED | ||
| CREATE TABLE pk_disable_validate (id NUMBER PRIMARY KEY DISABLE VALIDATE, name VARCHAR2(100)); | ||
| ERROR: DISABLE VALIDATE clause is not supported | ||
| LINE 1: ... TABLE pk_disable_validate (id NUMBER PRIMARY KEY DISABLE VA... | ||
| ^ | ||
| HINT: Update your CONSTRAINT definition. | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'pk_disable_validate_pkey'; | ||
| conname | contype | conenforced | convalidated | ||
| ---------+---------+-------------+-------------- | ||
| (0 rows) | ||
|
|
||
| -- Not supported: NOT ENFORCED NOT VALID | ||
| CREATE TABLE pk_disable_novalidate (id NUMBER PRIMARY KEY DISABLE NOVALIDATE, name VARCHAR2(100)); | ||
| ERROR: DISABLE clause is not supported | ||
| LINE 1: ...ABLE pk_disable_novalidate (id NUMBER PRIMARY KEY DISABLE NO... | ||
| ^ | ||
| SELECT conname, contype, conenforced, convalidated |
There was a problem hiding this comment.
Standardize HINT presence for unsupported DISABLE variants.
Some unsupported cases (e.g., Line 1807 and Line 1832) emit errors without a HINT, while similar cases earlier (e.g., Line 1734) include a HINT. If the implementation is meant to always provide guidance for unsupported combinations, the expected output should consistently include the HINT; otherwise, the error messaging should be normalized in code/tests.
As per coding guidelines, “These are expected test outputs from pg_regress. Review for: Correctness of query results; Proper Oracle compatibility behavior; Edge case coverage; Consistency with corresponding .sql test files”.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/oracle_test/regress/expected/constraints.out` around lines 1806 - 1836,
The error output for unsupported DISABLE variants is inconsistent: add the
missing HINT lines to the failing cases so they match the pk_disable_validate
case; update the expected file entries for pk_disable and pk_disable_novalidate
in constraints.out to include the same "HINT: Update your CONSTRAINT
definition." line immediately after their ERROR blocks (keeping the existing
ERROR text, caret line and spacing) so pk_disable, pk_disable_validate and
pk_disable_novalidate all show the HINT consistently.
| -- ENFORCED NOT VALID - saved as ENFORCED VALID | ||
| CREATE TABLE ccheck_enable_novalidate (id NUMBER, name VARCHAR2(100), | ||
| CONSTRAINT ccheck_check_enable_novalidate CHECK (id > 0) ENABLE NOVALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'ccheck_check_enable_novalidate'; | ||
| conname | contype | conenforced | convalidated | ||
| --------------------------------+---------+-------------+-------------- | ||
| ccheck_check_enable_novalidate | c | t | t | ||
| (1 row) | ||
|
|
||
| -- NOT ENFORCED | ||
| CREATE TABLE ccheck_disable (id NUMBER, name VARCHAR2(100), | ||
| CONSTRAINT ccheck_check_disable CHECK (id > 0) DISABLE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'ccheck_check_disable'; | ||
| conname | contype | conenforced | convalidated | ||
| ----------------------+---------+-------------+-------------- | ||
| ccheck_check_disable | c | f | f | ||
| (1 row) | ||
|
|
||
| -- VALIDATE .. NOT ENFORCED - saved as NOT ENFORCED NOT VALID | ||
| CREATE TABLE ccheck_disable_validate (id NUMBER, name VARCHAR2(100), | ||
| CONSTRAINT ccheck_check_disable_validate CHECK (id > 0) DISABLE VALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'ccheck_check_disable_validate'; | ||
| conname | contype | conenforced | convalidated | ||
| -------------------------------+---------+-------------+-------------- | ||
| ccheck_check_disable_validate | c | f | f | ||
| (1 row) | ||
|
|
||
| -- NOT ENFORCED NOT VALID | ||
| CREATE TABLE ccheck_disable_novalidate (id NUMBER, name VARCHAR2(100), | ||
| CONSTRAINT ccheck_check_disable_novalidate CHECK (id > 0) DISABLE NOVALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'ccheck_check_disable_novalidate'; | ||
| conname | contype | conenforced | convalidated | ||
| ---------------------------------+---------+-------------+-------------- | ||
| ccheck_check_disable_novalidate | c | f | f | ||
| (1 row) | ||
|
|
||
| -- CHECK | ||
| CREATE TABLE check_enable (id NUMBER CHECK (id>0) ENABLE, name VARCHAR2(100)); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'check_enable_id_check'; | ||
| conname | contype | conenforced | convalidated | ||
| -----------------------+---------+-------------+-------------- | ||
| check_enable_id_check | c | t | t | ||
| (1 row) | ||
|
|
||
| -- VALIDATE .. ENFORCED | ||
| CREATE TABLE check_enable_validate (id NUMBER CHECK (id>0) ENABLE VALIDATE, name VARCHAR2(100)); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'check_enable_validate_id_check'; | ||
| conname | contype | conenforced | convalidated | ||
| --------------------------------+---------+-------------+-------------- | ||
| check_enable_validate_id_check | c | t | t | ||
| (1 row) | ||
|
|
||
| -- Not supported: ENFORCED NOT VALID | ||
| CREATE TABLE check_enable_novalidate (id NUMBER CHECK (id>0) ENABLE NOVALIDATE, name VARCHAR2(100)); | ||
| ERROR: ENABLE NOVALIDATE clause is not supported | ||
| LINE 1: ...E check_enable_novalidate (id NUMBER CHECK (id>0) ENABLE NOV... | ||
| ^ | ||
| HINT: Update your CONSTRAINT definition. | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'check_enable_novalidate_id_check'; | ||
| conname | contype | conenforced | convalidated | ||
| ---------+---------+-------------+-------------- | ||
| (0 rows) |
There was a problem hiding this comment.
Align CREATE TABLE CHECK NOVALIDATE behavior across table- and column-level forms.
Line 2013 accepts CONSTRAINT ... CHECK ... ENABLE NOVALIDATE and records convalidated = t, but Line 2077 expects an error for CHECK ... ENABLE NOVALIDATE at column level. This inconsistency will make Oracle compatibility and parser behavior diverge depending on constraint form. Please make both forms consistent (either both accept and map to the same convalidated behavior, or both reject with the same error/HINT) and update the expected output accordingly.
As per coding guidelines, “These are expected test outputs from pg_regress. Review for: Correctness of query results; Proper Oracle compatibility behavior; Edge case coverage; Consistency with corresponding .sql test files”.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/oracle_test/regress/expected/constraints.out` around lines 2013 - 2088,
The test shows inconsistent handling of "ENABLE NOVALIDATE" between table-level
CONSTRAINT (e.g., ccheck_check_enable_novalidate) which is accepted and recorded
as convalidated = t, and column-level CHECK (check_enable_novalidate) which
currently errors; make them consistent by changing the column-level
parser/validator that handles CHECK ... ENABLE NOVALIDATE to either accept and
map to the same internal state as table-level constraints (so convalidated
becomes true) or to explicitly reject with the same error/HINT as the
table-level path—update the code path that processes column-level CHECK clauses
(look for the function that builds column constraints/flags for CHECK and the
handler for ENABLE NOVALIDATE) and then update the expected output in
constraints.out to match the chosen behavior (adjust the entry for
check_enable_novalidate_id_check or the error text to mirror the table-level
case).
|
|
||
| --- tests for CREATE TABLE (<column> .. ENABLE|DISABLE ..) | ||
| CREATE SCHEMA ivo_regress_enable; | ||
| SET search_path to ivo_regress_enable; | ||
|
|
||
| -- CONSTRAINT PRIMARY KEY | ||
| CREATE TABLE cpk_enable (id NUMBER, name VARCHAR2(100), | ||
| CONSTRAINT cpk_pk_enable PRIMARY KEY (id) ENABLE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'cpk_pk_enable'; | ||
|
|
||
| -- VALIDATE .. ENFORCED | ||
| CREATE TABLE cpk_enable_validate (id NUMBER, name VARCHAR2(100), | ||
| CONSTRAINT cpk_pk_enable_validate PRIMARY KEY (id) ENABLE VALIDATE); |
There was a problem hiding this comment.
Add ALTER CONSTRAINT state‑transition tests (ENABLE/DISABLE/VALIDATE/NOVALIDATE).
This block covers CREATE TABLE and ALTER TABLE ADD CONSTRAINT, but it doesn’t exercise toggling existing constraints (e.g., DISABLE NOVALIDATE → ENABLE VALIDATE, NOT VALID → VALIDATE CONSTRAINT). Those transitions are part of the ALTER feature surface and need regression coverage to catch state‑change regressions. As per coding guidelines: **/sql/*.sql: Test SQL files. Ensure comprehensive coverage of features.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/oracle_test/regress/sql/constraints.sql` around lines 1044 - 1058, Add
migration tests that exercise ALTER TABLE ... ALTER CONSTRAINT state transitions
for the existing schema/tables: use ivo_regress_enable and the constraints
cpk_pk_enable and cpk_pk_enable_validate to toggle through DISABLE NOVALIDATE →
ENABLE VALIDATE and NOT VALID → VALIDATE sequences; specifically, add ALTER
TABLE ... ALTER CONSTRAINT statements (e.g., ALTER TABLE cpk_enable ALTER
CONSTRAINT cpk_pk_enable DISABLE NOVALIDATE, then ENABLE VALIDATE) followed by
queries against pg_constraint (conname, contype, conenforced, convalidated) to
assert the expected state at each step so transitions are covered for both
cpk_pk_enable and cpk_pk_enable_validate.
| CREATE SCHEMA fkpart14; | ||
| SET search_path to fkpart14; | ||
|
|
||
| CREATE TABLE fk_r (id NUMBER PRIMARY KEY, name VARCHAR2(100)); | ||
|
|
||
| -- ENFORCED | ||
| CREATE TABLE fk_p1 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER REFERENCES fk_r(id) ENABLE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p1_fk_r_id_fkey'; | ||
|
|
||
| -- VALIDATE .. ENFORCED | ||
| CREATE TABLE fk_p2 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER REFERENCES fk_r(id) ENABLE VALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p2_fk_r_id_fkey'; | ||
|
|
||
| -- Not supported: ENFORCED NOT VALID | ||
| CREATE TABLE fk_p3 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER REFERENCES fk_r(id) ENABLE NOVALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p3_fk_r_id_fkey'; | ||
|
|
||
| -- NOT ENFORCED | ||
| CREATE TABLE fk_p4 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER REFERENCES fk_r(id) DISABLE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p4_fk_r_id_fkey'; | ||
|
|
||
| -- Not supported: VALIDATE .. NOT ENFORCED | ||
| CREATE TABLE fk_p5 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER REFERENCES fk_r(id) DISABLE VALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p5_fk_r_id_fkey'; | ||
|
|
||
| -- NOT ENFORCED NOT VALID | ||
| CREATE TABLE fk_p6 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER REFERENCES fk_r(id) DISABLE NOVALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p6_fk_r_id_fkey'; | ||
|
|
||
| -- ENFORCED | ||
| CREATE TABLE fk_p11 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) ENABLE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p11_fk_r_id_fkey'; | ||
|
|
||
| -- VALIDATE .. ENFORCED | ||
| CREATE TABLE fk_p12 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) ENABLE VALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p12_fk_r_id_fkey'; | ||
|
|
||
| -- ENFORCED NOT VALID - saved as ENFORCED VALID | ||
| CREATE TABLE fk_p13 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) ENABLE NOVALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p13_fk_r_id_fkey'; | ||
|
|
||
| -- NOT ENFORCED | ||
| CREATE TABLE fk_p14 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) DISABLE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p14_fk_r_id_fkey'; | ||
|
|
||
| -- VALIDATE .. NOT ENFORCED - saved as NOT ENFORCED NOT VALID | ||
| CREATE TABLE fk_p15 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) DISABLE VALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p15_fk_r_id_fkey'; | ||
|
|
||
| -- NOT ENFORCED NOT VALID | ||
| CREATE TABLE fk_p16 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) DISABLE NOVALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p16_fk_r_id_fkey'; | ||
|
|
||
| -- ENFORCED | ||
| CREATE TABLE fk_p21 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| CONSTRAINT fk_fk_p21 FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) ENABLE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_fk_p21'; | ||
|
|
||
| -- VALIDATE .. ENFORCED | ||
| CREATE TABLE fk_p22 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| CONSTRAINT fk_fk_p22 FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) ENABLE VALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_fk_p22'; | ||
|
|
||
| -- ENFORCED NOT VALID - saved as ENFORCED VALID | ||
| CREATE TABLE fk_p23 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| CONSTRAINT fk_fk_p23 FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) ENABLE NOVALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_fk_p23'; | ||
|
|
||
| -- NOT ENFORCED | ||
| CREATE TABLE fk_p24 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| CONSTRAINT fk_fk_p24 FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) DISABLE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_fk_p24'; | ||
|
|
||
| -- VALIDATE .. NOT ENFORCED - saved as NOT ENFORCED NOT VALID | ||
| CREATE TABLE fk_p25 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| CONSTRAINT fk_fk_p25 FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) DISABLE VALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_fk_p25'; | ||
|
|
||
| -- NOT ENFORCED NOT VALID | ||
| CREATE TABLE fk_p26 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER, | ||
| CONSTRAINT fk_fk_p26 FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) DISABLE NOVALIDATE); | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_fk_p26'; | ||
|
|
||
| -- ENFORCED | ||
| CREATE TABLE fk_p31 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER); | ||
| ALTER TABLE fk_p31 ADD FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) ENABLE; | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p31_fk_r_id_fkey'; | ||
|
|
||
| -- VALIDATE .. ENFORCED | ||
| CREATE TABLE fk_p32 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER); | ||
| ALTER TABLE fk_p32 ADD FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) ENABLE VALIDATE; | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p32_fk_r_id_fkey'; | ||
|
|
||
| -- ENFORCED NOT VALID | ||
| CREATE TABLE fk_p33 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER); | ||
| ALTER TABLE fk_p33 ADD FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) ENABLE NOVALIDATE; | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p33_fk_r_id_fkey'; | ||
|
|
||
| -- NOT ENFORCED | ||
| CREATE TABLE fk_p34 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER); | ||
| ALTER TABLE fk_p34 ADD FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) DISABLE; | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p34_fk_r_id_fkey'; | ||
|
|
||
| -- VALIDATE .. NOT ENFORCED - saved as NOT ENFORCED NOT VALID | ||
| CREATE TABLE fk_p35 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER); | ||
| ALTER TABLE fk_p35 ADD FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) DISABLE VALIDATE; | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p35_fk_r_id_fkey'; | ||
|
|
||
| -- NOT ENFORCED NOT VALID | ||
| CREATE TABLE fk_p36 (id NUMBER PRIMARY KEY, name VARCHAR2(100), fk_r_id NUMBER); | ||
| ALTER TABLE fk_p36 ADD FOREIGN KEY (fk_r_id) REFERENCES fk_r(id) DISABLE NOVALIDATE; | ||
| SELECT conname, contype, conenforced, convalidated | ||
| FROM pg_constraint | ||
| WHERE conname = 'fk_p36_fk_r_id_fkey'; | ||
|
|
||
| DROP SCHEMA fkpart14 CASCADE; |
There was a problem hiding this comment.
Add regression coverage for ENABLE/DISABLE transitions and conflicting clauses
This block exercises creation-time permutations, but it doesn’t cover ALTER transitions (e.g., NOT ENFORCED/NOT VALID → ENFORCED VALIDATE) or conflicting/duplicate clause combinations (e.g., ENABLE DISABLE / ENFORCED DISABLE). These are explicitly called out as TODOs in the PR objectives; adding them here will complete coverage and protect the parser/state logic from regressions.
As per coding guidelines, **/sql/*.sql: Test SQL files. Ensure comprehensive coverage of features.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/oracle_test/regress/sql/foreign_key.sql` around lines 2391 - 2558, Add
SQL regression cases that exercise ALTER-time transitions and
conflicting/duplicate clause combinations: add ALTER TABLE ... ENABLE / DISABLE
/ VALIDATE / NOVALIDATE transitions for representative tables (e.g., fk_p36,
fk_p33, fk_p13) to test moves like NOT ENFORCED NOT VALID → ENFORCED VALIDATE
and vice versa, and add creation/alter statements with conflicting clauses
(e.g., CREATE/ALTER with both ENABLE and DISABLE, ENABLE NOVALIDATE vs ENABLE
VALIDATE, or duplicate ENABLE/ENABLE) for tables such as fk_p1/fk_p4/fk_p16 and
constraint names like fk_p13_fk_r_id_fkey or fk_fk_p23 to validate parser/state
handling and ensure SELECT checks against pg_constraint (conenforced,
convalidated) follow each transition.
Add support for
{ ENABLE | DISABLE } [ VALIDATE | NOVALIDATE ]onCONSTRAINT.This merge request supports
CREATEandALTERstatements at the moment, though I have not added test to cover transitions like "notvalid->valid".It maps with existing constraints clause in PostgreSQL. Clauses not supported by PostgreSQL return an error with appropriate HINT message.
TODO:
ENFORCED DISABLEExample of syntax:
Example not supported:
Summary by CodeRabbit
New Features
Behavior
Tests
Public API