0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: * Free SoftwareFoundation, Inc.
0023: * 59 Temple Place, Suite 330
0024: * Boston, MA 02111-1307 USA
0025: *
0026: * @author Scott Ferguson
0027: */
0028:
0029: package com.caucho.db.sql;
0030:
0031: import com.caucho.db.Database;
0032: import com.caucho.db.table.Column;
0033: import com.caucho.db.table.Table;
0034: import com.caucho.db.table.TableFactory;
0035: import com.caucho.log.Log;
0036: import com.caucho.util.CharBuffer;
0037: import com.caucho.util.IntMap;
0038: import com.caucho.util.L10N;
0039:
0040: import java.sql.SQLException;
0041: import java.util.ArrayList;
0042: import java.util.HashSet;
0043: import java.util.logging.Level;
0044: import java.util.logging.Logger;
0045:
0046: public class Parser {
0047: private static final Logger log = Log.open(Parser.class);
0048: private static final L10N L = new L10N(Parser.class);
0049:
0050: final static int IDENTIFIER = 128;
0051: final static int INTEGER = IDENTIFIER + 1;
0052: final static int LONG = INTEGER + 1;
0053: final static int DOUBLE = LONG + 1;
0054: final static int STRING = DOUBLE + 1;
0055: final static int TRUE = STRING + 1;
0056: final static int FALSE = TRUE + 1;
0057: final static int UNKNOWN = FALSE + 1;
0058: final static int NULL = UNKNOWN + 1;
0059: final static int EXISTS = NULL + 1;
0060:
0061: final static int FROM = EXISTS + 1;
0062: final static int IN = FROM + 1;
0063: final static int SELECT = IN + 1;
0064: final static int DISTINCT = SELECT + 1;
0065: final static int WHERE = SELECT + 1;
0066: final static int AS = WHERE + 1;
0067: final static int ORDER = AS + 1;
0068: final static int GROUP = ORDER + 1;
0069: final static int BY = GROUP + 1;
0070: final static int ASC = BY + 1;
0071: final static int DESC = ASC + 1;
0072: final static int LIMIT = DESC + 1;
0073: final static int OFFSET = LIMIT + 1;
0074:
0075: final static int BETWEEN = OFFSET + 1;
0076: final static int LIKE = BETWEEN + 1;
0077: final static int ESCAPE = LIKE + 1;
0078: final static int IS = ESCAPE + 1;
0079: final static int CONCAT = IS + 1;
0080:
0081: final static int EQ = CONCAT + 1;
0082: final static int NE = EQ + 1;
0083: final static int LT = NE + 1;
0084: final static int LE = LT + 1;
0085: final static int GT = LE + 1;
0086: final static int GE = GT + 1;
0087:
0088: final static int AND = GE + 1;
0089: final static int OR = AND + 1;
0090: final static int NOT = OR + 1;
0091:
0092: final static int ARG = NOT + 1;
0093:
0094: final static int CREATE = ARG + 1;
0095: final static int TABLE = CREATE + 1;
0096: final static int INSERT = TABLE + 1;
0097: final static int INTO = INSERT + 1;
0098: final static int VALUES = INTO + 1;
0099: final static int DROP = VALUES + 1;
0100: final static int UPDATE = DROP + 1;
0101: final static int SET = UPDATE + 1;
0102: final static int DELETE = SET + 1;
0103:
0104: final static int CONSTRAINT = DELETE + 1;
0105: final static int UNIQUE = CONSTRAINT + 1;
0106: final static int PRIMARY = UNIQUE + 1;
0107: final static int CHECK = PRIMARY + 1;
0108: final static int FOREIGN = CHECK + 1;
0109: final static int KEY = FOREIGN + 1;
0110:
0111: private final static IntMap _reserved;
0112:
0113: private Database _database;
0114:
0115: private final String _sql;
0116: private final char[] _sqlChars;
0117: private final int _sqlLength;
0118:
0119: private int _parseIndex;
0120:
0121: private final CharBuffer _cb = new CharBuffer();
0122:
0123: private String _lexeme;
0124: private int _token;
0125:
0126: private ArrayList<ParamExpr> _params = new ArrayList<ParamExpr>();
0127:
0128: private Query _query;
0129: private AndExpr _andExpr;
0130:
0131: private Parser(Database database, String sql) {
0132: _database = database;
0133: _sql = sql;
0134: _sqlLength = _sql.length();
0135: _sqlChars = new char[_sqlLength];
0136: _sql.getChars(0, _sqlLength, _sqlChars, 0);
0137: }
0138:
0139: public static Query parse(Database database, String sql)
0140: throws SQLException {
0141: Parser parser = new Parser(database, sql);
0142:
0143: Query query = parser.parse();
0144:
0145: query.bind();
0146:
0147: return query;
0148: }
0149:
0150: public static Expr parseExpr(Database database, String sql)
0151: throws SQLException {
0152: Parser parser = new Parser(database, sql);
0153:
0154: Expr expr = parser.parseExpr();
0155:
0156: return expr.bind(null);
0157: }
0158:
0159: /**
0160: * Parses the query.
0161: */
0162: private Query parse() throws SQLException {
0163: int token = scanToken();
0164:
0165: switch (token) {
0166: case SELECT:
0167: return parseSelect();
0168:
0169: case CREATE:
0170: return parseCreate();
0171:
0172: case INSERT:
0173: return parseInsert();
0174:
0175: case DELETE:
0176: return parseDelete();
0177:
0178: case DROP:
0179: return parseDrop();
0180:
0181: case UPDATE:
0182: return parseUpdate();
0183:
0184: default:
0185: throw new SQLParseException(L.l("unknown query at `{0}'",
0186: tokenName(token)));
0187: }
0188: }
0189:
0190: /**
0191: * Parses the select.
0192: */
0193: private SelectQuery parseSelect() throws SQLException {
0194: return parseSelect(new SelectQuery(_database, _sql));
0195: }
0196:
0197: /**
0198: * Parses the select.
0199: */
0200: private SelectQuery parseSelect(SelectQuery query)
0201: throws SQLException {
0202: boolean distinct = false;
0203:
0204: int token = scanToken();
0205:
0206: if (token == DISTINCT)
0207: distinct = true;
0208: else
0209: _token = token;
0210:
0211: ArrayList<Expr> resultItems = new ArrayList<Expr>();
0212:
0213: int startToken = scanToken();
0214: String startLexeme = _lexeme;
0215: int startOffset = _parseIndex;
0216:
0217: while ((token = scanToken()) >= 0 && token != FROM) {
0218: }
0219:
0220: if (token != FROM)
0221: throw error(L.l("expected FROM at `{0}'", tokenName(token)));
0222:
0223: query.setParent(_query);
0224: _query = query;
0225:
0226: AndExpr oldAnd = _andExpr;
0227: _andExpr = new AndExpr();
0228:
0229: ArrayList<FromItem> fromItems = parseFromItems();
0230:
0231: query.setFromItems(fromItems);
0232:
0233: token = scanToken();
0234:
0235: int tailToken = token;
0236: int tailOffset = _parseIndex;
0237:
0238: _token = startToken;
0239: _parseIndex = startOffset;
0240: _lexeme = startLexeme;
0241:
0242: Expr expr = parseSelectExpr();
0243:
0244: resultItems.add(expr);
0245:
0246: while ((token = scanToken()) == ',') {
0247: expr = parseSelectExpr();
0248:
0249: resultItems.add(expr);
0250: }
0251:
0252: _token = tailToken;
0253: _parseIndex = tailOffset;
0254:
0255: token = scanToken();
0256:
0257: if (token == WHERE)
0258: _andExpr.add(parseExpr());
0259: else
0260: _token = token;
0261:
0262: ParamExpr[] params = _params.toArray(new ParamExpr[_params
0263: .size()]);
0264:
0265: Expr whereExpr = _andExpr.getSingleExpr();
0266: _andExpr = null;
0267: query.setWhereExpr(whereExpr);
0268: query.setParams(params);
0269:
0270: for (int i = resultItems.size() - 1; i >= 0; i--) {
0271: Expr subExpr = resultItems.get(i);
0272:
0273: if (subExpr instanceof UnboundStarExpr) {
0274: UnboundStarExpr unboundExpr = (UnboundStarExpr) subExpr;
0275: ArrayList<Expr> exprList = unboundExpr.expand(query
0276: .getFromItems());
0277:
0278: resultItems.remove(i);
0279: resultItems.addAll(i, exprList);
0280: }
0281: }
0282:
0283: ArrayList<Expr> groupItems = null;
0284: token = scanToken();
0285: if (token == GROUP) {
0286: token = scanToken();
0287:
0288: if (token != BY)
0289: throw error(L.l("expected BY at `{0}'",
0290: tokenName(token)));
0291:
0292: groupItems = parseGroup(query);
0293: } else
0294: _token = token;
0295:
0296: token = scanToken();
0297: if (token == ORDER) {
0298: token = scanToken();
0299:
0300: if (token != BY)
0301: throw error(L.l("expected BY at `{0}'",
0302: tokenName(token)));
0303:
0304: Order order = parseOrder(query, resultItems);
0305: } else
0306: _token = token;
0307:
0308: Expr[] resultArray = resultItems.toArray(new Expr[resultItems
0309: .size()]);
0310:
0311: query.setResults(resultArray);
0312:
0313: if (query.isGroup()) {
0314: Expr[] resultList = query.getResults();
0315:
0316: bindGroup(query, groupItems);
0317:
0318: for (int i = 0; i < resultList.length; i++) {
0319: Expr subExpr = resultList[i];
0320:
0321: if (!(subExpr instanceof GroupExpr)) {
0322: resultList[i] = new GroupResultExpr(i, subExpr);
0323: }
0324: }
0325: }
0326:
0327: token = scanToken();
0328: if (token == LIMIT) {
0329: parseLimit(query);
0330: } else
0331: _token = token;
0332:
0333: if (query.getParent() == null && token >= 0 && token != LIMIT
0334: && token != OFFSET)
0335: throw error(L.l("unexpected token at end '{0}'",
0336: tokenName(token)));
0337:
0338: _query = query.getParent();
0339: _andExpr = oldAnd;
0340:
0341: return query;
0342: }
0343:
0344: private ArrayList<FromItem> parseFromItems() throws SQLException {
0345: ArrayList<FromItem> fromItems = new ArrayList<FromItem>();
0346:
0347: int token;
0348:
0349: // XXX: somewhat hacked syntax
0350: while ((token = scanToken()) == '(') {
0351: }
0352: _token = token;
0353:
0354: FromItem fromItem = parseFromItem();
0355:
0356: if (fromItem != null)
0357: fromItems.add(fromItem);
0358:
0359: while (true) {
0360: token = scanToken();
0361:
0362: boolean isNatural = false;
0363: boolean isOuter = false;
0364: boolean isLeft = true;
0365: boolean isRight = true;
0366:
0367: if (token == ',') {
0368: fromItem = parseFromItem();
0369: fromItems.add(fromItem);
0370: continue;
0371: } else if (token == '(' || token == ')')
0372: continue;
0373: else if (token != IDENTIFIER) {
0374: _token = token;
0375: break;
0376: } else if ("join".equalsIgnoreCase(_lexeme)) {
0377: } else if ("inner".equalsIgnoreCase(_lexeme)) {
0378: String join = parseIdentifier();
0379:
0380: if (!"join".equalsIgnoreCase(join))
0381: throw error(L.l("expected JOIN at '{0}'", join));
0382: } else if ("left".equalsIgnoreCase(_lexeme)) {
0383: String name = parseIdentifier();
0384:
0385: if ("outer".equalsIgnoreCase(name))
0386: name = parseIdentifier();
0387:
0388: if (!"join".equalsIgnoreCase(name))
0389: throw error(L.l("expected JOIN at '{0}'", name));
0390:
0391: isOuter = true;
0392: } else if ("right".equalsIgnoreCase(_lexeme)) {
0393: String name = parseIdentifier();
0394:
0395: if ("outer".equalsIgnoreCase(name))
0396: name = parseIdentifier();
0397:
0398: if (!"join".equalsIgnoreCase(name))
0399: throw error(L.l("expected JOIN at '{0}'", name));
0400:
0401: isRight = true;
0402: isOuter = true;
0403:
0404: throw error(L.l("right outer joins are not supported"));
0405: } else if ("natural".equalsIgnoreCase(_lexeme)) {
0406: String name = parseIdentifier();
0407:
0408: isNatural = true;
0409:
0410: if ("left".equalsIgnoreCase(name)) {
0411: name = parseIdentifier();
0412:
0413: if ("outer".equalsIgnoreCase(name))
0414: name = parseIdentifier();
0415:
0416: isOuter = true;
0417: } else if ("right".equalsIgnoreCase(name)) {
0418: name = parseIdentifier();
0419:
0420: if ("outer".equalsIgnoreCase(name))
0421: name = parseIdentifier();
0422:
0423: isRight = true;
0424: isOuter = true;
0425:
0426: throw error(L
0427: .l("right outer joins are not supported"));
0428: }
0429:
0430: if (!"join".equalsIgnoreCase(name))
0431: throw error(L.l("expected JOIN at '{0}'", name));
0432: } else {
0433: _token = token;
0434: break;
0435: }
0436:
0437: fromItem = parseFromItem();
0438: fromItems.add(fromItem);
0439:
0440: _query.setFromItems(fromItems);
0441:
0442: token = scanToken();
0443: if (token == IDENTIFIER && "on".equalsIgnoreCase(_lexeme)) {
0444: Expr onExpr = parseExpr();
0445:
0446: if (isOuter) {
0447: FromItem leftItem = fromItems
0448: .get(fromItems.size() - 2);
0449: FromItem rightItem = fromItems
0450: .get(fromItems.size() - 1);
0451:
0452: onExpr = new LeftOuterJoinExpr(rightItem, onExpr);
0453:
0454: rightItem.setDependTable(leftItem);
0455: }
0456:
0457: _andExpr.add(onExpr);
0458: } else
0459: _token = token;
0460: }
0461:
0462: return fromItems;
0463: }
0464:
0465: /**
0466: * Parses a select expression.
0467: */
0468: private Expr parseSelectExpr() throws SQLException {
0469: int token = scanToken();
0470:
0471: if (token == '*')
0472: return new UnboundStarExpr();
0473: else {
0474: _token = token;
0475:
0476: return parseExpr();
0477: }
0478: }
0479:
0480: /**
0481: * Parses a from item
0482: */
0483: private FromItem parseFromItem() throws SQLException {
0484: String tableName = parseIdentifier();
0485:
0486: if (tableName.equalsIgnoreCase("DUAL"))
0487: return null;
0488:
0489: Table table = _database.getTable(tableName);
0490:
0491: if (table == null)
0492: throw error(L
0493: .l(
0494: "'{0}' is an unknown table. 'FROM table' requires an existing table.",
0495: tableName));
0496:
0497: String name = table.getName();
0498:
0499: int token = scanToken();
0500: if (token == AS)
0501: name = parseIdentifier();
0502: else if (token == IDENTIFIER)
0503: name = _lexeme;
0504: else
0505: _token = token;
0506:
0507: return new FromItem(table, name);
0508: }
0509:
0510: /**
0511: * Parses the ORDER BY
0512: */
0513: private Order parseOrder(SelectQuery query,
0514: ArrayList<Expr> resultList) throws SQLException {
0515: int token;
0516:
0517: Order order = null;
0518:
0519: do {
0520: Expr expr = parseExpr();
0521:
0522: expr = expr.bind(query);
0523:
0524: token = scanToken();
0525: boolean isAsc = true;
0526: if (token == ASC)
0527: isAsc = true;
0528: else if (token == DESC)
0529: isAsc = false;
0530: else
0531: _token = token;
0532:
0533: int index;
0534: for (index = 0; index < resultList.size(); index++) {
0535: Expr resultExpr = resultList.get(index);
0536:
0537: if (expr.equals(resultExpr))
0538: break;
0539: }
0540:
0541: if (resultList.size() <= index) {
0542: resultList.add(expr);
0543: }
0544:
0545: Order tailOrder = expr.createOrder(index);
0546: tailOrder.setAscending(isAsc);
0547:
0548: order = Order.append(order, tailOrder);
0549:
0550: // ascList.add(isAsc ? Boolean.TRUE : Boolean.FALSE);
0551: } while ((token = scanToken()) == ',');
0552:
0553: query.setOrder(order);
0554:
0555: _token = token;
0556:
0557: return order;
0558: }
0559:
0560: /**
0561: * Parses the GROUP BY
0562: */
0563: private ArrayList<Expr> parseGroup(SelectQuery query)
0564: throws SQLException {
0565: query.setGroup(true);
0566: int token;
0567:
0568: ArrayList<Expr> groupList = new ArrayList<Expr>();
0569:
0570: do {
0571: groupList.add(parseExpr());
0572: } while ((token = scanToken()) == ',');
0573:
0574: _token = token;
0575:
0576: return groupList;
0577: }
0578:
0579: /**
0580: * Parses the GROUP BY
0581: */
0582: private void bindGroup(SelectQuery query, ArrayList<Expr> groupList)
0583: throws SQLException {
0584: query.setGroup(true);
0585:
0586: Expr[] resultList = query.getResults();
0587:
0588: for (int i = 0; i < groupList.size(); i++) {
0589: Expr expr = groupList.get(i);
0590:
0591: expr = expr.bind(query);
0592:
0593: int index;
0594: for (index = 0; index < resultList.length; index++) {
0595: Expr resultExpr = resultList[index];
0596:
0597: if (expr.equals(resultExpr)) {
0598: resultList[index] = new GroupResultExpr(index,
0599: resultExpr);
0600:
0601: break;
0602: }
0603: }
0604:
0605: if (resultList.length <= index) {
0606: throw error(L
0607: .l(
0608: "GROUP BY field '{0}' must refer to a result field.",
0609: expr));
0610: }
0611:
0612: query.setGroupResult(index);
0613: }
0614: }
0615:
0616: /**
0617: * Parses the LIMIT
0618: */
0619: private void parseLimit(SelectQuery query) throws SQLException {
0620: int token = scanToken();
0621:
0622: if (token == INTEGER) {
0623: query.setLimit(Integer.valueOf(_lexeme));
0624: _token = scanToken();
0625: } else
0626: throw error(L.l("LIMIT expected LIMIT int"));
0627: }
0628:
0629: /**
0630: * Parses the create.
0631: */
0632: private Query parseCreate() throws SQLException {
0633: int token;
0634:
0635: TableFactory factory = _database.createTableFactory();
0636:
0637: if ((token = scanToken()) != TABLE)
0638: throw error(L
0639: .l("expected TABLE at `{0}'", tokenName(token)));
0640:
0641: if ((token = scanToken()) != IDENTIFIER)
0642: throw error(L.l("expected identifier at `{0}'",
0643: tokenName(token)));
0644:
0645: factory.startTable(_lexeme);
0646:
0647: if ((token = scanToken()) != '(')
0648: throw error(L.l("expected '(' at `{0}'", tokenName(token)));
0649:
0650: do {
0651: token = scanToken();
0652:
0653: switch (token) {
0654: case IDENTIFIER:
0655: parseCreateColumn(factory, _lexeme);
0656: break;
0657:
0658: case UNIQUE:
0659: factory.addUnique(parseColumnNames());
0660: break;
0661:
0662: case PRIMARY:
0663: token = scanToken();
0664: if (token != KEY)
0665: throw error(L.l("expected 'key' at {0}",
0666: tokenName(token)));
0667:
0668: factory.addPrimaryKey(parseColumnNames());
0669: break;
0670:
0671: case KEY:
0672: String key = parseIdentifier();
0673:
0674: parseColumnNames(); // factory.addPrimaryKey(parseColumnNames());
0675: break;
0676:
0677: case CHECK:
0678: if ((token = scanToken()) != '(')
0679: throw error(L.l("Expected '(' at '{0}'",
0680: tokenName(token)));
0681:
0682: parseExpr();
0683:
0684: if ((token = scanToken()) != ')')
0685: throw error(L.l("Expected ')' at '{0}'",
0686: tokenName(token)));
0687: break;
0688:
0689: default:
0690: throw error(L.l("unexpected token `{0}'",
0691: tokenName(token)));
0692: }
0693:
0694: token = scanToken();
0695: } while (token == ',');
0696:
0697: if (token != ')')
0698: throw error(L.l("expected ')' at `{0}'", tokenName(token)));
0699:
0700: return new CreateQuery(_database, _sql, factory);
0701: }
0702:
0703: /**
0704: * Parses a column declaration.
0705: */
0706: private void parseCreateColumn(TableFactory factory, String name)
0707: throws SQLException {
0708: int token;
0709:
0710: if ((token = scanToken()) != IDENTIFIER)
0711: throw error(L.l("expected column type at {0}",
0712: tokenName(token)));
0713:
0714: String type = _lexeme;
0715: int length = -1;
0716: int scale = -1;
0717:
0718: if (type.equalsIgnoreCase("double")) {
0719: if ((token = scanToken()) == IDENTIFIER) {
0720: if (_lexeme.equalsIgnoreCase("precision")) {
0721: } else
0722: throw error(L.l("unexpected double type at {0}",
0723: _lexeme));
0724: } else
0725: _token = token;
0726: }
0727:
0728: if ((token = scanToken()) == '(') {
0729: if ((token = scanToken()) != INTEGER)
0730: throw error(L.l("expected column width at `{0}'",
0731: tokenName(token)));
0732:
0733: length = Integer.parseInt(_lexeme);
0734:
0735: if ((token = scanToken()) == ',') {
0736: if ((token = scanToken()) != INTEGER)
0737: throw error(L.l("expected column scale at `{0}'",
0738: tokenName(token)));
0739:
0740: scale = Integer.parseInt(_lexeme);
0741:
0742: token = scanToken();
0743: }
0744:
0745: if (token != ')')
0746: throw error(L.l("expected ')' at '{0}'",
0747: tokenName(token)));
0748: } else
0749: _token = token;
0750:
0751: if (type.equalsIgnoreCase("varchar")) {
0752: if (length < 0)
0753: throw error(L.l("VARCHAR needs a defined length"));
0754:
0755: factory.addVarchar(name, length);
0756: } else if (type.equalsIgnoreCase("char")) {
0757: if (length < 0)
0758: length = 1;
0759:
0760: factory.addVarchar(name, length);
0761: } else if (type.equalsIgnoreCase("varbinary")) {
0762: if (length < 0)
0763: throw error(L.l("VARBINARY needs a defined length"));
0764:
0765: factory.addVarbinary(name, length);
0766: } else if (type.equalsIgnoreCase("blob")) {
0767: factory.addBlob(name);
0768: } else if (type.equalsIgnoreCase("integer")
0769: || type.equalsIgnoreCase("int")
0770: || type.equalsIgnoreCase("smallint")
0771: || type.equalsIgnoreCase("tinyint")
0772: || type.equalsIgnoreCase("mediumint")
0773: || type.equalsIgnoreCase("bit")) {
0774: factory.addInteger(name);
0775: } else if (type.equalsIgnoreCase("bigint")) {
0776: factory.addLong(name);
0777: } else if (type.equalsIgnoreCase("double")
0778: || type.equalsIgnoreCase("float")
0779: || type.equalsIgnoreCase("real")) {
0780: factory.addDouble(name);
0781: } else if (type.equalsIgnoreCase("datetime")
0782: || type.equalsIgnoreCase("timestamp")) {
0783: factory.addDateTime(name);
0784: } else if (type.equalsIgnoreCase("text")
0785: || type.equalsIgnoreCase("clob")) {
0786: factory.addVarchar(name, 255);
0787: } else if (type.equalsIgnoreCase("decimal")
0788: || type.equalsIgnoreCase("numeric")) {
0789: factory.addNumeric(name, length, scale);
0790: } else
0791: throw error(L.l("Unknown type {0}", type));
0792:
0793: token = scanToken();
0794: if (token == IDENTIFIER && _lexeme.equalsIgnoreCase("default")) {
0795: Expr defaultExpr = parseExpr();
0796:
0797: factory.setDefault(name, defaultExpr);
0798: } else
0799: _token = token;
0800:
0801: while (true) {
0802: token = scanToken();
0803:
0804: // XXX: stuff like NOT NULL
0805:
0806: switch (token) {
0807: case ')':
0808: case ',':
0809: _token = token;
0810: return;
0811:
0812: case UNIQUE:
0813: factory.setUnique(name);
0814: break;
0815:
0816: case PRIMARY:
0817: token = scanToken();
0818: if (token != KEY)
0819: throw error(L.l("expected key at {0}",
0820: tokenName(token)));
0821:
0822: factory.setPrimaryKey(name);
0823: break;
0824:
0825: case CHECK:
0826: if ((token = scanToken()) != '(')
0827: throw error(L.l("Expected '(' at '{0}'",
0828: tokenName(token)));
0829:
0830: parseExpr();
0831:
0832: if ((token = scanToken()) != ')')
0833: throw error(L.l("Expected ')' at '{0}'",
0834: tokenName(token)));
0835: break;
0836:
0837: case IDENTIFIER:
0838: String id = _lexeme;
0839: if (id.equalsIgnoreCase("references")) {
0840: ArrayList<String> foreignKey = new ArrayList<String>();
0841: foreignKey.add(name);
0842: parseReferences(foreignKey);
0843: } else if (id.equalsIgnoreCase("default")) {
0844: Expr expr = parseExpr();
0845: } else if (id.equalsIgnoreCase("auto_increment")) {
0846: factory.setAutoIncrement(name, 1);
0847: } else if (id.equalsIgnoreCase("unsigned")) {
0848: } else if (id.equalsIgnoreCase("binary")) {
0849: } else
0850: throw error(L.l("unexpected token '{0}'",
0851: tokenName(token)));
0852: break;
0853:
0854: case NULL:
0855: break;
0856:
0857: case NOT:
0858: if ((token = scanToken()) == NULL)
0859: factory.setNotNull(name);
0860: else
0861: throw error(L.l("unexpected token '{0}'",
0862: tokenName(token)));
0863: break;
0864:
0865: default:
0866: throw error(L.l("unexpected token '{0}'",
0867: tokenName(token)));
0868: }
0869: }
0870: }
0871:
0872: /**
0873: * Parses a key constraint declaration.
0874: */
0875: private void parseKeyConstraint(TableFactory factory)
0876: throws SQLException {
0877: String key = parseIdentifier();
0878:
0879: int token = scanToken();
0880:
0881: if (token == '(') {
0882: parseIdentifier();
0883:
0884: token = scanToken();
0885: if (token != ')')
0886: throw error("expected ')'");
0887: } else
0888: _token = token;
0889: }
0890:
0891: /**
0892: * Parses the references clause.
0893: */
0894: public void parseReferences(ArrayList<String> name)
0895: throws SQLException {
0896: String foreignTable = parseIdentifier();
0897:
0898: int token = scanToken();
0899:
0900: ArrayList<String> foreignColumns = new ArrayList<String>();
0901:
0902: if (token == '(') {
0903: _token = token;
0904:
0905: foreignColumns = parseColumnNames();
0906: } else
0907: _token = token;
0908: }
0909:
0910: /**
0911: * Parses a list of column names
0912: */
0913: public ArrayList<String> parseColumnNames() throws SQLException {
0914: ArrayList<String> columns = new ArrayList<String>();
0915:
0916: int token = scanToken();
0917: if (token == '(') {
0918: do {
0919: columns.add(parseIdentifier());
0920:
0921: token = scanToken();
0922: } while (token == ',');
0923:
0924: if (token != ')')
0925: throw error(L.l("expected ')' at '{0}'",
0926: tokenName(token)));
0927: } else if (token == IDENTIFIER) {
0928: columns.add(_lexeme);
0929:
0930: _token = token;
0931: } else
0932: throw error(L.l("expected '(' at '{0}'", tokenName(token)));
0933:
0934: return columns;
0935: }
0936:
0937: /**
0938: * Parses the insert.
0939: */
0940: private Query parseInsert() throws SQLException {
0941: int token;
0942:
0943: if ((token = scanToken()) != INTO)
0944: throw error(L.l("expected INTO at `{0}'", tokenName(token)));
0945:
0946: if ((token = scanToken()) != IDENTIFIER)
0947: throw error(L.l("expected identifier at `{0}'",
0948: tokenName(token)));
0949:
0950: Table table = _database.getTable(_lexeme);
0951:
0952: if (table == null)
0953: throw error(L.l("unknown table `{0}'", tokenName(token)));
0954:
0955: FromItem fromItem = new FromItem(table, table.getName());
0956: FromItem[] fromList = new FromItem[] { fromItem };
0957:
0958: ArrayList<Column> columns = new ArrayList<Column>();
0959:
0960: if ((token = scanToken()) == '(') {
0961: do {
0962: String columnName = parseIdentifier();
0963:
0964: Column column = table.getColumn(columnName);
0965:
0966: if (column == null)
0967: throw new SQLException(L.l(
0968: "`{0}' is not a valid column in {1}",
0969: columnName, table.getName()));
0970: columns.add(column);
0971: } while ((token = scanToken()) == ',');
0972:
0973: if (token != ')')
0974: throw error(L.l("expected ')' at `{0}'",
0975: tokenName(token)));
0976:
0977: token = scanToken();
0978: } else {
0979: Column[] columnArray = table.getColumns();
0980:
0981: for (int i = 0; i < columnArray.length; i++)
0982: columns.add(columnArray[i]);
0983: }
0984:
0985: if (token != VALUES)
0986: throw error(L.l("expected VALUES at `{0}'",
0987: tokenName(token)));
0988:
0989: if ((token = scanToken()) != '(')
0990: throw error(L.l("expected '(' at `{0}'", tokenName(token)));
0991:
0992: ArrayList<Expr> values = new ArrayList<Expr>();
0993:
0994: InsertQuery query = new InsertQuery(_database, _sql, table,
0995: columns);
0996: _query = query;
0997:
0998: int i = 0;
0999: do {
1000: Expr expr = parseExpr();
1001:
1002: expr = expr.bind(new TempQuery(fromList));
1003:
1004: values.add(expr);
1005:
1006: i++;
1007: } while ((token = scanToken()) == ',');
1008:
1009: if (token != ')')
1010: throw error(L.l("expected ')' at {0}", tokenName(token)));
1011:
1012: if (columns.size() != values.size())
1013: throw error(L
1014: .l("number of columns does not match number of values"));
1015:
1016: ParamExpr[] params = _params.toArray(new ParamExpr[_params
1017: .size()]);
1018:
1019: query.setParams(params);
1020: query.setValues(values);
1021: query.init();
1022:
1023: return query;
1024: }
1025:
1026: /**
1027: * Parses the delete.
1028: */
1029: private Query parseDelete() throws SQLException {
1030: int token;
1031:
1032: if ((token = scanToken()) != FROM)
1033: throw error(L.l("expected FROM at `{0}'", tokenName(token)));
1034:
1035: if ((token = scanToken()) != IDENTIFIER)
1036: throw error(L.l("expected identifier at `{0}'",
1037: 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
1054: .l("expected WHERE at `{0}'", tokenName(token)));
1055:
1056: ParamExpr[] params = _params.toArray(new ParamExpr[_params
1057: .size()]);
1058:
1059: query.setParams(params);
1060: query.setWhereExpr(whereExpr);
1061:
1062: return query;
1063: }
1064:
1065: /**
1066: * Parses the insert.
1067: */
1068: private Query parseDrop() throws SQLException {
1069: int token;
1070:
1071: if ((token = scanToken()) != TABLE)
1072: throw error(L
1073: .l("expected TABLE at `{0}'", tokenName(token)));
1074:
1075: if ((token = scanToken()) != IDENTIFIER)
1076: throw error(L.l("expected identifier at `{0}'",
1077: tokenName(token)));
1078:
1079: String table = _lexeme;
1080:
1081: if ((token = scanToken()) >= 0)
1082: throw error(L.l("expected end of query at `{0}'",
1083: tokenName(token)));
1084:
1085: return new DropQuery(_sql, _database, table);
1086: }
1087:
1088: /**
1089: * Parses the select.
1090: */
1091: private Query parseUpdate() throws SQLException {
1092: int token;
1093:
1094: if ((token = scanToken()) != IDENTIFIER)
1095: throw error(L.l("expected identifier at `{0}'",
1096: tokenName(token)));
1097:
1098: String name = _lexeme;
1099:
1100: Table table = _database.getTable(name);
1101:
1102: if (table == null)
1103: throw error(L.l("`{0}' is an unknown table in INSERT.",
1104: name));
1105:
1106: if ((token = scanToken()) != SET)
1107: throw error(L.l("expected SET at {0}", tokenName(token)));
1108:
1109: UpdateQuery query = new UpdateQuery(_database, _sql, table);
1110: _query = query;
1111:
1112: ArrayList<SetItem> setItemList = new ArrayList<SetItem>();
1113:
1114: do {
1115: SetItem item = parseSetItem(table);
1116:
1117: setItemList.add(item);
1118: } while ((token = scanToken()) == ',');
1119:
1120: Expr whereExpr = null;
1121:
1122: if (token == WHERE)
1123: whereExpr = parseExpr();
1124:
1125: SetItem[] setItems = new SetItem[setItemList.size()];
1126: setItemList.toArray(setItems);
1127:
1128: ParamExpr[] params = _params.toArray(new ParamExpr[_params
1129: .size()]);
1130:
1131: query.setSetItems(setItems);
1132: query.setParams(params);
1133: query.setWhereExpr(whereExpr);
1134:
1135: return query;
1136: }
1137:
1138: /**
1139: * Parses a set item.
1140: */
1141: private SetItem parseSetItem(Table table) throws SQLException {
1142: int token;
1143:
1144: if ((token = scanToken()) != IDENTIFIER)
1145: throw error(L.l("expected identifier at `{0}'",
1146: tokenName(token)));
1147:
1148: Column column = table.getColumn(_lexeme);
1149:
1150: if (column == null)
1151: throw error(L.l("`{0}' is an unknown column in table {1}.",
1152: _lexeme, table.getName()));
1153:
1154: if ((token = scanToken()) != EQ)
1155: throw error(L.l("expected `=' at {0}", tokenName(token)));
1156:
1157: Expr expr = parseExpr();
1158:
1159: return new SetItem(table, column, expr);
1160: }
1161:
1162: /**
1163: * Parses an expression.
1164: */
1165: private Expr parseExpr() throws SQLException {
1166: int token = scanToken();
1167:
1168: if (token == SELECT)
1169: return parseSubSelect();
1170: else {
1171: _token = token;
1172: return parseOrExpr();
1173: }
1174: }
1175:
1176: /**
1177: * Parses a sub-select expression.
1178: */
1179: private Expr parseSubSelect() throws SQLException {
1180: return parseSubSelect(new SelectQuery(_database, _sql));
1181: }
1182:
1183: /**
1184: * Parses a sub-select expression.
1185: */
1186: private Expr parseSubSelect(SelectQuery query) throws SQLException {
1187: parseSelect(query);
1188:
1189: SubSelectExpr expr = new SubSelectExpr(query);
1190:
1191: query.setSubSelect(expr);
1192:
1193: _andExpr.add(new SubSelectEvalExpr(expr));
1194:
1195: return expr;
1196: }
1197:
1198: /**
1199: * Parses an OR expression.
1200: */
1201: private Expr parseOrExpr() throws SQLException {
1202: Expr left = parseAndExpr();
1203:
1204: while (true) {
1205: int token = scanToken();
1206:
1207: switch (token) {
1208: case OR:
1209: left = new OrExpr(left, parseAndExpr());
1210: break;
1211:
1212: default:
1213: _token = token;
1214: return left;
1215: }
1216: }
1217: }
1218:
1219: /**
1220: * Parses an AND expression.
1221: */
1222: private Expr parseAndExpr() throws SQLException {
1223: AndExpr oldAndExpr = _andExpr;
1224: AndExpr andExpr = new AndExpr();
1225: _andExpr = andExpr;
1226:
1227: andExpr.add(parseNotExpr());
1228:
1229: while (true) {
1230: int token = scanToken();
1231:
1232: switch (token) {
1233: case AND:
1234: andExpr.add(parseNotExpr());
1235: break;
1236:
1237: default:
1238: _token = token;
1239:
1240: _andExpr = oldAndExpr;
1241:
1242: return andExpr.getSingleExpr();
1243: }
1244: }
1245: }
1246:
1247: /**
1248: * Parses a term.
1249: */
1250: private Expr parseNotExpr() throws SQLException {
1251: int token = scanToken();
1252:
1253: switch (token) {
1254: case NOT:
1255: return new NotExpr(parseNotExpr());
1256:
1257: default:
1258: _token = token;
1259: return parseCmpExpr();
1260: }
1261: }
1262:
1263: /**
1264: * Parses a CMP expression.
1265: */
1266: private Expr parseCmpExpr() throws SQLException {
1267: Expr left = parseConcatExpr();
1268:
1269: int token = scanToken();
1270: boolean isNot = false;
1271:
1272: if (token == NOT) {
1273: isNot = true;
1274:
1275: token = scanToken();
1276:
1277: if (token != BETWEEN && token != LIKE && token != IN) {
1278: _token = token;
1279:
1280: return left;
1281: }
1282: }
1283:
1284: switch (token) {
1285: case EQ:
1286: return new EqExpr(left, parseConcatExpr());
1287:
1288: case LT:
1289: case LE:
1290: case GT:
1291: case GE:
1292: case NE:
1293: return new CmpExpr(left, parseConcatExpr(), token);
1294:
1295: case BETWEEN: {
1296: Expr min = parseConcatExpr();
1297:
1298: token = scanToken();
1299: if (token != AND)
1300: throw error(L.l("expected AND at '{0}'",
1301: tokenName(token)));
1302:
1303: Expr max = parseConcatExpr();
1304:
1305: return new BetweenExpr(left, min, max, isNot);
1306: }
1307:
1308: case IS: {
1309: token = scanToken();
1310: isNot = false;
1311: if (token == NOT) {
1312: token = scanToken();
1313: isNot = true;
1314: }
1315:
1316: if (token == NULL)
1317: return new IsNullExpr(left, isNot);
1318: else
1319: throw error(L.l("expected NULL at '{0}'",
1320: tokenName(token)));
1321: }
1322:
1323: case LIKE: {
1324: token = scanToken();
1325:
1326: if (token == STRING)
1327: return new LikeExpr(left, _lexeme, isNot);
1328: else
1329: throw error(L.l("expected string at '{0}'",
1330: tokenName(token)));
1331: }
1332:
1333: case IN: {
1334: HashSet<String> values = parseInValues();
1335:
1336: return new InExpr(left, values, isNot);
1337: }
1338:
1339: default:
1340: _token = token;
1341: return left;
1342: }
1343: }
1344:
1345: /**
1346: * Parses the IN values.
1347: */
1348: private HashSet<String> parseInValues() throws SQLException {
1349: int token = scanToken();
1350:
1351: if (token != '(')
1352: throw error(L.l("Expected '('"));
1353:
1354: HashSet<String> values = new HashSet<String>();
1355:
1356: while ((token = scanToken()) != ')') {
1357: if (token == STRING) {
1358: values.add(_lexeme);
1359: } else
1360: throw error(L.l("expected STRING at {0}",
1361: tokenName(token)));
1362:
1363: if ((token = scanToken()) != ',')
1364: break;
1365: }
1366:
1367: if (token != ')')
1368: throw error(L.l("expected ')' at {0}", tokenName(token)));
1369:
1370: return values;
1371: }
1372:
1373: /**
1374: * Parses a concat expression.
1375: */
1376: private Expr parseConcatExpr() throws SQLException {
1377: Expr left = parseAddExpr();
1378:
1379: while (true) {
1380: int token = scanToken();
1381:
1382: switch (token) {
1383: case CONCAT:
1384: left = new ConcatExpr(left, parseAddExpr());
1385: break;
1386:
1387: default:
1388: _token = token;
1389: return left;
1390: }
1391: }
1392: }
1393:
1394: /**
1395: * Parses a +/- expression.
1396: */
1397: private Expr parseAddExpr() throws SQLException {
1398: Expr left = parseMulExpr();
1399:
1400: while (true) {
1401: int token = scanToken();
1402:
1403: switch (token) {
1404: case '+':
1405: case '-':
1406: left = new BinaryExpr(left, parseMulExpr(), token);
1407: break;
1408:
1409: default:
1410: _token = token;
1411: return left;
1412: }
1413: }
1414: }
1415:
1416: /**
1417: * Parses a mul/div expression
1418: */
1419: private Expr parseMulExpr() throws SQLException {
1420: Expr left = parseTerm();
1421:
1422: while (true) {
1423: int token = scanToken();
1424:
1425: switch (token) {
1426: case '*':
1427: case '/':
1428: case '%':
1429: left = new BinaryExpr(left, parseTerm(), token);
1430: break;
1431:
1432: default:
1433: _token = token;
1434: return left;
1435: }
1436: }
1437: }
1438:
1439: /**
1440: * Parses a term.
1441: */
1442: private Expr parseTerm() throws SQLException {
1443: int token = scanToken();
1444:
1445: switch (token) {
1446: case '+':
1447: return parseTerm();
1448:
1449: case '-':
1450: return new UnaryExpr(parseTerm(), token);
1451:
1452: case '(':
1453: Expr expr = parseExpr();
1454: int peekToken;
1455: if ((peekToken = scanToken()) != ')')
1456: throw error(L.l("expected ')' at {0}",
1457: tokenName(peekToken)));
1458: return expr;
1459:
1460: default:
1461: _token = token;
1462: return parseSimpleTerm();
1463: }
1464: }
1465:
1466: /**
1467: * Parses a simple term.
1468: */
1469: private Expr parseSimpleTerm() throws SQLException {
1470: int token = scanToken();
1471:
1472: switch (token) {
1473: case IDENTIFIER: {
1474: String name = _lexeme;
1475:
1476: token = scanToken();
1477: if (token == '.') {
1478: token = scanToken();
1479:
1480: if (token == IDENTIFIER) {
1481: String column = _lexeme;
1482: return _query.bind(name, column);
1483: } else if (token == '*') {
1484: return new UnboundStarExpr(name);
1485: } else
1486: throw error("expected IDENTIFIER");
1487: } else if (token == '(') {
1488: FunExpr fun = null;
1489: if (name.equalsIgnoreCase("max"))
1490: fun = new MaxExpr();
1491: else if (name.equalsIgnoreCase("min"))
1492: fun = new MinExpr();
1493: else if (name.equalsIgnoreCase("sum"))
1494: fun = new SumExpr();
1495: else if (name.equalsIgnoreCase("avg"))
1496: fun = new AvgExpr();
1497: else if (name.equalsIgnoreCase("count")) {
1498: fun = new CountExpr();
1499:
1500: token = scanToken();
1501: if (token == '*') {
1502: fun.addArg(new UnboundStarExpr());
1503: } else
1504: _token = token;
1505: } else if (name.equalsIgnoreCase("exists")) {
1506: token = scanToken();
1507:
1508: if (token != SELECT)
1509: throw error(L.l(
1510: "exists requires SELECT at '{0}'",
1511: tokenName(token)));
1512:
1513: ExistsQuery query = new ExistsQuery(_database, _sql);
1514:
1515: parseSelect(query);
1516:
1517: ExistsExpr expr = new ExistsExpr(query);
1518:
1519: query.setSubSelect(expr);
1520:
1521: _andExpr.add(new ExistsEvalExpr(expr));
1522:
1523: token = scanToken();
1524:
1525: if (token != ')')
1526: throw error(L.l("exists requires ')' at '{0}'",
1527: tokenName(token)));
1528:
1529: return expr;
1530: } else {
1531: String funName = (Character.toUpperCase(name
1532: .charAt(0)) + name.substring(1)
1533: .toLowerCase());
1534:
1535: funName = "com.caucho.db.fun." + funName + "Expr";
1536:
1537: try {
1538: Class cl = Class.forName(funName);
1539:
1540: fun = (FunExpr) cl.newInstance();
1541: } catch (ClassNotFoundException e) {
1542: log.finer(e.toString());
1543: } catch (Throwable e) {
1544: log.log(Level.FINER, e.toString(), e);
1545: }
1546:
1547: if (fun == null)
1548: throw error(L.l(
1549: "`{0}' is an unknown function.", name));
1550: }
1551:
1552: token = scanToken();
1553: while (token > 0 && token != ')') {
1554: _token = token;
1555:
1556: Expr arg = parseExpr();
1557:
1558: fun.addArg(arg);
1559:
1560: token = scanToken();
1561:
1562: if (token == ',')
1563: token = scanToken();
1564: }
1565:
1566: return fun;
1567: } else {
1568: _token = token;
1569: return _query.bind(null, name);
1570: }
1571: }
1572:
1573: case STRING:
1574: return new StringExpr(_lexeme);
1575:
1576: case DOUBLE:
1577: case INTEGER:
1578: case LONG:
1579: return NumberExpr.create(_lexeme);
1580:
1581: case NULL:
1582: return new NullExpr();
1583:
1584: case TRUE:
1585: return BooleanLiteralExpr.create(true);
1586:
1587: case FALSE:
1588: return BooleanLiteralExpr.create(false);
1589:
1590: case '?':
1591: ParamExpr param = new ParamExpr(_params.size());
1592: _params.add(param);
1593: return param;
1594:
1595: default:
1596: throw error(L.l("unexpected term {0}", tokenName(token)));
1597: }
1598: }
1599:
1600: /**
1601: * Parses an identifier.
1602: */
1603: private String parseIdentifier() throws SQLException {
1604: int token = scanToken();
1605:
1606: if (token != IDENTIFIER)
1607: throw error(L.l("expected identifier at {0}",
1608: tokenName(token)));
1609:
1610: return _lexeme;
1611: }
1612:
1613: /**
1614: * Scan the next token. If the lexeme is a string, its string
1615: * representation is in "lexeme".
1616: *
1617: * @return integer code for the token
1618: */
1619: private int scanToken() throws SQLException {
1620: if (_token > 0) {
1621: int value = _token;
1622: _token = -1;
1623: return value;
1624: }
1625:
1626: int sign = 1;
1627: int ch;
1628:
1629: for (ch = read(); Character.isWhitespace((char) ch); ch = read()) {
1630: }
1631:
1632: switch (ch) {
1633: case -1:
1634: case '(':
1635: case ')':
1636: case '.':
1637: case '*':
1638: case '/':
1639: case '%':
1640: case ',':
1641: case '?':
1642: return ch;
1643:
1644: case '+':
1645: if ((ch = read()) >= '0' && ch <= '9')
1646: break;
1647: else {
1648: unread(ch);
1649: return '+';
1650: }
1651:
1652: case '-':
1653: if ((ch = read()) >= '0' && ch <= '9') {
1654: sign = -1;
1655: break;
1656: } else {
1657: unread(ch);
1658: return '-';
1659: }
1660:
1661: case '=':
1662: return EQ;
1663:
1664: case '<':
1665: if ((ch = read()) == '=')
1666: return LE;
1667: else if (ch == '>')
1668: return NE;
1669: else {
1670: unread(ch);
1671: return LT;
1672: }
1673:
1674: case '>':
1675: if ((ch = read()) == '=')
1676: return GE;
1677: else {
1678: unread(ch);
1679: return GT;
1680: }
1681:
1682: case '|':
1683: if ((ch = read()) == '|')
1684: return CONCAT;
1685: else {
1686: throw error(L.l("'|' expected at {0}", charName(ch)));
1687: }
1688:
1689: // @@ is useless?
1690: case '@':
1691: if ((ch = read()) != '@')
1692: throw error(L.l("`@' expected at {0}", charName(ch)));
1693: return scanToken();
1694: }
1695:
1696: if (Character.isJavaIdentifierStart((char) ch)) {
1697: CharBuffer cb = _cb;
1698: cb.clear();
1699:
1700: for (; ch > 0 && Character.isJavaIdentifierPart((char) ch); ch = read())
1701: cb.append((char) ch);
1702:
1703: unread(ch);
1704:
1705: _lexeme = cb.toString();
1706: String lower = _lexeme.toLowerCase();
1707:
1708: int token = _reserved.get(lower);
1709:
1710: if (token > 0)
1711: return token;
1712: else
1713: return IDENTIFIER;
1714: } else if (ch >= '0' && ch <= '9') {
1715: CharBuffer cb = _cb;
1716: cb.clear();
1717:
1718: int type = INTEGER;
1719:
1720: if (sign < 0)
1721: cb.append('-');
1722:
1723: for (; ch >= '0' && ch <= '9'; ch = read())
1724: cb.append((char) ch);
1725:
1726: if (ch == '.') {
1727: type = DOUBLE;
1728:
1729: cb.append('.');
1730: for (ch = read(); ch >= '0' && ch <= '9'; ch = read())
1731: cb.append((char) ch);
1732: }
1733:
1734: if (ch == 'e' || ch == 'E') {
1735: type = DOUBLE;
1736:
1737: cb.append('e');
1738: if ((ch = read()) == '+' || ch == '-') {
1739: cb.append((char) ch);
1740: ch = read();
1741: }
1742:
1743: if (!(ch >= '0' && ch <= '9'))
1744: throw error(L.l("exponent needs digits at {0}",
1745: charName(ch)));
1746:
1747: for (; ch >= '0' && ch <= '9'; ch = read())
1748: cb.append((char) ch);
1749: }
1750:
1751: if (ch == 'F' || ch == 'D')
1752: type = DOUBLE;
1753: else if (ch == 'L') {
1754: type = LONG;
1755: } else
1756: unread(ch);
1757:
1758: _lexeme = cb.toString();
1759:
1760: return type;
1761: } else if (ch == '\'') {
1762: CharBuffer cb = _cb;
1763: cb.clear();
1764:
1765: for (ch = read(); ch >= 0; ch = read()) {
1766: if (ch == '\'') {
1767: if ((ch = read()) == '\'')
1768: cb.append('\'');
1769: else {
1770: unread(ch);
1771: break;
1772: }
1773: } else if (ch == '\\') {
1774: ch = read();
1775:
1776: if (ch >= 0)
1777: cb.append(ch);
1778: } else
1779: cb.append((char) ch);
1780: }
1781:
1782: _lexeme = cb.toString();
1783:
1784: return STRING;
1785: } else if (ch == '#') {
1786: // skip comment
1787: while ((ch = read()) >= 0 && ch != '\n' && ch != '\r') {
1788: }
1789:
1790: // XXX: cleanup to avoid recursion
1791: return scanToken();
1792: }
1793:
1794: throw error(L.l("unexpected char at {0} ({1})", "" + (char) ch,
1795: String.valueOf(ch)));
1796: }
1797:
1798: /**
1799: * Returns the next character.
1800: */
1801: private int read() {
1802: if (_parseIndex < _sqlLength)
1803: return _sqlChars[_parseIndex++];
1804: else
1805: return -1;
1806: }
1807:
1808: /**
1809: * Unread the last character.
1810: */
1811: private void unread(int ch) {
1812: if (ch >= 0)
1813: _parseIndex--;
1814: }
1815:
1816: /**
1817: * Returns the name for a character
1818: */
1819: private String charName(int ch) {
1820: if (ch < 0)
1821: return L.l("end of query");
1822: else
1823: return String.valueOf((char) ch);
1824: }
1825:
1826: /**
1827: * Returns the name of a token
1828: */
1829: private String tokenName(int token) {
1830: switch (token) {
1831: case AS:
1832: return "AS";
1833: case ARG:
1834: return "?";
1835: case FROM:
1836: return "FROM";
1837: case IN:
1838: return "IN";
1839: case SELECT:
1840: return "SELECT";
1841: case WHERE:
1842: return "WHERE";
1843: case OR:
1844: return "OR";
1845: case AND:
1846: return "AND";
1847: case NOT:
1848: return "NOT";
1849: case BETWEEN:
1850: return "BETWEEN";
1851: case TRUE:
1852: return "TRUE";
1853: case FALSE:
1854: return "FALSE";
1855: case NULL:
1856: return "NULL";
1857: case GROUP:
1858: return "GROUP";
1859: case ORDER:
1860: return "ORDER";
1861: case BY:
1862: return "BY";
1863: case ASC:
1864: return "ASC";
1865: case DESC:
1866: return "DESC";
1867: case LIMIT:
1868: return "LIMIT";
1869:
1870: case -1:
1871: return L.l("end of query");
1872:
1873: default:
1874: if (token < 128)
1875: return "'" + String.valueOf((char) token) + "'";
1876: else
1877: return "'" + _lexeme + "'";
1878: }
1879: }
1880:
1881: private SQLException error(String msg) {
1882: return new SQLParseException(msg + "\n" + _sql);
1883: }
1884:
1885: static {
1886: _reserved = new IntMap();
1887: _reserved.put("as", AS);
1888: _reserved.put("from", FROM);
1889: _reserved.put("in", IN);
1890: _reserved.put("select", SELECT);
1891: _reserved.put("distinct", DISTINCT);
1892: _reserved.put("where", WHERE);
1893: _reserved.put("order", ORDER);
1894: _reserved.put("group", GROUP);
1895: _reserved.put("by", BY);
1896: _reserved.put("asc", ASC);
1897: _reserved.put("desc", DESC);
1898: _reserved.put("limit", LIMIT);
1899: _reserved.put("offset", OFFSET);
1900:
1901: _reserved.put("or", OR);
1902: _reserved.put("and", AND);
1903: _reserved.put("not", NOT);
1904:
1905: _reserved.put("between", BETWEEN);
1906: _reserved.put("like", LIKE);
1907: _reserved.put("escape", ESCAPE);
1908: _reserved.put("is", IS);
1909:
1910: _reserved.put("true", TRUE);
1911: _reserved.put("false", FALSE);
1912: _reserved.put("unknown", UNKNOWN);
1913: _reserved.put("null", NULL);
1914:
1915: _reserved.put("create", CREATE);
1916: _reserved.put("table", TABLE);
1917: _reserved.put("insert", INSERT);
1918: _reserved.put("into", INTO);
1919: _reserved.put("values", VALUES);
1920: _reserved.put("drop", DROP);
1921: _reserved.put("update", UPDATE);
1922: _reserved.put("set", SET);
1923: _reserved.put("delete", DELETE);
1924:
1925: _reserved.put("constraint", CONSTRAINT);
1926: _reserved.put("unique", UNIQUE);
1927: _reserved.put("check", CHECK);
1928: _reserved.put("primary", PRIMARY);
1929: _reserved.put("key", KEY);
1930: _reserved.put("foreign", FOREIGN);
1931: }
1932: }
|