⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sqlparser.java

📁 這是一個油Java實作的資料庫系統 是個入門的好材料
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/* =============================================================
 * 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.]
 *
 * ---------------
 * SQLParser.java
 * ---------------
 * Author: Volker Berlin
 * 
 */
package smallsql.database;

import java.util.List;
import java.sql.*;
import smallsql.database.language.Language;

final class SQLParser {

	SSConnection con;
	private char[] sql;
    private List tokens;
    private int tokenIdx;

    Command parse(SSConnection con, String sqlString) throws SQLException{
    	this.con = con;
        Command cmd = parse( sqlString.toCharArray() );
        SQLToken token = nextToken();
        if(token != null){
        	throw createSyntaxError(token, Language.STXADD_ADDITIONAL_TOK);
        }
        return cmd;
    }
    
    final private Command parse(char[] sql) throws SQLException{
        this.sql = sql;
        this.tokens = SQLTokenizer.parseSQL( sql );
        tokenIdx = 0;

        SQLToken token = nextToken(COMMANDS);
        switch (token.value){
            case SQLTokenizer.SELECT:
                    return select();
            case SQLTokenizer.DELETE:
                    return delete();
            case SQLTokenizer.INSERT:
                    return insert();
            case SQLTokenizer.UPDATE:
                    return update();
            case SQLTokenizer.CREATE:
                    return create();
            case SQLTokenizer.DROP:
                    return drop();
            case SQLTokenizer.ALTER:
                    return alter();
            case SQLTokenizer.SET:
                    return set();
			case SQLTokenizer.USE:
					token = nextToken(MISSING_EXPRESSION);
					String name = token.getName( sql );
					checkValidIdentifier( name, token );
					CommandSet set = new CommandSet( con.log, SQLTokenizer.USE);
					set.name = name;
					return set;
            case SQLTokenizer.EXECUTE:
                    return execute();
            case SQLTokenizer.TRUNCATE:
            		return truncate();
            default:
                    throw new Error();
        }
    }
    
    
    Expression parseExpression(String expr) throws SQLException{
		this.sql = expr.toCharArray();
		this.tokens = SQLTokenizer.parseSQL( sql );
		tokenIdx = 0;
    	return expression( null, 0);
    }

    /**
	 * Create a syntax error message, using a custom message.
	 * 
	 * @param token
	 *            token object; if not null, generates a SYNTAX_BASE_OFS,
	 *            otherwise a SYNTAX_BASE_END.
	 * @param addMessage
	 *            additional message object to append.
	 */
    private SQLException createSyntaxError(SQLToken token, String addMessageCode) {
    	String message = getErrorString(token, addMessageCode, null);
    	return SmallSQLException.create(Language.CUSTOM_MESSAGE, message);
    }
    
    /**
	 * Create a syntax error message, using a message with a parameter.
	 * 
	 * @param token
	 *            token object; if not null, generates a SYNTAX_BASE_OFS,
	 *            otherwise a SYNTAX_BASE_END.
	 * @param addMessageCode
	 *            additional message[Code] to append.
	 * @param param0
	 *            parameter.
	 */
    private SQLException createSyntaxError(SQLToken token, String addMessageCode, 
    		Object param0) {
    	String message = getErrorString(token, addMessageCode, param0);
    	return SmallSQLException.create(Language.CUSTOM_MESSAGE, message);
    }
    
    /**
	 * Create an "Additional keyword required" syntax error.
	 * 
	 * @param token
	 *            token object.
	 * @param validValues
	 *            valid values.
	 * @return Exception.
	 */
    private SQLException createSyntaxError(SQLToken token, int[] validValues){
    	String msgStr = SmallSQLException.translateMsg(
    			Language.STXADD_KEYS_REQUIRED, new Object[] { });
    	
    	StringBuffer msgBuf = new StringBuffer( msgStr );

        for(int i=0; i<validValues.length; i++){
            String name = SQLTokenizer.getKeyWord(validValues[i]);
            if(name == null) name = String.valueOf( (char)validValues[i] );
            msgBuf.append( name );
            if (i < validValues.length - 2)
                msgBuf.append( ", ");
            else
            if ( i == validValues.length - 2 )
                msgBuf.append( " or ");
        }

    	String message = getErrorString(
    			token, Language.CUSTOM_MESSAGE, msgBuf);
    	return SmallSQLException.create(Language.CUSTOM_MESSAGE, message);
    }

    /**
	 * Create the complete error string (begin + middle + end).
	 * 
	 * @param token
	 *            token object.
	 * @param middleMsgCode
	 *            middle message[code].
	 * @param middleMsgParam
	 *            middle message[code] parameter.
	 * @return complete error message string.
	 */
    private String getErrorString(SQLToken token, String middleMsgCode, 
    		Object middleMsgParam) {
    	StringBuffer buffer = new StringBuffer(1024);

    	/* begin */
    	
        if(token != null){
        	Object[] params = { String.valueOf(token.offset),
        						String.valueOf(sql, token.offset, token.length) };
        	String begin = SmallSQLException.translateMsg(Language.SYNTAX_BASE_OFS, params);
        	buffer.append(begin);
        }
        else{
        	String begin = SmallSQLException.translateMsg(
        			Language.SYNTAX_BASE_END, new Object[] { });
        	buffer.append(begin);
        }
    	
    	/* middle */
    	
    	String middle = SmallSQLException.translateMsg(
    			middleMsgCode, new Object[] { middleMsgParam });
    	
    	buffer.append(middle);
    	
    	/* end */
    	
        int valOffset = (token != null) ? token.offset : sql.length;
        int valBegin = Math.max( 0, valOffset-40);
        int valEnd   = Math.min( valOffset+20, sql.length );
        String lineSeparator = System.getProperty( "line.separator" );
        buffer.append( lineSeparator );
        buffer.append( sql, valBegin, valEnd-valBegin);
        buffer.append( lineSeparator );
        for(; valBegin<valOffset; valBegin++) buffer.append(' ');
        buffer.append('^');
    	
    	return buffer.toString();    	
    }
    
    private void checkValidIdentifier(String name, SQLToken token) throws SQLException{
        if(token.value == SQLTokenizer.ASTERISK) return;
        if(token.value != SQLTokenizer.VALUE &&
		   token.value != SQLTokenizer.IDENTIFIER &&
           token.value < 200){
            throw createSyntaxError( token, Language.STXADD_IDENT_EXPECT);
        }
        if(name.length() == 0) {
            throw createSyntaxError( token, Language.STXADD_IDENT_EMPTY, name);
        }
        char firstChar = name.charAt(0);
		if(firstChar != '#' && firstChar < '@') {
			throw createSyntaxError( token, Language.STXADD_IDENT_WRONG, name );
		}
    }
    
	/**
     * Returns a valid identifier from this token.
     * @param token the token of the identifier
     * @return the string with the name
     * @throws SQLException if the identifier is invalid
     */
    private String getIdentifier(SQLToken token) throws SQLException{
    	String name = token.getName(sql);
    	checkValidIdentifier( name, token );
    	return name;
    }
    
    
    /**
     * Returns a valid identifier from the next token from token stack.
     * @return the string with the name
     * @throws SQLException if the identifier is invalid
     */
    private String nextIdentifier() throws SQLException{
    	return getIdentifier( nextToken( MISSING_IDENTIFIER ) );
    }
    
    
    /**
     * Check if the identifier is a 2 part name with a point in the middle like FIRST.SECOND
     * @param name the name of the first part
     * @return the second part if exist else returns the first part
     * @throws SQLException 
     */
    private String nextIdentiferPart(String name) throws SQLException{
        SQLToken token = nextToken();
        //check if the object name include a database name
        if(token != null && token.value == SQLTokenizer.POINT){
            return nextIdentifier();
        }else{
            previousToken();
        }
        return name;
    }
    
    
    final private boolean isKeyword(SQLToken token){
    	if(token == null) return false;
    	switch(token.value){
    		case SQLTokenizer.SELECT:
    		case SQLTokenizer.INSERT:
    		case SQLTokenizer.UPDATE:
    		case SQLTokenizer.UNION:
    		case SQLTokenizer.FROM:
    		case SQLTokenizer.WHERE:
    		case SQLTokenizer.GROUP:
    		case SQLTokenizer.HAVING:
			case SQLTokenizer.ORDER:
    		case SQLTokenizer.COMMA:
			case SQLTokenizer.SET:
            case SQLTokenizer.JOIN:
    			return true;
    	}
    	return false;
    }
    
	/** 
	 * Return the last token that the method nextToken has return
	 */
	private SQLToken lastToken(){
		if(tokenIdx > tokens.size()){
			return null;
		}
		return (SQLToken)tokens.get( tokenIdx-1 );
	}
    private void previousToken(){
        tokenIdx--;
    }

    private SQLToken nextToken(){
        if(tokenIdx >= tokens.size()){
            tokenIdx++; // must be ever increment that the method previousToken() is working
            return null;
        }
        return (SQLToken)tokens.get( tokenIdx++ );
    }

    private SQLToken nextToken( int[] validValues) throws SQLException{
        SQLToken token = nextToken();
        if(token == null) throw createSyntaxError( token, validValues);
        if(validValues == MISSING_EXPRESSION){
            return token; // an expression can be contained in every token.
        }
        if(validValues == MISSING_IDENTIFIER){
            // the follow token are not valid identifier
            switch(token.value){
                case SQLTokenizer.PARENTHESIS_L:
                case SQLTokenizer.PARENTHESIS_R:
                case SQLTokenizer.COMMA:
                    throw createSyntaxError( token, validValues);
            }
            return token;
        }
        for(int i=validValues.length-1; i>=0; i--){
            if(token.value == validValues[i]) return token;
        }
        throw createSyntaxError( token, validValues);
    }
    

    /**
     * A single SELECT of a UNION or only a simple single SELECT.
     * @return
     * @throws SQLException
     */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -