in HSQL/src/org/hsqldb1/Parser.java [392:729]
Select parseSelect(int brackets, boolean canHaveOrder,
boolean canHaveLimit, boolean limitWithOrder,
boolean isMain) throws HsqlException {
Select select = new Select();
String token = tokenizer.getString();
if (canHaveLimit || limitWithOrder) {
if (tokenizer.wasThis(Token.T_LIMIT)
|| tokenizer.wasThis(Token.T_TOP)) {
parseLimit(token, select, false);
token = tokenizer.getString();
}
}
if (tokenizer.wasThis(Token.T_DISTINCT)) {
select.isDistinctSelect = true;
} else if (tokenizer.wasThis(Token.T_ALL)) {}
else {
tokenizer.back();
}
// parse column list
HsqlArrayList vcolumn = new HsqlArrayList();
do {
int expPos = tokenizer.getPosition();
Expression e = parseExpression();
if (isCompilingView()) {
if (e.getType() == Expression.ASTERISK) {
if (select.asteriskPositions == null) {
select.asteriskPositions = new IntKeyHashMap();
}
// remember the position of the asterisk. For the moment, just
// remember the expression, so it can later be found and replaced
// with the concrete column list
select.asteriskPositions.put(expPos, e);
}
}
token = tokenizer.getString();
if (tokenizer.wasThis(Token.T_AS)) {
e.setAlias(tokenizer.getSimpleName(),
tokenizer.wasQuotedIdentifier());
token = tokenizer.getString();
} else if (tokenizer.wasSimpleName()) {
e.setAlias(token, tokenizer.wasQuotedIdentifier());
token = tokenizer.getString();
}
vcolumn.add(e);
} while (tokenizer.wasThis(Token.T_COMMA));
if (token.equals(Token.T_INTO)) {
boolean getname = true;
token = tokenizer.getString();
select.intoType = database.getDefaultTableType();
if (tokenizer.wasSimpleToken()) {
switch (Token.get(token)) {
case Token.CACHED :
select.intoType = Table.CACHED_TABLE;
break;
case Token.TEMP :
select.intoType = Table.TEMP_TABLE;
break;
case Token.TEXT :
select.intoType = Table.TEXT_TABLE;
break;
case Token.MEMORY :
select.intoType = Table.MEMORY_TABLE;
break;
default :
getname = false;
break;
}
if (getname) {
token = tokenizer.getName();
}
}
if (!tokenizer.wasName()) {
tokenizer.throwUnexpected();
}
select.sIntoTable = database.nameManager.newHsqlName(token,
tokenizer.wasQuotedIdentifier());
select.sIntoTable.schema =
session.getSchemaHsqlName(tokenizer.getLongNameFirst());
token = tokenizer.getString();
}
tokenizer.matchThis(Token.T_FROM);
Expression condition = null;
// parse table list
HsqlArrayList vfilter = new HsqlArrayList();
vfilter.add(parseTableFilter(false));
while (true) {
token = tokenizer.getString();
boolean cross = false;
if (tokenizer.wasThis(Token.T_INNER)) {
tokenizer.getThis(Token.T_JOIN);
token = Token.T_JOIN;
} else if (tokenizer.wasThis(Token.T_CROSS)) {
tokenizer.getThis(Token.T_JOIN);
token = Token.T_JOIN;
cross = true;
}
if (token.equals(Token.T_LEFT)
&& !tokenizer.wasQuotedIdentifier()) {
tokenizer.isGetThis(Token.T_OUTER);
tokenizer.getThis(Token.T_JOIN);
TableFilter tf = parseTableFilter(true);
vfilter.add(tf);
tokenizer.getThis(Token.T_ON);
Expression newcondition = parseExpression();
newcondition.checkTables(vfilter);
condition = addJoinCondition(condition, newcondition, tf,
true);
// MarcH HuugO RIGHT JOIN SUPPORT
} else if (token.equals(Token.T_RIGHT)
&& !tokenizer.wasQuotedIdentifier()) {
tokenizer.isGetThis(Token.T_OUTER);
tokenizer.getThis(Token.T_JOIN);
// this object is not an outerjoin, the next object is an outerjoin
TableFilter tf = parseTableFilter(false);
// insert new condition as first element in a new vfilter (nvfilter), copy the content of vfilter and rename nvfilter back to vfilter.
HsqlArrayList nvfilter = new HsqlArrayList();
nvfilter.add(tf);
nvfilter.addAll(vfilter);
vfilter = nvfilter;
// set isOuterJoin correct
((TableFilter) vfilter.get(1)).isOuterJoin = true;
tokenizer.getThis(Token.T_ON);
Expression newcondition = parseExpression();
newcondition.checkTables(vfilter);
condition = addJoinCondition(condition, newcondition,
((TableFilter) vfilter.get(1)),
true);
} else if (tokenizer.wasThis(Token.T_JOIN)) {
vfilter.add(parseTableFilter(false));
if (!cross) {
tokenizer.getThis(Token.T_ON);
Expression newcondition = parseExpression();
newcondition.checkTables(vfilter);
condition = addJoinCondition(condition, newcondition,
null, false);
}
} else if (tokenizer.wasThis(Token.T_COMMA)) {
vfilter.add(parseTableFilter(false));
} else {
tokenizer.back();
break;
}
}
resolveSelectTableFilter(select, vcolumn, vfilter);
// where
token = tokenizer.getString();
if (tokenizer.wasThis(Token.T_WHERE)) {
Expression newcondition = parseExpression();
condition = addCondition(condition, newcondition);
token = tokenizer.getString();
}
select.queryCondition = condition;
// group by
if (tokenizer.wasThis(Token.T_GROUP)) {
tokenizer.getThis(Token.T_BY);
int len = 0;
do {
Expression e = parseExpression();
vcolumn.add(e);
token = tokenizer.getString();
len++;
} while (tokenizer.wasThis(Token.T_COMMA));
select.iGroupLen = len;
}
// having
if (tokenizer.wasThis(Token.T_HAVING)) {
select.iHavingLen = 1;
select.havingCondition = parseExpression();
token = tokenizer.getString();
vcolumn.add(select.havingCondition);
}
if (isMain || limitWithOrder) {
if (tokenizer.wasThis(Token.T_ORDER)) {
tokenizer.getThis(Token.T_BY);
parseOrderBy(select, vcolumn);
token = tokenizer.getString();
}
if (tokenizer.wasThis(Token.T_LIMIT)) {
parseLimit(token, select, true);
token = tokenizer.getString();
}
}
boolean closebrackets = false;
if (brackets > 0 && token.equals(Token.T_CLOSEBRACKET)) {
closebrackets = true;
brackets -= parseCloseBrackets(brackets - 1) + 1;
token = tokenizer.getString();
}
select.unionDepth = brackets;
// checks for ORDER and LIMIT
if (!(isMain || closebrackets)) {
limitWithOrder = false;
}
boolean hasOrder = select.iOrderLen != 0;
boolean hasLimit = select.limitCondition != null;
if (limitWithOrder) {
if (hasLimit && !hasOrder) {
throw Trace.error(Trace.ORDER_LIMIT_REQUIRED);
}
} else {
if (hasOrder && !canHaveOrder) {
throw Trace.error(Trace.INVALID_ORDER_BY);
}
if (hasLimit && !canHaveLimit) {
throw Trace.error(Trace.INVALID_LIMIT);
}
}
int unionType = parseUnion(token);
if (unionType != Select.NOUNION) {
boolean openbracket = false;
select.unionType = unionType;
if (tokenizer.isGetThis(Token.T_OPENBRACKET)) {
openbracket = true;
brackets += parseOpenBrackets() + 1;
}
tokenizer.getThis(Token.T_SELECT);
// accept ORDRY BY with LIMIT when in brackets
select.unionSelect = parseSelect(brackets, false, false,
openbracket, false);
token = tokenizer.getString();
}
if (isMain && (canHaveOrder || limitWithOrder)
&& select.iOrderLen == 0) {
if (tokenizer.wasThis(Token.T_ORDER)) {
tokenizer.getThis(Token.T_BY);
parseOrderBy(select, vcolumn);
token = tokenizer.getString();
select.sortUnion = true;
}
if (tokenizer.wasThis(Token.T_LIMIT)) {
parseLimit(token, select, true);
token = tokenizer.getString();
}
}
tokenizer.back();
if (isMain) {
select.prepareUnions();
}
int len = vcolumn.size();
select.exprColumns = new Expression[len];
vcolumn.toArray(select.exprColumns);
return select;
}