帆软使用的第三方框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

418 lines
12 KiB

/* Copyright (c) 2001-2016, 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 HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* 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.
*/
package com.fr.third.org.hsqldb;
import com.fr.third.org.hsqldb.error.ErrorCode;
import com.fr.third.org.hsqldb.lib.ArrayListIdentity;
import com.fr.third.org.hsqldb.lib.ArrayUtil;
import com.fr.third.org.hsqldb.lib.HsqlArrayList;
import com.fr.third.org.hsqldb.lib.HsqlList;
import com.fr.third.org.hsqldb.types.ArrayType;
import com.fr.third.org.hsqldb.types.RowType;
import com.fr.third.org.hsqldb.error.Error;
import com.fr.third.org.hsqldb.types.Type;
/**
* Implementation of array aggregate operations
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 2.3.3
* @since 2.0.1
*/
public class ExpressionArrayAggregate extends Expression {
SortAndSlice sort;
String separator = ",";
ArrayType arrayDataType;
Type exprType;
Expression condition = Expression.EXPR_TRUE;
ExpressionArrayAggregate(int type, boolean distinct, Expression e,
SortAndSlice sort, String separator) {
super(type);
this.isDistinctAggregate = distinct;
this.sort = sort;
if (separator != null) {
this.separator = separator;
}
if (type == OpTypes.MEDIAN) {
nodes = new Expression[]{ e };
return;
}
if (sort == null) {
nodes = new Expression[]{ e };
} else {
HsqlArrayList list = sort.getExpressionList();
nodes = new Expression[list.size() + 1];
list.toArray(nodes);
nodes[list.size()] = e;
sort.prepare(1);
}
}
boolean isSelfAggregate() {
return true;
}
public String getSQL() {
StringBuffer sb = new StringBuffer(64);
String left = getContextSQL(nodes.length > 0 ? nodes[LEFT]
: null);
switch (opType) {
case OpTypes.ARRAY_AGG :
sb.append(' ').append(Tokens.T_ARRAY_AGG).append('(');
sb.append(left).append(')');
break;
case OpTypes.GROUP_CONCAT :
sb.append(' ').append(Tokens.T_GROUP_CONCAT).append('(');
sb.append(left).append(')');
break;
case OpTypes.MEDIAN :
sb.append(' ').append(Tokens.T_MEDIAN).append('(');
sb.append(left).append(')');
break;
default :
throw Error.runtimeError(ErrorCode.U_S0500,
"ExpressionAggregate");
}
return sb.toString();
}
protected String describe(Session session, int blanks) {
StringBuffer sb = new StringBuffer(64);
sb.append('\n');
for (int i = 0; i < blanks; i++) {
sb.append(' ');
}
switch (opType) {
case OpTypes.ARRAY_AGG :
sb.append(Tokens.T_ARRAY_AGG).append(' ');
break;
case OpTypes.GROUP_CONCAT :
sb.append(Tokens.T_GROUP_CONCAT).append(' ');
break;
case OpTypes.MEDIAN :
sb.append(Tokens.T_MEDIAN).append(' ');
break;
default :
}
if (getLeftNode() != null) {
sb.append(" arg=[");
sb.append(nodes[LEFT].describe(session, blanks + 1));
sb.append(']');
}
return sb.toString();
}
public HsqlList resolveColumnReferences(Session session,
RangeGroup rangeGroup, int rangeCount, RangeGroup[] rangeGroups,
HsqlList unresolvedSet, boolean acceptsSequences) {
HsqlList conditionSet = condition.resolveColumnReferences(session,
rangeGroup, rangeCount, rangeGroups, null, false);
if (conditionSet != null) {
ExpressionColumn.checkColumnsResolved(conditionSet);
}
if (unresolvedSet == null) {
unresolvedSet = new ArrayListIdentity();
}
unresolvedSet.add(this);
if (rangeGroup.getRangeVariables().length > 0) {
this.rangeGroups = rangeGroups;
this.rangeGroup = rangeGroup;
}
return unresolvedSet;
}
public void resolveTypes(Session session, Expression parent) {
nodeDataTypes = new Type[nodes.length];
for (int i = 0; i < nodes.length; i++) {
if (nodes[i] != null) {
nodes[i].resolveTypes(session, this);
if (nodes[i].isUnresolvedParam()) {
throw Error.error(ErrorCode.X_42567);
}
if (nodes[i].dataType == null) {
throw Error.error(ErrorCode.X_42567);
}
nodeDataTypes[i] = nodes[i].dataType;
}
}
exprType = nodes[nodes.length - 1].dataType;
if (exprType.isLobType()) {
throw Error.error(ErrorCode.X_42534);
}
if (exprType.isArrayType()) {
throw Error.error(ErrorCode.X_42534);
}
Type rowDataType = new RowType(nodeDataTypes);
switch (opType) {
case OpTypes.ARRAY_AGG :
arrayDataType =
new ArrayType(rowDataType,
ArrayType.defaultArrayCardinality);
dataType = new ArrayType(exprType,
ArrayType.defaultArrayCardinality);
break;
case OpTypes.GROUP_CONCAT :
arrayDataType =
new ArrayType(rowDataType,
ArrayType.defaultArrayCardinality);
dataType = Type.SQL_VARCHAR_DEFAULT;
break;
case OpTypes.MEDIAN :
arrayDataType =
new ArrayType(nodeDataTypes[0],
ArrayType.defaultArrayCardinality);
dataType = SetFunction.getType(session, OpTypes.MEDIAN,
exprType);
if (!exprType.isNumberType()) {
throw Error.error(ErrorCode.X_42563);
}
break;
}
condition.resolveTypes(session, null);
}
public boolean equals(Expression other) {
if (other instanceof ExpressionArrayAggregate) {
ExpressionArrayAggregate o = (ExpressionArrayAggregate) other;
return super.equals(other) && opType == other.opType
&& exprSubType == other.exprSubType
&& isDistinctAggregate == o.isDistinctAggregate
&& separator.equals(o.separator)
&& condition.equals(o.condition);
}
return false;
}
public Object updateAggregatingValue(Session session, Object currValue) {
if (!condition.testCondition(session)) {
return currValue;
}
Object currentVal = null;
switch (opType) {
case OpTypes.ARRAY_AGG :
case OpTypes.GROUP_CONCAT :
Object[] row = new Object[nodes.length];
for (int i = 0; i < nodes.length; i++) {
row[i] = nodes[i].getValue(session);
}
if (opType == OpTypes.GROUP_CONCAT
&& row[row.length - 1] == null) {
return currValue;
}
currentVal = row;
break;
case OpTypes.MEDIAN :
currentVal = nodes[0].getValue(session);
if (currentVal == null) {
return currValue;
}
break;
}
HsqlArrayList list = (HsqlArrayList) currValue;
if (list == null) {
list = new HsqlArrayList();
}
list.add(currentVal);
return list;
}
public Object getAggregatedValue(Session session, Object currValue) {
if (currValue == null) {
return null;
}
HsqlArrayList list = (HsqlArrayList) currValue;
Object[] array = list.toArray();
if (isDistinctAggregate) {
SortAndSlice exprSort = new SortAndSlice();
exprSort.prepareSingleColumn(nodes.length - 1);
arrayDataType.sort(session, array, exprSort);
int size = arrayDataType.deDuplicate(session, array, exprSort);
array = (Object[]) ArrayUtil.resizeArrayIfDifferent(array, size);
}
if (sort != null) {
arrayDataType.sort(session, array, sort);
}
switch (opType) {
case OpTypes.ARRAY_AGG : {
Object[] resultArray = new Object[array.length];
for (int i = 0; i < list.size(); i++) {
Object[] row = (Object[]) array[i];
resultArray[i] = row[row.length - 1];
}
return resultArray;
}
case OpTypes.GROUP_CONCAT : {
StringBuffer sb = new StringBuffer(16 * list.size());
for (int i = 0; i < array.length; i++) {
if (i > 0) {
sb.append(separator);
}
Object[] row = (Object[]) array[i];
Object value = row[row.length - 1];
String string =
(String) Type.SQL_VARCHAR.convertToType(session,
value, exprType);
sb.append(string);
}
return sb.toString();
}
case OpTypes.MEDIAN : {
SortAndSlice exprSort = new SortAndSlice();
exprSort.prepareSingleColumn(1);
arrayDataType.sort(session, array, exprSort);
boolean even = array.length % 2 == 0;
if (even) {
Object val1 = array[(array.length / 2) - 1];
Object val2 = array[array.length / 2];
Object val3 = dataType.add(session, val1, val2, dataType);
return dataType.divide(session, val3, Integer.valueOf(2));
} else {
return dataType.convertToType(session,
array[array.length / 2],
exprType);
}
}
}
return null;
}
public Expression getCondition() {
return condition;
}
public boolean hasCondition() {
return condition != null && !condition.isTrue();
}
public void setCondition(Expression e) {
condition = e;
}
public Expression duplicate() {
ExpressionArrayAggregate e =
(ExpressionArrayAggregate) super.duplicate();
if (condition != null) {
e.condition = condition.duplicate();
}
return e;
}
}