EMMA Coverage Report (generated Wed Jun 28 19:54:35 CEST 2006)
[all classes][smallsql.database]

COVERAGE SUMMARY FOR SOURCE FILE [SQLParser.java]

nameclass, %method, %block, %line, %
SQLParser.java100% (1/1)92%  (45/49)84%  (4076/4832)85%  (887,6/1044)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SQLParser100% (1/1)92%  (45/49)84%  (4076/4832)85%  (887,6/1044)
alter (): Command 0%   (0/1)0%   (0/4)0%   (0/1)
createIndex (): CommandCreateDatabase 0%   (0/1)0%   (0/4)0%   (0/1)
createProcedure (): CommandCreateDatabase 0%   (0/1)0%   (0/4)0%   (0/1)
execute (): Command 0%   (0/1)0%   (0/4)0%   (0/1)
create (): Command 100% (1/1)52%  (17/33)61%  (5,5/9)
checkValidIdentifer (String, SQLToken): void 100% (1/1)52%  (25/48)70%  (7/10)
parse (char []): Command 100% (1/1)54%  (41/76)59%  (13/22)
join (Command, DataSources, RowSource, int): Join 100% (1/1)57%  (39/68)48%  (6,3/13)
drop (): Command 100% (1/1)60%  (40/67)62%  (9,8/16)
delete (): Command 100% (1/1)64%  (21/33)67%  (6/9)
datatype (boolean): Column 100% (1/1)66%  (148/225)64%  (44/69)
expressionSingle (Command, SQLToken): Expression 100% (1/1)70%  (288/411)70%  (52,2/75)
set (): CommandSet 100% (1/1)71%  (10/14)75%  (3/4)
createDatabase (): CommandCreateDatabase 100% (1/1)76%  (16/21)83%  (2,5/3)
singleSelect (): CommandSelect 100% (1/1)79%  (118/150)87%  (37,6/43)
createTable (): CommandCreateTable 100% (1/1)81%  (224/277)83%  (59,8/72)
isKeyword (SQLToken): boolean 100% (1/1)82%  (9/11)88%  (3,5/4)
function (Command, SQLToken, boolean): Expression 100% (1/1)83%  (876/1059)89%  (226,8/255)
tableSource (Command, DataSources): RowSource 100% (1/1)83%  (89/107)81%  (21/26)
rowSource (Command, DataSources, int): RowSource 100% (1/1)84%  (140/167)95%  (39/41)
expressionDefList (Command, Expressions, Strings): void 100% (1/1)84%  (58/69)80%  (13,6/17)
setTransaction (): CommandSet 100% (1/1)87%  (54/62)89%  (17/19)
update (): Command 100% (1/1)87%  (68/78)94%  (18,7/20)
lastToken (): SQLToken 100% (1/1)88%  (15/17)67%  (2/3)
expressionParenthesisList (Command): Expressions 100% (1/1)89%  (34/38)92%  (11/12)
createSyntaxError (SQLToken, int []): SQLException 100% (1/1)90%  (53/59)96%  (10,5/11)
nextToken (int []): SQLToken 100% (1/1)90%  (45/50)90%  (9/10)
expressionTokenList (Command, int): Expressions 100% (1/1)91%  (48/53)94%  (17/18)
index (Command, int, String): IndexDescription 100% (1/1)93%  (50/54)92%  (12/13)
expression (Command, int): Expression 100% (1/1)95%  (196/207)92%  (51,7/56)
caseExpr (Command): ExpressionFunctionCase 100% (1/1)95%  (72/76)95%  (21/22)
insert (): Command 100% (1/1)96%  (104/108)97%  (28/29)
<static initializer> 100% (1/1)100% (771/771)100% (47/47)
SQLParser (): void 100% (1/1)100% (3/3)100% (1/1)
createSyntaxError (SQLToken, String): SQLException 100% (1/1)100% (11/11)100% (2/2)
createSyntaxError (StringBuffer, SQLToken): SQLException 100% (1/1)100% (62/62)100% (10/10)
createView (): CommandCreateView 100% (1/1)100% (49/49)100% (9/9)
from (CommandSelect): void 100% (1/1)100% (39/39)100% (14/14)
getSyntaxError (SQLToken): StringBuffer 100% (1/1)100% (32/32)100% (6/6)
group (CommandSelect): void 100% (1/1)100% (11/11)100% (3/3)
having (CommandSelect): void 100% (1/1)100% (7/7)100% (2/2)
nextToken (): SQLToken 100% (1/1)100% (26/26)100% (4/4)
order (CommandSelect): void 100% (1/1)100% (11/11)100% (3/3)
parse (SSConnection, String): Command 100% (1/1)100% (20/20)100% (6/6)
parseExpression (String): Expression 100% (1/1)100% (17/17)100% (4/4)
previousToken (): void 100% (1/1)100% (7/7)100% (2/2)
select (): CommandSelect 100% (1/1)100% (89/89)100% (21/21)
truncate (): Command 100% (1/1)100% (16/16)100% (4/4)
where (CommandSelect): void 100% (1/1)100% (7/7)100% (2/2)

1/* =============================================================
2 * SmallSQL : a free Java DBMS library for the Java(tm) platform
3 * =============================================================
4 *
5 * (C) Copyright 2004-2006, by Volker Berlin.
6 *
7 * Project Info:  http://www.smallsql.de/
8 *
9 * This library is free software; you can redistribute it and/or modify it 
10 * under the terms of the GNU Lesser General Public License as published by 
11 * the Free Software Foundation; either version 2.1 of the License, or 
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but 
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
17 * License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
22 * USA.  
23 *
24 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
25 * in the United States and other countries.]
26 *
27 * ---------------
28 * SQLParser.java
29 * ---------------
30 * Author: Volker Berlin
31 * 
32 */
33package smallsql.database;
34 
35import java.util.List;
36import java.sql.*;
37 
38 
39public class SQLParser {
40 
41        SSConnection con;
42        private char[] sql;
43    private List tokens;
44    private int tokenIdx;
45 
46    Command parse(SSConnection con, String sql) throws SQLException{
47            this.con = con;
48        Command cmd = parse( sql.toCharArray() );
49        SQLToken token = nextToken();
50        if(token != null){
51                        throw createSyntaxError( token, "Additional token after end of SQL statement");
52        }
53        return cmd;
54    }
55    
56    
57    final private Command parse(char[] sql) throws SQLException{
58        this.sql = sql;
59        this.tokens = SQLTokenizer.parseSQL( sql );
60        tokenIdx = 0;
61 
62        SQLToken token = nextToken(COMMANDS);
63        switch (token.value){
64            case SQLTokenizer.SELECT:
65                    return select();
66            case SQLTokenizer.DELETE:
67                    return delete();
68            case SQLTokenizer.INSERT:
69                    return insert();
70            case SQLTokenizer.UPDATE:
71                    return update();
72            case SQLTokenizer.CREATE:
73                    return create();
74            case SQLTokenizer.DROP:
75                    return drop();
76            case SQLTokenizer.ALTER:
77                    return alter();
78            case SQLTokenizer.SET:
79                    return set();
80                        case SQLTokenizer.USE:
81                                        token = nextToken(MISSING_EXPRESSION);
82                                        String name = token.getName( sql );
83                                        checkValidIdentifer( name, token );
84                                        CommandSet set = new CommandSet( con.log, SQLTokenizer.USE);
85                                        set.name = name;
86                                        return set;
87            case SQLTokenizer.EXECUTE:
88                    return execute();
89            case SQLTokenizer.TRUNCATE:
90                            return truncate();
91            default:
92                    throw new Error();
93        }
94    }
95    
96    
97    Expression parseExpression(String expr) throws SQLException{
98                this.sql = expr.toCharArray();
99                this.tokens = SQLTokenizer.parseSQL( sql );
100                tokenIdx = 0;
101            return expression( null, 0);
102    }
103 
104    private StringBuffer getSyntaxError( SQLToken token ){
105        StringBuffer msg = new StringBuffer(256);
106        if(token != null){
107            msg.append( "Syntax error at offset ").append( token.offset )
108               .append( " on '" ).append( sql, token.offset, token.length ).append("'. ");
109        }else{
110            msg.append( "Syntax error, unexpected end of SQL string. ");
111        }
112        return msg;
113    }
114 
115    private SQLException createSyntaxError(SQLToken token, int[] validValues){
116        StringBuffer msg = getSyntaxError( token );
117 
118        msg.append( "Requied keywords are: " );
119        for(int i=0; i<validValues.length; i++){
120            String name = SQLTokenizer.getKeyWord(validValues[i]);
121            if(name == null) name = String.valueOf( (char)validValues[i] );
122            msg.append( name );
123            if (i < validValues.length - 2)
124                msg.append( ", ");
125            else
126            if ( i == validValues.length - 2 )
127                msg.append( " or ");
128        }
129 
130        return createSyntaxError( msg, token );
131    }
132 
133    private SQLException createSyntaxError( StringBuffer msg, SQLToken token){
134        int offset = (token != null) ? token.offset : sql.length;
135        int begin = Math.max( 0, offset-40);
136        int end   = Math.min( offset+20, sql.length );
137        String lineSeparator = System.getProperty( "line.separator" );
138        msg.append( lineSeparator );
139        msg.append( sql, begin, end-begin);
140        msg.append( lineSeparator );
141        for(; begin<offset; begin++) msg.append(' ');
142        msg.append('^');
143        return new SQLException( msg.toString()/* , offset*/ );
144    }
145 
146    private SQLException createSyntaxError(SQLToken token, String errorMsg){
147        StringBuffer msg = getSyntaxError( token ).append(errorMsg);
148        return createSyntaxError( msg, token );
149    }
150    
151 
152    private void checkValidIdentifer(String name, SQLToken token) throws SQLException{
153        if(token.value == SQLTokenizer.ASTERISK) return;
154        if(token.value != SQLTokenizer.VALUE &&
155                   token.value != SQLTokenizer.IDENTIFER &&
156           token.value < 200){
157            throw createSyntaxError( token, "Identifer expected.");
158        }
159        if(name.length() == 0)
160            throw createSyntaxError( token, "Empty Identifer.");
161                if(name.charAt(0) < '@')
162            throw createSyntaxError( token, "Wrong Identifer '" + name + "'.");
163    }
164    
165    
166    final private boolean isKeyword(SQLToken token){
167            if(token == null) return false;
168            switch(token.value){
169                    case SQLTokenizer.SELECT:
170                    case SQLTokenizer.INSERT:
171                    case SQLTokenizer.UPDATE:
172                    case SQLTokenizer.UNION:
173                    case SQLTokenizer.FROM:
174                    case SQLTokenizer.WHERE:
175                    case SQLTokenizer.GROUP:
176                    case SQLTokenizer.HAVING:
177                        case SQLTokenizer.ORDER:
178                    case SQLTokenizer.COMMA:
179                        case SQLTokenizer.SET:
180                            return true;
181            }
182            return false;
183    }
184    
185        /** 
186         * Return the last token that the method nextToken has return
187         */
188        private SQLToken lastToken(){
189                if(tokenIdx > tokens.size()){
190                        return null;
191                }
192                return (SQLToken)tokens.get( tokenIdx-1 );
193        }
194    private void previousToken(){
195        tokenIdx--;
196    }
197 
198    private SQLToken nextToken(){
199        if(tokenIdx >= tokens.size()){
200            tokenIdx++; // erhöht werden, damit previousToken() funktioniert
201            return null;
202        }
203        return (SQLToken)tokens.get( tokenIdx++ );
204    }
205 
206    private SQLToken nextToken( int[] validValues) throws SQLException{
207        SQLToken token = nextToken();
208        if(token == null) throw createSyntaxError( token, validValues);
209        if(validValues == MISSING_EXPRESSION) return token; // eine Expression kann in jedem Token enthalten sein
210        if(validValues == MISSING_IDENTIFER){
211            // folgende Token sind keine gültigen Identifer
212            switch(token.value){
213                case SQLTokenizer.PARENTHESIS_L:
214                case SQLTokenizer.PARENTHESIS_R:
215                case SQLTokenizer.COMMA:
216                    throw createSyntaxError( token, validValues);
217            }
218            return token;
219        }
220        for(int i=validValues.length-1; i>=0; i--){
221            if(token.value == validValues[i]) return token;
222        }
223        throw createSyntaxError( token, validValues);
224    }
225    
226 
227    /**
228     * A single SELECT of a UNION or only a simple single SELECT.
229     * @return
230     * @throws SQLException
231     */
232    private CommandSelect singleSelect() throws SQLException{
233        CommandSelect selCmd = new CommandSelect(con.log);
234                SQLToken token;
235        // scan for prefixe like DISTINCT, ALL and the TOP clause; sample: SELECT TOP 15 ...
236Switch: while(true){
237                        token = nextToken(MISSING_EXPRESSION);
238                        switch(token.value){
239                                case SQLTokenizer.TOP:
240                                        token = nextToken(MISSING_EXPRESSION);
241                                        try{
242                                                int maxRows = Integer.parseInt(token.getName(sql));
243                                                selCmd.setMaxRows(maxRows);
244                                        }catch(Exception e){
245                                                throw createSyntaxError(token, e.getMessage());
246                                        }
247                                        break;
248                                case SQLTokenizer.ALL:
249                                        selCmd.setDistinct(false);
250                                        break;
251                                case SQLTokenizer.DISTINCT:
252                                        selCmd.setDistinct(true);
253                                        break;
254                                default:
255                                        previousToken();
256                                        break Switch;
257                        }
258                }
259 
260        while(true){
261            Expression column = expression(selCmd, 0);
262            selCmd.addColumnExpression( column );
263 
264            token = nextToken();
265            if(token == null) return selCmd; // SELECT ohne FROM
266 
267            boolean as = false;
268            if(token.value == SQLTokenizer.AS){
269                token = nextToken(MISSING_EXPRESSION);
270                as = true;
271            }
272 
273            if(as || (!isKeyword(token))){
274                    String alias = token.getName( sql );
275                    checkValidIdentifer( alias, token);
276                column.setAlias( alias );
277                token = nextToken();
278                if(token == null) return selCmd; // SELECT ohne FROM
279            }
280 
281            switch(token.value){
282                case SQLTokenizer.COMMA:
283                        if(column == null) throw createSyntaxError( token, MISSING_EXPRESSION );
284                        column = null;
285                        break;
286                case SQLTokenizer.FROM:
287                        if(column == null) throw createSyntaxError( token, MISSING_EXPRESSION );
288                        column = null;
289                        from(selCmd);
290                        return selCmd;
291 
292                default:
293                        if(!isKeyword(token))
294                                        throw createSyntaxError( token, new int[]{SQLTokenizer.COMMA, SQLTokenizer.FROM} );
295                        previousToken();
296                        return selCmd;
297            }
298        }
299    }
300    
301    
302    final private CommandSelect select() throws SQLException{
303                CommandSelect selCmd = singleSelect();
304                SQLToken token = nextToken();
305                                   
306            UnionAll union = null; 
307        
308                while(token != null && token.value == SQLTokenizer.UNION){
309                        if(union == null){
310                                union = new UnionAll();
311                                union.addDataSource(new ViewResult( con, selCmd ));
312                                selCmd = new CommandSelect(con.log);
313                                selCmd.setSource( union );
314                                DataSources from = new DataSources();
315                                from.add(union);
316                                selCmd.setFrom( from );
317                                selCmd.addColumnExpression( new ExpressionName("*") );
318                        }
319                        nextToken(MISSING_ALL);
320                        nextToken(MISSING_SELECT);
321                        union.addDataSource( new ViewResult( con, singleSelect() ) );
322                        token = nextToken();
323                }
324                if(token != null && token.value == SQLTokenizer.ORDER){
325                        order( selCmd );
326                }else{
327                        previousToken();
328                }
329                return selCmd;
330    }
331 
332 
333    private Command delete() throws SQLException{
334            CommandDelete cmd = new CommandDelete(con.log);
335            nextToken(MISSING_FROM);
336            from(cmd);
337                SQLToken token = nextToken();
338                if(token != null){
339                        if(token.value != SQLTokenizer.WHERE)
340                                throw this.createSyntaxError(token, MISSING_WHERE);
341                        where(cmd);
342                }
343                return cmd;
344    }
345 
346 
347        private Command truncate() throws SQLException{
348                CommandDelete cmd = new CommandDelete(con.log);
349                nextToken(MISSING_TABLE);
350                from(cmd);
351                return cmd;
352        }
353 
354 
355    private Command insert() throws SQLException{
356        SQLToken token = nextToken( MISSING_INTO );
357        token = nextToken( MISSING_IDENTIFER );
358        CommandInsert cmd = new CommandInsert( con.log, token.getName(sql) );
359 
360                int parthesisCount = 0;
361 
362                token = nextToken(MISSING_PARENTHESIS_VALUES_SELECT);
363        if(token.value == SQLTokenizer.PARENTHESIS_L){
364                token = nextToken(MISSING_EXPRESSION);
365                if(token.value == SQLTokenizer.SELECT){
366                                parthesisCount++;
367                                cmd.noColumns = true;
368                }else{
369                                previousToken();
370                    Expressions list = expressionParenthesisList(cmd);
371                    for(int i=0; i<list.size(); i++){
372                        cmd.addColumnExpression( list.get( i ) );
373                    }
374                    token = nextToken(MISSING_PARENTHESIS_VALUES_SELECT);
375                }
376        }else cmd.noColumns = true;
377        
378Switch: while(true)
379        switch(token.value){
380                case SQLTokenizer.VALUES:{
381                    token = nextToken(MISSING_PARENTHESIS_L);
382                    cmd.addValues( expressionParenthesisList(cmd) );
383                    return cmd;
384                }
385                case SQLTokenizer.SELECT:
386                        cmd.addValues( select() );
387                        while(parthesisCount-- > 0){
388                                nextToken(MISSING_PARENTHESIS_R);
389                        }
390                        return cmd;
391                case SQLTokenizer.PARENTHESIS_L:
392                        token = nextToken(MISSING_PARENTHESIS_VALUES_SELECT);
393                        parthesisCount++;
394                        continue Switch;
395                default:
396                        throw new Error();
397        }
398    }
399 
400 
401    private Command update() throws SQLException{
402                CommandUpdate cmd = new CommandUpdate(con.log);
403                // read table name
404                DataSources tables = new DataSources();
405                cmd.setFrom( tables );
406                cmd.setSource( rowSource( cmd, tables, 0 ) );
407                
408                SQLToken token = nextToken(MISSING_SET);
409                while(true){
410                        token = nextToken();
411                        Expression dest = expressionSingle( cmd, token);
412                        if(dest.getType() != Expression.NAME) throw createSyntaxError( token, MISSING_IDENTIFER );
413                        nextToken(MISSING_EQUALS);
414                        Expression src = expression(cmd, 0);
415                        cmd.addSetting( dest, src);
416                        token = nextToken();
417                        if(token == null) break;
418                        switch(token.value){
419                                case SQLTokenizer.WHERE:
420                                        where(cmd);
421                                        return cmd;                                
422                                case SQLTokenizer.COMMA:
423                                        continue;
424                                default: throw createSyntaxError( token, MISSING_WHERE_COMMA );
425                        }
426                }
427                return cmd;
428    }
429 
430 
431    private Command create() throws SQLException{
432        SQLToken token = nextToken();
433        if(token == null) throw createSyntaxError( token, COMMANDS_CREATE );
434        switch(token.value){
435            case SQLTokenizer.DATABASE:
436                return createDatabase();
437            case SQLTokenizer.TABLE:
438                return createTable();
439            case SQLTokenizer.VIEW:
440                return createView();
441            case SQLTokenizer.INDEX:
442                return createIndex();
443            case SQLTokenizer.PROCEDURE:
444                return createProcedure();
445            default:
446                throw createSyntaxError( token, COMMANDS_CREATE );
447        }
448    }
449        
450 
451    private CommandCreateDatabase createDatabase() throws SQLException{
452        SQLToken token = nextToken();
453        if(token == null) throw createSyntaxError( token, MISSING_EXPRESSION );
454        return new CommandCreateDatabase( con.log, token.getName(sql));
455    }
456        
457 
458    private CommandCreateTable createTable() throws SQLException{
459        SQLToken token = nextToken( MISSING_IDENTIFER ); // table name
460        String tableName = token.getName(sql);
461        CommandCreateTable cmdCreate = new CommandCreateTable( con.log, tableName);
462        token = nextToken( MISSING_PARENTHESIS_L );
463 
464        nextCol:
465        while(true){
466            token = nextToken( MISSING_EXPRESSION );
467                        
468                        String constraintName;
469            if(token.value == SQLTokenizer.CONSTRAINT){
470                    // reading a CONSTRAINT with name
471                                token = nextToken( MISSING_IDENTIFER );
472                            constraintName = token.getName(sql);
473                                checkValidIdentifer( constraintName, token );
474                                
475                                token = nextToken( MISSING_KEYTYPE );
476            }else{
477                                constraintName = null;
478            }
479                        switch(token.value){
480                                case SQLTokenizer.PRIMARY:
481                                case SQLTokenizer.UNIQUE:
482                                case SQLTokenizer.FOREIGN:
483                                        IndexDescription index = index(cmdCreate, token.value, null);
484                                        index.setName(constraintName);
485                    if(token.value == SQLTokenizer.FOREIGN){
486                        nextToken( MISSING_REFERENCES );
487                        token = nextToken( MISSING_IDENTIFER );
488                        String pk = token.getName(sql);
489                        Expressions expressions = new Expressions();
490                        Strings columns = new Strings();
491                        expressionDefList( cmdCreate, expressions, columns );
492                        IndexDescription pkIndex = new IndexDescription( SQLTokenizer.UNIQUE, expressions, columns);
493                        ForeignKey foreignKey = new ForeignKey(pk, pkIndex, tableName, index);
494                        cmdCreate.addForeingnKey(foreignKey);
495                    }else{
496                        cmdCreate.addIndex( index );
497                    }
498        
499                                        token = nextToken( MISSING_COMMA_PARENTHESIS );
500                                        switch(token.value){
501                                                case SQLTokenizer.PARENTHESIS_R:
502                                                        return cmdCreate;
503                                                case SQLTokenizer.COMMA:
504                                                        continue nextCol;
505                                        }
506            }
507            // the token is a column name
508            String colName = token.getName( sql );
509            
510            Column col = datatype(false);
511            col.setName( colName );
512 
513                        token = nextToken(MISSING_OPTIONS_DATATYPE);
514            boolean nullableWasSet = false;
515            boolean defaultWasSet = col.isAutoIncrement(); // with data type COUNTER allready this value is set
516            while(true){
517                switch(token.value){
518                    case SQLTokenizer.PARENTHESIS_R:
519                        cmdCreate.addColumn( col );
520                        return cmdCreate;
521                    case SQLTokenizer.COMMA:
522                        cmdCreate.addColumn( col );
523                        continue nextCol;
524                    case SQLTokenizer.DEFAULT:
525                        if(defaultWasSet) throw createSyntaxError( token, MISSING_COMMA_PARENTHESIS );
526                                                int offset = token.offset + token.length;
527                        token = nextToken();
528                        if(token != null) offset = token.offset;
529                                            previousToken();                    
530                                                Expression expr = expression(cmdCreate, 0);
531                                                SQLToken last = lastToken();
532                                                int length = last.offset + last.length - offset;
533                                                String def = new String( sql, offset, length );
534                        col.setDefaultValue( expr, def );
535                        defaultWasSet = true;
536                        break;
537                    case SQLTokenizer.IDENTITY:
538                        if(defaultWasSet) throw createSyntaxError( token, MISSING_COMMA_PARENTHESIS );
539                        col.setAutoIncrement(true);
540                        defaultWasSet = true;
541                        break;
542                    case SQLTokenizer.NULL:
543                        if(nullableWasSet) throw createSyntaxError( token, MISSING_COMMA_PARENTHESIS );
544                        //col.setNullable(true); ist bereits default
545                        nullableWasSet = true;
546                        break;
547                    case SQLTokenizer.NOT:
548                        if(nullableWasSet) throw createSyntaxError( token, MISSING_COMMA_PARENTHESIS );
549                        token = nextToken( MISSING_NULL );
550                        col.setNullable(false);
551                        nullableWasSet = true;
552                        break;
553                    case SQLTokenizer.PARENTHESIS_L:
554                        throw createSyntaxError(token, MISSING_COMMA_PARENTHESIS);
555                                        case SQLTokenizer.PRIMARY:
556                                        case SQLTokenizer.UNIQUE:
557                                                IndexDescription index = index(cmdCreate, token.value, colName);
558                                                cmdCreate.addIndex( index );
559                                                break;
560                    default:
561                        throw new Error();
562                }
563                token = nextToken( MISSING_OPTIONS_DATATYPE );
564            }
565        }
566    }
567        
568        /**
569         * Parse construct like:<br>
570         * <li>PRIMARY KEY (col1)
571         * <li>UNIQUE (col1, col2)
572         * <li>FOREIGN KEY REFERENCES ref_table(col1)
573         * @param cmd
574         * @param constraintType one of SQLTokenizer.PRIMARY, SQLTokenizer.UNIQUE or SQLTokenizer.FOREIGN.
575         * @param if it a constrain of the current column else null
576         * @return a new IndexDescription
577         */
578        private IndexDescription index(Command cmd, int constraintType, String columnName) throws SQLException{
579                if(constraintType != SQLTokenizer.UNIQUE) nextToken( MISSING_KEY );
580                SQLToken token = nextToken( MISSING_EXPRESSION );
581                switch(token.value){
582                        case SQLTokenizer.CLUSTERED:
583                        case SQLTokenizer.NONCLUSTERED:
584                                // skipping, this tokens form MS SQL Server are ignored
585                                token = nextToken( MISSING_EXPRESSION );
586                                break;
587                }
588                Strings columns = new Strings();
589                Expressions expressions = new Expressions();
590                if(columnName != null){
591                        //Constraint for a single column together with the column defination
592                        columns.add(columnName);
593                        expressions.add(new ExpressionName(columnName));
594                        previousToken();
595                }else{
596                        //Constraint as addition defination
597            previousToken();
598            expressionDefList( cmd, expressions, columns );
599                }
600 
601                return new IndexDescription( constraintType, expressions, columns);
602        }
603 
604 
605    /**
606     * Read a DataTpe description. This is used for CREATE TABLE and CONVERT function. 
607     * @param isEscape true then the datatypes start with SQL_
608     */
609    private Column datatype(boolean isEscape) throws SQLException{
610                SQLToken token;
611                int dataType;
612                if(isEscape){
613                        token = nextToken( MISSING_SQL_DATATYPE );
614                        switch(token.value){
615                                case SQLTokenizer.SQL_BIGINT:                         dataType = SQLTokenizer.BIGINT;                break;
616                                case SQLTokenizer.SQL_BINARY:                        dataType = SQLTokenizer.BINARY;         break;
617                                case SQLTokenizer.SQL_BIT:                                dataType = SQLTokenizer.BIT;                break;
618                                case SQLTokenizer.SQL_CHAR:                                dataType = SQLTokenizer.CHAR;                break;
619                                case SQLTokenizer.SQL_DATE:                                dataType = SQLTokenizer.DATE;                break;
620                                case SQLTokenizer.SQL_DECIMAL:                        dataType = SQLTokenizer.DECIMAL;        break;
621                                case SQLTokenizer.SQL_DOUBLE:                        dataType = SQLTokenizer.DOUBLE;                break;
622                                case SQLTokenizer.SQL_FLOAT:                        dataType = SQLTokenizer.FLOAT;                break;
623                                case SQLTokenizer.SQL_INTEGER:                        dataType = SQLTokenizer.INT;                break;
624                                case SQLTokenizer.SQL_LONGVARBINARY:        dataType = SQLTokenizer.LONGVARBINARY;break;
625                                case SQLTokenizer.SQL_LONGVARCHAR:                dataType = SQLTokenizer.LONGVARCHAR;break;
626                                case SQLTokenizer.SQL_REAL:                                dataType = SQLTokenizer.REAL;                break;
627                                case SQLTokenizer.SQL_SMALLINT:                        dataType = SQLTokenizer.SMALLINT;        break;
628                                case SQLTokenizer.SQL_TIME:                                dataType = SQLTokenizer.TIME;                break;
629                                case SQLTokenizer.SQL_TIMESTAMP:                dataType = SQLTokenizer.TIMESTAMP;        break;
630                                case SQLTokenizer.SQL_TINYINT:                        dataType = SQLTokenizer.TINYINT;        break;
631                                case SQLTokenizer.SQL_VARBINARY:                dataType = SQLTokenizer.VARBINARY;        break;
632                                case SQLTokenizer.SQL_VARCHAR:                        dataType = SQLTokenizer.VARCHAR;        break;
633                                default: throw new Error();
634                        }
635                }else{
636                        token = nextToken( MISSING_DATATYPE );
637                        dataType = token.value;
638                }
639                Column col = new Column();
640 
641                // zweiteiliger Datentyp
642                if(dataType == SQLTokenizer.LONG){
643                        token = nextToken();
644                        if(token != null && token.value == SQLTokenizer.RAW){
645                                dataType = SQLTokenizer.LONGVARBINARY;
646                        }else{
647                                dataType = SQLTokenizer.LONGVARCHAR;
648                                previousToken();
649                        }
650                }
651 
652                token = nextToken( MISSING_OPTIONS_DATATYPE );
653                switch(dataType){
654                        case SQLTokenizer.RAW:
655                                dataType = SQLTokenizer.VARBINARY;
656                                // no break;
657                        case SQLTokenizer.CHAR:
658                        case SQLTokenizer.VARCHAR:
659                        case SQLTokenizer.NCHAR:
660                        case SQLTokenizer.NVARCHAR:
661                        case SQLTokenizer.BINARY:
662                        case SQLTokenizer.VARBINARY:
663                        {
664                                // maximale Spaltengröße ermitteln
665                                int displaySize;
666                                if(token.value != SQLTokenizer.PARENTHESIS_L){
667                                        displaySize = 30;
668                                }else{
669                                        token = nextToken( MISSING_EXPRESSION );
670                                        try{
671                                                displaySize = Integer.parseInt(token.getName(sql) );
672                                        }catch(Exception e){
673                                                throw createSyntaxError(token, MISSING_NUMBERVALUE );
674                                        }
675                                        nextToken( MISSING_PARENTHESIS_R );
676                                        token = nextToken(MISSING_OPTIONS_DATATYPE);
677                                }
678                                col.setPrecision( displaySize );
679                                break;
680                        }
681                        case SQLTokenizer.SYSNAME:
682                                col.setPrecision(255);
683                                dataType = SQLTokenizer.VARCHAR;
684                                break;
685                        case SQLTokenizer.COUNTER:
686                                col.setAutoIncrement(true);
687                                dataType = SQLTokenizer.INT;
688                                break;
689                        case SQLTokenizer.NUMERIC:
690                        case SQLTokenizer.DECIMAL:
691                                if(token.value == SQLTokenizer.PARENTHESIS_L){
692                                        // read the precision of the data type
693                                        token = nextToken( MISSING_EXPRESSION );
694                                        int value;
695                                        try{
696                                                value = Integer.parseInt(token.getName(sql) );
697                                        }catch(Exception e){
698                                                throw createSyntaxError(token, MISSING_NUMBERVALUE );
699                                        }
700                                        col.setPrecision(value);
701                                        token = nextToken( MISSING_COMMA_PARENTHESIS );
702                                        if(token.value == SQLTokenizer.COMMA){
703                                                // read the scale of the data type
704                                                token = nextToken( MISSING_EXPRESSION );
705                                                try{
706                                                        value = Integer.parseInt(token.getName(sql) );
707                                                }catch(Exception e){
708                                                        throw createSyntaxError(token, MISSING_NUMBERVALUE );
709                                                }
710                                                col.setScale(value);
711                                                nextToken( MISSING_PARENTHESIS_R );
712                                        }
713                                        token = nextToken(MISSING_OPTIONS_DATATYPE);
714                                }else{
715                                        col.setPrecision(18); //default Precision for decimal and numeric
716                                }
717                                break;
718                }
719                col.setDataType( dataType );
720                this.previousToken();
721                return col;
722    }
723    
724    private CommandCreateView createView() throws SQLException{
725            SQLToken token = nextToken(MISSING_IDENTIFER );
726            String viewName = token.getName(sql);
727                checkValidIdentifer( viewName, token );
728 
729                nextToken(MISSING_AS);
730                token = nextToken(MISSING_SELECT);
731                CommandCreateView cmd = new CommandCreateView( con.log, viewName );
732                
733                cmd.sql = new String(sql, token.offset, sql.length-token.offset );
734                select(); //Parse to check for valid
735        return cmd;
736    }
737 
738 
739    private CommandCreateDatabase createIndex() throws SQLException{
740        throw new java.lang.UnsupportedOperationException();
741    }
742 
743    private CommandCreateDatabase createProcedure() throws SQLException{
744        throw new java.lang.UnsupportedOperationException();
745    }
746 
747    private Command drop() throws SQLException{
748        SQLToken tokenType = nextToken(COMMANDS_CREATE);
749        
750                SQLToken token = nextToken( MISSING_EXPRESSION );
751                String catalog = null;
752                String name = token.getName( sql );
753                checkValidIdentifer( name, token );
754                token = nextToken();
755                //check if the object name include a database name
756                if(token != null && token.value == SQLTokenizer.POINT){
757                        token = nextToken(MISSING_EXPRESSION);
758                        catalog = name;
759                        name = token.getName( sql );
760                        checkValidIdentifer( name, token );
761                        token = nextToken();
762                }
763                previousToken();
764 
765        switch(tokenType.value){
766            case SQLTokenizer.DATABASE:
767            case SQLTokenizer.TABLE:
768            case SQLTokenizer.VIEW:
769            case SQLTokenizer.INDEX:
770            case SQLTokenizer.PROCEDURE:
771                    return new CommandDrop( con.log, catalog, name, tokenType.value);
772            default:
773                throw createSyntaxError( tokenType, COMMANDS_CREATE );
774        }
775    }
776 
777 
778    private Command alter() throws SQLException{
779        throw new java.lang.UnsupportedOperationException();
780    }
781    
782 
783    private CommandSet set() throws SQLException{
784        SQLToken token = nextToken( COMMANDS_SET );
785        switch(token.value){
786            case SQLTokenizer.TRANSACTION:
787                return setTransaction();
788            default:
789                throw new Error();
790        }
791    }
792 
793    private CommandSet setTransaction() throws SQLException{
794        SQLToken token = nextToken( MISSING_ISOLATION );
795        token = nextToken( MISSING_LEVEL );
796        token = nextToken( COMMANDS_TRANS_LEVEL );
797        CommandSet cmd = new CommandSet( con.log, SQLTokenizer.LEVEL );
798        switch(token.value){
799            case SQLTokenizer.READ:
800                token = nextToken( MISSING_COMM_UNCOMM );
801                switch(token.value){
802                    case SQLTokenizer.COMMITTED:
803                        cmd.isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
804                        break;
805                    case SQLTokenizer.UNCOMMITTED:
806                        cmd.isolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
807                        break;
808                    default:
809                        throw new Error();
810                }
811                return cmd;
812            case SQLTokenizer.REPEATABLE:
813                token = nextToken( MISSING_READ );
814                cmd.isolationLevel = Connection.TRANSACTION_REPEATABLE_READ;
815                return cmd;
816            case SQLTokenizer.SERIALIZABLE:
817                cmd.isolationLevel = Connection.TRANSACTION_SERIALIZABLE;
818                return cmd;
819            default:
820                throw new Error();
821        }
822 
823 
824    }
825 
826    private Command execute() throws SQLException{
827        throw new java.lang.UnsupportedOperationException();
828    }
829 
830    /**
831     * Read a Expression list in parenthesis like of VALUES() or functions. 
832     * The left parenthesis is already consumed.
833     * 
834     * @param cmd is needed to add parameters "?" with addParameter() 
835     * @see #expressionDefList
836     */ 
837    private Expressions expressionParenthesisList(Command cmd) throws SQLException{
838                Expressions list = new Expressions();
839                {
840                        SQLToken token = nextToken();
841                        if(token != null && token.value == SQLTokenizer.PARENTHESIS_R){
842                                // empty list like functions without params
843                                return list;
844                        }
845                        previousToken();
846                }
847        while(true){
848            list.add( expression(cmd, 0) );
849            SQLToken token = nextToken(MISSING_COMMA_PARENTHESIS);
850            switch(token.value){
851                case SQLTokenizer.PARENTHESIS_R:
852                    return list;
853                case SQLTokenizer.COMMA:
854                    continue;
855                default:
856                    throw new Error();
857            }
858        }
859    }
860 
861    
862    /**
863     * Read a list of expressions. The list is limit from specific SQL keywords like SELECT, GROUP BY, ORDER BY
864     */
865    private Expressions expressionTokenList(Command cmd, int listType) throws SQLException{
866                Expressions list = new Expressions();
867        while(true){
868                Expression expr = expression(cmd, 0);
869            list.add( expr );
870            SQLToken token = nextToken();
871            
872                        if(listType == SQLTokenizer.ORDER && token != null){
873                                switch(token.value){
874                                        case SQLTokenizer.DESC:
875                                                expr.setAlias(SQLTokenizer.DESC_STR);
876                                                //kein break;
877                                        case SQLTokenizer.ASC:
878                                                token = nextToken();
879                                }                                
880                        }
881                        
882                        if(token == null) {
883                                previousToken();
884                                return list;
885                        }
886 
887                        switch(token.value){
888                case SQLTokenizer.COMMA:
889                    continue;
890                default:
891                                        if(isKeyword(token) ){
892                                                previousToken();
893                                                return list;
894                                        }
895                    throw createSyntaxError( token, MISSING_TOKEN_LIST);
896            }
897        }
898    }
899    
900    
901    private void expressionDefList(Command cmd, Expressions expressions, Strings columns) throws SQLException{
902        SQLToken token = nextToken();
903        if(token.value != SQLTokenizer.PARENTHESIS_L) throw createSyntaxError(token, MISSING_PARENTHESIS_L );
904        Loop:
905        while(true){
906            int offset = token.offset + token.length;
907            token = nextToken();
908            if(token != null) offset = token.offset;
909            previousToken();  
910            
911            expressions.add( expression(cmd, 0) );
912            SQLToken last = lastToken();
913            int length = last.offset + last.length - offset;
914            columns.add( new String( sql, offset, length ) );
915 
916            token = nextToken(MISSING_COMMA_PARENTHESIS);
917            switch(token.value){
918                case SQLTokenizer.PARENTHESIS_R:
919                    break Loop;
920                case SQLTokenizer.COMMA:
921                    continue;
922                default:
923                    throw new Error();
924            }
925        }
926    }
927    
928 
929        /**
930         * Read a complex expression that can be build from multiple atomic expressions.
931     * @param cmd is needed to add parameters "?" with addParameter() 
932         * @param previousOperationLevel the level of the left operation.
933         */
934    private Expression expression(Command cmd, int previousOperationLevel) throws SQLException{
935        SQLToken token = nextToken();
936        if(token == null) return null;
937        Expression leftExpr;
938        switch(token.value){
939            case SQLTokenizer.NOT:
940                    leftExpr =  new ExpressionArithmetic( expression( cmd, ExpressionArithmetic.NOT      / 10), ExpressionArithmetic.NOT);
941                    break;
942            case SQLTokenizer.MINUS:
943                    leftExpr =  new ExpressionArithmetic( expression( cmd, ExpressionArithmetic.NEGATIVE / 10), ExpressionArithmetic.NEGATIVE);
944                    break;
945            case SQLTokenizer.TILDE:
946                    leftExpr =  new ExpressionArithmetic( expression( cmd, ExpressionArithmetic.BIT_NOT  / 10), ExpressionArithmetic.BIT_NOT);
947                    break;
948            case SQLTokenizer.PARENTHESIS_L:
949                leftExpr = expression( cmd, 0);
950                token = nextToken(MISSING_PARENTHESIS_R);
951                break;
952            default:
953                leftExpr = expressionSingle( cmd, token);
954        }
955        boolean isNot = false;
956        while((token = nextToken()) != null){
957            Expression rightExpr;
958            int operation = ExpressionArithmetic.getOperationFromToken(token.value);
959            int level = operation / 10;
960            if(previousOperationLevel >= level){
961                previousToken();
962                return leftExpr;
963            }
964            switch(token.value){
965                case SQLTokenizer.PLUS:
966                case SQLTokenizer.MINUS:
967                case SQLTokenizer.ASTERISK:
968                case SQLTokenizer.SLACH:
969                case SQLTokenizer.PERCENT:
970                case SQLTokenizer.EQUALS:
971                case SQLTokenizer.LESSER:
972                case SQLTokenizer.LESSER_EQU:
973                case SQLTokenizer.GREATER:
974                case SQLTokenizer.GREATER_EQU:
975                case SQLTokenizer.UNEQUALS:
976                case SQLTokenizer.LIKE:
977                case SQLTokenizer.OR:
978                case SQLTokenizer.AND:
979                case SQLTokenizer.BIT_AND:
980                case SQLTokenizer.BIT_OR:
981                case SQLTokenizer.BIT_XOR:
982                    rightExpr = expression( cmd, level );
983                    leftExpr = new ExpressionArithmetic( leftExpr, rightExpr, operation );
984                    break;
985                case SQLTokenizer.BETWEEN:
986                    rightExpr = expression( cmd, ExpressionArithmetic.AND );
987                    nextToken( MISSING_AND );
988                    Expression rightExpr2 = expression( cmd, level );
989                    leftExpr = new ExpressionArithmetic( leftExpr, rightExpr, rightExpr2, operation );
990                    break;
991                case SQLTokenizer.IN:
992                            nextToken(MISSING_PARENTHESIS_L);
993                        token = nextToken(MISSING_EXPRESSION);
994                        if(token.value == SQLTokenizer.SELECT){
995                                CommandSelect cmdSel = select();
996                                                leftExpr = new ExpressionInSelect( con, leftExpr, cmdSel, operation );
997                                                nextToken(MISSING_PARENTHESIS_R);
998                        }else{
999                                previousToken();
1000                                Expressions list = expressionParenthesisList( cmd );
1001                                leftExpr = new ExpressionArithmetic( leftExpr, list, operation );
1002                        }
1003                    break;
1004                case SQLTokenizer.IS:
1005                        token = nextToken(MISSING_NOT_NULL);
1006                        if(token.value == SQLTokenizer.NOT){
1007                                nextToken(MISSING_NULL);
1008                                                operation++;
1009                        }
1010                        leftExpr = new ExpressionArithmetic( leftExpr, operation );
1011                        break;
1012                case SQLTokenizer.NOT:
1013                        token = nextToken(MISSING_BETWEEN_IN);
1014                        previousToken();
1015                        isNot = true;
1016                        continue;
1017                default:
1018                        previousToken();
1019                        return leftExpr;
1020            }
1021            if(isNot){
1022                    isNot = false;
1023                                leftExpr =  new ExpressionArithmetic( leftExpr, ExpressionArithmetic.NOT);
1024            }
1025        }
1026        previousToken();
1027        return leftExpr;
1028    }
1029 
1030    /**
1031     * parst einen einzelne Expression, wie 12, 'qwert', 0x3F oder column name
1032     * 
1033     * @param cmd is needed to add parameters "?" with addParameter() 
1034     */
1035    private Expression expressionSingle(Command cmd, SQLToken token) throws SQLException{
1036        boolean isMinus = false;
1037        if(token != null){
1038            switch(token.value){
1039                case SQLTokenizer.NULL:
1040                        return new ExpressionValue( null, SQLTokenizer.NULL );
1041                case SQLTokenizer.STRING:
1042                        return new ExpressionValue( token.getName(null), SQLTokenizer.VARCHAR );
1043                case SQLTokenizer.IDENTIFER:
1044                        {
1045                        String name = token.getName(null);
1046                        checkValidIdentifer( name, token );
1047                        ExpressionName expr =  new ExpressionName( name );
1048                        SQLToken token2 = nextToken();
1049                        if(token2 != null && token2.value == SQLTokenizer.POINT){
1050                            token = nextToken(MISSING_EXPRESSION);
1051                            expr.setNameAfterTableAlias( token.getName( sql ) );
1052                        }else{
1053                            previousToken();
1054                        }
1055                        return expr;
1056                        }
1057                case SQLTokenizer.TRUE:
1058                        return new ExpressionValue( Boolean.TRUE, SQLTokenizer.BOOLEAN );
1059                case SQLTokenizer.FALSE:
1060                        return new ExpressionValue( Boolean.FALSE, SQLTokenizer.BOOLEAN );
1061                case SQLTokenizer.ESCAPE_L:{
1062                        token = nextToken(COMMANDS_ESCAPE);
1063                        SQLToken para = nextToken(MISSING_EXPRESSION);
1064                        Expression expr;
1065                        switch(token.value){
1066                            case SQLTokenizer.D: // date escape sequence
1067                                    expr = new ExpressionValue( DateTime.valueOf(para.getName(sql), SQLTokenizer.DATE), SQLTokenizer.DATE );
1068                                    break;
1069                            case SQLTokenizer.T: // time escape sequnce
1070                                expr = new ExpressionValue( DateTime.valueOf(para.getName(sql), SQLTokenizer.TIME), SQLTokenizer.TIME );
1071                                    break;
1072                            case SQLTokenizer.TS: // timestamp escape sequence
1073                                expr = new ExpressionValue( DateTime.valueOf(para.getName(sql), SQLTokenizer.TIMESTAMP), SQLTokenizer.TIMESTAMP );
1074                                    break;
1075                            case SQLTokenizer.FN: // function escape sequence
1076                                    nextToken(MISSING_PARENTHESIS_L);
1077                                    expr = function(cmd, para, true);
1078                                    break;
1079                            case SQLTokenizer.CALL: // call escape sequence
1080                                throw new java.lang.UnsupportedOperationException("call escape sequence");
1081                            default: throw new Error();
1082                        }
1083                        token = nextToken( ESCAPE_MISSING_CLOSE );
1084                        return expr;
1085                }
1086                case SQLTokenizer.QUESTION:
1087                        ExpressionValue param = new ExpressionValue();
1088                        cmd.addParameter( param );
1089                        return param;
1090                case SQLTokenizer.CASE:
1091                                return caseExpr(cmd);
1092                case SQLTokenizer.MINUS:
1093                case SQLTokenizer.PLUS:
1094                        // Vorzeichenerkennung
1095                        do{
1096                            if(token.value == SQLTokenizer.MINUS)
1097                                    isMinus = !isMinus;
1098                            token = nextToken();
1099                            if(token == null) throw createSyntaxError( token, MISSING_EXPRESSION );
1100                        }while(token.value == SQLTokenizer.MINUS || token.value == SQLTokenizer.PLUS);
1101                        // kein Break
1102                default:
1103                        SQLToken token2 = nextToken();
1104                        if(token2 != null && token2.value == SQLTokenizer.PARENTHESIS_L){
1105                            if(isMinus)
1106                                return new ExpressionArithmetic( function( cmd, token, false ),  ExpressionArithmetic.NEGATIVE );
1107                            return function( cmd, token, false );
1108                        }else{
1109                            // Konstanter Ausdruck oder Identifer
1110                            char chr1 = sql[ token.offset ];
1111                                                        if(chr1 == '$'){
1112                                                                previousToken();
1113                                    String tok = new String(sql, token.offset+1, token.length-1);
1114                                if(isMinus) tok = "-" + tok;
1115                                                                return new ExpressionValue( new Money(Double.parseDouble(tok)), SQLTokenizer.MONEY );
1116                                                        }
1117                            String tok = new String(sql, token.offset, token.length);
1118                            if((chr1 >= '0' && '9' >= chr1) || chr1 == '.'){
1119                                previousToken();
1120                                //erstes Zeichen ein digit
1121                                if(token.length>1 && (sql[ token.offset +1 ] | 0x20) == 'x'){
1122                                    // binär Daten als Hex
1123                                    if(isMinus) throw createSyntaxError( token, "Invalid operator binary for data type varbinary.");
1124                                    return new ExpressionValue( Utils.hex2bytes( sql, token.offset+2, token.length-2), SQLTokenizer.BINARY );
1125                                }
1126                                if(isMinus) tok = "-" + tok;
1127                                if(Utils.indexOf( '.', sql, token.offset, token.length ) >= 0 ||
1128                                   Utils.indexOf( 'e', sql, token.offset, token.length ) >= 0){
1129                                    return new ExpressionValue( new Double(tok), SQLTokenizer.DOUBLE );
1130                                }else{
1131                                    try{
1132                                        return new ExpressionValue( new Integer(tok), SQLTokenizer.INT );
1133                                    }catch(NumberFormatException e){
1134                                        return new ExpressionValue( new Long(tok), SQLTokenizer.BIGINT );
1135                                    }
1136                                }
1137                            }else{
1138                                // Bezeichner
1139                                checkValidIdentifer( tok, token );
1140                                ExpressionName expr = new ExpressionName(tok);
1141                                if(token2 != null && token2.value == SQLTokenizer.POINT){
1142                                    token = nextToken(MISSING_EXPRESSION);
1143                                    expr.setNameAfterTableAlias( token.getName( sql ) );
1144                                }else{
1145                                    previousToken();
1146                                }
1147                                if(isMinus)
1148                                    return new ExpressionArithmetic( expr,  ExpressionArithmetic.NEGATIVE );
1149                                return expr;
1150                            }
1151                        }
1152            }
1153        }
1154        return null;
1155    }
1156    
1157    
1158    ExpressionFunctionCase caseExpr(final Command cmd) throws SQLException{
1159                ExpressionFunctionCase expr = new ExpressionFunctionCase();
1160                SQLToken token = nextToken(MISSING_EXPRESSION);
1161                
1162                Expression input = null;
1163                if(token.value != SQLTokenizer.WHEN){
1164                        // simple CASE Syntax
1165                        previousToken();
1166                        input = expression(cmd, 0);
1167                        token = nextToken(MISSING_WHEN_ELSE_END);
1168                }                        
1169                        
1170                while(true){
1171                        switch(token.value){
1172                                case SQLTokenizer.WHEN:                                
1173                                        Expression condition = expression(cmd, 0);
1174                                        if(input != null){
1175                                                // simple CASE Syntax
1176                                                condition = new ExpressionArithmetic( input, condition, ExpressionArithmetic.EQUALS);
1177                                        }
1178                                        nextToken(MISSING_THEN);
1179                                        Expression result = expression(cmd, 0);
1180                                        expr.addCase(condition, result);
1181                                        break;
1182                                case SQLTokenizer.ELSE:
1183                                        expr.setElseResult(expression(cmd, 0));
1184                                        break;
1185                                case SQLTokenizer.END:
1186                                        expr.setEnd();
1187                                        return expr;
1188                                default:
1189                                        throw new Error();
1190                        }
1191                        token = nextToken(MISSING_WHEN_ELSE_END);
1192                }
1193    }
1194    
1195 
1196    /**
1197     * Parse any functions. The left parenthesis is allready consumed from token list.
1198     * @param token the SQLToken of the function
1199     * @param isEscape If the function is a FN ESCAPE sequence
1200     */ 
1201    private Expression function( Command cmd, SQLToken token, boolean isEscape ) throws SQLException{
1202        Expression expr;
1203        switch(token.value){
1204                case SQLTokenizer.CONVERT:{
1205                        Column col;
1206                        Expression style = null;
1207                        if(isEscape){
1208                                expr = expression( cmd, 0);
1209                                        nextToken(MISSING_COMMA);
1210                                        col = datatype(isEscape);
1211                        }else{
1212                                col = datatype(isEscape);
1213                                nextToken(MISSING_COMMA);
1214                                        expr = expression( cmd, 0);
1215                                        token = nextToken(MISSING_COMMA_PARENTHESIS);
1216                                        if(token.value == SQLTokenizer.COMMA){
1217                                                style = expression( cmd, 0);;
1218                                        }else
1219                                                previousToken();
1220                        }
1221                        nextToken(MISSING_PARENTHESIS_R);
1222                        return new ExpressionFunctionConvert( col, expr, style );
1223                }
1224                case SQLTokenizer.CAST:
1225                        expr = expression( cmd, 0);
1226                        nextToken(MISSING_AS);
1227                        Column col = datatype(false);
1228                        nextToken(MISSING_PARENTHESIS_R);
1229                        return new ExpressionFunctionConvert( col, expr, null );
1230                        case SQLTokenizer.TIMESTAMPDIFF:
1231                                token = nextToken(MISSING_INTERVALS);
1232                                nextToken(MISSING_COMMA);
1233                                expr = expression( cmd, 0);
1234                                nextToken(MISSING_COMMA);
1235                                expr = new ExpressionFunctionTimestampDiff( token.value, expr, expression( cmd, 0));
1236                                nextToken(MISSING_PARENTHESIS_R);
1237                                return expr;
1238                        case SQLTokenizer.TIMESTAMPADD:
1239                                token = nextToken(MISSING_INTERVALS);
1240                                nextToken(MISSING_COMMA);
1241                                expr = expression( cmd, 0);
1242                                nextToken(MISSING_COMMA);
1243                                expr = new ExpressionFunctionTimestampAdd( token.value, expr, expression( cmd, 0));
1244                                nextToken(MISSING_PARENTHESIS_R);
1245                                return expr;
1246        }
1247                Expressions paramList = expressionParenthesisList(cmd);
1248        int paramCount = paramList.size();
1249        Expression[] params = paramList.toArray();
1250        boolean invalidParamCount;
1251        switch(token.value){
1252        // numeric functions:
1253            case SQLTokenizer.ABS:
1254                invalidParamCount = (paramCount != 1);
1255                expr = new ExpressionFunctionAbs();
1256                break;
1257            case SQLTokenizer.ACOS:
1258                invalidParamCount = (paramCount != 1);
1259                expr = new ExpressionFunctionACos();
1260                break;
1261            case SQLTokenizer.ASIN:
1262                invalidParamCount = (paramCount != 1);
1263                expr = new ExpressionFunctionASin();
1264                break;
1265            case SQLTokenizer.ATAN:
1266                invalidParamCount = (paramCount != 1);
1267                expr = new ExpressionFunctionATan();
1268                break;
1269            case SQLTokenizer.ATAN2:
1270                invalidParamCount = (paramCount !=