parser.java
来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,992 行 · 第 1/3 页
JAVA
1,992 行
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */package com.caucho.db.sql;import com.caucho.db.Database;import com.caucho.db.table.Column;import com.caucho.db.table.Table;import com.caucho.db.table.TableFactory;import com.caucho.log.Log;import com.caucho.util.CharBuffer;import com.caucho.util.IntMap;import com.caucho.util.L10N;import java.sql.SQLException;import java.util.ArrayList;import java.util.HashSet;import java.util.logging.Level;import java.util.logging.Logger;public class Parser { private static final Logger log = Log.open(Parser.class); private static final L10N L = new L10N(Parser.class); final static int IDENTIFIER = 128; final static int INTEGER = IDENTIFIER + 1; final static int LONG = INTEGER + 1; final static int DOUBLE = LONG + 1; final static int STRING = DOUBLE + 1; final static int TRUE = STRING + 1; final static int FALSE = TRUE + 1; final static int UNKNOWN = FALSE + 1; final static int NULL = UNKNOWN + 1; final static int EXISTS = NULL + 1; final static int FROM = EXISTS + 1; final static int IN = FROM + 1; final static int SELECT = IN + 1; final static int DISTINCT = SELECT + 1; final static int WHERE = SELECT + 1; final static int AS = WHERE + 1; final static int ORDER = AS + 1; final static int GROUP = ORDER + 1; final static int BY = GROUP + 1; final static int ASC = BY + 1; final static int DESC = ASC + 1; final static int LIMIT = DESC + 1; final static int OFFSET = LIMIT + 1; final static int BETWEEN = OFFSET + 1; final static int LIKE = BETWEEN + 1; final static int ESCAPE = LIKE + 1; final static int IS = ESCAPE + 1; final static int CONCAT = IS + 1; final static int EQ = CONCAT + 1; final static int NE = EQ + 1; final static int LT = NE + 1; final static int LE = LT + 1; final static int GT = LE + 1; final static int GE = GT + 1; final static int AND = GE + 1; final static int OR = AND + 1; final static int NOT = OR + 1; final static int ARG = NOT + 1; final static int CREATE = ARG + 1; final static int TABLE = CREATE + 1; final static int INSERT = TABLE + 1; final static int INTO = INSERT + 1; final static int VALUES = INTO + 1; final static int DROP = VALUES + 1; final static int UPDATE = DROP + 1; final static int SET = UPDATE + 1; final static int DELETE = SET + 1; final static int CONSTRAINT = DELETE + 1; final static int UNIQUE = CONSTRAINT + 1; final static int PRIMARY = UNIQUE + 1; final static int CHECK = PRIMARY + 1; final static int FOREIGN = CHECK + 1; final static int KEY = FOREIGN + 1; private final static IntMap _reserved; private Database _database; private final String _sql; private final char []_sqlChars; private final int _sqlLength; private int _parseIndex; private final CharBuffer _cb = new CharBuffer(); private String _lexeme; private int _token; private ArrayList<ParamExpr> _params = new ArrayList<ParamExpr>(); private Query _query; private AndExpr _andExpr; private Parser(Database database, String sql) { _database = database; _sql = sql; _sqlLength = _sql.length(); _sqlChars = new char[_sqlLength]; _sql.getChars(0, _sqlLength, _sqlChars, 0); } public static Query parse(Database database, String sql) throws SQLException { Parser parser = new Parser(database, sql); Query query = parser.parse(); query.bind(); return query; } public static Expr parseExpr(Database database, String sql) throws SQLException { Parser parser = new Parser(database, sql); Expr expr = parser.parseExpr(); return expr.bind(null); } /** * Parses the query. */ private Query parse() throws SQLException { int token = scanToken(); switch (token) { case SELECT: return parseSelect(); case CREATE: return parseCreate(); case INSERT: return parseInsert(); case DELETE: return parseDelete(); case DROP: return parseDrop(); case UPDATE: return parseUpdate(); default: throw new SQLParseException(L.l("unknown query at `{0}'", tokenName(token))); } } /** * Parses the select. */ private SelectQuery parseSelect() throws SQLException { return parseSelect(new SelectQuery(_database, _sql)); } /** * Parses the select. */ private SelectQuery parseSelect(SelectQuery query) throws SQLException { boolean distinct = false; int token = scanToken(); if (token == DISTINCT) distinct = true; else _token = token; ArrayList<Expr> resultItems = new ArrayList<Expr>(); int startToken = scanToken(); String startLexeme = _lexeme; int startOffset = _parseIndex; while ((token = scanToken()) >= 0 && token != FROM) { } if (token != FROM) throw error(L.l("expected FROM at `{0}'", tokenName(token))); query.setParent(_query); _query = query; AndExpr oldAnd = _andExpr; _andExpr = new AndExpr(); ArrayList<FromItem> fromItems = parseFromItems(); query.setFromItems(fromItems); token = scanToken(); int tailToken = token; int tailOffset = _parseIndex; _token = startToken; _parseIndex = startOffset; _lexeme = startLexeme; Expr expr = parseSelectExpr(); resultItems.add(expr); while ((token = scanToken()) == ',') { expr = parseSelectExpr(); resultItems.add(expr); } _token = tailToken; _parseIndex = tailOffset; token = scanToken(); if (token == WHERE) _andExpr.add(parseExpr()); else _token = token; ParamExpr []params = _params.toArray(new ParamExpr[_params.size()]); Expr whereExpr = _andExpr.getSingleExpr(); _andExpr = null; query.setWhereExpr(whereExpr); query.setParams(params); for (int i = resultItems.size() - 1; i >= 0; i--) { Expr subExpr = resultItems.get(i); if (subExpr instanceof UnboundStarExpr) { UnboundStarExpr unboundExpr = (UnboundStarExpr) subExpr; ArrayList<Expr> exprList = unboundExpr.expand(query.getFromItems()); resultItems.remove(i); resultItems.addAll(i, exprList); } } ArrayList<Expr> groupItems = null; token = scanToken(); if (token == GROUP) { token = scanToken(); if (token != BY) throw error(L.l("expected BY at `{0}'", tokenName(token))); groupItems = parseGroup(query); } else _token = token; token = scanToken(); if (token == ORDER) { token = scanToken(); if (token != BY) throw error(L.l("expected BY at `{0}'", tokenName(token))); Order order = parseOrder(query, resultItems); } else _token = token; Expr []resultArray = resultItems.toArray(new Expr[resultItems.size()]); query.setResults(resultArray); if (query.isGroup()) { Expr []resultList = query.getResults(); bindGroup(query, groupItems); for (int i = 0; i < resultList.length; i++) { Expr subExpr = resultList[i]; if (! (subExpr instanceof GroupExpr)) { resultList[i] = new GroupResultExpr(i, subExpr); } } } token = scanToken(); if (token == LIMIT) { parseLimit(query); } else _token = token; if (query.getParent() == null && token >= 0 && token != LIMIT && token != OFFSET) throw error(L.l("unexpected token at end '{0}'", tokenName(token))); _query = query.getParent(); _andExpr = oldAnd; return query; } private ArrayList<FromItem> parseFromItems() throws SQLException { ArrayList<FromItem> fromItems = new ArrayList<FromItem>(); int token; // XXX: somewhat hacked syntax while ((token = scanToken()) == '(') { } _token = token; FromItem fromItem = parseFromItem(); if (fromItem != null) fromItems.add(fromItem); while (true) { token = scanToken(); boolean isNatural = false; boolean isOuter = false; boolean isLeft = true; boolean isRight = true; if (token == ',') { fromItem = parseFromItem(); fromItems.add(fromItem); continue; } else if (token == '(' || token == ')') continue; else if (token != IDENTIFIER) { _token = token; break; } else if ("join".equalsIgnoreCase(_lexeme)) { } else if ("inner".equalsIgnoreCase(_lexeme)) { String join = parseIdentifier(); if (! "join".equalsIgnoreCase(join)) throw error(L.l("expected JOIN at '{0}'", join)); } else if ("left".equalsIgnoreCase(_lexeme)) { String name = parseIdentifier(); if ("outer".equalsIgnoreCase(name)) name = parseIdentifier(); if (! "join".equalsIgnoreCase(name)) throw error(L.l("expected JOIN at '{0}'", name)); isOuter = true; } else if ("right".equalsIgnoreCase(_lexeme)) { String name = parseIdentifier(); if ("outer".equalsIgnoreCase(name)) name = parseIdentifier(); if (! "join".equalsIgnoreCase(name)) throw error(L.l("expected JOIN at '{0}'", name)); isRight = true; isOuter = true; throw error(L.l("right outer joins are not supported")); } else if ("natural".equalsIgnoreCase(_lexeme)) { String name = parseIdentifier(); isNatural = true; if ("left".equalsIgnoreCase(name)) { name = parseIdentifier(); if ("outer".equalsIgnoreCase(name)) name = parseIdentifier(); isOuter = true; } else if ("right".equalsIgnoreCase(name)) { name = parseIdentifier(); if ("outer".equalsIgnoreCase(name)) name = parseIdentifier(); isRight = true; isOuter = true; throw error(L.l("right outer joins are not supported")); } if (! "join".equalsIgnoreCase(name)) throw error(L.l("expected JOIN at '{0}'", name)); } else { _token = token; break; } fromItem = parseFromItem(); fromItems.add(fromItem); _query.setFromItems(fromItems); token = scanToken(); if (token == IDENTIFIER && "on".equalsIgnoreCase(_lexeme)) { Expr onExpr = parseExpr(); if (isOuter) { FromItem leftItem = fromItems.get(fromItems.size() - 2); FromItem rightItem = fromItems.get(fromItems.size() - 1); onExpr = new LeftOuterJoinExpr(rightItem, onExpr); rightItem.setDependTable(leftItem); } _andExpr.add(onExpr); } else _token = token; } return fromItems; } /** * Parses a select expression. */ private Expr parseSelectExpr() throws SQLException { int token = scanToken(); if (token == '*') return new UnboundStarExpr(); else { _token = token; return parseExpr(); } } /** * Parses a from item */ private FromItem parseFromItem() throws SQLException { String tableName = parseIdentifier(); if (tableName.equalsIgnoreCase("DUAL")) return null; Table table = _database.getTable(tableName); if (table == null) throw error(L.l("'{0}' is an unknown table. 'FROM table' requires an existing table.", tableName)); String name = table.getName(); int token = scanToken(); if (token == AS) name = parseIdentifier(); else if (token == IDENTIFIER) name = _lexeme; else _token = token; return new FromItem(table, name); } /** * Parses the ORDER BY */ private Order parseOrder(SelectQuery query, ArrayList<Expr> resultList) throws SQLException { int token; Order order = null; do { Expr expr = parseExpr(); expr = expr.bind(query); token = scanToken(); boolean isAsc = true; if (token == ASC) isAsc = true; else if (token == DESC) isAsc = false; else _token = token; int index; for (index = 0; index < resultList.size(); index++) { Expr resultExpr = resultList.get(index); if (expr.equals(resultExpr)) break; } if (resultList.size() <= index) { resultList.add(expr); } Order tailOrder = expr.createOrder(index); tailOrder.setAscending(isAsc); order = Order.append(order, tailOrder); // ascList.add(isAsc ? Boolean.TRUE : Boolean.FALSE); } while ((token = scanToken()) == ','); query.setOrder(order); _token = token; return order; } /** * Parses the GROUP BY */ private ArrayList<Expr> parseGroup(SelectQuery query) throws SQLException { query.setGroup(true); int token; ArrayList<Expr> groupList = new ArrayList<Expr>(); do { groupList.add(parseExpr()); } while ((token = scanToken()) == ','); _token = token; return groupList; } /** * Parses the GROUP BY */ private void bindGroup(SelectQuery query, ArrayList<Expr> groupList) throws SQLException { query.setGroup(true); Expr []resultList = query.getResults(); for (int i = 0; i < groupList.size(); i++) { Expr expr = groupList.get(i); expr = expr.bind(query); int index; for (index = 0; index < resultList.length; index++) { Expr resultExpr = resultList[index]; if (expr.equals(resultExpr)) { resultList[index] = new GroupResultExpr(index, resultExpr); break; } } if (resultList.length <= index) { throw error(L.l("GROUP BY field '{0}' must refer to a result field.", expr)); } query.setGroupResult(index); } } /** * Parses the LIMIT */ private void parseLimit(SelectQuery query) throws SQLException { int token = scanToken(); if (token == INTEGER) { query.setLimit(Integer.valueOf(_lexeme)); _token = scanToken(); } else throw error(L.l("LIMIT expected LIMIT int")); } /** * Parses the create. */ private Query parseCreate() throws SQLException { int token; TableFactory factory = _database.createTableFactory(); if ((token = scanToken()) != TABLE) throw error(L.l("expected TABLE at `{0}'", tokenName(token))); if ((token = scanToken()) != IDENTIFIER) throw error(L.l("expected identifier at `{0}'", tokenName(token))); factory.startTable(_lexeme);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?