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 + -
显示快捷键?