@@ -425,11 +425,10 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
425425 Token token = getToken(offset);
426426 switch (token.kind) {
427427 case K_SET:
428- int nameEnd = offset + 2;
429- while (".".equals(getToken(nameEnd) .image)) {
430- nameEnd += 2 ;
428+ Token assignment = getToken( offset + 2) ;
429+ while (".".equals(assignment .image)) {
430+ assignment = nextWithItemToken(nextWithItemToken(assignment)) ;
431431 }
432- Token assignment = getToken(nameEnd);
433432 return assignment.kind == K_TO || "=".equals(assignment.image)
434433 || assignment.kind == K_FROM;
435434 case K_RESET:
@@ -521,15 +520,14 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
521520 boolean statementStart = true;
522521 boolean statements = false;
523522 int caseDepth = 0;
524- for (int i = 2; ; i++) {
525- Token token = getToken(i);
523+ for (Token token = getToken(2); ; token = nextWithItemToken(token)) {
526524 if (token.kind == EOF) {
527525 return false;
528526 } else if (token.kind == ST_SEMICOLON) {
529527 statementStart = true;
530528 } else if (statementStart) {
531529 if (token.kind == K_END) {
532- int next = getToken(i + 1 ).kind;
530+ int next = nextWithItemToken(token ).kind;
533531 return statements && (next == ST_SEMICOLON || next == EOF);
534532 }
535533 switch (token.kind) {
@@ -676,8 +674,7 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
676674 try {
677675 int depth = 0;
678676 Token prev = null;
679- for (int i = 2; ; i++) {
680- Token t = getToken(i);
677+ for (Token t = getToken(2); ; t = nextWithItemToken(t)) {
681678 if (t == null || t.kind == EOF) {
682679 return false;
683680 }
@@ -841,8 +838,7 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
841838 // CHAIN_CACHE_THRESHOLD delimiter/part pairs (only in the non-filling pass).
842839 private int isFunctionAheadWalk(boolean fill) {
843840 try {
844- int i = 1;
845- Token t = getToken(i);
841+ Token t = getToken(1);
846842
847843 // JDBC escape function: {fn ...} — must check for FN keyword
848844 if (t.image.equals("{")) {
@@ -851,8 +847,7 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
851847
852848 // Optional APPROXIMATE keyword
853849 if (t.kind == K_APPROXIMATE) {
854- i++;
855- t = getToken(i);
850+ t = getToken(2);
856851 }
857852
858853 // Exclude tokens that have their own dedicated branches
@@ -867,32 +862,31 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
867862 || t.kind == CLOSING_BRACKET || t.kind == EOF || "[".equals(t.image)) {
868863 return 0;
869864 }
870- i++;
871-
872- // Walk through dotted name chain
865+ // Walk through dotted name chain, following the token chain directly;
866+ // repeated getToken(i) calls rescan from the start each time
873867 int delimiters = 0;
874868 List<Token> chainParts = fill ? new ArrayList<Token>() : null;
869+ t = nextWithItemToken(t);
875870 while (true) {
876- t = getToken(i);
877871 if (t.image.equals(".") || t.image.equals("..")
878872 || t.image.equals("...") || t.image.equals(":")) {
879873 if (!fill && ++delimiters > CHAIN_CACHE_THRESHOLD) {
880874 return LONG_CHAIN;
881875 }
876+ Token part = nextWithItemToken(t); // skip delimiter
882877 if (fill) {
883- chainParts.add(getToken(i + 1) );
878+ chainParts.add(part );
884879 }
885- i++; // skip delimiter
886- i++; // skip next name part
880+ t = nextWithItemToken(part); // skip next name part
887881 } else {
888882 break;
889883 }
890884 }
891885
892886 // Must be followed by (, and not by the Oracle join syntax column(+)
893- boolean result = getToken(i) .kind == OPENING_BRACKET
894- && !(getToken(i + 1 ).image.equals("+")
895- && getToken(i + 2 ).kind == CLOSING_BRACKET);
887+ boolean result = t .kind == OPENING_BRACKET
888+ && !(nextWithItemToken(t ).image.equals("+")
889+ && nextWithItemToken(nextWithItemToken(t) ).kind == CLOSING_BRACKET);
896890
897891 // Each eligible chain part would walk the same remaining suffix and
898892 // obtain the same answer, so memoize them all in one pass.
@@ -1492,41 +1486,38 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
14921486 // Returns 1 for true, 0 for false, or LONG_CHAIN when the walk exceeded
14931487 // CHAIN_CACHE_THRESHOLD delimiter/part pairs (only in the non-filling pass).
14941488 private int isAllTableColumnsWalk(boolean fill) {
1495- int i = 1;
1496- Token t = getToken(i);
1489+ Token last = getToken(1);
14971490
14981491 // Must start with a name-like token
1499- if (t .kind == S_LONG || t .kind == S_DOUBLE || t .kind == S_HEX
1500- || t .kind == S_CHAR_LITERAL || t .kind == OPENING_BRACKET
1501- || t .kind == CLOSING_BRACKET || t .kind == EOF) {
1492+ if (last .kind == S_LONG || last .kind == S_DOUBLE || last .kind == S_HEX
1493+ || last .kind == S_CHAR_LITERAL || last .kind == OPENING_BRACKET
1494+ || last .kind == CLOSING_BRACKET || last .kind == EOF) {
15021495 return 0;
15031496 }
1504- i++;
15051497
1506- // Walk through dotted name chain
1498+ // Walk through dotted name chain, following the token chain directly;
1499+ // repeated getToken(i) calls rescan from the start each time
15071500 int delimiters = 0;
15081501 List<Token> chainParts = fill ? new ArrayList<Token>() : null;
15091502 while (true) {
1510- t = getToken(i );
1503+ Token t = nextWithItemToken(last );
15111504 if (t.image.equals(".") || t.image.equals("..")
15121505 || t.image.equals("...")) {
15131506 if (!fill && ++delimiters > CHAIN_CACHE_THRESHOLD) {
15141507 return LONG_CHAIN;
15151508 }
1509+ last = nextWithItemToken(t); // skip delimiter, take next part (could be "*")
15161510 if (fill) {
1517- chainParts.add(getToken(i + 1) );
1511+ chainParts.add(last );
15181512 }
1519- i++; // skip delimiter
1520- i++; // skip next part (could be "*")
15211513 } else {
15221514 break;
15231515 }
15241516 }
15251517
15261518 // It's AllTableColumns if the chain ended on "*"
15271519 // i.e., the last name part we skipped over was "*"
1528- // Back up: the last token consumed was at (i-1)
1529- boolean result = getToken(i - 1).image.equals("*");
1520+ boolean result = last.image.equals("*");
15301521
15311522 // Each chain part that would pass the name-like guard walks the same
15321523 // remaining suffix and obtains the same answer.
@@ -2721,9 +2712,8 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
27212712 return false;
27222713 }
27232714 int depth = 1;
2724- int i = 4;
27252715 while (depth > 0) {
2726- t = getToken(i++ );
2716+ t = nextWithItemToken(t );
27272717 if (t == null || t.kind == EOF) {
27282718 return false;
27292719 }
@@ -2733,7 +2723,7 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
27332723 depth--;
27342724 }
27352725 }
2736- t = getToken(i );
2726+ t = nextWithItemToken(t );
27372727 if (t.kind == K_DO) {
27382728 return true;
27392729 }
@@ -2742,8 +2732,8 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
27422732 }
27432733 // the index predicate ends where the conflict action's DO begins
27442734 depth = 0;
2745- for (i++; ; i++ ) {
2746- t = getToken(i );
2735+ while (true ) {
2736+ t = nextWithItemToken(t );
27472737 if (t == null || t.kind == EOF) {
27482738 return false;
27492739 }
@@ -2874,11 +2864,14 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
28742864 * user@host, which the lexer reads as one identifier, counts only when merged is set.
28752865 */
28762866 private boolean isMySqlAccountHostAhead(int offset, boolean merged) {
2877- Token name = getToken(offset);
2867+ return isMySqlAccountHost(getToken(offset), merged);
2868+ }
2869+
2870+ private boolean isMySqlAccountHost(Token name, boolean merged) {
28782871 if (name.kind == S_IDENTIFIER && name.image.indexOf('@') > 0) {
28792872 return merged || name.image.endsWith("@");
28802873 }
2881- Token next = getToken(offset + 1 );
2874+ Token next = nextWithItemToken(name );
28822875 return next.kind == K_AT_SIGN
28832876 || next.kind == S_AT_IDENTIFIER && !next.image.startsWith("@@");
28842877 }
@@ -2901,9 +2894,9 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
29012894 if (isMySqlDialect()) { return true; }
29022895 if (next.kind == K_ALL) { return getToken(4).kind == K_EXCEPT; }
29032896 // role [@ host] [, role [@ host]] ...
2904- for (int i = 3 ; ; i += 2 ) {
2905- if (isMySqlAccountHostAhead(i , false)) { return true; }
2906- if (!",".equals(getToken(i + 1 ).image)) { return false; }
2897+ for (Token role = next ; ; role = nextWithItemToken(nextWithItemToken(role)) ) {
2898+ if (isMySqlAccountHost(role , false)) { return true; }
2899+ if (!",".equals(nextWithItemToken(role ).image)) { return false; }
29072900 }
29082901 }
29092902
@@ -2937,8 +2930,7 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
29372930
29382931 private boolean isObjectPrivilegeAhead() {
29392932 int depth = 0;
2940- for (int i = 1; ; i++) {
2941- Token token = getToken(i);
2933+ for (Token token = getToken(1); ; token = nextWithItemToken(token)) {
29422934 if (token.kind == EOF || ";".equals(token.image)) { return false; }
29432935 if ("(".equals(token.image)) { depth++; }
29442936 else if (")".equals(token.image)) { depth--; }
@@ -2983,10 +2975,9 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
29832975 private boolean isPostgreSqlTriggerAhead() {
29842976 if (getToken(1).kind == K_CONSTRAINT) { return true; }
29852977 if (getToken(1).kind != K_TRIGGER) { return false; }
2986- for (int i = 2; ; i++) {
2987- Token token = getToken(i);
2978+ for (Token token = getToken(2); ; token = nextWithItemToken(token)) {
29882979 if (token.kind == EOF || ";".equals(token.image) || token.kind == K_BEGIN) { return false; }
2989- if (token.kind == K_EXECUTE && (getToken(i + 1 ).kind == K_FUNCTION || getToken(i + 1 ).kind == K_PROCEDURE)) { return true; }
2980+ if (token.kind == K_EXECUTE && (nextWithItemToken(token ).kind == K_FUNCTION || nextWithItemToken(token ).kind == K_PROCEDURE)) { return true; }
29902981 // DuckDB 2.0 uses the standard header with a statement body instead of EXECUTE
29912982 if ("REFERENCING".equalsIgnoreCase(token.image) || token.kind == K_STATEMENT) { return true; }
29922983 }
@@ -3404,8 +3395,7 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
34043395 */
34053396 protected boolean isNamedExprListAhead() {
34063397 int depth = 0;
3407- for (int i = 1; ; i++) {
3408- Token t = getToken(i);
3398+ for (Token t = getToken(1); ; t = nextWithItemToken(t)) {
34093399 if (t.kind == EOF) {
34103400 return false;
34113401 }
0 commit comments