KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > db > sql > Parser


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.db.sql;
30
31 import com.caucho.db.Database;
32 import com.caucho.db.table.Column;
33 import com.caucho.db.table.Table;
34 import com.caucho.db.table.TableFactory;
35 import com.caucho.log.Log;
36 import com.caucho.util.CharBuffer;
37 import com.caucho.util.IntMap;
38 import com.caucho.util.L10N;
39
40 import java.sql.SQLException JavaDoc;
41 import java.util.ArrayList JavaDoc;
42 import java.util.HashSet JavaDoc;
43 import java.util.logging.Level JavaDoc;
44 import java.util.logging.Logger JavaDoc;
45
46 public class Parser {
47   private static final Logger JavaDoc log = Log.open(Parser.class);
48   private static final L10N L = new L10N(Parser.class);
49
50   final static int IDENTIFIER = 128;
51   final static int INTEGER = IDENTIFIER + 1;
52   final static int LONG = INTEGER + 1;
53   final static int DOUBLE = LONG + 1;
54   final static int STRING = DOUBLE + 1;
55   final static int TRUE = STRING + 1;
56   final static int FALSE = TRUE + 1;
57   final static int UNKNOWN = FALSE + 1;
58   final static int NULL = UNKNOWN + 1;
59   final static int EXISTS = NULL + 1;
60
61   final static int FROM = EXISTS + 1;
62   final static int IN = FROM + 1;
63   final static int SELECT = IN + 1;
64   final static int DISTINCT = SELECT + 1;
65   final static int WHERE = SELECT + 1;
66   final static int AS = WHERE + 1;
67   final static int ORDER = AS + 1;
68   final static int GROUP = ORDER + 1;
69   final static int BY = GROUP + 1;
70   final static int ASC = BY + 1;
71   final static int DESC = ASC + 1;
72   final static int LIMIT = DESC + 1;
73   final static int OFFSET = LIMIT + 1;
74
75   final static int BETWEEN = OFFSET + 1;
76   final static int LIKE = BETWEEN + 1;
77   final static int ESCAPE = LIKE + 1;
78   final static int IS = ESCAPE + 1;
79   final static int CONCAT = IS + 1;
80
81   final static int EQ = CONCAT + 1;
82   final static int NE = EQ + 1;
83   final static int LT = NE + 1;
84   final static int LE = LT + 1;
85   final static int GT = LE + 1;
86   final static int GE = GT + 1;
87
88   final static int AND = GE + 1;
89   final static int OR = AND + 1;
90   final static int NOT = OR + 1;
91
92   final static int ARG = NOT + 1;
93
94   final static int CREATE = ARG + 1;
95   final static int TABLE = CREATE + 1;
96   final static int INSERT = TABLE + 1;
97   final static int INTO = INSERT + 1;
98   final static int VALUES = INTO + 1;
99   final static int DROP = VALUES + 1;
100   final static int UPDATE = DROP + 1;
101   final static int SET = UPDATE + 1;
102   final static int DELETE = SET + 1;
103
104   final static int CONSTRAINT = DELETE + 1;
105   final static int UNIQUE = CONSTRAINT + 1;
106   final static int PRIMARY = UNIQUE + 1;
107   final static int CHECK = PRIMARY + 1;
108   final static int FOREIGN = CHECK + 1;
109   final static int KEY = FOREIGN + 1;
110
111   private final static IntMap _reserved;
112
113   private Database _database;
114
115   private final String JavaDoc _sql;
116   private final char []_sqlChars;
117   private final int _sqlLength;
118
119   private int _parseIndex;
120
121   private final CharBuffer _cb = new CharBuffer();
122
123   private String JavaDoc _lexeme;
124   private int _token;
125
126   private ArrayList JavaDoc<ParamExpr> _params = new ArrayList JavaDoc<ParamExpr>();
127
128   private Query _query;
129   private AndExpr _andExpr;
130
131   private Parser(Database database, String JavaDoc sql)
132   {
133     _database = database;
134     _sql = sql;
135     _sqlLength = _sql.length();
136     _sqlChars = new char[_sqlLength];
137     _sql.getChars(0, _sqlLength, _sqlChars, 0);
138   }
139
140   public static Query parse(Database database, String JavaDoc sql)
141     throws SQLException JavaDoc
142   {
143     Parser parser = new Parser(database, sql);
144
145     Query query = parser.parse();
146
147     query.bind();
148
149     return query;
150   }
151
152   public static Expr parseExpr(Database database, String JavaDoc sql)
153     throws SQLException JavaDoc
154   {
155     Parser parser = new Parser(database, sql);
156
157     Expr expr = parser.parseExpr();
158
159     return expr.bind(null);
160   }
161
162   /**
163    * Parses the query.
164    */

165   private Query parse()
166     throws SQLException JavaDoc
167   {
168     int token = scanToken();
169
170     switch (token) {
171     case SELECT:
172       return parseSelect();
173
174     case CREATE:
175       return parseCreate();
176
177     case INSERT:
178       return parseInsert();
179
180     case DELETE:
181       return parseDelete();
182
183     case DROP:
184       return parseDrop();
185
186     case UPDATE:
187       return parseUpdate();
188
189     default:
190       throw new SQLParseException(L.l("unknown query at `{0}'",
191                       tokenName(token)));
192     }
193   }
194
195   /**
196    * Parses the select.
197    */

198   private SelectQuery parseSelect()
199     throws SQLException JavaDoc
200   {
201     return parseSelect(new SelectQuery(_database, _sql));
202   }
203
204   /**
205    * Parses the select.
206    */

207   private SelectQuery parseSelect(SelectQuery query)
208     throws SQLException JavaDoc
209   {
210     boolean distinct = false;
211
212     int token = scanToken();
213
214     if (token == DISTINCT)
215       distinct = true;
216     else
217       _token = token;
218
219     ArrayList JavaDoc<Expr> resultItems = new ArrayList JavaDoc<Expr>();
220
221     int startToken = scanToken();
222     String JavaDoc startLexeme = _lexeme;
223     int startOffset = _parseIndex;
224
225     while ((token = scanToken()) >= 0 && token != FROM) {
226     }
227
228     if (token != FROM)
229       throw error(L.l("expected FROM at `{0}'", tokenName(token)));
230
231     query.setParent(_query);
232     _query = query;
233
234     AndExpr oldAnd = _andExpr;
235     _andExpr = new AndExpr();
236
237     ArrayList JavaDoc<FromItem> fromItems = parseFromItems();
238
239     query.setFromItems(fromItems);
240
241     token = scanToken();
242
243     int tailToken = token;
244     int tailOffset = _parseIndex;
245
246     _token = startToken;
247     _parseIndex = startOffset;
248     _lexeme = startLexeme;
249
250     Expr expr = parseSelectExpr();
251
252     resultItems.add(expr);
253
254     while ((token = scanToken()) == ',') {
255       expr = parseSelectExpr();
256
257       resultItems.add(expr);
258     }
259
260     _token = tailToken;
261     _parseIndex = tailOffset;
262
263     token = scanToken();
264
265     if (token == WHERE)
266       _andExpr.add(parseExpr());
267     else
268       _token = token;
269
270     ParamExpr []params = _params.toArray(new ParamExpr[_params.size()]);
271
272     Expr whereExpr = _andExpr.getSingleExpr();
273     _andExpr = null;
274     query.setWhereExpr(whereExpr);
275     query.setParams(params);
276
277     for (int i = resultItems.size() - 1; i >= 0; i--) {
278       Expr subExpr = resultItems.get(i);
279
280       if (subExpr instanceof UnboundStarExpr) {
281     UnboundStarExpr unboundExpr = (UnboundStarExpr) subExpr;
282     ArrayList JavaDoc<Expr> exprList = unboundExpr.expand(query.getFromItems());
283
284     resultItems.remove(i);
285     resultItems.addAll(i, exprList);
286       }
287     }
288
289     ArrayList JavaDoc<Expr> groupItems = null;
290     token = scanToken();
291     if (token == GROUP) {
292       token = scanToken();
293
294       if (token != BY)
295     throw error(L.l("expected BY at `{0}'", tokenName(token)));
296
297       groupItems = parseGroup(query);
298     }
299     else
300       _token = token;
301
302     token = scanToken();
303     if (token == ORDER) {
304       token = scanToken();
305
306       if (token != BY)
307     throw error(L.l("expected BY at `{0}'", tokenName(token)));
308
309       Order order = parseOrder(query, resultItems);
310     }
311     else
312       _token = token;
313
314     Expr []resultArray = resultItems.toArray(new Expr[resultItems.size()]);
315
316     query.setResults(resultArray);
317
318     if (query.isGroup()) {
319       Expr []resultList = query.getResults();
320
321       bindGroup(query, groupItems);
322
323       for (int i = 0; i < resultList.length; i++) {
324     Expr subExpr = resultList[i];
325
326     if (! (subExpr instanceof GroupExpr)) {
327       resultList[i] = new GroupResultExpr(i, subExpr);
328     }
329       }
330     }
331
332     token = scanToken();
333     _token = token;
334     if (query.getParent() == null &&
335     token >= 0 && token != LIMIT && token != OFFSET)
336       throw error(L.l("unexpected token at end '{0}'", tokenName(token)));
337
338     _query = query.getParent();
339     _andExpr = oldAnd;
340
341     return query;
342   }
343
344   private ArrayList JavaDoc<FromItem> parseFromItems()
345     throws SQLException JavaDoc
346   {
347     ArrayList JavaDoc<FromItem> fromItems = new ArrayList JavaDoc<FromItem>();
348
349     int token;
350
351     // XXX: somewhat hacked syntax
352
while ((token = scanToken()) == '(') {
353     }
354     _token = token;
355     
356     FromItem fromItem = parseFromItem();
357
358     if (fromItem != null)
359       fromItems.add(fromItem);
360
361     while (true) {
362       token = scanToken();
363
364       boolean isNatural = false;
365       boolean isOuter = false;
366       boolean isLeft = true;
367       boolean isRight = true;
368
369       if (token == ',') {
370     fromItem = parseFromItem();
371     fromItems.add(fromItem);
372     continue;
373       }
374       else if (token == '(' || token == ')')
375     continue;
376       else if (token != IDENTIFIER) {
377     _token = token;
378     break;
379       }
380       else if ("join".equalsIgnoreCase(_lexeme)) {
381       }
382       else if ("inner".equalsIgnoreCase(_lexeme)) {
383     String JavaDoc join = parseIdentifier();
384
385     if (! "join".equalsIgnoreCase(join))
386       throw error(L.l("expected JOIN at '{0}'", join));
387       }
388       else if ("left".equalsIgnoreCase(_lexeme)) {
389     String JavaDoc name = parseIdentifier();
390
391     if ("outer".equalsIgnoreCase(name))
392       name = parseIdentifier();
393
394     if (! "join".equalsIgnoreCase(name))
395       throw error(L.l("expected JOIN at '{0}'", name));
396
397     isOuter = true;
398       }
399       else if ("right".equalsIgnoreCase(_lexeme)) {
400     String JavaDoc name = parseIdentifier();
401
402     if ("outer".equalsIgnoreCase(name))
403       name = parseIdentifier();
404
405     if (! "join".equalsIgnoreCase(name))
406       throw error(L.l("expected JOIN at '{0}'", name));
407
408     isRight = true;
409     isOuter = true;
410
411     throw error(L.l("right outer joins are not supported"));
412       }
413       else if ("natural".equalsIgnoreCase(_lexeme)) {
414     String JavaDoc name = parseIdentifier();
415
416     isNatural = true;
417
418     if ("left".equalsIgnoreCase(name)) {
419       name = parseIdentifier();
420
421       if ("outer".equalsIgnoreCase(name))
422         name = parseIdentifier();
423
424       isOuter = true;
425     }
426     else if ("right".equalsIgnoreCase(name)) {
427       name = parseIdentifier();
428
429       if ("outer".equalsIgnoreCase(name))
430         name = parseIdentifier();
431
432       isRight = true;
433       isOuter = true;
434
435       throw error(L.l("right outer joins are not supported"));
436     }
437
438     if (! "join".equalsIgnoreCase(name))
439       throw error(L.l("expected JOIN at '{0}'", name));
440       }
441       else {
442     _token = token;
443     break;
444       }
445
446       fromItem = parseFromItem();
447       fromItems.add(fromItem);
448
449       _query.setFromItems(fromItems);
450
451       token = scanToken();
452       if (token == IDENTIFIER && "on".equalsIgnoreCase(_lexeme)) {
453     Expr onExpr = parseExpr();
454
455     if (isOuter) {
456       FromItem leftItem = fromItems.get(fromItems.size() - 2);
457       FromItem rightItem = fromItems.get(fromItems.size() - 1);
458
459       onExpr = new LeftOuterJoinExpr(rightItem, onExpr);
460
461       rightItem.setDependTable(leftItem);
462     }
463
464     _andExpr.add(onExpr);
465       }
466       else
467     _token = token;
468     }
469
470     return fromItems;
471   }
472
473   /**
474    * Parses a select expression.
475    */

476   private Expr parseSelectExpr()
477     throws SQLException JavaDoc
478   {
479     int token = scanToken();
480
481     if (token == '*')
482       return new UnboundStarExpr();
483     else {
484       _token = token;
485
486       return parseExpr();
487     }
488   }
489
490   /**
491    * Parses a from item
492    */

493   private FromItem parseFromItem()
494     throws SQLException JavaDoc
495   {
496     String JavaDoc tableName = parseIdentifier();
497
498     if (tableName.equalsIgnoreCase("DUAL"))
499       return null;
500
501     Table table = _database.getTable(tableName);
502
503     if (table == null)
504       throw error(L.l("'{0}' is an unknown table. 'FROM table' requires an existing table.", tableName));
505
506     String JavaDoc name = table.getName();
507
508     int token = scanToken();
509     if (token == AS)
510       name = parseIdentifier();
511     else if (token == IDENTIFIER)
512       name = _lexeme;
513     else
514       _token = token;
515
516     return new FromItem(table, name);
517   }
518
519   /**
520    * Parses the ORDER BY
521    */

522   private Order parseOrder(SelectQuery query,
523                ArrayList JavaDoc<Expr> resultList)
524     throws SQLException JavaDoc
525   {
526     int token;
527
528     Order order = null;
529
530     do {
531       Expr expr = parseExpr();
532
533       expr = expr.bind(query);
534
535       token = scanToken();
536       boolean isAsc = true;
537       if (token == ASC)
538     isAsc = true;
539       else if (token == DESC)
540     isAsc = false;
541       else
542     _token = token;
543
544       int index;
545       for (index = 0; index < resultList.size(); index++) {
546     Expr resultExpr = resultList.get(index);
547
548     if (expr.equals(resultExpr))
549       break;
550       }
551
552       if (resultList.size() <= index) {
553     resultList.add(expr);
554       }
555
556       Order tailOrder = expr.createOrder(index);
557       tailOrder.setAscending(isAsc);
558
559       order = Order.append(order, tailOrder);
560
561       // ascList.add(isAsc ? Boolean.TRUE : Boolean.FALSE);
562
} while ((token = scanToken()) == ',');
563
564     query.setOrder(order);
565
566     _token = token;
567
568     return order;
569   }
570
571   /**
572    * Parses the GROUP BY
573    */

574   private ArrayList JavaDoc<Expr> parseGroup(SelectQuery query)
575     throws SQLException JavaDoc
576   {
577     query.setGroup(true);
578     int token;
579
580     ArrayList JavaDoc<Expr> groupList = new ArrayList JavaDoc<Expr>();
581
582     do {
583       groupList.add(parseExpr());
584     } while ((token = scanToken()) == ',');
585
586     _token = token;
587
588     return groupList;
589   }
590
591   /**
592    * Parses the GROUP BY
593    */

594   private void bindGroup(SelectQuery query, ArrayList JavaDoc<Expr> groupList)
595     throws SQLException JavaDoc
596   {
597     query.setGroup(true);
598
599     Expr []resultList = query.getResults();
600
601     for (int i = 0; i < groupList.size(); i++) {
602       Expr expr = groupList.get(i);
603
604       expr = expr.bind(query);
605
606       int index;
607       for (index = 0; index < resultList.length; index++) {
608     Expr resultExpr = resultList[index];
609
610     if (expr.equals(resultExpr)) {
611       resultList[index] = new GroupResultExpr(index, resultExpr);
612
613       break;
614     }
615       }
616
617       if (resultList.length <= index) {
618     throw error(L.l("GROUP BY field '{0}' must refer to a result field.",
619             expr));
620       }
621
622       query.setGroupResult(index);
623     }
624   }
625
626   /**
627    * Parses the create.
628    */

629   private Query parseCreate()
630     throws SQLException JavaDoc
631   {
632     int token;
633
634     TableFactory factory = _database.createTableFactory();
635
636     if ((token = scanToken()) != TABLE)
637       throw error(L.l("expected TABLE at `{0}'", tokenName(token)));
638
639     if ((token = scanToken()) != IDENTIFIER)
640       throw error(L.l("expected identifier at `{0}'", tokenName(token)));
641
642     factory.startTable(_lexeme);
643
644     if ((token = scanToken()) != '(')
645       throw error(L.l("expected '(' at `{0}'", tokenName(token)));
646
647     do {
648       token = scanToken();
649
650       switch (token) {
651       case IDENTIFIER:
652     parseCreateColumn(factory, _lexeme);
653     break;
654
655       case UNIQUE:
656     factory.addUnique(parseColumnNames());
657     break;
658
659       case PRIMARY:
660     token = scanToken();
661     if (token != KEY)
662       throw error(L.l("expected 'key' at {0}", tokenName(token)));
663
664     factory.addPrimaryKey(parseColumnNames());
665     break;
666
667       case KEY:
668     String JavaDoc key = parseIdentifier();
669
670     parseColumnNames(); // factory.addPrimaryKey(parseColumnNames());
671
break;
672
673       case CHECK:
674     if ((token = scanToken()) != '(')
675       throw error(L.l("Expected '(' at '{0}'", tokenName(token)));
676
677     parseExpr();
678
679     if ((token = scanToken()) != ')')
680       throw error(L.l("Expected ')' at '{0}'", tokenName(token)));
681     break;
682
683       default:
684     throw error(L.l("unexpected token `{0}'", tokenName(token)));
685       }
686
687       token = scanToken();
688     } while (token == ',');
689
690     if (token != ')')
691       throw error(L.l("expected ')' at `{0}'", tokenName(token)));
692
693     return new CreateQuery(_database, _sql, factory);
694   }
695
696   /**
697    * Parses a column declaration.
698    */

699   private void parseCreateColumn(TableFactory factory, String JavaDoc name)
700     throws SQLException JavaDoc
701   {
702     int token;
703
704     if ((token = scanToken()) != IDENTIFIER)
705       throw error(L.l("expected column type at {0}", tokenName(token)));
706
707     String JavaDoc type = _lexeme;
708     int length = -1;
709     int scale = -1;
710
711     if (type.equalsIgnoreCase("double")) {
712       if ((token = scanToken()) == IDENTIFIER) {
713     if (_lexeme.equalsIgnoreCase("precision")) {
714     }
715     else
716       throw error(L.l("unexpected double type at {0}", _lexeme));
717       }
718       else
719     _token = token;
720     }
721
722     if ((token = scanToken()) == '(') {
723       if ((token = scanToken()) != INTEGER)
724     throw error(L.l("expected column width at `{0}'", tokenName(token)));
725
726       length = Integer.parseInt(_lexeme);
727
728       if ((token = scanToken()) == ',') {
729     if ((token = scanToken()) != INTEGER)
730       throw error(L.l("expected column scale at `{0}'", tokenName(token)));
731
732     scale = Integer.parseInt(_lexeme);
733
734     token = scanToken();
735       }
736
737       if (token != ')')
738     throw error(L.l("expected ')' at '{0}'", tokenName(token)));
739     }
740     else
741       _token = token;
742
743     if (type.equalsIgnoreCase("varchar")) {
744       if (length < 0)
745     throw error(L.l("VARCHAR needs a defined length"));
746
747       factory.addVarchar(name, length);
748     }
749     else if (type.equalsIgnoreCase("char")) {
750       if (length < 0)
751     length = 1;
752
753       factory.addVarchar(name, length);
754     }
755     else if (type.equalsIgnoreCase("blob")) {
756       factory.addBlob(name);
757     }
758     else if (type.equalsIgnoreCase("integer") ||
759          type.equalsIgnoreCase("int") ||
760          type.equalsIgnoreCase("smallint") ||
761          type.equalsIgnoreCase("tinyint") ||
762          type.equalsIgnoreCase("mediumint") ||
763          type.equalsIgnoreCase("bit")) {
764       factory.addInteger(name);
765     }
766     else if (type.equalsIgnoreCase("bigint")) {
767       factory.addLong(name);
768     }
769     else if (type.equalsIgnoreCase("double") ||
770          type.equalsIgnoreCase("float") ||
771          type.equalsIgnoreCase("real")) {
772       factory.addDouble(name);
773     }
774     else if (type.equalsIgnoreCase("datetime") ||
775          type.equalsIgnoreCase("timestamp")) {
776       factory.addDateTime(name);
777     }
778     else if (type.equalsIgnoreCase("text") ||
779          type.equalsIgnoreCase("clob")) {
780       factory.addVarchar(name, 255);
781     }
782     else if (type.equalsIgnoreCase("decimal") ||
783          type.equalsIgnoreCase("numeric")) {
784       factory.addNumeric(name, length, scale);
785     }
786     else
787       throw error(L.l("Unknown type {0}", type));
788
789     token = scanToken();
790     if (token == IDENTIFIER && _lexeme.equalsIgnoreCase("default")) {
791       Expr defaultExpr = parseExpr();
792
793       factory.setDefault(name, defaultExpr);
794     }
795     else
796       _token = token;
797
798     while (true) {
799       token = scanToken();
800
801       // XXX: stuff like NOT NULL
802

803       switch (token) {
804       case ')':
805       case ',':
806     _token = token;
807     return;
808
809       case UNIQUE:
810     factory.setUnique(name);
811     break;
812
813       case PRIMARY:
814     token = scanToken();
815     if (token != KEY)
816       throw error(L.l("expected key at {0}", tokenName(token)));
817
818     factory.setPrimaryKey(name);
819     break;
820
821       case CHECK:
822     if ((token = scanToken()) != '(')
823       throw error(L.l("Expected '(' at '{0}'", tokenName(token)));
824
825     parseExpr();
826
827     if ((token = scanToken()) != ')')
828       throw error(L.l("Expected ')' at '{0}'", tokenName(token)));
829     break;
830
831       case IDENTIFIER:
832     String JavaDoc id = _lexeme;
833     if (id.equalsIgnoreCase("references")) {
834       ArrayList JavaDoc<String JavaDoc> foreignKey = new ArrayList JavaDoc<String JavaDoc>();
835       foreignKey.add(name);
836       parseReferences(foreignKey);
837     }
838     else if (id.equalsIgnoreCase("default")) {
839       Expr expr = parseExpr();
840     }
841     else if (id.equalsIgnoreCase("auto_increment")) {
842       factory.setAutoIncrement(name, 1);
843     }
844     else if (id.equalsIgnoreCase("unsigned")) {
845     }
846     else if (id.equalsIgnoreCase("binary")) {
847     }
848     else
849       throw error(L.l("unexpected token '{0}'", tokenName(token)));
850     break;
851
852       case NULL:
853     break;
854
855       case NOT:
856     if ((token = scanToken()) == NULL)
857       factory.setNotNull(name);
858     else
859       throw error(L.l("unexpected token '{0}'", tokenName(token)));
860     break;
861
862       default:
863     throw error(L.l("unexpected token '{0}'", tokenName(token)));
864       }
865     }
866   }
867   
868   /**
869    * Parses a key constraint declaration.
870    */

871   private void parseKeyConstraint(TableFactory factory)
872     throws SQLException JavaDoc
873   {
874     String JavaDoc key = parseIdentifier();
875
876     int token = scanToken();
877
878     if (token == '(') {
879       parseIdentifier();
880
881       token = scanToken();
882       if (token != ')')
883     throw error("expected ')'");
884     }
885     else
886       _token = token;
887   }
888
889   /**
890    * Parses the references clause.
891    */

892   public void parseReferences(ArrayList JavaDoc<String JavaDoc> name)
893     throws SQLException JavaDoc
894   {
895     String JavaDoc foreignTable = parseIdentifier();
896
897     int token = scanToken();
898
899     ArrayList JavaDoc<String JavaDoc> foreignColumns = new ArrayList JavaDoc<String JavaDoc>();
900
901     if (token == '(') {
902       _token = token;
903
904       foreignColumns = parseColumnNames();
905     }
906     else
907       _token = token;
908   }
909
910   /**
911    * Parses a list of column names
912    */

913   public ArrayList JavaDoc<String JavaDoc> parseColumnNames()
914     throws SQLException JavaDoc
915   {
916     ArrayList JavaDoc<String JavaDoc> columns = new ArrayList JavaDoc<String JavaDoc>();
917
918     int token = scanToken();
919     if (token == '(') {
920       do {
921     columns.add(parseIdentifier());
922
923     token = scanToken();
924       } while (token == ',');
925
926       if (token != ')')
927     throw error(L.l("expected ')' at '{0}'", tokenName(token)));
928     }
929     else if (token == IDENTIFIER) {
930       columns.add(_lexeme);
931
932       _token = token;
933     }
934     else
935       throw error(L.l("expected '(' at '{0}'", tokenName(token)));
936
937     return columns;
938   }
939
940   /**
941    * Parses the insert.
942    */

943   private Query parseInsert()
944     throws SQLException JavaDoc
945   {
946     int token;
947
948     if ((token = scanToken()) != INTO)
949       throw error(L.l("expected INTO at `{0}'", tokenName(token)));
950
951     if ((token = scanToken()) != IDENTIFIER)
952       throw error(L.l("expected identifier at `{0}'", tokenName(token)));
953
954     Table table = _database.getTable(_lexeme);
955
956     if (table == null)
957       throw error(L.l("unknown table `{0}'", tokenName(token)));
958
959     FromItem fromItem = new FromItem(table, table.getName());
960     FromItem[] fromList = new FromItem[] { fromItem };
961
962     ArrayList JavaDoc<Column> columns = new ArrayList JavaDoc<Column>();
963
964     if ((token = scanToken()) == '(') {
965       do {
966     String JavaDoc columnName = parseIdentifier();
967
968     Column column = table.getColumn(columnName);
969
970     if (column == null)
971       throw new SQLException JavaDoc(L.l("`{0}' is not a valid column in {1}",
972                      columnName, table.getName()));
973     columns.add(column);
974       } while ((token = scanToken()) == ',');
975
976       if (token != ')')
977     throw error(L.l("expected ')' at `{0}'", tokenName(token)));
978
979       token = scanToken();
980     }
981     else {
982       Column []columnArray = table.getColumns();
983
984       for (int i = 0; i < columnArray.length; i++)
985     columns.add(columnArray[i]);
986     }
987
988     if (token != VALUES)
989       throw error(L.l("expected VALUES at `{0}'", tokenName(token)));
990
991     if ((token = scanToken()) != '(')
992       throw error(L.l("expected '(' at `{0}'", tokenName(token)));
993
994     ArrayList JavaDoc<Expr> values = new ArrayList JavaDoc<Expr>();
995
996     InsertQuery query = new InsertQuery(_database, _sql, table, columns);
997     _query = query;
998
999     int i = 0;
1000    do {
1001      Expr expr = parseExpr();
1002
1003      expr = expr.bind(new TempQuery(fromList));
1004
1005      values.add(expr);
1006
1007      i++;
1008    } while ((token = scanToken()) == ',');
1009
1010    if (token != ')')
1011      throw error(L.l("expected ')' at {0}", tokenName(token)));
1012
1013    if (columns.size() != values.size())
1014      throw error(L.l("number of columns does not match number of values"));
1015
1016    ParamExpr []params = _params.toArray(new ParamExpr[_params.size()]);
1017
1018    query.setParams(params);
1019    query.setValues(values);
1020    query.init();
1021
1022    return query;
1023  }
1024
1025  /**
1026   * Parses the delete.
1027   */

1028  private Query parseDelete()
1029    throws SQLException JavaDoc
1030  {
1031    int token;
1032
1033    if ((token = scanToken()) != FROM)
1034      throw error(L.l("expected FROM at `{0}'", tokenName(token)));
1035
1036    if ((token = scanToken()) != IDENTIFIER)
1037      throw error(L.l("expected identifier at `{0}'", tokenName(token)));
1038
1039    Table table = _database.getTable(_lexeme);
1040
1041    if (table == null)
1042      throw error(L.l("unknown table `{0}'", tokenName(token)));
1043
1044    DeleteQuery query = new DeleteQuery(_database, _sql, table);
1045    _query = query;
1046
1047    Expr whereExpr = null;
1048
1049    token = scanToken();
1050    if (token == WHERE)
1051      whereExpr = parseExpr();
1052    else if (token >= 0)
1053      throw error(L.l("expected WHERE at `{0}'", tokenName(token)));
1054
1055    ParamExpr []params = _params.toArray(new ParamExpr[_params.size()]);
1056
1057    query.setParams(params);
1058    query.setWhereExpr(whereExpr);
1059
1060    return query;
1061  }
1062
1063  /**
1064   * Parses the insert.
1065   */

1066  private Query parseDrop()
1067    throws SQLException JavaDoc
1068  {
1069    int token;
1070
1071    if ((token = scanToken()) != TABLE)
1072      throw error(L.l("expected TABLE at `{0}'", tokenName(token)));
1073
1074    if ((token = scanToken()) != IDENTIFIER)
1075      throw error(L.l("expected identifier at `{0}'", tokenName(token)));
1076
1077    String JavaDoc table = _lexeme;
1078
1079    if ((token = scanToken()) >= 0)
1080      throw error(L.l("expected end of query at `{0}'", tokenName(token)));
1081
1082    return new DropQuery(_sql, _database, table);
1083  }
1084
1085  /**
1086   * Parses the select.
1087   */

1088  private Query parseUpdate()
1089    throws SQLException JavaDoc
1090  {
1091    int token;
1092
1093    if ((token = scanToken()) != IDENTIFIER)
1094      throw error(L.l("expected identifier at `{0}'", tokenName(token)));
1095
1096    String JavaDoc name = _lexeme;
1097
1098    Table table = _database.getTable(name);
1099
1100    if (table == null)
1101      throw error(L.l("`{0}' is an unknown table in INSERT.", name));
1102
1103    if ((token = scanToken()) != SET)
1104      throw error(L.l("expected SET at {0}", tokenName(token)));
1105
1106    UpdateQuery query = new UpdateQuery(_database, _sql, table);
1107    _query = query;
1108
1109    ArrayList JavaDoc<SetItem> setItemList = new ArrayList JavaDoc<SetItem>();
1110
1111    do {
1112      SetItem item = parseSetItem(table);
1113
1114      setItemList.add(item);
1115    } while ((token = scanToken()) == ',');
1116
1117    Expr whereExpr = null;
1118
1119    if (token == WHERE)
1120      whereExpr = parseExpr();
1121
1122    SetItem []setItems = new SetItem[setItemList.size()];
1123    setItemList.toArray(setItems);
1124
1125    ParamExpr []params = _params.toArray(new ParamExpr[_params.size()]);
1126
1127    query.setSetItems(setItems);
1128    query.setParams(params);
1129    query.setWhereExpr(whereExpr);
1130
1131    return query;
1132  }
1133
1134  /**
1135   * Parses a set item.
1136   */

1137  private SetItem parseSetItem(Table table)
1138    throws SQLException JavaDoc
1139  {
1140    int token;
1141
1142    if ((token = scanToken()) != IDENTIFIER)
1143      throw error(L.l("expected identifier at `{0}'", tokenName(token)));
1144
1145    Column column = table.getColumn(_lexeme);
1146
1147    if (column == null)
1148      throw error(L.l("`{0}' is an unknown column in table {1}.",
1149              _lexeme, table.getName()));
1150
1151    if ((token = scanToken()) != EQ)
1152      throw error(L.l("expected `=' at {0}", tokenName(token)));
1153
1154    Expr expr = parseExpr();
1155
1156    return new SetItem(table, column, expr);
1157  }
1158
1159  /**
1160   * Parses an expression.
1161   */

1162  private Expr parseExpr()
1163    throws SQLException JavaDoc
1164  {
1165    int token = scanToken();
1166
1167    if (token == SELECT)
1168      return parseSubSelect();
1169    else {
1170      _token = token;
1171      return parseOrExpr();
1172    }
1173  }
1174
1175  /**
1176   * Parses a sub-select expression.
1177   */

1178  private Expr parseSubSelect()
1179    throws SQLException JavaDoc
1180  {
1181    return parseSubSelect(new SelectQuery(_database, _sql));
1182  }
1183
1184  /**
1185   * Parses a sub-select expression.
1186   */

1187  private Expr parseSubSelect(SelectQuery query)
1188    throws SQLException JavaDoc
1189  {
1190    parseSelect(query);
1191
1192    SubSelectExpr expr = new SubSelectExpr(query);
1193
1194    query.setSubSelect(expr);
1195
1196    _andExpr.add(new SubSelectEvalExpr(expr));
1197
1198    return expr;
1199  }
1200
1201  /**
1202   * Parses an OR expression.
1203   */

1204  private Expr parseOrExpr()
1205    throws SQLException JavaDoc
1206  {
1207    Expr left = parseAndExpr();
1208
1209    while (true) {
1210      int token = scanToken();
1211
1212      switch (token) {
1213      case OR:
1214    left = new OrExpr(left, parseAndExpr());
1215    break;
1216
1217      default:
1218    _token = token;
1219    return left;
1220      }
1221    }
1222  }
1223
1224  /**
1225   * Parses an AND expression.
1226   */

1227  private Expr parseAndExpr()
1228    throws SQLException JavaDoc
1229  {
1230    AndExpr oldAndExpr = _andExpr;
1231    AndExpr andExpr = new AndExpr();
1232    _andExpr = andExpr;
1233
1234    andExpr.add(parseNotExpr());
1235
1236    while (true) {
1237      int token = scanToken();
1238
1239      switch (token) {
1240      case AND:
1241    andExpr.add(parseNotExpr());
1242    break;
1243
1244      default:
1245    _token = token;
1246
1247    _andExpr = oldAndExpr;
1248
1249    return andExpr.getSingleExpr();
1250      }
1251    }
1252  }
1253
1254  /**
1255   * Parses a term.
1256   */

1257  private Expr parseNotExpr()
1258    throws SQLException JavaDoc
1259  {
1260    int token = scanToken();
1261
1262    switch (token) {
1263    case NOT:
1264      return new NotExpr(parseNotExpr());
1265
1266    default:
1267      _token = token;
1268      return parseCmpExpr();
1269    }
1270  }
1271
1272  /**
1273   * Parses a CMP expression.
1274   */

1275  private Expr parseCmpExpr()
1276    throws SQLException JavaDoc
1277  {
1278    Expr left = parseConcatExpr();
1279
1280    int token = scanToken();
1281    boolean isNot = false;
1282
1283    if (token == NOT) {
1284      isNot = true;
1285
1286      token = scanToken();
1287
1288      if (token != BETWEEN && token != LIKE && token != IN) {
1289    _token = token;
1290    
1291    return left;
1292      }
1293    }
1294
1295    switch (token) {
1296    case EQ:
1297      return new EqExpr(left, parseConcatExpr());
1298
1299    case LT:
1300    case LE:
1301    case GT:
1302    case GE:
1303    case NE:
1304      return new CmpExpr(left, parseConcatExpr(), token);
1305
1306    case BETWEEN:
1307      {
1308    Expr min = parseConcatExpr();
1309
1310    token = scanToken();
1311    if (token != AND)
1312      throw error(L.l("expected AND at '{0}'", tokenName(token)));
1313
1314    Expr max = parseConcatExpr();
1315
1316    return new BetweenExpr(left, min, max, isNot);
1317      }
1318
1319    case IS:
1320      {
1321    token = scanToken();
1322    isNot = false;
1323    if (token == NOT) {
1324      token = scanToken();
1325      isNot = true;
1326    }
1327
1328    if (token == NULL)
1329      return new IsNullExpr(left, isNot);
1330    else
1331      throw error(L.l("expected NULL at '{0}'", tokenName(token)));
1332      }
1333
1334    case LIKE:
1335      {
1336    token = scanToken();
1337
1338    if (token == STRING)
1339      return new LikeExpr(left, _lexeme, isNot);
1340    else
1341      throw error(L.l("expected string at '{0}'", tokenName(token)));
1342      }
1343
1344    case IN:
1345      {
1346    HashSet JavaDoc<String JavaDoc> values = parseInValues();
1347
1348    return new InExpr(left, values, isNot);
1349      }
1350
1351    default:
1352      _token = token;
1353      return left;
1354    }
1355  }
1356
1357  /**
1358   * Parses the IN values.
1359   */

1360  private HashSet JavaDoc<String JavaDoc> parseInValues()
1361    throws SQLException JavaDoc
1362  {
1363    int token = scanToken();
1364
1365    if (token != '(')
1366      throw error(L.l("Expected '('"));
1367
1368    HashSet JavaDoc<String JavaDoc> values = new HashSet JavaDoc<String JavaDoc>();
1369
1370    while ((token = scanToken()) != ')') {
1371      if (token == STRING) {
1372    values.add(_lexeme);
1373      }
1374      else
1375    throw error(L.l("expected STRING at {0}", tokenName(token)));
1376    
1377      if ((token = scanToken()) != ',')
1378    break;
1379    }
1380
1381    if (token != ')')
1382    throw error(L.l("expected ')' at {0}", tokenName(token)));
1383
1384    return values;
1385  }
1386
1387  /**
1388   * Parses a concat expression.
1389   */

1390  private Expr parseConcatExpr()
1391    throws SQLException JavaDoc
1392  {
1393    Expr left = parseAddExpr();
1394
1395    while (true) {
1396      int token = scanToken();
1397
1398      switch (token) {
1399      case CONCAT:
1400    left = new ConcatExpr(left, parseAddExpr());
1401    break;
1402
1403      default:
1404    _token = token;
1405    return left;
1406      }
1407    }
1408  }
1409
1410  /**
1411   * Parses a +/- expression.
1412   */

1413  private Expr parseAddExpr()
1414    throws SQLException JavaDoc
1415  {
1416    Expr left = parseMulExpr();
1417
1418    while (true) {
1419      int token = scanToken();
1420
1421      switch (token) {
1422      case '+':
1423      case '-':
1424    left = new BinaryExpr(left, parseMulExpr(), token);
1425    break;
1426
1427      default:
1428    _token = token;
1429    return left;
1430      }
1431    }
1432  }
1433
1434  /**
1435   * Parses a mul/div expression
1436   */

1437  private Expr parseMulExpr()
1438    throws SQLException JavaDoc
1439  {
1440    Expr left = parseTerm();
1441
1442    while (true) {
1443      int token = scanToken();
1444
1445      switch (token) {
1446      case '*':
1447      case '/':
1448      case '%':
1449    left = new BinaryExpr(left, parseTerm(), token);
1450    break;
1451
1452      default:
1453    _token = token;
1454    return left;
1455      }
1456    }
1457  }
1458
1459  /**
1460   * Parses a term.
1461   */

1462  private Expr parseTerm()
1463    throws SQLException JavaDoc
1464  {
1465    int token = scanToken();
1466
1467    switch (token) {
1468    case '+':
1469      return parseTerm();
1470
1471    case '-':
1472      return new UnaryExpr(parseTerm(), token);
1473
1474    case '(':
1475      Expr expr = parseExpr();
1476      int peekToken;
1477      if ((peekToken = scanToken()) != ')')
1478    throw error(L.l("expected ')' at {0}", tokenName(peekToken)));
1479      return expr;
1480
1481    default:
1482      _token = token;
1483      return parseSimpleTerm();
1484    }
1485  }
1486
1487  /**
1488   * Parses a simple term.
1489   */

1490  private Expr parseSimpleTerm()
1491    throws SQLException JavaDoc
1492  {
1493    int token = scanToken();
1494
1495    switch (token) {
1496    case IDENTIFIER:
1497      {
1498    String JavaDoc name = _lexeme;
1499
1500    token = scanToken();
1501    if (token == '.') {
1502      token = scanToken();
1503
1504      if (token == IDENTIFIER) {
1505        String JavaDoc column = _lexeme;
1506        return _query.bind(name, column);
1507      }
1508      else if (token == '*') {
1509        return new UnboundStarExpr(name);
1510      }
1511      else
1512        throw error("expected IDENTIFIER");
1513    }
1514    else if (token == '(') {
1515      FunExpr fun = null;
1516      if (name.equalsIgnoreCase("max"))
1517        fun = new MaxExpr();
1518      else if (name.equalsIgnoreCase("min"))
1519        fun = new MinExpr();
1520      else if (name.equalsIgnoreCase("sum"))
1521        fun = new SumExpr();
1522      else if (name.equalsIgnoreCase("avg"))
1523        fun = new AvgExpr();
1524      else if (name.equalsIgnoreCase("count")) {
1525        fun = new CountExpr();
1526
1527        token = scanToken();
1528        if (token == '*') {
1529          fun.addArg(new UnboundStarExpr());
1530        }
1531        else
1532          _token = token;
1533      }
1534      else if (name.equalsIgnoreCase("exists")) {
1535        token = scanToken();
1536
1537        if (token != SELECT)
1538          throw error(L.l("exists requires SELECT at '{0}'",
1539                  tokenName(token)));
1540
1541        ExistsQuery query = new ExistsQuery(_database, _sql);
1542
1543        parseSelect(query);
1544
1545        ExistsExpr expr = new ExistsExpr(query);
1546
1547        query.setSubSelect(expr);
1548
1549        _andExpr.add(new ExistsEvalExpr(expr));
1550
1551        token = scanToken();
1552
1553        if (token != ')')
1554          throw error(L.l("exists requires ')' at '{0}'",
1555                  tokenName(token)));
1556
1557        return expr;
1558      }
1559      else {
1560        String JavaDoc funName = (Character.toUpperCase(name.charAt(0)) +
1561                  name.substring(1).toLowerCase());
1562
1563        funName = "com.caucho.db.fun." + funName + "Expr";
1564
1565        try {
1566          Class JavaDoc cl = Class.forName(funName);
1567
1568          fun = (FunExpr) cl.newInstance();
1569        } catch (ClassNotFoundException JavaDoc e) {
1570          log.finer(e.toString());
1571        } catch (Throwable JavaDoc e) {
1572          log.log(Level.FINER, e.toString(), e);
1573        }
1574
1575        if (fun == null)
1576          throw error(L.l("`{0}' is an unknown function.", name));
1577      }
1578
1579      token = scanToken();
1580      while (token > 0 && token != ')') {
1581        _token = token;
1582
1583        Expr arg = parseExpr();
1584
1585        fun.addArg(arg);
1586
1587        token = scanToken();
1588
1589        if (token == ',')
1590          token = scanToken();
1591      }
1592
1593      return fun;
1594    }
1595    else {
1596      _token = token;
1597      return _query.bind(null, name);
1598    }
1599      }
1600
1601    case STRING:
1602      return new StringExpr(_lexeme);
1603
1604    case DOUBLE:
1605    case INTEGER:
1606    case LONG:
1607      return NumberExpr.create(_lexeme);
1608
1609    case NULL:
1610      return new NullExpr();
1611
1612    case TRUE:
1613      return BooleanLiteralExpr.create(true);
1614
1615    case FALSE:
1616      return BooleanLiteralExpr.create(false);
1617
1618    case '?':
1619      ParamExpr param = new ParamExpr(_params.size());
1620      _params.add(param);
1621      return param;
1622
1623    default:
1624      throw error(L.l("unexpected term {0}", tokenName(token)));
1625    }
1626  }
1627
1628  /**
1629   * Parses an identifier.
1630   */

1631  private String JavaDoc parseIdentifier()
1632    throws SQLException JavaDoc
1633  {
1634    int token = scanToken();
1635
1636    if (token != IDENTIFIER)
1637      throw error(L.l("expected identifier at {0}", tokenName(token)));
1638
1639    return _lexeme;
1640  }
1641
1642  /**
1643   * Scan the next token. If the lexeme is a string, its string
1644   * representation is in "lexeme".
1645   *
1646   * @return integer code for the token
1647   */

1648  private int scanToken()
1649    throws SQLException JavaDoc
1650  {
1651    if (_token > 0) {
1652      int value = _token;
1653      _token = -1;
1654      return value;
1655    }
1656
1657    int sign = 1;
1658    int ch;
1659
1660    for (ch = read(); Character.isWhitespace((char) ch); ch = read()) {
1661    }
1662
1663    switch (ch) {
1664    case -1:
1665    case '(':
1666    case ')':
1667    case '.':
1668    case '*':
1669    case '/':
1670    case '%':
1671    case ',':
1672    case '?':
1673      return ch;
1674
1675    case '+':
1676      if ((ch = read()) >= '0' && ch <= '9')
1677        break;
1678      else {
1679        unread(ch);
1680        return '+';
1681      }
1682
1683    case '-':
1684      if ((ch = read()) >= '0' && ch <= '9') {
1685        sign = -1;
1686        break;
1687      }
1688      else {
1689        unread(ch);
1690        return '-';
1691      }
1692
1693    case '=':
1694      return EQ;
1695
1696    case '<':
1697      if ((ch = read()) == '=')
1698        return LE;
1699      else if (ch == '>')
1700        return NE;
1701      else {
1702        unread(ch);
1703        return LT;
1704      }
1705
1706    case '>':
1707      if ((ch = read()) == '=')
1708        return GE;
1709      else {
1710        unread(ch);
1711        return GT;
1712      }
1713
1714    case '|':
1715      if ((ch = read()) == '|')
1716        return CONCAT;
1717      else {
1718        throw error(L.l("'|' expected at {0}", charName(ch)));
1719      }
1720
1721      // @@ is useless?
1722
case '@':
1723      if ((ch = read()) != '@')
1724        throw error(L.l("`@' expected at {0}", charName(ch)));
1725      return scanToken();
1726    }
1727
1728    if (Character.isJavaIdentifierStart((char) ch)) {
1729      CharBuffer cb = _cb;
1730      cb.clear();
1731
1732      for (; ch > 0 && Character.isJavaIdentifierPart((char) ch); ch = read())
1733        cb.append((char) ch);
1734
1735      unread(ch);
1736
1737      _lexeme = cb.toString();
1738      String JavaDoc lower = _lexeme.toLowerCase();
1739
1740      int token = _reserved.get(lower);
1741
1742      if (token > 0)
1743        return token;
1744      else
1745        return IDENTIFIER;
1746    }
1747    else if (ch >= '0' && ch <= '9') {
1748      CharBuffer cb = _cb;
1749      cb.clear();
1750
1751      int type = INTEGER;
1752
1753      if (sign < 0)
1754        cb.append('-');
1755
1756      for (; ch >= '0' && ch <= '9'; ch = read())
1757        cb.append((char) ch);
1758
1759      if (ch == '.') {
1760        type = DOUBLE;
1761
1762        cb.append('.');
1763        for (ch = read(); ch >= '0' && ch <= '9'; ch = read())
1764          cb.append((char) ch);
1765      }
1766
1767      if (ch == 'e' || ch == 'E') {
1768        type = DOUBLE;
1769
1770        cb.append('e');
1771        if ((ch = read()) == '+' || ch == '-') {
1772          cb.append((char) ch);
1773          ch = read();
1774        }
1775
1776        if (! (ch >= '0' && ch <= '9'))
1777          throw error(L.l("exponent needs digits at {0}",
1778                          charName(ch)));
1779
1780        for (; ch >= '0' && ch <= '9'; ch = read())
1781          cb.append((char) ch);
1782      }
1783
1784      if (ch == 'F' || ch == 'D')
1785        type = DOUBLE;
1786      else if (ch == 'L') {
1787        type = LONG;
1788      }
1789      else
1790        unread(ch);
1791
1792      _lexeme = cb.toString();
1793
1794      return type;
1795    }
1796    else if (ch == '\'') {
1797      CharBuffer cb = _cb;
1798      cb.clear();
1799
1800      for (ch = read(); ch >= 0; ch = read()) {
1801    if (ch == '\'') {
1802      if ((ch = read()) == '\'')
1803        cb.append('\'');
1804      else {
1805        unread(ch);
1806        break;
1807      }
1808    }
1809    else if (ch == '\\') {
1810      ch = read();
1811
1812      if (ch >= 0)
1813        cb.append(ch);
1814    }
1815    else
1816      cb.append((char) ch);
1817      }
1818
1819      _lexeme = cb.toString();
1820
1821      return STRING;
1822    }
1823    else if (ch == '#') {
1824      // skip comment
1825
while ((ch = read()) >= 0 && ch != '\n' && ch != '\r') {
1826      }
1827
1828      // XXX: cleanup to avoid recursion
1829
return scanToken();
1830    }
1831
1832    throw error(L.l("unexpected char at {0} ({1})", "" + (char) ch,
1833            String.valueOf(ch)));
1834  }
1835
1836  /**
1837   * Returns the next character.
1838   */

1839  private int read()
1840  {
1841    if (_parseIndex < _sqlLength)
1842      return _sqlChars[_parseIndex++];
1843    else
1844      return -1;
1845  }
1846
1847  /**
1848   * Unread the last character.
1849   */

1850  private void unread(int ch)
1851  {
1852    if (ch >= 0)
1853      _parseIndex--;
1854  }
1855
1856  /**
1857   * Returns the name for a character
1858   */

1859  private String JavaDoc charName(int ch)
1860  {
1861    if (ch < 0)
1862      return L.l("end of query");
1863    else
1864      return String.valueOf((char) ch);
1865  }
1866
1867  /**
1868   * Returns the name of a token
1869   */

1870  private String JavaDoc tokenName(int token)
1871  {
1872    switch (token) {
1873    case AS: return "AS";
1874    case ARG: return "?";
1875    case FROM: return "FROM";
1876    case IN: return "IN";
1877    case SELECT: return "SELECT";
1878    case WHERE: return "WHERE";
1879    case OR: return "OR";
1880    case AND: return "AND";
1881    case NOT: return "NOT";
1882    case BETWEEN: return "BETWEEN";
1883    case TRUE: return "TRUE";
1884    case FALSE: return "FALSE";
1885    case NULL: return "NULL";
1886    case GROUP: return "GROUP";
1887    case ORDER: return "ORDER";
1888    case BY: return "BY";
1889    case ASC: return "ASC";
1890    case DESC: return "DESC";
1891    case LIMIT: return "LIMIT";
1892
1893    case -1:
1894      return L.l("end of query");
1895
1896    default:
1897      if (token < 128)
1898        return "'" + String.valueOf((char) token) + "'";
1899      else
1900        return "'" + _lexeme + "'";
1901    }
1902  }
1903
1904  private SQLException JavaDoc error(String JavaDoc msg)
1905  {
1906    return new SQLParseException(msg + "\n" + _sql);
1907  }
1908
1909  static {
1910    _reserved = new IntMap();
1911    _reserved.put("as", AS);
1912    _reserved.put("from", FROM);
1913    _reserved.put("in", IN);
1914    _reserved.put("select", SELECT);
1915    _reserved.put("distinct", DISTINCT);
1916    _reserved.put("where", WHERE);
1917    _reserved.put("order", ORDER);
1918    _reserved.put("group", GROUP);
1919    _reserved.put("by", BY);
1920    _reserved.put("asc", ASC);
1921    _reserved.put("desc", DESC);
1922    _reserved.put("limit", LIMIT);
1923    _reserved.put("offset", OFFSET);
1924
1925    _reserved.put("or", OR);
1926    _reserved.put("and", AND);
1927    _reserved.put("not", NOT);
1928
1929    _reserved.put("between", BETWEEN);
1930    _reserved.put("like", LIKE);
1931    _reserved.put("escape", ESCAPE);
1932    _reserved.put("is", IS);
1933
1934    _reserved.put("true", TRUE);
1935    _reserved.put("false", FALSE);
1936    _reserved.put("unknown", UNKNOWN);
1937    _reserved.put("null", NULL);
1938
1939    _reserved.put("create", CREATE);
1940    _reserved.put("table", TABLE);
1941    _reserved.put("insert", INSERT);
1942    _reserved.put("into", INTO);
1943    _reserved.put("values", VALUES);
1944    _reserved.put("drop", DROP);
1945    _reserved.put("update", UPDATE);
1946    _reserved.put("set", SET);
1947    _reserved.put("delete", DELETE);
1948
1949    _reserved.put("constraint", CONSTRAINT);
1950    _reserved.put("unique", UNIQUE);
1951    _reserved.put("check", CHECK);
1952    _reserved.put("primary", PRIMARY);
1953    _reserved.put("key", KEY);
1954    _reserved.put("foreign", FOREIGN);
1955  }
1956}
1957
Popular Tags