/** * NOTE: {@link MySQLToken#IDENTIFIER id} dosn't include <code>'.'</code> for sake of performance * issue (based on <i>shaojin.wensj</i>'s design). However, it is not convenient for MySQL * compatibility. e.g. <code>".123f"</code> will be regarded as <code>".123"</code> and <code>"f" * </code> in MySQL, but in this {@link MySQLLexer}, it will be <code>"."</code> and <code>"123f" * </code> because <code>".123f"</code> may be part of <code>"db1.123f"</code> and <code>"123f" * </code> is the table name. * * @param initSize how many char has already been consumed */ private void scanIdentifierFromNumber(int initOffset, int initSize) throws SQLSyntaxErrorException { offsetCache = initOffset; sizeCache = initSize; for (; CharTypes.isIdentifierChar(ch); ++sizeCache) { scanChar(); } updateStringValue(sql, offsetCache, sizeCache); MySQLToken tok = keywods.getKeyword(stringValueUppercase); token = tok == null ? MySQLToken.IDENTIFIER : tok; }
/** * if first char is <code>.</code>, token may be {@link MySQLToken#PUNC_DOT} if invalid char is * presented after <code>.</code> */ protected void scanNumber() throws SQLSyntaxErrorException { offsetCache = curIndex; sizeCache = 1; final boolean fstDot = ch == '.'; boolean dot = fstDot; boolean sign = false; int state = fstDot ? 1 : 0; for (; scanChar() != MySQLLexer.EOI; ++sizeCache) { switch (state) { case 0: if (CharTypes.isDigit(ch)) { } else if (ch == '.') { dot = true; state = 1; } else if (ch == 'e' || ch == 'E') { state = 3; } else if (CharTypes.isIdentifierChar(ch)) { scanIdentifierFromNumber(offsetCache, sizeCache); return; } else { token = MySQLToken.LITERAL_NUM_PURE_DIGIT; return; } break; case 1: if (CharTypes.isDigit(ch)) { state = 2; } else if (ch == 'e' || ch == 'E') { state = 3; } else if (CharTypes.isIdentifierChar(ch) && fstDot) { sizeCache = 1; ch = sql[curIndex = offsetCache + 1]; token = MySQLToken.PUNC_DOT; return; } else { token = MySQLToken.LITERAL_NUM_MIX_DIGIT; return; } break; case 2: if (CharTypes.isDigit(ch)) { } else if (ch == 'e' || ch == 'E') { state = 3; } else if (CharTypes.isIdentifierChar(ch) && fstDot) { sizeCache = 1; ch = sql[curIndex = offsetCache + 1]; token = MySQLToken.PUNC_DOT; return; } else { token = MySQLToken.LITERAL_NUM_MIX_DIGIT; return; } break; case 3: if (CharTypes.isDigit(ch)) { state = 5; } else if (ch == '+' || ch == '-') { sign = true; state = 4; } else if (fstDot) { sizeCache = 1; ch = sql[curIndex = offsetCache + 1]; token = MySQLToken.PUNC_DOT; return; } else if (!dot) { if (CharTypes.isIdentifierChar(ch)) { scanIdentifierFromNumber(offsetCache, sizeCache); } else { updateStringValue(sql, offsetCache, sizeCache); MySQLToken tok = keywods.getKeyword(stringValueUppercase); token = tok == null ? MySQLToken.IDENTIFIER : tok; } return; } else { throw err("invalid char after '.' and 'e' for as part of number: " + ch); } break; case 4: if (CharTypes.isDigit(ch)) { state = 5; break; } else if (fstDot) { sizeCache = 1; ch = sql[curIndex = offsetCache + 1]; token = MySQLToken.PUNC_DOT; } else if (!dot) { ch = sql[--curIndex]; --sizeCache; updateStringValue(sql, offsetCache, sizeCache); MySQLToken tok = keywods.getKeyword(stringValueUppercase); token = tok == null ? MySQLToken.IDENTIFIER : tok; } else { throw err("expect digit char after SIGN for 'e': " + ch); } return; case 5: if (CharTypes.isDigit(ch)) { break; } else if (CharTypes.isIdentifierChar(ch)) { if (fstDot) { sizeCache = 1; ch = sql[curIndex = offsetCache + 1]; token = MySQLToken.PUNC_DOT; } else if (!dot) { if (sign) { ch = sql[curIndex = offsetCache]; scanIdentifierFromNumber(curIndex, 0); } else { scanIdentifierFromNumber(offsetCache, sizeCache); } } else { token = MySQLToken.LITERAL_NUM_MIX_DIGIT; } } else { token = MySQLToken.LITERAL_NUM_MIX_DIGIT; } return; } } switch (state) { case 0: token = MySQLToken.LITERAL_NUM_PURE_DIGIT; return; case 1: if (fstDot) { token = MySQLToken.PUNC_DOT; return; } case 2: case 5: token = MySQLToken.LITERAL_NUM_MIX_DIGIT; return; case 3: if (fstDot) { sizeCache = 1; ch = sql[curIndex = offsetCache + 1]; token = MySQLToken.PUNC_DOT; } else if (!dot) { updateStringValue(sql, offsetCache, sizeCache); MySQLToken tok = keywods.getKeyword(stringValueUppercase); token = tok == null ? MySQLToken.IDENTIFIER : tok; } else { throw err("expect digit char after SIGN for 'e': " + ch); } return; case 4: if (fstDot) { sizeCache = 1; ch = sql[curIndex = offsetCache + 1]; token = MySQLToken.PUNC_DOT; } else if (!dot) { ch = sql[--curIndex]; --sizeCache; updateStringValue(sql, offsetCache, sizeCache); MySQLToken tok = keywods.getKeyword(stringValueUppercase); token = tok == null ? MySQLToken.IDENTIFIER : tok; } else { throw err("expect digit char after SIGN for 'e': " + ch); } return; } }