📄 select.java
字号:
/*
* Select.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 Select {
boolean bDistinct;
TableFilter tFilter[];
Expression eCondition; // null means no condition
Expression eColumn[]; // 'result', 'group' and 'order' columns
int iResultLen; // number of columns that are 'result'
int iGroupLen; // number of columns that are 'group'
int iOrderLen; // number of columns that are 'order'
Select sUnion; // null means no union select
String sIntoTable; // null means not select..into
int iUnionType;
final static int UNION = 1, UNIONALL = 2, INTERSECT = 3, EXCEPT = 4;
// fredt@users.sourceforge.net begin changes from 1.50
int limitStart = 0;
int limitCount = -1;
// fredt@users.sourceforge.net end changes from 1.50
/**
* Method declaration
*
*
* @throws SQLException
*/
void resolve() throws SQLException {
int len = tFilter.length;
for (int i = 0; i < len; i++) {
resolve(tFilter[i], true);
}
}
/**
* Method declaration
*
*
* @param f
* @param ownfilter
*
* @throws SQLException
*/
void resolve(TableFilter f, boolean ownfilter) throws SQLException {
if (eCondition != null) {
// first set the table filter in the condition
eCondition.resolve(f);
if (f != null && ownfilter) {
// the table filter tries to get as many conditions as possible
// but only if the table filter belongs to this query
f.setCondition(eCondition);
}
}
int len = eColumn.length;
for (int i = 0; i < len; i++) {
eColumn[i].resolve(f);
}
}
/**
* Method declaration
*
*
* @throws SQLException
*/
void checkResolved() throws SQLException {
if (eCondition != null) {
eCondition.checkResolved();
}
int len = eColumn.length;
for (int i = 0; i < len; i++) {
eColumn[i].checkResolved();
}
}
/**
* Method declaration
*
*
* @param type
*
* @return
*
* @throws SQLException
*/
Object getValue(int type) throws SQLException {
resolve();
Result r = getResult(2); // 2 records are (already) too much
int size = r.getSize();
int len = r.getColumnCount();
Trace.check(size == 1 && len == 1, Trace.SINGLE_VALUE_EXPECTED);
Object o = r.rRoot.data[0];
if (r.iType[0] == type) {
return o;
}
String s = Column.convertObject(o);
return Column.convertString(s, type);
}
/**
* Method declaration
*
*
* @param maxrows
*
* @return
*
* @throws SQLException
*/
Result getResult(int maxrows) throws SQLException {
// fredt@users.sourceforge.net begin changes from 1.50
return getResult( 0, maxrows );
}
// fredt@users.sourceforge.net end changes from 1.50
// fredt@users.sourceforge.net begin changes from 1.50
Result getResult(int start, int cnt) throws SQLException {
int maxrows=start+cnt; //<-new, cut definitly
// fredt@users.sourceforge.net begin changes from 1.50
resolve();
checkResolved();
if (sUnion != null && sUnion.iResultLen != iResultLen) {
throw Trace.error(Trace.COLUMN_COUNT_DOES_NOT_MATCH);
}
int len = eColumn.length;
Result r = new Result(len);
boolean aggregated = false;
boolean grouped = false;
for (int i = 0; i < len; i++) {
Expression e = eColumn[i];
r.iType[i] = e.getDataType();
if (e.isAggregate()) {
aggregated = true;
}
}
Object agg[] = null;
if (aggregated) {
agg = new Object[len];
}
if (iGroupLen > 0) { // has been set in Parser
grouped = true;
}
boolean simple_maxrows = false;
if (maxrows != 0 && grouped == false && sUnion == null
&& iOrderLen == 0) {
simple_maxrows = true;
} else {
simple_maxrows = false;
}
int count = 0;
int filter = tFilter.length;
boolean first[] = new boolean[filter];
int level = 0;
while (level >= 0) {
TableFilter t = tFilter[level];
boolean found;
if (!first[level]) {
found = t.findFirst();
first[level] = found;
} else {
found = t.next();
first[level] = found;
}
if (!found) {
level--;
continue;
}
if (level < filter - 1) {
level++;
continue;
}
if (eCondition == null || eCondition.test()) {
Object row[] = new Object[len];
for (int i = 0; i < len; i++) {
row[i] = eColumn[i].getValue();
}
count++;
if (aggregated) {
updateAggregateRow(agg, row, len);
// fredt@users.sourceforge.net 20010701
// bug fix for 416144 416146 430615 by fredt
if ( grouped )
r.add(row);
} else {
r.add(row);
if (simple_maxrows && count >= maxrows) {
break;
}
}
}
}
if (aggregated &&!grouped) {
addAggregateRow(r, agg, len, count);
} else if (grouped) {
int order[] = new int[iGroupLen];
int way[] = new int[iGroupLen];
for (int i = iResultLen, j = 0; j < iGroupLen; i++, j++) {
order[j] = i;
way[j] = 1;
}
r = sortResult(r, order, way);
Record n = r.rRoot;
Result x = new Result(len);
for (int i = 0; i < len; i++) {
x.iType[i] = r.iType[i];
}
do {
Object row[] = new Object[len];
count = 0;
boolean newgroup = false;
while (n != null && newgroup == false) {
count++;
for (int i = 0; i < iGroupLen; i++) {
if (n.next == null) {
newgroup = true;
} else if (Column.compare(n.data[i], n.next.data[i], r.iType[i])
!= 0) {
// can't use .equals because 'null' is also one group
newgroup = true;
}
}
updateAggregateRow(row, n.data, len);
n = n.next;
}
addAggregateRow(x, row, len, count);
} while (n != null);
r = x;
}
if (iOrderLen != 0) {
int order[] = new int[iOrderLen];
int way[] = new int[iOrderLen];
for (int i = iResultLen, j = 0; j < iOrderLen; i++, j++) {
order[j] = i;
way[j] = eColumn[i].isDescending() ? -1 : 1;
}
r = sortResult(r, order, way);
}
// the result is maybe bigger (due to group and order by)
// but don't tell this anybody else
r.setColumnCount(iResultLen);
if (bDistinct) {
r = removeDuplicates(r);
}
for (int i = 0; i < iResultLen; i++) {
Expression e = eColumn[i];
r.sLabel[i] = e.getAlias();
r.sTable[i] = e.getTableName();
r.sName[i] = e.getColumnName();
}
if (sUnion != null) {
Result x = sUnion.getResult(0);
if (iUnionType == UNION) {
r.append(x);
r = removeDuplicates(r);
} else if (iUnionType == UNIONALL) {
r.append(x);
} else if (iUnionType == INTERSECT) {
r = removeDuplicates(r);
x = removeDuplicates(x);
r = removeDifferent(r, x);
} else if (iUnionType == EXCEPT) {
r = removeDuplicates(r);
x = removeDuplicates(x);
r = removeSecond(r, x);
}
}
if (maxrows > 0 &&!simple_maxrows) {
trimResult(r, maxrows);
}
// fredt@users.sourceforge.net begin changes from 1.50
if (start > 0) { //then cut the first 'start' elements
trimResultFront( r, start );
}
// fredt@users.sourceforge.net end changes from 1.50
return r;
}
/**
* Method declaration
*
*
* @param row
* @param n
* @param len
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -