Skip to content

Commit 0d91757

Browse files
committed
refactor: keep the ALTER constraint lookahead in the grammar
Move AlterConstraintLookahead from its own file into the grammar as a private nested class, as done for TokenNesting in #2849. Split needsSharedTableConstraint into a check for the forms only the shared production accepts and a scan for constraint attributes. Codacy's PMD reported an NPath complexity of 440 for the combined method; the largest part is now 14. The nested class keeps its branches out of CCJSqlParser.class. Behaviour does not change. Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 95dc95b commit 0d91757

2 files changed

Lines changed: 79 additions & 80 deletions

File tree

‎src/main/java/net/sf/jsqlparser/parser/AlterConstraintLookahead.java‎

Lines changed: 0 additions & 80 deletions
This file was deleted.

‎src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2530,6 +2530,85 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
25302530
}
25312531
}
25322532

2533+
/**
2534+
* Decides whether an ALTER TABLE ADD table constraint needs the table-constraint production
2535+
* shared with CREATE TABLE in dialects that otherwise keep the generic ALTER representation. A
2536+
* nested class keeps its branches out of CCJSqlParser.class, whose constant pool is close to
2537+
* what JaCoCo can still instrument.
2538+
*/
2539+
private static final class AlterConstraintLookahead {
2540+
private AlterConstraintLookahead() {}
2541+
2542+
/**
2543+
* Whether the action starting at {@code first} is an unnamed CHECK, a FOREIGN KEY,
2544+
* EXCLUDE, or uses a constraint attribute (INITIALLY IMMEDIATE|DEFERRED, NOT VALID, or
2545+
* ENFORCED outside CHECK) before the end of the action.
2546+
*/
2547+
static boolean needsSharedTableConstraint(Token first, CCJSqlParserTokenManager source) {
2548+
Token second = next(first, source);
2549+
Token body = first.kind == K_CONSTRAINT ? next(second, source) : first;
2550+
if (isSharedOnlyConstraint(first, second, body, source)) {
2551+
return true;
2552+
}
2553+
return (first.kind == K_CONSTRAINT || first.kind == K_PRIMARY
2554+
|| first.kind == K_UNIQUE)
2555+
&& hasConstraintAttribute(first, body.kind == K_CHECK, source);
2556+
}
2557+
2558+
/** An unnamed CHECK, a FOREIGN KEY or an EXCLUDE constraint. */
2559+
private static boolean isSharedOnlyConstraint(Token first, Token second, Token body,
2560+
CCJSqlParserTokenManager source) {
2561+
return first.kind == K_CHECK && second.kind == OPENING_BRACKET
2562+
|| first.kind == K_FOREIGN || isExcludeConstraint(body, source);
2563+
}
2564+
2565+
/** Whether a constraint attribute follows at the top level before the end of the action. */
2566+
private static boolean hasConstraintAttribute(Token first, boolean check,
2567+
CCJSqlParserTokenManager source) {
2568+
int depth = 0;
2569+
for (Token token = first; token.kind != EOF; token = next(token, source)) {
2570+
if (token.kind == OPENING_BRACKET) {
2571+
depth++;
2572+
} else if (token.kind == CLOSING_BRACKET) {
2573+
if (depth-- == 0) {
2574+
return false;
2575+
}
2576+
} else if (depth == 0) {
2577+
if (token.kind == ST_SEMICOLON || token.kind == K_COMMA) {
2578+
return false;
2579+
}
2580+
if (isConstraintAttribute(token, next(token, source), check)) {
2581+
return true;
2582+
}
2583+
}
2584+
}
2585+
return false;
2586+
}
2587+
2588+
private static boolean isConstraintAttribute(Token token, Token next, boolean check) {
2589+
if ("INITIALLY".equalsIgnoreCase(token.image)) {
2590+
return "IMMEDIATE".equalsIgnoreCase(next.image)
2591+
|| "DEFERRED".equalsIgnoreCase(next.image);
2592+
}
2593+
return token.kind == K_NOT && "VALID".equalsIgnoreCase(next.image)
2594+
|| token.kind == K_ENFORCED && !check;
2595+
}
2596+
2597+
/** EXCLUDE starts an exclusion constraint only before USING, its elements or WHERE. */
2598+
private static boolean isExcludeConstraint(Token token, CCJSqlParserTokenManager source) {
2599+
int following = next(token, source).kind;
2600+
return token.kind == K_EXCLUDE && (following == K_USING
2601+
|| following == OPENING_BRACKET || following == K_WHERE);
2602+
}
2603+
2604+
private static Token next(Token token, CCJSqlParserTokenManager source) {
2605+
if (token.next == null) {
2606+
token.next = source.getNextToken();
2607+
}
2608+
return token.next;
2609+
}
2610+
}
2611+
25332612
/**
25342613
* True when an IS after a condition opens a postfix test
25352614
* (IS [NOT] TRUE/FALSE/UNKNOWN/NULL/JSON) rather than IS DISTINCT FROM or

0 commit comments

Comments
 (0)