KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > Parser


1 /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the Hypersonic SQL Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * This software consists of voluntary contributions made by many individuals
31  * on behalf of the Hypersonic SQL Group.
32  *
33  *
34  * For work added by the HSQL Development Group:
35  *
36  * Copyright (c) 2001-2005, The HSQL Development Group
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions are met:
41  *
42  * Redistributions of source code must retain the above copyright notice, this
43  * list of conditions and the following disclaimer.
44  *
45  * Redistributions in binary form must reproduce the above copyright notice,
46  * this list of conditions and the following disclaimer in the documentation
47  * and/or other materials provided with the distribution.
48  *
49  * Neither the name of the HSQL Development Group nor the names of its
50  * contributors may be used to endorse or promote products derived from this
51  * software without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
54  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
57  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
60  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
61  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64  */

65
66
67 package org.hsqldb;
68
69 import java.util.Locale JavaDoc;
70
71 import org.hsqldb.HsqlNameManager.HsqlName;
72 import org.hsqldb.lib.ArrayUtil;
73 import org.hsqldb.lib.HashMap;
74 import org.hsqldb.lib.HashMappedList;
75 import org.hsqldb.lib.HsqlArrayList;
76 import org.hsqldb.lib.IntValueHashMap;
77 import org.hsqldb.store.ValuePool;
78 import org.hsqldb.lib.HashSet;
79
80 // fredt@users 20020130 - patch 497872 by Nitin Chauhan - reordering for speed
81
// fredt@users 20020215 - patch 1.7.0 by fredt - support GROUP BY with more than one column
82
// fredt@users 20020215 - patch 1.7.0 by fredt - SQL standard quoted identifiers
83
// fredt@users 20020218 - patch 1.7.0 by fredt - DEFAULT keyword
84
// fredt@users 20020221 - patch 513005 by sqlbob@users - SELECT INTO types
85
// fredt@users 20020425 - patch 548182 by skitt@users - DEFAULT enhancement
86
// thertz@users 20020320 - patch 473613 by thertz - outer join condition bug
87
// fredt@users 20021229 - patch 1.7.2 by fredt - new solution for above
88
// fredt@users 20020420 - patch 523880 by leptipre@users - VIEW support
89
// fredt@users 20020525 - patch 559914 by fredt@users - SELECT INTO logging
90
// tony_lai@users 20021020 - patch 1.7.2 - improved aggregates and HAVING
91
// aggregate functions can now be used in expressions - HAVING supported
92
// kloska@users 20021030 - patch 1.7.2 - ON UPDATE CASCADE
93
// fredt@users 20021112 - patch 1.7.2 by Nitin Chauhan - use of switch
94
// rewrite of the majority of multiple if(){}else{} chains with switch(){}
95
// boucherb@users 20030705 - patch 1.7.2 - prepared statement support
96
// fredt@users 20030819 - patch 1.7.2 - EXTRACT({YEAR | MONTH | DAY | HOUR | MINUTE | SECOND } FROM datetime)
97
// fredt@users 20030820 - patch 1.7.2 - CHAR_LENGTH | CHARACTER_LENGTH | OCTET_LENGTH(string)
98
// fredt@users 20030820 - patch 1.7.2 - POSITION(string IN string)
99
// fredt@users 20030820 - patch 1.7.2 - SUBSTRING(string FROM pos [FOR length])
100
// fredt@users 20030820 - patch 1.7.2 - TRIM({LEADING | TRAILING | BOTH} [<character>] FROM <string expression>)
101
// fredt@users 20030820 - patch 1.7.2 - CASE [expr] WHEN ... THEN ... [ELSE ...] END and its variants
102
// fredt@users 20030820 - patch 1.7.2 - NULLIF(expr,expr)
103
// fredt@users 20030820 - patch 1.7.2 - COALESCE(expr,expr,...)
104
// fredt@users 20031012 - patch 1.7.2 - improved scoping for column names in all areas
105
// boucherb@users 200403xx - patch 1.7.2 - added support for prepared SELECT INTO
106
// boucherb@users 200403xx - doc 1.7.2 - some
107
// thomasm@users 20041001 - patch 1.7.3 - BOOLEAN undefined handling
108
// fredt@users 20050220 - patch 1.8.0 - CAST with precision / scale
109
/* todo: fredt - implement remaining numeric value functions (SQL92 6.6)
110  *
111  * EXTRACT({TIMEZONE_HOUR | TIMEZONE_MINUTE} FROM {datetime | interval})
112  */

113
114 /**
115  * Responsible for parsing non-DDL statements.
116  *
117  * Extensively rewritten and extended in successive versions of HSQLDB.
118  *
119  * @author Thomas Mueller (Hypersonic SQL Group)
120  * @version 1.8.0
121  * @since Hypersonic SQL
122  */

123 class Parser {
124
125     private Database database;
126     private Tokenizer tokenizer;
127     private Session session;
128     private String JavaDoc sSchema;
129     private String JavaDoc sTable;
130     private String JavaDoc sToken;
131     private boolean wasQuoted;
132     private Object JavaDoc oData;
133     private int iType;
134     private int iToken;
135
136     //
137
private int subQueryLevel;
138     private HsqlArrayList subQueryList = new HsqlArrayList();
139
140     /**
141      * Constructs a new Parser object with the given context.
142      *
143      * @param db the Database instance against which to resolve named
144      * database object references
145      * @param t the token source from which to parse commands
146      * @param session the connected context
147      */

148     Parser(Session session, Database db, Tokenizer t) {
149
150         database = db;
151         tokenizer = t;
152         this.session = session;
153     }
154
155     /**
156      * Resets this parse context with the given SQL character sequence.
157      *
158      * Internal structures are reset as though a new parser were created
159      * with the given sql and the originally specified database and session
160      *
161      * @param a new SQL character sequence to replace the current one
162      */

163     void reset(String JavaDoc sql) {
164
165         sTable = null;
166         sToken = null;
167         oData = null;
168
169         tokenizer.reset(sql);
170         subQueryList.clear();
171
172         subQueryLevel = 0;
173
174         parameters.clear();
175     }
176
177     /**
178      * Tests whether the parsing session has the given write access on the
179      * given Table object. <p>
180      *
181      * @param table the Table object to check
182      * @param userRight the numeric code of the right to check
183      * @throws HsqlException if the session user does not have the right
184      * or the given Table object is simply not writable (e.g. is a
185      * non-updateable View)
186      */

187     void checkTableWriteAccess(Table table,
188                                int userRight) throws HsqlException {
189
190         // session level user rights
191
session.checkReadWrite();
192
193         // object level user rights
194
session.check(table.getName(), userRight);
195
196         // object type
197
if (table.isView()) {
198             throw Trace.error(Trace.NOT_A_TABLE, table.getName().name);
199         }
200
201         // object readonly
202
table.checkDataReadOnly();
203     }
204
205     /**
206      * Parses a comma-separated, right-bracket terminated list of column
207      * names. <p>
208      *
209      * @param db the Database instance whose name manager is to provide the
210      * resulting HsqlName objects, when the full argument is true
211      * @param t the tokenizer representing the character sequence to be parsed
212      * @param full if true, generate a list of HsqlNames, else a list of
213      * String objects
214      */

215     static HsqlArrayList getColumnNames(Database db, Table table,
216                                         Tokenizer t,
217                                         boolean full) throws HsqlException {
218
219         HsqlArrayList columns = new HsqlArrayList();
220
221         while (true) {
222             if (full) {
223                 String JavaDoc token = t.getSimpleName();
224                 boolean quoted = t.wasQuotedIdentifier();
225                 HsqlName name = db.nameManager.newHsqlName(token, quoted);
226
227                 columns.add(name);
228             } else {
229                 columns.add(t.getName());
230
231                 if (t.wasLongName()
232                         &&!t.getLongNameFirst().equals(
233                             table.getName().name)) {
234                     throw (Trace.error(Trace.TABLE_NOT_FOUND,
235                                        t.getLongNameFirst()));
236                 }
237             }
238
239             String JavaDoc token = t.getSimpleToken();
240
241             if (token.equals(Token.T_COMMA)) {
242                 continue;
243             }
244
245             if (token.equals(Token.T_CLOSEBRACKET)) {
246                 break;
247             }
248
249             t.throwUnexpected();
250         }
251
252         return columns;
253     }
254
255     /**
256      * The SubQuery objects are added to the end of subquery list.
257      *
258      * When parsing the SELECT for a view, optional HsqlName[] array is used
259      * for view column aliases.
260      *
261      */

262     SubQuery parseSubquery(int brackets, HsqlName[] colNames,
263                            boolean resolveAll,
264                            int predicateType) throws HsqlException {
265
266         SubQuery sq;
267
268         sq = new SubQuery();
269
270         subQueryLevel++;
271
272         boolean canHaveOrder = predicateType == Expression.VIEW;
273         boolean limitWithOrder = predicateType == Expression.VIEW
274                                  || predicateType == Expression.QUERY
275                                  || predicateType == Expression.IN
276                                  || predicateType == Expression.ALL
277                                  || predicateType == Expression.ANY
278                                  || predicateType == Expression.SELECT;
279         Select s = parseSelect(brackets, canHaveOrder, false, limitWithOrder,
280                                true);
281
282         sq.level = subQueryLevel;
283
284         subQueryLevel--;
285
286         boolean isResolved = s.resolveAll(session, resolveAll);
287
288         sq.select = s;
289         sq.isResolved = isResolved;
290
291         // it's not a problem that this table has not a unique name
292
HsqlName sqtablename =
293             database.nameManager.newHsqlName("SYSTEM_SUBQUERY", false);
294
295         sqtablename.schema = database.schemaManager.SYSTEM_SCHEMA_HSQLNAME;
296
297         Table table = new Table(database, sqtablename, Table.SYSTEM_SUBQUERY);
298
299         if (colNames != null) {
300             if (colNames.length != s.iResultLen) {
301                 throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
302             }
303
304             for (int i = 0; i < s.iResultLen; i++) {
305                 HsqlName name = colNames[i];
306
307                 s.exprColumns[i].setAlias(name.name, name.isNameQuoted);
308             }
309         } else {
310             for (int i = 0; i < s.iResultLen; i++) {
311                 String JavaDoc colname = s.exprColumns[i].getAlias();
312
313                 if (colname == null || colname.length() == 0) {
314
315                     // fredt - this does not guarantee the uniqueness of column
316
// names but addColumns() will throw if names are not unique.
317
colname = "COL_" + String.valueOf(i + 1);
318
319                     s.exprColumns[i].setAlias(colname, false);
320                 }
321             }
322         }
323
324         table.addColumns(s);
325
326         boolean uniqueValues = predicateType == Expression.EXISTS
327                                || predicateType == Expression.IN
328                                || predicateType == Expression.ALL
329                                || predicateType == Expression.ANY;
330         int[] pcol = null;
331
332         if (uniqueValues) {
333             pcol = new int[s.iResultLen];
334
335             ArrayUtil.fillSequence(pcol);
336         }
337
338         table.createPrimaryKey(pcol);
339
340         sq.table = table;
341         sq.uniqueRows = uniqueValues;
342
343         subQueryList.add(sq);
344
345         return sq;
346     }
347
348     SubQuery getViewSubquery(View v) {
349
350         SubQuery sq = v.viewSubQuery;
351
352         for (int i = 0; i < v.viewSubqueries.length; i++) {
353             subQueryList.add(v.viewSubqueries[i]);
354         }
355
356         return sq;
357     }
358
359     /**
360      * Constructs and returns a Select object.
361      *
362      * @param canHaveOrder whether the SELECT being parsed can have an ORDER BY
363      * @param canHaveLimit whether LIMIT without ORDER BY is allowed
364      * @param limitWithOrder whether LIMIT is allowed only with ORDER BY
365      * @param isMain whether the SELECT being parsed is the first
366      * select statement in the set
367      * @return a new Select object
368      * @throws HsqlException if a parsing error occurs
369      */

370     Select parseSelect(int brackets, boolean canHaveOrder,
371                        boolean canHaveLimit, boolean limitWithOrder,
372                        boolean isMain) throws HsqlException {
373
374         Select select = new Select();
375         String JavaDoc token = tokenizer.getString();
376
377         if (canHaveLimit || limitWithOrder) {
378             if (tokenizer.wasThis(Token.T_LIMIT)
379                     || tokenizer.wasThis(Token.T_TOP)) {
380                 parseLimit(token, select, false);
381
382                 token = tokenizer.getString();
383             }
384         }
385
386         if (tokenizer.wasThis(Token.T_DISTINCT)) {
387             select.isDistinctSelect = true;
388         } else if (tokenizer.wasThis(Token.T_ALL)) {}
389         else {
390             tokenizer.back();
391         }
392
393         // parse column list
394
HsqlArrayList vcolumn = new HsqlArrayList();
395
396         do {
397             Expression e = parseExpression();
398
399             token = tokenizer.getString();
400
401             if (tokenizer.wasThis(Token.T_AS)) {
402                 e.setAlias(tokenizer.getSimpleName(),
403                            tokenizer.wasQuotedIdentifier());
404
405                 token = tokenizer.getString();
406             } else if (tokenizer.wasSimpleName()) {
407                 e.setAlias(token, tokenizer.wasQuotedIdentifier());
408
409                 token = tokenizer.getString();
410             }
411
412             vcolumn.add(e);
413         } while (tokenizer.wasThis(Token.T_COMMA));
414
415         if (token.equals(Token.T_INTO)) {
416             boolean getname = true;
417
418             token = tokenizer.getString();
419
420             if (tokenizer.wasSimpleToken()) {
421                 switch (Token.get(token)) {
422
423                     case Token.CACHED :
424                         select.intoType = Table.CACHED_TABLE;
425                         break;
426
427                     case Token.TEMP :
428                         select.intoType = Table.TEMP_TABLE;
429                         break;
430
431                     case Token.TEXT :
432                         select.intoType = Table.TEXT_TABLE;
433                         break;
434
435                     case Token.MEMORY :
436                         select.intoType = Table.MEMORY_TABLE;
437                         break;
438
439                     default :
440                         select.intoType = database.getDefaultTableType();
441                         getname = false;
442                         break;
443                 }
444
445                 if (getname) {
446                     token = tokenizer.getName();
447                 } else {
448                     if (!tokenizer.wasName()) {
449                         tokenizer.throwUnexpected();
450                     }
451                 }
452             }
453
454             select.sIntoTable = database.nameManager.newHsqlName(token,
455                     tokenizer.wasQuotedIdentifier());
456             select.sIntoTable.schema =
457                 session.getSchemaHsqlName(tokenizer.getLongNameFirst());
458             token = tokenizer.getString();
459         }
460
461         tokenizer.matchThis(Token.T_FROM);
462
463         Expression condition = null;
464
465         // parse table list
466
HsqlArrayList vfilter = new HsqlArrayList();
467
468         vfilter.add(parseTableFilter(false));
469
470         while (true) {
471             token = tokenizer.getString();
472
473             boolean cross = false;
474
475             if (tokenizer.wasThis(Token.T_INNER)) {
476                 tokenizer.getThis(Token.T_JOIN);
477
478                 token = Token.T_JOIN;
479             } else if (tokenizer.wasThis(Token.T_CROSS)) {
480                 tokenizer.getThis(Token.T_JOIN);
481
482                 token = Token.T_JOIN;
483                 cross = true;
484             }
485
486             if (token.equals(Token.T_LEFT)
487                     &&!tokenizer.wasQuotedIdentifier()) {
488                 tokenizer.isGetThis(Token.T_OUTER);
489                 tokenizer.getThis(Token.T_JOIN);
490
491                 TableFilter tf = parseTableFilter(true);
492
493                 vfilter.add(tf);
494                 tokenizer.getThis(Token.T_ON);
495
496                 Expression newcondition = parseExpression();
497
498                 newcondition.checkTables(vfilter);
499
500                 condition = addJoinCondition(condition, newcondition, tf,
501                                              true);
502
503                 // MarcH HuugO RIGHT JOIN SUPPORT
504
} else if (token.equals(Token.T_RIGHT)
505                        &&!tokenizer.wasQuotedIdentifier()) {
506                 tokenizer.isGetThis(Token.T_OUTER);
507                 tokenizer.getThis(Token.T_JOIN);
508
509                 // this object is not an outerjoin, the next object is an outerjoin
510
TableFilter tf = parseTableFilter(false);
511
512                 // insert new condition as first element in a new vfilter (nvfilter), copy the content of vfilter and rename nvfilter back to vfilter.
513
HsqlArrayList nvfilter = new HsqlArrayList();
514
515                 nvfilter.add(tf);
516                 nvfilter.addAll(vfilter);
517
518                 vfilter = nvfilter;
519
520                 // set isOuterJoin correct
521
((TableFilter) vfilter.get(1)).isOuterJoin = true;
522
523                 tokenizer.getThis(Token.T_ON);
524
525                 Expression newcondition = parseExpression();
526
527                 newcondition.checkTables(vfilter);
528
529                 condition = addJoinCondition(condition, newcondition,
530                                              ((TableFilter) vfilter.get(1)),
531                                              true);
532             } else if (tokenizer.wasThis(Token.T_JOIN)) {
533                 vfilter.add(parseTableFilter(false));
534
535                 if (!cross) {
536                     tokenizer.getThis(Token.T_ON);
537
538                     Expression newcondition = parseExpression();
539
540                     newcondition.checkTables(vfilter);
541
542                     condition = addJoinCondition(condition, newcondition,
543                                                  null, false);
544                 }
545             } else if (tokenizer.wasThis(Token.T_COMMA)) {
546                 vfilter.add(parseTableFilter(false));
547             } else {
548                 tokenizer.back();
549
550                 break;
551             }
552         }
553
554         resolveSelectTableFilter(select, vcolumn, vfilter);
555
556         // where
557
token = tokenizer.getString();
558
559         if (tokenizer.wasThis(Token.T_WHERE)) {
560             Expression newcondition = parseExpression();
561
562             condition = addCondition(condition, newcondition);
563             token = tokenizer.getString();
564         }
565
566         select.queryCondition = condition;
567
568         // group by
569
if (tokenizer.wasThis(Token.T_GROUP)) {
570             tokenizer.getThis(Token.T_BY);
571
572             int len = 0;
573
574             do {
575                 Expression e = parseExpression();
576
577                 vcolumn.add(e);
578
579                 token = tokenizer.getString();
580
581                 len++;
582             } while (tokenizer.wasThis(Token.T_COMMA));
583
584             select.iGroupLen = len;
585         }
586
587         // having
588
if (tokenizer.wasThis(Token.T_HAVING)) {
589             select.iHavingLen = 1;
590             select.havingCondition = parseExpression();
591             token = tokenizer.getString();
592
593             vcolumn.add(select.havingCondition);
594         }
595
596         if (isMain || limitWithOrder) {
597             if (tokenizer.wasThis(Token.T_ORDER)) {
598                 tokenizer.getThis(Token.T_BY);
599                 parseOrderBy(select, vcolumn);
600
601                 token = tokenizer.getString();
602             }
603
604             if (tokenizer.wasThis(Token.T_LIMIT)) {
605                 parseLimit(token, select, true);
606
607                 token = tokenizer.getString();
608             }
609         }
610
611         boolean closebrackets = false;
612
613         if (brackets > 0 && token.equals(Token.T_CLOSEBRACKET)) {
614             closebrackets = true;
615             brackets -= parseCloseBrackets(brackets - 1) + 1;
616             token = tokenizer.getString();
617         }
618
619         select.unionDepth = brackets;
620
621         // checks for ORDER and LIMIT
622
if (!(isMain || closebrackets)) {
623             limitWithOrder = false;
624         }
625
626         boolean hasOrder = select.iOrderLen != 0;
627         boolean hasLimit = select.limitCondition != null;
628
629         if (limitWithOrder) {
630             if (hasLimit &&!hasOrder) {
631                 throw Trace.error(Trace.ORDER_LIMIT_REQUIRED);
632             }
633         } else {
634             if (hasOrder &&!canHaveOrder) {
635                 throw Trace.error(Trace.INVALID_ORDER_BY);
636             }
637
638             if (hasLimit &&!canHaveLimit) {
639                 throw Trace.error(Trace.INVALID_LIMIT);
640             }
641         }
642
643         int unionType = parseUnion(token);
644
645         if (unionType != Select.NOUNION) {
646             boolean openbracket = false;
647
648             select.unionType = unionType;
649
650             if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
651                 openbracket = true;
652                 brackets += parseOpenBrackets() + 1;
653             }
654
655             tokenizer.getThis(Token.T_SELECT);
656
657             // accept ORDRY BY with LIMIT when in brackets
658
select.unionSelect = parseSelect(brackets, false, false,
659                                              openbracket, false);
660             token = tokenizer.getString();
661         }
662
663         if (isMain && (canHaveOrder || limitWithOrder)
664                 && select.iOrderLen == 0) {
665             if (tokenizer.wasThis(Token.T_ORDER)) {
666                 tokenizer.getThis(Token.T_BY);
667                 parseOrderBy(select, vcolumn);
668
669                 token = tokenizer.getString();
670                 select.sortUnion = true;
671             }
672
673             if (tokenizer.wasThis(Token.T_LIMIT)) {
674                 parseLimit(token, select, true);
675
676                 token = tokenizer.getString();
677             }
678         }
679
680         tokenizer.back();
681
682         if (isMain) {
683             select.prepareUnions();
684         }
685
686         int len = vcolumn.size();
687
688         select.exprColumns = new Expression[len];
689
690         vcolumn.toArray(select.exprColumns);
691
692         return select;
693     }
694
695     /**
696      * Parses the given token and any further tokens in tokenizer to return
697      * any UNION or other set operation ID.
698      */

699     int parseUnion(String JavaDoc token) throws HsqlException {
700
701         int unionType = Select.NOUNION;
702
703         if (tokenizer.wasSimpleToken()) {
704             switch (Token.get(token)) {
705
706                 case Token.UNION :
707                     token = tokenizer.getSimpleToken();
708
709                     if (token.equals(Token.T_ALL)) {
710                         unionType = Select.UNIONALL;
711                     } else if (token.equals(Token.T_DISTINCT)) {
712                         unionType = Select.UNION;
713                     } else {
714                         unionType = Select.UNION;
715
716                         tokenizer.back();
717                     }
718                     break;
719
720                 case Token.INTERSECT :
721                     tokenizer.isGetThis(Token.T_DISTINCT);
722
723                     unionType = Select.INTERSECT;
724                     break;
725
726                 case Token.EXCEPT :
727                 case Token.MINUS :
728                     tokenizer.isGetThis(Token.T_DISTINCT);
729
730                     unionType = Select.EXCEPT;
731                     break;
732
733                 default :
734                     break;
735             }
736         }
737
738         return unionType;
739     }
740
741 // fredt@users 20011010 - patch 471710 by fredt - LIMIT rewritten
742
// SELECT LIMIT n m DISTINCT ... queries and error message
743
// "SELECT LIMIT n m ..." creates the result set for the SELECT statement then
744
// discards the first n rows and returns m rows of the remaining result set
745
// "SELECT LIMIT 0 m" is equivalent to "SELECT TOP m" or "SELECT FIRST m"
746
// in other RDBMS's
747
// "SELECT LIMIT n 0" discards the first n rows and returns the remaining rows
748
// fredt@users 20020225 - patch 456679 by hiep256 - TOP keyword
749
private void parseLimit(String JavaDoc token, Select select,
750                             boolean isEnd) throws HsqlException {
751
752         if (select.limitCondition != null) {
753             return;
754         }
755
756         Expression e1 = null;
757         Expression e2;
758         boolean islimit = false;
759
760         if (isEnd) {
761             if (token.equals(Token.T_LIMIT)) {
762                 islimit = true;
763
764                 read();
765
766                 e2 = readTerm();
767
768                 if (sToken.equals(Token.T_OFFSET)) {
769                     read();
770
771                     e1 = readTerm();
772                 }
773
774                 tokenizer.back();
775             } else {
776                 return;
777             }
778         } else if (token.equals(Token.T_LIMIT)) {
779             read();
780
781             e1 = readTerm();
782             e2 = readTerm();
783             islimit = true;
784
785             tokenizer.back();
786         } else if (token.equals(Token.T_TOP)) {
787             read();
788
789             e2 = readTerm();
790
791             tokenizer.back();
792         } else {
793             return;
794         }
795
796         if (e1 == null) {
797             e1 = new Expression(Types.INTEGER, ValuePool.getInt(0));
798         }
799
800         if (e1.isParam()
801                 || (e1.getType() == Expression.VALUE
802                     && e1.getDataType() == Types.INTEGER
803                     && e1.getValue(null) != null
804                     && ((Integer JavaDoc) e1.getValue(null)).intValue() >= 0)) {
805             if (e2.isParam()
806                     || (e2.getType() == Expression.VALUE
807                         && e2.getDataType() == Types.INTEGER
808                         && e2.getValue(null) != null
809                         && ((Integer JavaDoc) e2.getValue(null)).intValue() >= 0)) {
810
811                 // necessary for params
812
e1.setDataType(Types.INTEGER);
813                 e2.setDataType(Types.INTEGER);
814
815                 select.limitCondition = new Expression(Expression.LIMIT, e1,
816                                                        e2);
817
818                 return;
819             }
820         }
821
822         int messageid = islimit ? Trace.INVALID_LIMIT_EXPRESSION
823                                 : Trace.INVALID_TOP_EXPRESSION;
824
825         throw Trace.error(Trace.WRONG_DATA_TYPE, messageid);
826     }
827
828     private void parseOrderBy(Select select,
829                               HsqlArrayList vcolumn) throws HsqlException {
830
831         String JavaDoc token;
832         int len = 0;
833
834         do {
835             Expression e = parseExpression();
836
837             e = resolveOrderByExpression(e, select, vcolumn);
838             token = tokenizer.getString();
839
840             if (token.equals(Token.T_DESC)) {
841                 e.setDescending();
842
843                 token = tokenizer.getString();
844             } else if (token.equals(Token.T_ASC)) {
845                 token = tokenizer.getString();
846             }
847
848             vcolumn.add(e);
849
850             len++;
851         } while (token.equals(Token.T_COMMA));
852
853         tokenizer.back();
854
855         select.iOrderLen = len;
856     }
857
858     private void resolveSelectTableFilter(Select select,
859                                           HsqlArrayList vcolumn,
860                                           HsqlArrayList vfilter)
861                                           throws HsqlException {
862
863         int colcount;
864         TableFilter[] filters = new TableFilter[vfilter.size()];
865
866         vfilter.toArray(filters);
867
868         select.tFilter = filters;
869
870         // expand [table.]* columns
871
colcount = vcolumn.size();
872
873         for (int pos = 0; pos < colcount; ) {
874             Expression e = (Expression) (vcolumn.get(pos));
875
876             if (e.getType() == Expression.ASTERISK) {
877                 vcolumn.remove(pos);
878
879                 colcount = vcolumn.size();
880
881                 String JavaDoc tablename = e.getTableName();
882
883                 if (tablename == null) {
884                     for (int i = 0; i < filters.length; i++) {
885                         pos = addFilterColumns(filters[i], vcolumn, pos);
886                         colcount = vcolumn.size();
887                     }
888                 } else {
889                     TableFilter f = e.findTableFilter(filters);
890
891                     if (f == null) {
892                         throw Trace.error(Trace.TABLE_NOT_FOUND, tablename);
893                     }
894
895                     pos = addFilterColumns(f, vcolumn, pos);
896                     colcount = vcolumn.size();
897                 }
898             } else {
899                 if (e.getFilter() == null) {
900                     for (int i = 0; i < filters.length; i++) {
901                         e.resolveTables(filters[i]);
902                     }
903                 }
904
905                 pos++;
906             }
907         }
908
909         for (int i = 0; i < colcount; i++) {
910             Expression e = (Expression) (vcolumn.get(i));
911
912             e.resolveTypes(session);
913         }
914
915         select.iResultLen = colcount;
916     }
917
918     /**
919      * Add all columns of a table filter to list of columns
920      */

921     static int addFilterColumns(TableFilter filter, HsqlArrayList columnList,
922                                 int position) {
923
924         Table table = filter.getTable();
925         int count = table.getColumnCount();
926
927         for (int i = 0; i < count; i++) {
928             Expression e = new Expression(filter, table.getColumn(i));
929
930             columnList.add(position++, e);
931         }
932
933         return position;
934     }
935
936     /**
937      * Resolves an ORDER BY Expression, returning the column Expression object
938      * to which it refers if it is an alias or column index. <p>
939      *
940      * If select is a SET QUERY, then only column indexes or names in the first
941      * query are allowed.
942      *
943      * @param e search column expression
944      * @param vcolumn list of columns
945      * @param union is select a union
946      * @return new or the same expression
947      * @throws HsqlException if an ambiguous reference to an alias or
948      * non-integer column index is encountered
949      */

950     private static Expression resolveOrderByExpression(Expression e,
951             Select select, HsqlArrayList vcolumn) throws HsqlException {
952
953         int visiblecols = select.iResultLen;
954         boolean union = select.unionSelect != null;
955
956         if (e.getType() == Expression.VALUE) {
957             return resolveOrderByColumnIndex(e, vcolumn, visiblecols);
958         }
959
960         if (e.getType() != Expression.COLUMN) {
961             if (union) {
962                 throw Trace.error(Trace.INVALID_ORDER_BY);
963             }
964
965             return e;
966         }
967
968         String JavaDoc ecolname = e.getColumnName();
969         String JavaDoc etablename = e.getTableName();
970
971         for (int i = 0, size = visiblecols; i < size; i++) {
972             Expression colexpr = (Expression) vcolumn.get(i);
973             String JavaDoc colalias = colexpr.getDefinedAlias();
974             String JavaDoc colname = colexpr.getColumnName();
975             String JavaDoc tablename = colexpr.getTableName();
976             String JavaDoc filtername = colexpr.getFilterTableName();
977
978             if ((ecolname.equals(colalias) || ecolname.equals(colname))
979                     && (etablename == null || etablename.equals(tablename)
980                         || etablename.equals(filtername))) {
981                 colexpr.joinedTableColumnIndex = i;
982
983                 return colexpr;
984             }
985         }
986
987         if (union) {
988             throw Trace.error(Trace.INVALID_ORDER_BY, ecolname);
989         }
990
991         return e;
992     }
993
994     private static Expression resolveOrderByColumnIndex(Expression e,
995             HsqlArrayList vcolumn, int visiblecols) throws HsqlException {
996
997         // order by 1,2,3
998
if (e.getDataType() == Types.INTEGER) {
999             int i = ((Integer JavaDoc) e.getValue(null)).intValue();
1000
1001            if (0 < i && i <= visiblecols) {
1002                Expression colexpr = (Expression) vcolumn.get(i - 1);
1003
1004                colexpr.joinedTableColumnIndex = i - 1;
1005
1006                return colexpr;
1007            }
1008        }
1009
1010        throw Trace.error(Trace.INVALID_ORDER_BY);
1011    }
1012
1013    private TableFilter parseSimpleTableFilter(int type)
1014    throws HsqlException {
1015
1016        String JavaDoc alias = null;
1017        String JavaDoc token = tokenizer.getName();
1018        String JavaDoc schema = session.getSchemaName(tokenizer.getLongNameFirst());
1019        Table table = database.schemaManager.getTable(session, token, schema);
1020
1021        checkTableWriteAccess(table, type);
1022
1023//
1024
token = tokenizer.getString();
1025
1026        if (token.equals(Token.T_AS)) {
1027            alias = tokenizer.getSimpleName();
1028        } else if (tokenizer.wasSimpleName()) {
1029            alias = token;
1030        } else {
1031            tokenizer.back();
1032        }
1033
1034        return new TableFilter(table, alias, null, false);
1035    }
1036
1037    /**
1038     * Retrieves a TableFilter object newly constructed from the current
1039     * parse context. <p>
1040     *
1041     * @param outerjoin if the filter is to back an outer join
1042     * @return a newly constructed TableFilter object
1043     * @throws HsqlException if a parsing error occurs
1044     */

1045    private TableFilter parseTableFilter(boolean outerjoin)
1046    throws HsqlException {
1047
1048        Table t = null;
1049        SubQuery sq = null;
1050        String JavaDoc sAlias = null;
1051        HashMappedList columnList = null;
1052
1053        if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
1054            int brackets = parseOpenBrackets();
1055
1056            tokenizer.getThis(Token.T_SELECT);
1057
1058            // fredt - not correlated - a joined subquery table must resolve fully
1059
sq = parseSubquery(brackets, null, true, Expression.QUERY);
1060
1061            tokenizer.getThis(Token.T_CLOSEBRACKET);
1062
1063            t = sq.table;
1064        } else {
1065            String JavaDoc token = tokenizer.getName();
1066            String JavaDoc schema =
1067                session.getSchemaName(tokenizer.getLongNameFirst());
1068
1069            t = database.schemaManager.getTable(session, token, schema);
1070
1071            session.check(t.getName(), UserManager.SELECT);
1072
1073            if (t.isView()) {
1074                sq = getViewSubquery((View) t);
1075                sq.select = ((View) t).viewSelect;
1076                t = sq.table;
1077                sAlias = token;
1078            }
1079        }
1080
1081        // fredt - we removed LEFT from the list of reserved words in Tokenizer
1082
// to allow LEFT() to work. Thus wasName() will return true for LEFT
1083
// and we check separately for this token
1084
String JavaDoc token = tokenizer.getString();
1085
1086        if (tokenizer.wasLongName()) {
1087            tokenizer.throwUnexpected();
1088        }
1089
1090        if ((token.equals(Token.T_LEFT) || token.equals(Token.T_RIGHT))
1091                &&!tokenizer.wasQuotedIdentifier()) {
1092            tokenizer.back();
1093        } else if (token.equals(Token.T_AS)
1094                   &&!tokenizer.wasQuotedIdentifier()) {
1095            sAlias = tokenizer.getSimpleName();
1096
1097            if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
1098                tokenizer.back();
1099
1100                columnList = parseColumnList();
1101            }
1102        } else if (tokenizer.wasSimpleName()) {
1103            sAlias = token;
1104
1105            if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
1106                tokenizer.back();
1107
1108                columnList = parseColumnList();
1109            }
1110        } else {
1111            tokenizer.back();
1112        }
1113
1114        if (columnList != null && t.getColumnCount() != columnList.size()) {
1115            throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
1116        }
1117
1118        return new TableFilter(t, sAlias, columnList, outerjoin);
1119    }
1120
1121    /**
1122     * Add a condition from the WHERE clause.
1123     *
1124     * @param e1
1125     * @param e2
1126     * @return
1127     */

1128    private static Expression addCondition(Expression e1, Expression e2) {
1129
1130        if (e1 == null) {
1131            return e2;
1132        } else if (e2 == null) {
1133            return e1;
1134        } else {
1135            return new Expression(Expression.AND, e1, e2);
1136        }
1137    }
1138
1139    /**
1140     * Conjuntively adds a condition from the JOIN table ON clause.
1141     *
1142     * @param e1 an existing condition with which e2 is to be combined
1143     * in order to form a new conjunction
1144     * @param e2 the new condition
1145     * @param tf the table filter that should become e2's join
1146     * table filter
1147     * @param outer true if join is outer
1148     * @throws HsqlException if e2 responds that it cannot participate
1149     * in the join
1150     * @return a new Expression object; the conjunction of e1 and e2
1151     */

1152    private static Expression addJoinCondition(Expression e1, Expression e2,
1153            TableFilter tf, boolean outer) throws HsqlException {
1154
1155        if (!e2.setForJoin(tf, outer)) {
1156            throw Trace.error(Trace.OUTER_JOIN_CONDITION);
1157        }
1158
1159        return addCondition(e1, e2);
1160    }
1161
1162    /**
1163     * Method declaration
1164     *
1165     * @return the Expression resulting from the parse
1166     * @throws HsqlException
1167     */

1168    Expression parseExpression() throws HsqlException {
1169
1170        read();
1171
1172        Expression r = readOr();
1173
1174        tokenizer.back();
1175
1176        return r;
1177    }
1178
1179    private Expression readAggregate() throws HsqlException {
1180
1181        boolean distinct = false;
1182        boolean all = false;
1183        int type = iToken;
1184
1185        read();
1186
1187        String JavaDoc token = tokenizer.getString();
1188
1189        if (token.equals(Token.T_DISTINCT)) {
1190            distinct = true;
1191        } else if (token.equals(Token.T_ALL)) {
1192            all = true;
1193        } else {
1194            tokenizer.back();
1195        }
1196
1197        readThis(Expression.OPEN);
1198
1199        Expression s = readOr();
1200
1201        readThis(Expression.CLOSE);
1202
1203        if ((all || distinct)
1204                && (type == Expression.STDDEV_POP
1205                    || type == Expression.STDDEV_SAMP
1206                    || type == Expression.VAR_POP
1207                    || type == Expression.VAR_SAMP)) {
1208            throw Trace.error(Trace.INVALID_FUNCTION_ARGUMENT);
1209        }
1210
1211        Expression aggregateExp = new Expression(type, s, null);
1212
1213        aggregateExp.setDistinctAggregate(distinct);
1214
1215        return aggregateExp;
1216    }
1217
1218    /**
1219     * Method declaration
1220     *
1221     * @return a disjuntion, possibly degenerate
1222     * @throws HsqlException
1223     */

1224    private Expression readOr() throws HsqlException {
1225
1226        Expression r = readAnd();
1227
1228        while (iToken == Expression.OR) {
1229            int type = iToken;
1230            Expression a = r;
1231
1232            read();
1233
1234            r = new Expression(type, a, readAnd());
1235        }
1236
1237        return r;
1238    }
1239
1240    /**
1241     * Method declaration
1242     *
1243     * @return a conjunction, possibly degenerate
1244     * @throws HsqlException
1245     */

1246    private Expression readAnd() throws HsqlException {
1247
1248        Expression r = readCondition();
1249
1250        while (iToken == Expression.AND) {
1251            int type = iToken;
1252            Expression a = r;
1253
1254            read();
1255
1256            r = new Expression(type, a, readCondition());
1257        }
1258
1259        return r;
1260    }
1261
1262    /**
1263     * Method declaration
1264     *
1265     * @return a predicate, possibly composite
1266     * @throws HsqlException
1267     */

1268    private Expression readCondition() throws HsqlException {
1269
1270        switch (iToken) {
1271
1272            case Expression.NOT : {
1273                int type = iToken;
1274
1275                read();
1276
1277                return new Expression(type, readCondition(), null);
1278            }
1279            case Expression.EXISTS : {
1280                int type = iToken;
1281
1282                read();
1283                readThis(Expression.OPEN);
1284
1285                int brackets = 0;
1286
1287                if (iToken == Expression.OPEN) {
1288                    brackets += parseOpenBrackets() + 1;
1289
1290                    read();
1291                }
1292
1293                Trace.check(iToken == Expression.SELECT,
1294                            Trace.UNEXPECTED_TOKEN);
1295
1296                SubQuery sq = parseSubquery(brackets, null, false,
1297                                            Expression.EXISTS);
1298                Expression s = new Expression(sq);
1299
1300                read();
1301                readThis(Expression.CLOSE);
1302
1303                return new Expression(type, s, null);
1304            }
1305            default : {
1306                Expression a = readConcat();
1307
1308                if (iToken == Expression.IS) {
1309                    read();
1310
1311                    boolean not;
1312
1313                    if (iToken == Expression.NOT) {
1314                        not = true;
1315
1316                        read();
1317                    } else {
1318                        not = false;
1319                    }
1320
1321                    Trace.check(iToken == Expression.VALUE && oData == null,
1322                                Trace.UNEXPECTED_TOKEN);
1323                    read();
1324
1325                    // TODO: the TableFilter needs a right hand side to avoid null pointer exceptions...
1326
a = new Expression(Expression.IS_NULL, a,
1327                                       new Expression(Types.NULL, null));
1328
1329                    if (not) {
1330                        a = new Expression(Expression.NOT, a, null);
1331                    }
1332
1333                    return a;
1334                }
1335
1336                boolean not = false;
1337
1338                if (iToken == Expression.NOT) {
1339                    not = true;
1340
1341                    read();
1342                }
1343
1344                switch (iToken) {
1345
1346                    case Expression.LIKE : {
1347                        a = parseLikePredicate(a);
1348
1349                        break;
1350                    }
1351                    case Expression.BETWEEN : {
1352                        a = parseBetweenPredicate(a);
1353
1354                        break;
1355                    }
1356                    case Expression.IN : {
1357                        a = this.parseInPredicate(a);
1358
1359                        break;
1360                    }
1361                    default : {
1362                        Trace.check(!not, Trace.UNEXPECTED_TOKEN);
1363
1364                        if (Expression.isCompare(iToken)) {
1365                            int type = iToken;
1366
1367                            read();
1368
1369                            return new Expression(type, a, readConcat());
1370                        }
1371
1372                        return a;
1373                    }
1374                }
1375
1376                if (not) {
1377                    a = new Expression(Expression.NOT, a, null);
1378                }
1379
1380                return a;
1381            }
1382        }
1383    }
1384
1385    private Expression parseLikePredicate(Expression a) throws HsqlException {
1386
1387        read();
1388
1389        Expression b = readConcat();
1390        Character JavaDoc escape = null;
1391
1392        if (sToken.equals(Token.T_ESCAPE)) {
1393            read();
1394
1395            Expression c = readTerm();
1396
1397            Trace.check(c.getType() == Expression.VALUE,
1398                        Trace.INVALID_ESCAPE);
1399
1400            String JavaDoc s = (String JavaDoc) c.getValue(session, Types.VARCHAR);
1401
1402            // boucherb@users 2003-09-25
1403
// CHECKME:
1404
// Assert s.length() == 1 for xxxchar comparisons?
1405
// TODO:
1406
// SQL200n says binary escape can be 1 or more octets.
1407
// Maybe we need to retain s and check this in
1408
// Expression.resolve()?
1409
if (s == null || s.length() < 1) {
1410                throw Trace.error(Trace.INVALID_ESCAPE, s);
1411            }
1412
1413            escape = new Character JavaDoc(s.charAt(0));
1414        }
1415
1416        boolean hasCollation = database.collation.name != null;
1417
1418        a = new Expression(a, b, escape, hasCollation);
1419
1420        return a;
1421    }
1422
1423    private Expression parseBetweenPredicate(Expression a)
1424    throws HsqlException {
1425
1426        read();
1427
1428        Expression l = new Expression(Expression.BIGGER_EQUAL, a,
1429                                      readConcat());
1430
1431        readThis(Expression.AND);
1432
1433        Expression h = new Expression(Expression.SMALLER_EQUAL, a,
1434                                      readConcat());
1435
1436        if (l.getArg().isParam() && l.getArg2().isParam()) {
1437            throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
1438                              Trace.Parser_ambiguous_between1);
1439        }
1440
1441        if (h.getArg().isParam() && h.getArg2().isParam()) {
1442            throw Trace.error(Trace.UNRESOLVED_PARAMETER_TYPE,
1443                              Trace.Parser_ambiguous_between1);
1444        }
1445
1446        return new Expression(Expression.AND, l, h);
1447    }
1448
1449    private Expression parseInPredicate(Expression a) throws HsqlException {
1450
1451        int type = iToken;
1452
1453        read();
1454        readThis(Expression.OPEN);
1455
1456        Expression b = null;
1457        int brackets = 0;
1458
1459        if (iToken == Expression.OPEN) {
1460            brackets += parseOpenBrackets() + 1;
1461
1462            read();
1463        }
1464
1465        if (iToken == Expression.SELECT) {
1466            SubQuery sq = parseSubquery(brackets, null, false, Expression.IN);
1467
1468            // until we support rows in IN predicates
1469
Trace.check(sq.select.iResultLen == 1,
1470                        Trace.SINGLE_COLUMN_EXPECTED);
1471
1472            b = new Expression(sq);
1473
1474            read();
1475        } else {
1476            tokenizer.back();
1477
1478            HsqlArrayList v = new HsqlArrayList();
1479
1480            while (true) {
1481                Expression value = parseExpression();
1482
1483                if (value.exprType == Expression.VALUE
1484                        && value.valueData == null &&!value.isParam()) {
1485                    throw Trace.error(Trace.NULL_IN_VALUE_LIST);
1486                }
1487
1488                v.add(value);
1489                read();
1490
1491                if (iToken != Expression.COMMA) {
1492                    break;
1493                }
1494            }
1495
1496            Expression[] valueList;
1497
1498            valueList = (Expression[]) v.toArray(new Expression[v.size()]);
1499            b = new Expression(valueList);
1500        }
1501
1502        readThis(Expression.CLOSE);
1503
1504        return new Expression(type, a, b);
1505    }
1506
1507    private Expression parseAllAnyPredicate() throws HsqlException {
1508
1509        int type = iToken;
1510
1511        read();
1512        readThis(Expression.OPEN);
1513
1514        Expression b = null;
1515        int brackets = 0;
1516
1517        if (iToken == Expression.OPEN) {
1518            brackets += parseOpenBrackets() + 1;
1519
1520            read();
1521        }
1522
1523        if (iToken != Expression.SELECT) {
1524            throw Trace.error(Trace.INVALID_IDENTIFIER);
1525        }
1526
1527        SubQuery sq = parseSubquery(brackets, null, false, type);
1528        Select select = sq.select;
1529
1530        // until we support rows
1531
Trace.check(sq.select.iResultLen == 1, Trace.SINGLE_COLUMN_EXPECTED);
1532
1533        b = new Expression(sq);
1534
1535        read();
1536        readThis(Expression.CLOSE);
1537
1538        return new Expression(type, b, null);
1539    }
1540
1541    /**
1542     * Method declaration
1543     *
1544     * @param type
1545     * @throws HsqlException
1546     */

1547    private void readThis(int type) throws HsqlException {
1548        Trace.check(iToken == type, Trace.UNEXPECTED_TOKEN);
1549        read();
1550    }
1551
1552    /**
1553     * Method declaration
1554     *
1555     * @return a concatenation, possibly degenerate
1556     * @throws HsqlException
1557     */

1558    private Expression readConcat() throws HsqlException {
1559
1560        Expression r = readSum();
1561
1562        while (iToken == Expression.CONCAT) {
1563            int type = Expression.CONCAT;
1564            Expression a = r;
1565
1566            read();
1567
1568            r = new Expression(type, a, readSum());
1569        }
1570
1571        return r;
1572    }
1573
1574    static HashMap simpleFunctions = new HashMap();
1575
1576    static {
1577        simpleFunctions.put(Token.T_CURRENT_DATE,
1578                            "org.hsqldb.Library.curdate");
1579        simpleFunctions.put(Token.T_CURRENT_TIME,
1580                            "org.hsqldb.Library.curtime");
1581        simpleFunctions.put(Token.T_CURRENT_TIMESTAMP,
1582                            "org.hsqldb.Library.now");
1583        simpleFunctions.put(Token.T_CURRENT_USER, "org.hsqldb.Library.user");
1584        simpleFunctions.put(Token.T_SYSDATE, "org.hsqldb.Library.curdate");
1585        simpleFunctions.put(Token.T_NOW, "org.hsqldb.Library.now");
1586        simpleFunctions.put(Token.T_TODAY, "org.hsqldb.Library.curdate");
1587    }
1588
1589    /**
1590     * Method declaration
1591     *
1592     * @return a summation, possibly degenerate
1593     * @throws HsqlException
1594     */

1595    private Expression readSum() throws HsqlException {
1596
1597        Expression r = readFactor();
1598
1599        while (true) {
1600            int type;
1601
1602            if (iToken == Expression.PLUS) {
1603                type = Expression.ADD;
1604            } else if (iToken == Expression.NEGATE) {
1605                type = Expression.SUBTRACT;
1606            } else {
1607                break;
1608            }
1609
1610            Expression a = r;
1611
1612            read();
1613
1614            r = new Expression(type, a, readFactor());
1615        }
1616
1617        return r;
1618    }
1619
1620    /**
1621     * Method declaration
1622     *
1623     * @return a product, possibly degenerate
1624     * @throws HsqlException
1625     */

1626    private Expression readFactor() throws HsqlException {
1627
1628        Expression r = readTerm();
1629
1630        while (iToken == Expression.MULTIPLY || iToken == Expression.DIVIDE) {
1631            int type = iToken;
1632            Expression a = r;
1633
1634            read();
1635
1636            r = new Expression(type, a, readTerm());
1637        }
1638
1639        return r;
1640    }
1641
1642    /**
1643     * Method declaration
1644     *
1645     * @return a term, possibly composite
1646     * @throws HsqlException
1647     */

1648    private Expression readTerm() throws HsqlException {
1649
1650        Expression r = null;
1651
1652        switch (iToken) {
1653
1654            case Expression.COLUMN : {
1655                r = readColumnExpression();
1656
1657                break;
1658            }
1659            case Expression.NEGATE : {
1660                int type = iToken;
1661
1662                read();
1663
1664                r = new Expression(type, readTerm(), null);
1665
1666                Trace.check(!r.getArg().isParam(),
1667                            Trace.Expression_resolveTypes1);
1668
1669                break;
1670            }
1671            case Expression.PLUS : {
1672                read();
1673
1674                r = readTerm();
1675
1676                Trace.check(!r.isParam(), Trace.UNRESOLVED_PARAMETER_TYPE,
1677                            Trace.getMessage(Trace.Expression_resolveTypes1));
1678
1679                break;
1680            }
1681            case Expression.OPEN : {
1682                read();
1683
1684                r = readOr();
1685
1686                if (iToken != Expression.CLOSE) {
1687                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
1688                }
1689
1690                read();
1691
1692                break;
1693            }
1694            case Expression.VALUE : {
1695                r = new Expression(iType, oData);
1696
1697                read();
1698
1699                break;
1700            }
1701            case Expression.PARAM : {
1702                r = new Expression(Types.NULL, null, true);
1703
1704                parameters.add(r);
1705                read();
1706
1707                break;
1708            }
1709            case Expression.SELECT : {
1710/*
1711                // accept ORDRY BY with LIMIT
1712                Select select = parseSelect(0, false, false, true, true);
1713
1714                select.resolve(session);
1715
1716                SubQuery sq = new SubQuery();
1717
1718                sq.select = select;
1719 */

1720                SubQuery sq = parseSubquery(0, null, false,
1721                                            Expression.SELECT);
1722
1723                r = new Expression(sq);
1724
1725                read();
1726
1727                break;
1728            }
1729            case Expression.ANY :
1730            case Expression.ALL : {
1731                r = parseAllAnyPredicate();
1732
1733// read();
1734
break;
1735            }
1736            case Expression.MULTIPLY : {
1737                r = new Expression(sSchema, sTable, (String JavaDoc) null);
1738
1739                read();
1740
1741                break;
1742            }
1743            case Expression.CASEWHEN :
1744                return readCaseWhenExpression();
1745
1746            case Expression.CASE :
1747                return readCaseExpression();
1748
1749            case Expression.NULLIF :
1750                return readNullIfExpression();
1751
1752            case Expression.COALESCE :
1753            case Expression.IFNULL :
1754                return readCoalesceExpression();
1755
1756            case Expression.SEQUENCE :
1757                return readSequenceExpression();
1758
1759            case Expression.CAST :
1760            case Expression.CONVERT :
1761                return readCastExpression();
1762
1763            case Expression.EXTRACT :
1764                return readExtractExpression();
1765
1766            case Expression.TRIM :
1767                return readTrimExpression();
1768
1769            case Expression.POSITION :
1770                return readPositionExpression();
1771
1772            case Expression.SUBSTRING :
1773                return readSubstringExpression();
1774
1775            default :
1776                if (Expression.isAggregate(iToken)) {
1777                    return readAggregate();
1778                } else {
1779                    throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
1780                }
1781        }
1782
1783        return r;
1784    }
1785
1786    /**
1787     * reads a CASE .. WHEN expression
1788     */

1789    Expression readCaseExpression() throws HsqlException {
1790
1791        int type = Expression.CASEWHEN;
1792        Expression r = null;
1793        Expression predicand = null;
1794
1795        read();
1796
1797        if (iToken != Expression.WHEN) {
1798            predicand = readOr();
1799        }
1800
1801        Expression leaf = null;
1802
1803        while (true) {
1804            Expression casewhen = parseCaseWhen(predicand);
1805
1806            if (r == null) {
1807                r = casewhen;
1808            } else {
1809                leaf.setRightExpression(casewhen);
1810            }
1811
1812            leaf = casewhen.getRightExpression();
1813
1814            if (iToken != Expression.WHEN) {
1815                break;
1816            }
1817        }
1818
1819        if (iToken == Expression.ELSE) {
1820            readThis(Expression.ELSE);
1821
1822            Expression elsexpr = readOr();
1823
1824            leaf.setRightExpression(elsexpr);
1825        }
1826
1827        readThis(Expression.ENDWHEN);
1828
1829        return r;
1830    }
1831
1832    /**
1833     * Reads part of a CASE .. WHEN expression
1834     */

1835    private Expression parseCaseWhen(Expression r) throws HsqlException {
1836
1837        readThis(Expression.WHEN);
1838
1839        Expression condition;
1840
1841        if (r == null) {
1842            condition = readOr();
1843        } else {
1844            condition = new Expression(Expression.EQUAL, r, readOr());
1845        }
1846
1847        readThis(Expression.THEN);
1848
1849        Expression current = readOr();
1850        Expression alternatives = new Expression(Expression.ALTERNATIVE,
1851            current, new Expression(Types.NULL, null));
1852        Expression casewhen = new Expression(Expression.CASEWHEN, condition,
1853                                             alternatives);
1854
1855        return casewhen;
1856    }
1857
1858    /**
1859     * reads a CASEWHEN expression
1860     */

1861    private Expression readCaseWhenExpression() throws HsqlException {
1862
1863        int type = iToken;
1864        Expression r = null;
1865
1866        read();
1867        readThis(Expression.OPEN);
1868
1869        r = readOr();
1870
1871        readThis(Expression.COMMA);
1872
1873        Expression thenelse = readOr();
1874
1875        readThis(Expression.COMMA);
1876
1877        // thenelse part is never evaluated; only init
1878
thenelse = new Expression(Expression.ALTERNATIVE, thenelse, readOr());
1879        r = new Expression(type, r, thenelse);
1880
1881        readThis(Expression.CLOSE);
1882
1883        return r;
1884    }
1885
1886    /**
1887     * Reads a CAST or CONVERT expression
1888     */

1889    private Expression readCastExpression() throws HsqlException {
1890
1891        boolean isConvert = iToken == Expression.CONVERT;
1892
1893        read();
1894        readThis(Expression.OPEN);
1895
1896        Expression r = readOr();
1897
1898        if (isConvert) {
1899            readThis(Expression.COMMA);
1900        } else {
1901            readThis(Expression.AS);
1902        }
1903
1904        int typeNr = Types.getTypeNr(sToken);
1905        int length = 0;
1906        int scale = 0;
1907        boolean hasLength = false;
1908
1909        if (Types.acceptsPrecisionCreateParam(typeNr)
1910                && tokenizer.isGetThis(Token.T_OPENBRACKET)) {
1911            length = tokenizer.getInt();
1912            hasLength = true;
1913
1914            if (Types.acceptsScaleCreateParam(typeNr)
1915                    && tokenizer.isGetThis(Token.T_COMMA)) {
1916                scale = tokenizer.getInt();
1917            }
1918
1919            tokenizer.getThis(Token.T_CLOSEBRACKET);
1920        }
1921
1922        if (typeNr == Types.FLOAT && length > 53) {
1923            throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1924        }
1925
1926        if (typeNr == Types.TIMESTAMP) {
1927            if (!hasLength) {
1928                length = 6;
1929            } else if (length != 0 && length != 6) {
1930                throw Trace.error(Trace.NUMERIC_VALUE_OUT_OF_RANGE);
1931            }
1932        }
1933
1934        if (r.isParam()) {
1935            r.setDataType(typeNr);
1936        }
1937
1938        r = new Expression(r, typeNr, length, scale);
1939
1940        read();
1941        readThis(Expression.CLOSE);
1942
1943        return r;
1944    }
1945
1946    /**
1947     * reads a Column or Function expression
1948     */

1949    private Expression readColumnExpression() throws HsqlException {
1950
1951        String JavaDoc name = sToken;
1952        Expression r = new Expression(sTable, name, wasQuoted);
1953
1954        read();
1955
1956        if (iToken == Expression.OPEN) {
1957            String JavaDoc javaName = database.getJavaName(name);
1958            Function f = new Function(name, javaName, false);
1959
1960            session.check(javaName);
1961
1962            int len = f.getArgCount();
1963            int i = 0;
1964
1965            read();
1966
1967            if (iToken != Expression.CLOSE) {
1968                while (true) {
1969                    f.setArgument(i++, readOr());
1970
1971                    if (iToken != Expression.COMMA) {
1972                        break;
1973                    }
1974
1975                    read();
1976                }
1977            }
1978
1979            readThis(Expression.CLOSE);
1980
1981            r = new Expression(f);
1982        } else {
1983            String JavaDoc javaName = (String JavaDoc) simpleFunctions.get(name);
1984
1985            if (javaName != null) {
1986                Function f = new Function(name, javaName, true);
1987
1988                r = new Expression(f);
1989            }
1990        }
1991
1992        return r;
1993    }
1994
1995    /**
1996     * reads a CONCAT expression
1997     */

1998    private Expression readConcatExpression() throws HsqlException {
1999
2000        int type = iToken;
2001
2002        read();
2003        readThis(Expression.OPEN);
2004
2005        Expression r = readOr();
2006
2007        readThis(Expression.COMMA);
2008
2009        r = new Expression(type, r, readOr());
2010
2011        readThis(Expression.CLOSE);
2012
2013        return r;
2014    }
2015
2016    /**
2017     * Reads a NULLIF expression
2018     */

2019    private Expression readNullIfExpression() throws HsqlException {
2020
2021        // turn into a CASEWHEN
2022
read();
2023        readThis(Expression.OPEN);
2024
2025        Expression r = readOr();
2026
2027        readThis(Expression.COMMA);
2028
2029        Expression thenelse = new Expression(Expression.ALTERNATIVE,
2030                                             new Expression(Types.NULL, null),
2031                                             r);
2032
2033        r = new Expression(Expression.EQUAL, r, readOr());
2034        r = new Expression(Expression.CASEWHEN, r, thenelse);
2035
2036        readThis(Expression.CLOSE);
2037
2038        return r;
2039    }
2040
2041    /**
2042     * Reads a COALESE or IFNULL expression
2043     */

2044    private Expression readCoalesceExpression() throws HsqlException {
2045
2046        Expression r = null;
2047
2048        // turn into a CASEWHEN
2049
read();
2050        readThis(Expression.OPEN);
2051
2052        Expression leaf = null;
2053
2054        while (true) {
2055            Expression current = readOr();
2056
2057            if (leaf != null && iToken == Expression.CLOSE) {
2058                readThis(Expression.CLOSE);
2059                leaf.setLeftExpression(current);
2060
2061                break;
2062            }
2063
2064            Expression condition = new Expression(Expression.IS_NULL,
2065                                                  current, null);
2066            Expression alternatives = new Expression(Expression.ALTERNATIVE,
2067                new Expression(Types.NULL, null), current);
2068            Expression casewhen = new Expression(Expression.CASEWHEN,
2069                                                 condition, alternatives);
2070
2071            if (r == null) {
2072                r = casewhen;
2073            } else {
2074                leaf.setLeftExpression(casewhen);
2075            }
2076
2077            leaf = alternatives;
2078
2079            readThis(Expression.COMMA);
2080        }
2081
2082        return r;
2083    }
2084
2085    /**
2086     * Reads an EXTRACT expression
2087     */

2088    private Expression readExtractExpression() throws HsqlException {
2089
2090        read();
2091        readThis(Expression.OPEN);
2092
2093        String JavaDoc name = sToken;
2094
2095        // must be an accepted identifier
2096
if (!Expression.SQL_EXTRACT_FIELD_NAMES.contains(name)) {
2097            throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken);
2098        }
2099
2100        readToken();
2101        readThis(Expression.FROM);
2102
2103        // the name argument is DAY, MONTH etc. - OK for now for CHECK constraints
2104
Function f = new Function(name, database.getJavaName(name), false);
2105
2106        f.setArgument(0, readOr());
2107        readThis(Expression.CLOSE);
2108
2109        return new Expression(f);
2110    }
2111
2112    /**
2113     * Reads a POSITION expression
2114     */

2115    private Expression readPositionExpression() throws HsqlException {
2116
2117        read();
2118        readThis(Expression.OPEN);
2119
2120        Function f = new Function(Token.T_POSITION,
2121                                  "org.hsqldb.Library.position", false);
2122
2123        f.setArgument(0, readTerm());
2124        readThis(Expression.IN);
2125        f.setArgument(1, readOr());
2126        readThis(Expression.CLOSE);
2127
2128        return new Expression(f);
2129    }
2130
2131    /**
2132     * Reads a SUBSTRING expression
2133     */

2134    private Expression readSubstringExpression() throws HsqlException {
2135
2136        boolean commas = false;
2137
2138        read();
2139        readThis(Expression.OPEN);
2140
2141        // OK for now for CHECK search conditions
2142
Function f = new Function(Token.T_SUBSTRING,
2143                                  "org.hsqldb.Library.substring", false);
2144
2145        f.setArgument(0, readTerm());
2146
2147        if (iToken == Expression.FROM) {
2148            readThis(Expression.FROM);
2149        } else {
2150            readThis(Expression.COMMA);
2151
2152            commas = true;
2153        }
2154
2155        f.setArgument(1, readOr());
2156
2157        Expression count = null;
2158
2159        if (!commas && iToken == Expression.FOR) {
2160            readThis(Expression.FOR);
2161
2162            count = readTerm();
2163        } else if (commas && iToken == Expression.COMMA) {
2164            readThis(Expression.COMMA);
2165
2166            count = readTerm();
2167        }
2168
2169        f.setArgument(2, count);
2170        readThis(Expression.CLOSE);
2171
2172        return new Expression(f);
2173    }
2174
2175    private Expression readSequenceExpression() throws HsqlException {
2176
2177        tokenizer.getThis(Token.T_VALUE);
2178        tokenizer.getThis(Token.T_FOR);
2179
2180        String JavaDoc name = tokenizer.getName();
2181        String JavaDoc schemaname = tokenizer.getLongNameFirst();
2182
2183        schemaname = session.getSchemaName(schemaname);
2184
2185        // Read next because Tokenizer.back() will run after this.
2186
// (This is because usually when reading expressions, you need to
2187
// get the following token to know whether you have finished.
2188
tokenizer.getString();
2189
2190        NumberSequence sequence = database.schemaManager.getSequence(name,
2191            schemaname);
2192
2193        return new Expression(sequence);
2194    }
2195
2196    /**
2197     * Reads a TRIM expression
2198     */

2199    private Expression readTrimExpression() throws HsqlException {
2200
2201        read();
2202        readThis(Expression.OPEN);
2203
2204        String JavaDoc type = sToken;
2205
2206        if (Expression.SQL_TRIM_SPECIFICATION.contains(type)) {
2207            read();
2208        } else {
2209            type = Token.T_BOTH;
2210        }
2211
2212        String JavaDoc trimstr;
2213
2214        if (sToken.length() == 1) {
2215            trimstr = sToken;
2216
2217            read();
2218        } else {
2219            trimstr = " ";
2220        }
2221
2222        readThis(Expression.FROM);
2223
2224        Expression trim = new Expression(Types.CHAR, trimstr);
2225        Expression leading;
2226        Expression trailing;
2227
2228        if (type.equals(Token.T_LEADING)) {
2229            leading = new Expression(true);
2230            trailing = new Expression(false);
2231        } else if (type.equals(Token.T_TRAILING)) {
2232            leading = new Expression(false);
2233            trailing = new Expression(true);
2234        } else {
2235            leading = trailing = new Expression(true);
2236        }
2237
2238        // name argument is OK for now for CHECK constraints
2239
Function f = new Function(Token.T_TRIM, "org.hsqldb.Library.trim",
2240                                  false);
2241
2242        f.setArgument(0, readOr());
2243        f.setArgument(1, trim);
2244        f.setArgument(2, leading);
2245        f.setArgument(3, trailing);
2246        readThis(Expression.CLOSE);
2247
2248        return new Expression(f);
2249    }
2250
2251    /**
2252     * Reads a DEFAULT clause expression.
2253     */

2254    Expression readDefaultClause(int dataType) throws HsqlException {
2255
2256        Expression r = null;
2257
2258        read();
2259
2260        switch (iToken) {
2261
2262            case Expression.COLUMN : {
2263                String JavaDoc name = sToken;
2264                String JavaDoc javaName = (String JavaDoc) simpleFunctions.get(name);
2265
2266                if (javaName != null) {
2267                    Function f = new Function(name, javaName, true);
2268
2269                    return new Expression(f);
2270                }
2271
2272                break;
2273            }
2274            case Expression.NEGATE : {
2275                int exprType = iToken;
2276
2277                read();
2278
2279                if (iToken == Expression.VALUE) {
2280                    oData = Column.convertObject(oData, dataType);
2281
2282                    return new Expression(exprType,
2283                                          new Expression(dataType, oData),
2284                                          null);
2285                }
2286
2287                break;
2288            }
2289            case Expression.VALUE : {
2290                String JavaDoc name = sToken.toUpperCase(Locale.ENGLISH);
2291                String JavaDoc javaName = (String JavaDoc) simpleFunctions.get(name);
2292
2293                if (Types.isDatetimeType(dataType) && javaName != null) {
2294                    Function f = new Function(name, javaName, true);
2295
2296                    return new Expression(f);
2297                }
2298
2299                oData = Column.convertObject(oData, dataType);
2300
2301                return new Expression(dataType, oData);
2302            }
2303        }
2304
2305        throw Trace.error(Trace.WRONG_DEFAULT_CLAUSE, sToken);
2306    }
2307
2308    /**
2309     * Method declaration
2310     *
2311     * @throws HsqlException
2312     */

2313    private void read() throws HsqlException {
2314
2315        sToken = tokenizer.getString();
2316        wasQuoted = tokenizer.wasQuotedIdentifier();
2317
2318        if (tokenizer.wasValue()) {
2319            iToken = Expression.VALUE;
2320            oData = tokenizer.getAsValue();
2321            iType = tokenizer.getType();
2322        } else if (tokenizer.wasSimpleName()) {
2323            iToken = Expression.COLUMN;
2324            sTable = null;
2325        } else if (tokenizer.wasLongName()) {
2326            sSchema = tokenizer.getLongNamePre();
2327            sTable = tokenizer.getLongNameFirst();
2328
2329            if (sToken.equals(Token.T_MULTIPLY)) {
2330                iToken = Expression.MULTIPLY;
2331            } else {
2332                iToken = Expression.COLUMN;
2333            }
2334        } else if (tokenizer.wasParameter()) {
2335            iToken = Expression.PARAM;
2336        } else if (sToken.length() == 0) {
2337            iToken = Expression.END;
2338        } else {
2339            iToken = tokenSet.get(sToken, -1);
2340
2341            if (iToken == -1) {
2342                iToken = Expression.END;
2343            }
2344
2345            switch (iToken) {
2346
2347                case Expression.COMMA :
2348                case Expression.EQUAL :
2349                case Expression.NOT_EQUAL :
2350                case Expression.SMALLER :
2351                case Expression.BIGGER :
2352                case Expression.SMALLER_EQUAL :
2353                case Expression.BIGGER_EQUAL :
2354                case Expression.AND :
2355                case Expression.OR :
2356                case Expression.NOT :
2357                case Expression.ALL :
2358                case Expression.ANY :
2359                case Expression.IN :
2360                case Expression.EXISTS :
2361                case Expression.BETWEEN :
2362                case Expression.PLUS :
2363                case Expression.NEGATE :
2364                case Expression.DIVIDE :
2365                case Expression.CONCAT :
2366                case Expression.OPEN :
2367                case Expression.CLOSE :
2368                case Expression.SELECT :
2369                case Expression.LIKE :
2370                case Expression.COUNT :
2371                case Expression.SUM :
2372                case Expression.MIN :
2373                case Expression.MAX :
2374                case Expression.AVG :
2375                case Expression.EVERY :
2376                case Expression.SOME :
2377                case Expression.STDDEV_POP :
2378                case Expression.STDDEV_SAMP :
2379                case Expression.VAR_POP :
2380                case Expression.VAR_SAMP :
2381                case Expression.CONVERT :
2382                case Expression.CAST :
2383                case Expression.SEQUENCE :
2384                case Expression.IFNULL :
2385                case Expression.COALESCE :
2386                case Expression.NULLIF :
2387                case Expression.CASE :
2388                case Expression.WHEN :
2389                case Expression.THEN :
2390                case Expression.ELSE :
2391                case Expression.ENDWHEN :
2392                case Expression.CASEWHEN :
2393                case Expression.EXTRACT :
2394                case Expression.POSITION :
2395                case Expression.SUBSTRING :
2396                case Expression.FROM :
2397                case Expression.FOR :
2398                case Expression.END :
2399                case Expression.PARAM :
2400                case Expression.TRIM :
2401                case Expression.LEADING :
2402                case Expression.TRAILING :
2403                case Expression.BOTH :
2404                case Expression.AS :
2405                case Expression.IS :
2406                case Expression.DISTINCT :
2407                    break; // nothing else required, iToken initialized properly
2408

2409                case Expression.MULTIPLY :
2410                    sTable = null; // in case of ASTERIX
2411
break;
2412
2413                default :
2414                    iToken = Expression.END;
2415            }
2416        }
2417    }
2418
2419    /**
2420     * A workaround for parsing EXTRACT clause elements such as MONTH, DAY
2421     * and YEAR, without having to make each of them SQL KEYWORDS in Tokenizer.
2422     *
2423     * @throws HsqlException if a tokenization error occurs
2424     */

2425    private void readToken() throws HsqlException {
2426        sToken = tokenizer.getString();
2427        iToken = tokenSet.get(sToken, -1);
2428    }
2429
2430    private static IntValueHashMap tokenSet = new IntValueHashMap(37);
2431
2432    static {
2433        tokenSet.put(Token.T_COMMA, Expression.COMMA);
2434        tokenSet.put(Token.T_EQUALS, Expression.EQUAL);
2435        tokenSet.put("!=", Expression.NOT_EQUAL);
2436        tokenSet.put("<>", Expression.NOT_EQUAL);
2437        tokenSet.put("<", Expression.SMALLER);
2438        tokenSet.put(">", Expression.BIGGER);
2439        tokenSet.put("<=", Expression.SMALLER_EQUAL);
2440        tokenSet.put(">=", Expression.BIGGER_EQUAL);
2441        tokenSet.put(Token.T_AND, Expression.AND);
2442        tokenSet.put(Token.T_NOT, Expression.NOT);
2443        tokenSet.put(Token.T_OR, Expression.OR);
2444        tokenSet.put(Token.T_ALL, Expression.ALL);
2445        tokenSet.put(Token.T_ANY, Expression.ANY);
2446        tokenSet.put(Token.T_IN, Expression.IN);
2447        tokenSet.put(Token.T_EXISTS, Expression.EXISTS);
2448        tokenSet.put(Token.T_BETWEEN, Expression.BETWEEN);
2449        tokenSet.put(Token.T_PLUS, Expression.PLUS);
2450        tokenSet.put("-", Expression.NEGATE);
2451        tokenSet.put(Token.T_MULTIPLY, Expression.MULTIPLY);
2452        tokenSet.put("/", Expression.DIVIDE);
2453        tokenSet.put("||", Expression.CONCAT);
2454        tokenSet.put(Token.T_OPENBRACKET, Expression.OPEN);
2455        tokenSet.put(Token.T_CLOSEBRACKET, Expression.CLOSE);
2456        tokenSet.put(Token.T_SELECT, Expression.SELECT);
2457        tokenSet.put(Token.T_LIKE, Expression.LIKE);
2458        tokenSet.put(Token.T_COUNT, Expression.COUNT);
2459        tokenSet.put(Token.T_SUM, Expression.SUM);
2460        tokenSet.put(Token.T_MIN, Expression.MIN);
2461        tokenSet.put(Token.T_MAX, Expression.MAX);
2462        tokenSet.put(Token.T_AVG, Expression.AVG);
2463        tokenSet.put(Token.T_EVERY, Expression.EVERY);
2464        tokenSet.put(Token.T_SOME, Expression.SOME);
2465        tokenSet.put(Token.T_STDDEV_POP, Expression.STDDEV_POP);
2466        tokenSet.put(Token.T_STDDEV_SAMP, Expression.STDDEV_SAMP);
2467        tokenSet.put(Token.T_VAR_POP, Expression.VAR_POP);
2468        tokenSet.put(Token.T_VAR_SAMP, Expression.VAR_SAMP);
2469        tokenSet.put(Token.T_IFNULL, Expression.IFNULL);
2470        tokenSet.put(Token.T_NVL, Expression.IFNULL);
2471        tokenSet.put(Token.T_NULLIF, Expression.NULLIF);
2472        tokenSet.put(Token.T_CONVERT, Expression.CONVERT);
2473        tokenSet.put(Token.T_CAST, Expression.CAST);
2474        tokenSet.put(Token.T_NEXT, Expression.SEQUENCE);
2475        tokenSet.put(Token.T_CASE, Expression.CASE);
2476        tokenSet.put(Token.T_WHEN, Expression.WHEN);
2477        tokenSet.put(Token.T_THEN, Expression.THEN);
2478        tokenSet.put(Token.T_ELSE, Expression.ELSE);
2479        tokenSet.put(Token.T_END, Expression.ENDWHEN);
2480        tokenSet.put(Token.T_CASEWHEN, Expression.CASEWHEN);
2481        tokenSet.put(Token.T_COALESCE, Expression.COALESCE);
2482        tokenSet.put(Token.T_EXTRACT, Expression.EXTRACT);
2483        tokenSet.put(Token.T_POSITION, Expression.POSITION);
2484        tokenSet.put(Token.T_FROM, Expression.FROM);
2485        tokenSet.put(Token.T_TRIM, Expression.TRIM);
2486        tokenSet.put(Token.T_SUBSTRING, Expression.SUBSTRING);
2487        tokenSet.put(Token.T_FOR, Expression.FOR);
2488        tokenSet.put(Token.T_AS, Expression.AS);
2489        tokenSet.put(Token.T_IS, Expression.IS);
2490        tokenSet.put(Token.T_QUESTION, Expression.PARAM);
2491    }
2492
2493// boucherb@users 20030411 - patch 1.7.2 - for prepared statements
2494
// ---------------------------------------------------------------
2495
HsqlArrayList parameters = new HsqlArrayList();
2496    private static final Expression[] noParameters = new Expression[0];
2497    private static final SubQuery[] noSubqueries = new SubQuery[0];
2498
2499    /**
2500     * Destructive get method
2501     */

2502    Expression[] getParameters() {
2503
2504        Expression[] result = parameters.size() == 0 ? noParameters
2505                                                     : (Expression[]) parameters.toArray(
2506                                                         new Expression[parameters.size()]);
2507
2508        parameters.clear();
2509
2510        return result;
2511    }
2512
2513    void clearParameters() {
2514        parameters.clear();
2515    }
2516
2517    // fredt - new implementation of subquery list
2518

2519    /**
2520     * Sets the subqueries as belonging to the View being constructed
2521     */

2522    void setAsView(View view) {
2523
2524        for (int i = 0; i < subQueryList.size(); i++) {
2525            SubQuery sq = (SubQuery) subQueryList.get(i);
2526
2527            if (sq.view == null) {
2528                sq.view = view;
2529            }
2530        }
2531    }
2532
2533    /**
2534     * Return the list of subqueries as an array sorted according to the order
2535     * of materialization, then clear the internal subquery list
2536     */

2537    SubQuery[] getSortedSubqueries() {
2538
2539        if (subQueryList.size() == 0) {
2540            return noSubqueries;
2541        }
2542
2543        subQueryList.sort((SubQuery) subQueryList.get(0));
2544
2545        SubQuery[] subqueries = new SubQuery[subQueryList.size()];
2546
2547        subQueryList.toArray(subqueries);
2548        subQueryList.clear();
2549
2550        return subqueries;
2551    }
2552
2553    /**
2554     * Retrieves a CALL-type CompiledStatement from this parse context.
2555     */

2556    CompiledStatement compileCallStatement() throws HsqlException {
2557
2558        clearParameters();
2559
2560        Expression expression = parseExpression();
2561        CompiledStatement cs = new CompiledStatement(session, database,
2562            session.currentSchema, expression, getSortedSubqueries(),
2563            getParameters());
2564
2565        return cs;
2566    }
2567
2568    /**
2569     * Retrieves a DELETE-type CompiledStatement from this parse context.
2570     */

2571    CompiledStatement compileDeleteStatement() throws HsqlException {
2572
2573        String JavaDoc token;
2574        Expression condition = null;
2575        TableFilter tableFilter;
2576
2577        clearParameters();
2578        tokenizer.getThis(Token.T_FROM);
2579
2580        tableFilter = parseSimpleTableFilter(UserManager.DELETE);
2581        token = tokenizer.getString();
2582
2583        if (token.equals(Token.T_WHERE)) {
2584            condition = parseExpression();
2585        } else {
2586            tokenizer.back();
2587        }
2588
2589        CompiledStatement cs = new CompiledStatement(session, database,
2590            session.currentSchema, tableFilter, condition,
2591            getSortedSubqueries(), getParameters());
2592
2593        return cs;
2594    }
2595
2596    private void getInsertColumnValueExpressions(Table t, Expression[] acve,
2597            int len) throws HsqlException {
2598
2599        tokenizer.getThis(Token.T_OPENBRACKET);
2600
2601        for (int i = 0; i < len; i++) {
2602            Expression columnValExpression = parseExpression();
2603
2604            columnValExpression.resolveTables(null);
2605            columnValExpression.resolveTypes(session);
2606
2607            acve[i] = columnValExpression;
2608
2609            String JavaDoc token = tokenizer.getSimpleToken();
2610
2611            if (token.equals(Token.T_COMMA)) {
2612                continue;
2613            }
2614
2615            if (token.equals(Token.T_CLOSEBRACKET)) {
2616                if (i == len - 1) {
2617                    return;
2618                } else {
2619                    break;
2620                }
2621            }
2622
2623            tokenizer.throwUnexpected();
2624        }
2625
2626        throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
2627    }
2628
2629    /**
2630     * Retrieves an INSERT_XXX-type CompiledStatement from this parse context.
2631     */

2632    CompiledStatement compileInsertStatement() throws HsqlException {
2633
2634        clearParameters();
2635        tokenizer.getThis(Token.T_INTO);
2636
2637        HsqlArrayList columnNames;
2638        boolean[] columnCheckList;
2639        int[] columnMap;
2640        int len;
2641        String JavaDoc token = tokenizer.getName();
2642        String JavaDoc schema = session.getSchemaName(tokenizer.getLongNameFirst());
2643        Table table = database.schemaManager.getTable(session, token, schema);
2644
2645        checkTableWriteAccess(table, UserManager.INSERT);
2646
2647        columnNames = null;
2648        columnCheckList = null;
2649        columnMap = table.getColumnMap();
2650        len = table.getColumnCount();
2651
2652        int brackets = parseOpenBrackets();
2653
2654        token = tokenizer.getString();
2655
2656        if (brackets == 1 &&!tokenizer.wasThis(Token.T_SELECT)) {
2657            brackets = 0;
2658
2659            tokenizer.back();
2660
2661            columnNames = getColumnNames(database, table, tokenizer, false);
2662
2663            if (columnNames.size() > len) {
2664                throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
2665            }
2666
2667            len = columnNames.size();
2668            columnCheckList = table.getNewColumnCheckList();
2669            columnMap = new int[len];
2670
2671            for (int i = 0; i < len; i++) {
2672                int ci = table.getColumnNr((String JavaDoc) columnNames.get(i));
2673
2674                columnMap[i] = ci;
2675                columnCheckList[ci] = true;
2676            }
2677
2678            token = tokenizer.getSimpleToken();
2679        } else if (!tokenizer.wasSimpleToken()) {
2680            tokenizer.throwUnexpected();
2681        }
2682
2683        int command = Token.get(token);
2684
2685        switch (command) {
2686
2687            case Token.VALUES : {
2688                Expression[] acve = new Expression[len];
2689
2690                getInsertColumnValueExpressions(table, acve, len);
2691
2692                CompiledStatement cs =
2693                    new CompiledStatement(session.currentSchema, table,
2694                                          columnMap, acve, columnCheckList,
2695                                          getSortedSubqueries(),
2696                                          getParameters());
2697
2698                return cs;
2699            }
2700            case Token.OPENBRACKET : {
2701                brackets = parseOpenBrackets() + 1;
2702
2703                tokenizer.getThis(Token.T_SELECT);
2704            }
2705            case Token.SELECT : {
2706
2707                // accept ORDER BY or ORDRY BY with LIMIT
2708
Select select = parseSelect(brackets, true, false, true,
2709                                            true);
2710
2711                if (len != select.iResultLen) {
2712                    throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
2713                }
2714
2715                CompiledStatement cs = new CompiledStatement(session,
2716                    database, session.currentSchema, table, columnMap,
2717                    columnCheckList, select, getSortedSubqueries(),
2718                    getParameters());
2719
2720                return cs;
2721            }
2722            default : {
2723                throw Trace.error(Trace.UNEXPECTED_TOKEN, token);
2724            }
2725        }
2726    }
2727
2728    /**
2729     * Retrieves a SELECT-type CompiledStatement from this parse context.
2730     */

2731    CompiledStatement compileSelectStatement(int brackets)
2732    throws HsqlException {
2733
2734        clearParameters();
2735
2736        Select select = parseSelect(brackets, true, true, false, true);
2737
2738        if (select.sIntoTable != null) {
2739            String JavaDoc name = select.sIntoTable.name;
2740            String JavaDoc schema = select.sIntoTable.schema.name;
2741
2742            if (database.schemaManager.findUserTable(session, name, schema)
2743                    != null) {
2744                throw Trace.error(Trace.TABLE_ALREADY_EXISTS, name);
2745            }
2746        }
2747
2748        CompiledStatement cs = new CompiledStatement(session, database,
2749            session.currentSchema, select, getSortedSubqueries(),
2750            getParameters());
2751
2752        return cs;
2753    }
2754
2755    /**
2756     * Retrieves an UPDATE-type CompiledStatement from this parse context.
2757     */

2758    CompiledStatement compileUpdateStatement() throws HsqlException {
2759
2760        String JavaDoc token;
2761        Table table;
2762        int[] colList;
2763        Expression[] exprList;
2764        int len;
2765        Expression cve;
2766        Expression condition;
2767
2768        clearParameters();
2769
2770        TableFilter tableFilter = parseSimpleTableFilter(UserManager.UPDATE);
2771
2772        table = tableFilter.filterTable;
2773
2774        tokenizer.getThis(Token.T_SET);
2775
2776        colList = table.getNewColumnMap();
2777        exprList = new Expression[colList.length];
2778        len = 0;
2779        token = null;
2780
2781        do {
2782            int ci = table.getColumnNr(tokenizer.getName());
2783            String JavaDoc tablename = tokenizer.getLongNameFirst();
2784
2785            if (tablename != null
2786                    &&!tableFilter.getName().equals(tablename)) {
2787                throw Trace.error(Trace.TABLE_NOT_FOUND);
2788            }
2789
2790            tokenizer.getThis(Token.T_EQUALS);
2791
2792            cve = parseExpression();
2793
2794            if (len == colList.length) {
2795
2796                // too many (repeat) assignments
2797
throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
2798            }
2799
2800            colList[len] = ci;
2801            exprList[len] = cve;
2802            token = tokenizer.getSimpleToken();
2803
2804            len++;
2805        } while (token.equals(Token.T_COMMA));
2806
2807        condition = null;
2808
2809        if (token.equals(Token.T_WHERE)) {
2810            condition = parseExpression();
2811        } else {
2812            tokenizer.back();
2813        }
2814
2815        colList = (int[]) ArrayUtil.resizeArray(colList, len);
2816        exprList = (Expression[]) ArrayUtil.resizeArray(exprList, len);
2817
2818        CompiledStatement cs = new CompiledStatement(session, database,
2819            session.currentSchema, tableFilter, colList, exprList, condition,
2820            getSortedSubqueries(), getParameters());
2821
2822        return cs;
2823    }
2824
2825    int parseOpenBracketsSelect() throws HsqlException {
2826
2827        int count = parseOpenBrackets();
2828
2829        tokenizer.getThis(Token.T_SELECT);
2830
2831        return count;
2832    }
2833
2834    int parseOpenBrackets() throws HsqlException {
2835
2836        int count = 0;
2837
2838        while (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
2839            count++;
2840        }
2841
2842        return count;
2843    }
2844
2845    int parseCloseBrackets(int limit) throws HsqlException {
2846
2847        int count = 0;
2848
2849        while (count < limit && tokenizer.isGetThis(Token.T_CLOSEBRACKET)) {
2850            count++;
2851        }
2852
2853        return count;
2854    }
2855
2856    HashMappedList parseColumnList() throws HsqlException {
2857        return processColumnList(tokenizer, false);
2858    }
2859
2860    static HashMappedList processColumnList(Tokenizer tokenizer,
2861            boolean acceptAscDesc) throws HsqlException {
2862
2863        HashMappedList list;
2864        String JavaDoc token;
2865
2866        list = new HashMappedList();
2867
2868        tokenizer.getThis(Token.T_OPENBRACKET);
2869
2870        while (true) {
2871            token = tokenizer.getSimpleName();
2872
2873            boolean result = list.add(token, null);
2874
2875            if (!result) {
2876                throw Trace.error(Trace.COLUMN_ALREADY_EXISTS, token);
2877            }
2878
2879            token = tokenizer.getSimpleToken();
2880
2881            if (acceptAscDesc
2882                    && (token.equals(Token.T_DESC)
2883                        || token.equals(Token.T_ASC))) {
2884                token = tokenizer.getSimpleToken(); // OJ: eat it up
2885
}
2886
2887            if (token.equals(Token.T_COMMA)) {
2888                continue;
2889            }
2890
2891            if (token.equals(Token.T_CLOSEBRACKET)) {
2892                break;
2893            }
2894
2895            throw Trace.error(Trace.UNEXPECTED_TOKEN, token);
2896        }
2897
2898        return list;
2899    }
2900}
2901
Popular Tags