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

📄 sqlparser.java

📁 java 数据库 功能强大 效率高 SmallSQL Database is a free DBMS library for the Java(tm) platform. It runs on
💻 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.*;


final class SQLParser {

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

    Command parse(SSConnection con, String sql) throws SQLException{
    	this.con = con;
        Command cmd = parse( sql.toCharArray() );
        SQLToken token = nextToken();
        if(token != null){
        		throw createSyntaxError( token, "Additional token after end of SQL statement");
        }
        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);
    }

    private StringBuffer getSyntaxError( SQLToken token ){
        StringBuffer msg = new StringBuffer(256);
        if(token != null){
            msg.append( "Syntax error at offset ").append( token.offset )
               .append( " on '" ).append( sql, token.offset, token.length ).append("'. ");
        }else{
            msg.append( "Syntax error, unexpected end of SQL string. ");
        }
        return msg;
    }

    private SQLException createSyntaxError(SQLToken token, int[] validValues){
        StringBuffer msg = getSyntaxError( token );

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

        return createSyntaxError( msg, token );
    }

    private SQLException createSyntaxError( StringBuffer msg, SQLToken token){
        int offset = (token != null) ? token.offset : sql.length;
        int begin = Math.max( 0, offset-40);
        int end   = Math.min( offset+20, sql.length );
        String lineSeparator = System.getProperty( "line.separator" );
        msg.append( lineSeparator );
        msg.append( sql, begin, end-begin);
        msg.append( lineSeparator );
        for(; begin<offset; begin++) msg.append(' ');
        msg.append('^');
        return Utils.createSQLException( msg.toString()/* , offset*/ );
    }

    private SQLException createSyntaxError(SQLToken token, String errorMsg){
        StringBuffer msg = getSyntaxError( token ).append(errorMsg);
        return createSyntaxError( msg, token );
    }
    

    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, "Identifier expected.");
        }
        if(name.length() == 0)
            throw createSyntaxError( token, "Empty Identifier.");
        char firstChar = name.charAt(0);
		if(firstChar != '#' && firstChar < '@')
            throw createSyntaxError( token, "Wrong Identifier '" + 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 identifer from the next token from token stack.
     * @return the string with the name
     * @throws SQLException if the identifer is invalid
     */
    private String nextIdentifier() throws SQLException{
    	return getIdentifier( nextToken( MISSING_IDENTIFIER ) );
    }
    
    
    /**
     * Check if the identifer 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:
    			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++; // erh鰄t werden, damit previousToken() funktioniert
            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; // eine Expression kann in jedem Token enthalten sein
        if(validValues == MISSING_IDENTIFIER){
            // folgende Token sind keine g黮tigen Identifer
            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
     */
    private CommandSelect singleSelect() throws SQLException{
        CommandSelect selCmd = new CommandSelect(con.log);
		SQLToken token;
        // scan for prefixe like DISTINCT, ALL and the TOP clause; sample: SELECT TOP 15 ...
Switch: while(true){
			token = nextToken(MISSING_EXPRESSION);
			switch(token.value){
				case SQLTokenizer.TOP:
					token = nextToken(MISSING_EXPRESSION);
					try{
						int maxRows = Integer.parseInt(token.getName(sql));
						selCmd.setMaxRows(maxRows);
					}catch(Exception e){
						throw createSyntaxError(token, e.getMessage());
					}
					break;
				case SQLTokenizer.ALL:
					selCmd.setDistinct(false);
					break;
				case SQLTokenizer.DISTINCT:
					selCmd.setDistinct(true);
					break;
				default:
					previousToken();
					break Switch;
			}
		}

        while(true){
            Expression column = expression(selCmd, 0);
            selCmd.addColumnExpression( column );

            token = nextToken();
            if(token == null) return selCmd; // SELECT ohne FROM

            boolean as = false;
            if(token.value == SQLTokenizer.AS){
                token = nextToken(MISSING_EXPRESSION);
                as = true;
            }

            if(as || (!isKeyword(token))){
            	String alias = getIdentifier( token);
                column.setAlias( alias );
                token = nextToken();
                if(token == null) return selCmd; // SELECT ohne FROM
            }

            switch(token.value){
                case SQLTokenizer.COMMA:
                        if(column == null) throw createSyntaxError( token, MISSING_EXPRESSION );
                        column = null;
                        break;
                case SQLTokenizer.FROM:
                        if(column == null) throw createSyntaxError( token, MISSING_EXPRESSION );
                        column = null;
                        from(selCmd);
                        return selCmd;

                default:
                        if(!isKeyword(token))
                			throw createSyntaxError( token, new int[]{SQLTokenizer.COMMA, SQLTokenizer.FROM} );
                        previousToken();
                        return selCmd;
            }
        }

⌨️ 快捷键说明

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