📄 sqltokenizer.java
字号:
/* =============================================================
* SmallSQL : a free Java DBMS library for the Java(tm) platform
* =============================================================
*
* (C) Copyright 2004-2007, by Volker Berlin.
*
* Project Info: http://www.smallsql.de/
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------
* SQLTokenizer.java
* ---------------
* Author: Volker Berlin
*
*/
package smallsql.database;
import java.util.*;
import java.sql.Types;
public class SQLTokenizer {
public static List parseSQL( char[] sql ){
SearchNode node = searchTree;
ArrayList tokens = new ArrayList();
int value = 0;
int tokenStart = 0;
boolean wasWhiteSpace = true;
char quote = 0;
StringBuffer quoteBuffer = new StringBuffer();
for(int i=0; i<sql.length; i++){
char c = sql[i];
switch(c){
case '\"':
case '\'':
if(quote == 0){
quote = c;
}else if(quote == c){
// check on escaped quote
if(i+1<sql.length && sql[i+1] == quote){
quoteBuffer.append(quote);
i++;
}else{
tokens.add( new SQLToken( quoteBuffer.toString(), (quote == '\'') ? STRING : IDENTIFIER, tokenStart, i+1) );
quoteBuffer.setLength(0);
quote = 0;
tokenStart = i+1;
wasWhiteSpace = true;
}
}else quoteBuffer.append(c);
break;
case '.':
if(quote == 0){
// there are follow cases with a point
// "abc"."abc" --> identifier --> multiple tokens
// "5"."3" --> identifier --> multiple tokens
// 5.3 --> number --> one token
// 5.e3 --> number --> one token
// .3 --> number --> one token
// .e3 --> identifier --> multiple tokens
int k=tokenStart;
if(k == i){ // point is first character
if(sql.length> k+1){
char cc = sql[k+1];
if((cc >= '0') && cc <= '9') break; // is a number --> break
}
}else{
for(; k<i; k++){
char cc = sql[k];
if((cc != '-' && cc != '$' && cc < '0') || cc > '9') break; // is identifier --> break
}
if(k>=i) break; // preceding tokens are only digits that it is not an identifier else a floating number
}
}
// character before is not a digit that it is an identifier
// no break;
case '-':
if(quote == 0 && !wasWhiteSpace){
char c1 = sql[tokenStart];
char cx = sql[i-1];
if(((c1 >= '0' && c1 <= '9') || c1 == '.') && (cx == 'e' || cx == 'E'))
//negative exponential number
break;
if(c1 == '$' && tokenStart+1 == i)
// money number
break;
}
case ' ':
case '\t':
case '\n':
case '\r':
case ',':
case '(':
case ')':
case '{':
case '}':
case '*':
case '+':
case '/':
case '%':
case '&':
case '|':
case '=':
case '<':
case '>':
case '?':
case '^':
case '~':
if(quote == 0){
if(!wasWhiteSpace){
tokens.add( new SQLToken( value, tokenStart, i) );
value = 0;
}
switch(c){
case ' ':
case '\t':
case '\n':
case '\r':
// skip this characters, this are not tokens, this are only source formatter
break;
case '<':
if((i+1 < sql.length) && (sql[i+1] == '>')){
tokens.add( new SQLToken( UNEQUALS, i, i+2) );
i++;
break;
}
case '>':
if((i+1 < sql.length) && (sql[i+1] == '=')){
tokens.add( new SQLToken( 100 + c, i, i+2) );
i++;
break;
}
default:
tokens.add( new SQLToken( c, i, i+1) );
}
wasWhiteSpace = true;
tokenStart = i+1;
}else{
quoteBuffer.append(c);
}
break;
default:
if(quote == 0){
if(wasWhiteSpace){
node = searchTree;
}else{
if(node == null){
value = 0;
wasWhiteSpace = false;
break;
}
}
c |= 0x20; // case insensitive
while(node != null && node.letter != c) node = node.nextEntry;
if(node != null){
value = node.value;
node = node.nextLetter;
}else{
value = 0;
node = null;
}
}else{
quoteBuffer.append(c);
}
wasWhiteSpace = false;
break;
}
}
if(!wasWhiteSpace){
tokens.add( new SQLToken( value, tokenStart, sql.length) );
}
return tokens;
}
static private void addKeyWord( String keyword, int value){
keywords.put( Utils.getInteger( value), keyword );
char[] letters = keyword.toCharArray();
if(searchTree == null){
searchTree = new SearchNode();
searchTree.letter = (char)(letters[0] | 0x20);
}
SearchNode prev = null;
SearchNode node = searchTree;
boolean wasNextEntry = true;
for(int i=0; i<letters.length; i++){
char c = (char)(letters[i] | 0x20);
while(node != null && node.letter != c) {
prev = node;
node = node.nextEntry;
wasNextEntry = true;
}
if(node == null){
node = new SearchNode();
node.letter = c;
if(wasNextEntry)
prev.nextEntry = node;
else prev.nextLetter = node;
wasNextEntry = false;
prev = node;
node = null;
}else{
prev = node;
node = node.nextLetter;
wasNextEntry = false;
}
}
prev.value = value;
}
static final String getKeyWord(int key){
return (String)keywords.get( Utils.getInteger(key) );
}
static final int getSQLDataType(int type){
// on change of this map the order from getTypeInfo need to be change
switch(type){
case SQLTokenizer.BIT:
return Types.BIT;
case SQLTokenizer.BOOLEAN:
return Types.BOOLEAN;
case SQLTokenizer.BINARY:
return Types.BINARY;
case SQLTokenizer.VARBINARY:
return Types.VARBINARY;
case SQLTokenizer.LONGVARBINARY:
return Types.LONGVARBINARY;
case SQLTokenizer.BLOB:
return Types.BLOB;
case SQLTokenizer.TINYINT:
return Types.TINYINT;
case SQLTokenizer.SMALLINT:
return Types.SMALLINT;
case SQLTokenizer.INT:
return Types.INTEGER;
case SQLTokenizer.BIGINT:
return Types.BIGINT;
case SQLTokenizer.SMALLMONEY:
case SQLTokenizer.MONEY:
case SQLTokenizer.DECIMAL:
return Types.DECIMAL;
case SQLTokenizer.NUMERIC:
return Types.NUMERIC;
case SQLTokenizer.REAL:
return Types.REAL;
case SQLTokenizer.FLOAT:
return Types.FLOAT;
case SQLTokenizer.DOUBLE:
return Types.DOUBLE;
case SQLTokenizer.DATE:
return Types.DATE;
case SQLTokenizer.TIME:
return Types.TIME;
case SQLTokenizer.TIMESTAMP:
case SQLTokenizer.SMALLDATETIME:
return Types.TIMESTAMP;
case SQLTokenizer.CHAR:
case SQLTokenizer.NCHAR:
return Types.CHAR;
case SQLTokenizer.VARCHAR:
case SQLTokenizer.NVARCHAR:
return Types.VARCHAR;
case SQLTokenizer.LONGNVARCHAR:
case SQLTokenizer.LONGVARCHAR:
return Types.LONGVARCHAR;
case SQLTokenizer.CLOB:
case SQLTokenizer.NCLOB:
return Types.CLOB;
case SQLTokenizer.JAVA_OBJECT:
return Types.JAVA_OBJECT;
case SQLTokenizer.UNIQUEIDENTIFIER:
return -11;
case SQLTokenizer.NULL:
return Types.NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -