📄 parser.java
字号:
/*
* Parser.java
*
* Copyright (c) 2001, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This package is based on HypersonicSQL, originally developed by Thomas Mueller.
*
*/
package org.hsqldb;
import java.util.*;
import java.sql.*;
/**
* Class declaration
*
*
* @version 1.0.0.1
*/
class Parser {
private Database dDatabase;
private Tokenizer tTokenizer;
private Channel cChannel;
private String sTable;
private String sToken;
private Object oData;
private int iType;
private int iToken;
/**
* Constructor declaration
*
*
* @param db
* @param t
* @param channel
*/
Parser(Database db, Tokenizer t, Channel channel) {
dDatabase = db;
tTokenizer = t;
cChannel = channel;
}
/**
* Method declaration
*
*
* @return
*
* @throws SQLException
*/
Result processSelect() throws SQLException {
Select select = parseSelect();
if (select.sIntoTable == null) {
// fredt@users.sourceforge.net begin changes from 1.50
// return select.getResult(cChannel.getMaxRows());
return select.getResult( select.limitStart, select.limitCount );
// fredt@users.sourceforge.net end changes from 1.50
} else {
Result r = select.getResult(0);
Table t = new Table(dDatabase, true, select.sIntoTable, false);
t.addColumns(r);
t.createPrimaryKey();
// SELECT .. INTO can't fail because of violation of primary key
t.insert(r, cChannel);
dDatabase.linkTable(t);
int i = r.getSize();
r = new Result();
r.iUpdateCount = i;
return r;
}
}
/**
* Method declaration
*
*
* @return
*
* @throws SQLException
*/
Result processCall() throws SQLException {
Expression e = parseExpression();
e.resolve(null);
int type = e.getDataType();
Object o = e.getValue();
Result r = new Result(1);
r.sTable[0] = "";
r.iType[0] = type;
r.sLabel[0] = "";
r.sName[0] = "";
Object row[] = new Object[1];
row[0] = o;
r.add(row);
return r;
}
/**
* Method declaration
*
*
* @return
*
* @throws SQLException
*/
Result processUpdate() throws SQLException {
String token = tTokenizer.getString();
cChannel.checkReadWrite();
cChannel.check(token, Access.UPDATE);
Table table = dDatabase.getTable(token, cChannel);
TableFilter filter = new TableFilter(table, null, false);
tTokenizer.getThis("SET");
Vector vColumn = new Vector();
Vector eColumn = new Vector();
int len = 0;
token = null;
do {
len++;
int i = table.getColumnNr(tTokenizer.getString());
vColumn.addElement(new Integer(i));
tTokenizer.getThis("=");
Expression e = parseExpression();
e.resolve(filter);
eColumn.addElement(e);
token = tTokenizer.getString();
} while (token.equals(","));
Expression eCondition = null;
if (token.equals("WHERE")) {
eCondition = parseExpression();
eCondition.resolve(filter);
filter.setCondition(eCondition);
} else {
tTokenizer.back();
}
// do the update
table.fireAll(TriggerDef.UPDATE_BEFORE);
Expression exp[] = new Expression[len];
eColumn.copyInto(exp);
int col[] = new int[len];
int type[] = new int[len];
for (int i = 0; i < len; i++) {
col[i] = ((Integer) vColumn.elementAt(i)).intValue();
type[i] = table.getType(col[i]);
}
int count = 0;
if (filter.findFirst()) {
Result del = new Result(); // don't need column count and so on
Result ins = new Result();
int size = table.getColumnCount();
do {
if (eCondition == null || eCondition.test()) {
Object nd[] = filter.oCurrentData;
del.add(nd);
Object ni[] = table.getNewRow();
for (int i = 0; i < size; i++) {
ni[i] = nd[i];
}
for (int i = 0; i < len; i++) {
ni[col[i]] = exp[i].getValue(type[i]);
}
ins.add(ni);
}
} while (filter.next());
cChannel.beginNestedTransaction();
try {
Record nd = del.rRoot;
while (nd != null) {
table.fireAll(TriggerDef.UPDATE_BEFORE_ROW, nd.data);
table.deleteNoCheck(nd.data, cChannel);
nd = nd.next;
}
Record ni = ins.rRoot;
while (ni != null) {
table.insertNoCheck(ni.data, cChannel);
ni = ni.next;
count++;
}
table.checkUpdate(col, del, ins);
ni = ins.rRoot;
while (ni
!= null) { // fire triggers now that update has been checked
table.fireAll(TriggerDef.UPDATE_AFTER_ROW, ni.data);
ni = ni.next;
}
cChannel.endNestedTransaction(false);
} catch (SQLException e) {
// update failed (violation of primary key / referential integrity)
cChannel.endNestedTransaction(true);
throw e;
}
}
table.fireAll(TriggerDef.UPDATE_AFTER);
Result r = new Result();
r.iUpdateCount = count;
return r;
}
/**
* Method declaration
*
*
* @return
*
* @throws SQLException
*/
Result processDelete() throws SQLException {
tTokenizer.getThis("FROM");
String token = tTokenizer.getString();
cChannel.checkReadWrite();
cChannel.check(token, Access.DELETE);
Table table = dDatabase.getTable(token, cChannel);
TableFilter filter = new TableFilter(table, null, false);
token = tTokenizer.getString();
Expression eCondition = null;
if (token.equals("WHERE")) {
eCondition = parseExpression();
eCondition.resolve(filter);
filter.setCondition(eCondition);
} else {
tTokenizer.back();
}
table.fireAll(TriggerDef.DELETE_BEFORE);
int count = 0;
if (filter.findFirst()) {
Result del = new Result(); // don't need column count and so on
do {
if (eCondition == null || eCondition.test()) {
del.add(filter.oCurrentData);
}
} while (filter.next());
Record n = del.rRoot;
while (n != null) {
table.delete(n.data, cChannel);
count++;
n = n.next;
}
}
table.fireAll(TriggerDef.DELETE_AFTER);
Result r = new Result();
r.iUpdateCount = count;
return r;
}
/**
* Method declaration
*
*
* @return
*
* @throws SQLException
*/
Result processInsert() throws SQLException {
tTokenizer.getThis("INTO");
String token = tTokenizer.getString();
cChannel.checkReadWrite();
cChannel.check(token, Access.INSERT);
Table t = dDatabase.getTable(token, cChannel);
token = tTokenizer.getString();
Vector vcolumns = null;
if (token.equals("(")) {
vcolumns = new Vector();
int i = 0;
while (true) {
vcolumns.addElement(tTokenizer.getString());
i++;
token = tTokenizer.getString();
if (token.equals(")")) {
break;
}
if (!token.equals(",")) {
throw Trace.error(Trace.UNEXPECTED_TOKEN, token);
}
}
token = tTokenizer.getString();
}
int count = 0;
int len;
if (vcolumns == null) {
len = t.getColumnCount();
} else {
len = vcolumns.size();
}
if (token.equals("VALUES")) {
tTokenizer.getThis("(");
Object row[] = t.getNewRow();
int i = 0;
while (true) {
int column;
if (vcolumns == null) {
column = i;
if (i > len) {
throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
}
} else {
column = t.getColumnNr((String) vcolumns.elementAt(i));
}
row[column] = getValue(t.getType(column));
i++;
token = tTokenizer.getString();
if (token.equals(")")) {
break;
}
if (!token.equals(",")) {
throw Trace.error(Trace.UNEXPECTED_TOKEN, token);
}
}
t.insert(row, cChannel);
count = 1;
} else if (token.equals("SELECT")) {
Result result = processSelect();
Record r = result.rRoot;
Trace.check(len == result.getColumnCount(),
Trace.COLUMN_COUNT_DOES_NOT_MATCH);
int col[] = new int[len];
int type[] = new int[len];
for (int i = 0; i < len; i++) {
int j;
if (vcolumns == null) {
j = i;
} else {
j = t.getColumnNr((String) vcolumns.elementAt(i));
}
col[i] = j;
type[i] = t.getType(j);
}
cChannel.beginNestedTransaction();
try {
while (r != null) {
Object row[] = t.getNewRow();
for (int i = 0; i < len; i++) {
row[col[i]] = Column.convertObject(r.data[i],
type[i]);
}
t.insert(row, cChannel);
count++;
r = r.next;
}
cChannel.endNestedTransaction(false);
} catch (SQLException e) {
// insert failed (violation of primary key)
cChannel.endNestedTransaction(true);
throw e;
}
} else {
throw Trace.error(Trace.UNEXPECTED_TOKEN, token);
}
Result r = new Result();
r.iUpdateCount = count;
return r;
}
/**
* Method declaration
*
*
* @return
*
* @throws SQLException
*/
private Select parseSelect() throws SQLException {
Select select = new Select();
// fredt@users.sourceforge.net begin changes from 1.50
select.limitStart = 0;
select.limitCount = cChannel.getMaxRows();
// fredt@users.sourceforge.net end changes from 1.50
String token = tTokenizer.getString();
if (token.equals("DISTINCT")) {
select.bDistinct = true;
// fredt@users.sourceforge.net begin changes from 1.50
} else if( token.equals("LIMIT")) {
String limStart = tTokenizer.getString();
String limEnd = tTokenizer.getString();
//System.out.println( "LIMIT used from "+limStart+","+limEnd);
select.limitStart = new Integer(limStart).intValue();
select.limitCount = new Integer(limEnd).intValue();
// fredt@users.sourceforge.net end changes from 1.50
} else {
tTokenizer.back();
}
// parse column list
Vector vcolumn = new Vector();
do {
Expression e = parseExpression();
token = tTokenizer.getString();
if (token.equals("AS")) {
e.setAlias(tTokenizer.getName());
token = tTokenizer.getString();
} else if (tTokenizer.wasName()) {
e.setAlias(token);
token = tTokenizer.getString();
}
vcolumn.addElement(e);
} while (token.equals(","));
if (token.equals("INTO")) {
select.sIntoTable = tTokenizer.getString();
token = tTokenizer.getString();
}
if (!token.equals("FROM")) {
throw Trace.error(Trace.UNEXPECTED_TOKEN, token);
}
Expression condition = null;
// parse table list
Vector vfilter = new Vector();
vfilter.addElement(parseTableFilter(false));
while (true) {
token = tTokenizer.getString();
if (token.equals("LEFT")) {
token = tTokenizer.getString();
if (token.equals("OUTER")) {
token = tTokenizer.getString();
}
Trace.check(token.equals("JOIN"), Trace.UNEXPECTED_TOKEN,
token);
vfilter.addElement(parseTableFilter(true));
tTokenizer.getThis("ON");
condition = addCondition(condition, parseExpression());
} else if (token.equals("INNER")) {
tTokenizer.getThis("JOIN");
vfilter.addElement(parseTableFilter(false));
tTokenizer.getThis("ON");
condition = addCondition(condition, parseExpression());
} else if (token.equals(",")) {
vfilter.addElement(parseTableFilter(false));
} else {
break;
}
}
tTokenizer.back();
int len = vfilter.size();
TableFilter filter[] = new TableFilter[len];
vfilter.copyInto(filter);
select.tFilter = filter;
// expand [table.]* columns
len = vcolumn.size();
for (int i = 0; i < len; i++) {
Expression e = (Expression) (vcolumn.elementAt(i));
if (e.getType() == Expression.ASTERIX) {
int current = i;
Table table = null;
String n = e.getTableName();
for (int t = 0; t < filter.length; t++) {
TableFilter f = filter[t];
e.resolve(f);
if (n != null &&!n.equals(f.getName())) {
continue;
}
table = f.getTable();
int col = table.getColumnCount();
for (int c = 0; c < col; c++) {
Expression ins =
new Expression(f.getName(),
table.getColumnName(c));
vcolumn.insertElementAt(ins, current++);
// now there is one element more to parse
len++;
}
}
Trace.check(table != null, Trace.TABLE_NOT_FOUND, n);
// minus the asterix element
len--;
vcolumn.removeElementAt(current);
}
else if (e.getType()==Expression.COLUMN){
if (e.getTableName() == null) {
for (int filterIndex=0; filterIndex < filter.length; filterIndex++) {
e.resolve(filter[filterIndex]);
}
}
}
}
select.iResultLen = len;
// where
token = tTokenizer.getString();
if (token.equals("WHERE")) {
condition = addCondition(condition, parseExpression());
token = tTokenizer.getString();
}
select.eCondition = condition;
if (token.equals("GROUP")) {
tTokenizer.getThis("BY");
len = 0;
do {
vcolumn.addElement(parseExpression());
token = tTokenizer.getString();
len++;
} while (token.equals(","));
select.iGroupLen = len;
}
if (token.equals("ORDER")) {
tTokenizer.getThis("BY");
len = 0;
do {
Expression e = parseExpression();
if (e.getType() == Expression.VALUE) {
// order by 1,2,3
if (e.getDataType() == Column.INTEGER) {
int i = ((Integer) e.getValue()).intValue();
e = (Expression) vcolumn.elementAt(i - 1);
}
} else if (e.getType() == Expression.COLUMN
&& e.getTableName() == null) {
// this could be an alias column
String s = e.getColumnName();
for (int i = 0; i < vcolumn.size(); i++) {
Expression ec = (Expression) vcolumn.elementAt(i);
if (s.equals(ec.getAlias())) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -