帆软使用的第三方框架。
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.
 
 

271 lines
8.0 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.Error;
import com.fr.third.org.hsqldb.error.ErrorCode;
import com.fr.third.org.hsqldb.lib.ArrayUtil;
import com.fr.third.org.hsqldb.map.ValuePool;
import com.fr.third.org.hsqldb.navigator.RowSetNavigator;
import com.fr.third.org.hsqldb.navigator.RowSetNavigatorData;
import com.fr.third.org.hsqldb.persist.PersistentStore;
import com.fr.third.org.hsqldb.result.Result;
import com.fr.third.org.hsqldb.types.RowType;
import com.fr.third.org.hsqldb.types.Type;
/**
* Implementation of table conversion.
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 2.3.4
* @since 2.0.0
*/
public class ExpressionTable extends Expression {
boolean isTable;
boolean ordinality = false;
/**
* Creates an UNNEST ARRAY or MULTISET expression
*/
ExpressionTable(Expression[] e, boolean ordinality) {
super(OpTypes.TABLE);
nodes = e;
this.ordinality = ordinality;
}
public String getSQL() {
if (isTable) {
return Tokens.T_TABLE;
} else {
return Tokens.T_UNNEST;
}
}
protected String describe(Session session, int blanks) {
StringBuffer sb = new StringBuffer(64);
sb.append('\n');
for (int i = 0; i < blanks; i++) {
sb.append(' ');
}
if (isTable) {
sb.append(Tokens.T_TABLE).append(' ');
} else {
sb.append(Tokens.T_UNNEST).append(' ');
}
sb.append(nodes[LEFT].describe(session, blanks));
return sb.toString();
}
public void resolveTypes(Session session, Expression parent) {
for (int i = 0; i < nodes.length; i++) {
if (nodes[i] != null) {
nodes[i].resolveTypes(session, this);
}
}
if (nodes.length == 1) {
if (nodes[LEFT].dataType.isRowType()) {
if (ordinality) {
throw Error.error(ErrorCode.X_42581, Tokens.T_ORDINALITY);
}
nodeDataTypes =
((RowType) nodes[LEFT].dataType).getTypesArray();
table.prepareTable(session);
table.columnList =
((FunctionSQLInvoked) nodes[LEFT]).routine.getTable()
.columnList;
isTable = true;
return;
}
}
for (int i = 0; i < nodes.length; i++) {
if (!nodes[i].dataType.isArrayType()) {
throw Error.error(ErrorCode.X_42563, Tokens.T_UNNEST);
}
}
int columnCount = ordinality ? nodes.length + 1
: nodes.length;
nodeDataTypes = new Type[columnCount];
for (int i = 0; i < nodes.length; i++) {
nodeDataTypes[i] = nodes[i].dataType.collectionBaseType();
if (nodeDataTypes[i] == null
|| nodeDataTypes[i] == Type.SQL_ALL_TYPES) {
throw Error.error(ErrorCode.X_42567, Tokens.T_UNNEST);
}
}
if (ordinality) {
nodeDataTypes[nodes.length] = Type.SQL_INTEGER;
}
table.prepareTable(session);
}
public Result getResult(Session session) {
switch (opType) {
case OpTypes.TABLE : {
RowSetNavigatorData navigator = table.getNavigator(session);
Result result = Result.newResult(navigator);
result.metaData = table.queryExpression.getMetaData();
return result;
}
default : {
throw Error.runtimeError(ErrorCode.U_S0500, "ExpressionTable");
}
}
}
public Object[] getRowValue(Session session) {
switch (opType) {
case OpTypes.TABLE : {
return table.queryExpression.getValues(session);
}
default :
throw Error.runtimeError(ErrorCode.U_S0500, "Expression");
}
}
Object getValue(Session session, Type type) {
switch (opType) {
case OpTypes.TABLE : {
materialise(session);
Object[] value = table.getValues(session);
if (value.length == 1) {
return value[0];
}
return value;
}
default :
throw Error.runtimeError(ErrorCode.U_S0500, "Expression");
}
}
public Object getValue(Session session) {
return valueData;
}
void insertValuesIntoSubqueryTable(Session session,
PersistentStore store) {
if (isTable) {
insertTableValues(session, store);
} else {
insertArrayValues(session, store);
}
}
private void insertTableValues(Session session, PersistentStore store) {
Result result = nodes[LEFT].getResult(session);
RowSetNavigator nav = result.navigator;
while (nav.hasNext()) {
Object[] data = nav.getNext();
Object[] newdata = (Object[]) ArrayUtil.duplicateArray(data);
Row row = (Row) store.getNewCachedObject(session, newdata, false);
try {
store.indexRow(session, row);
} catch (HsqlException e) {}
}
}
private void insertArrayValues(Session session, PersistentStore store) {
Object[][] array = new Object[nodes.length][];
for (int i = 0; i < array.length; i++) {
Object[] values = (Object[]) nodes[i].getValue(session);
if (values == null) {
values = ValuePool.emptyObjectArray;
}
array[i] = values;
}
for (int i = 0; ; i++) {
boolean isRow = false;
Object[] data = new Object[nodeDataTypes.length];
for (int arrayIndex = 0; arrayIndex < array.length; arrayIndex++) {
if (i < array[arrayIndex].length) {
data[arrayIndex] = array[arrayIndex][i];
isRow = true;
}
}
if (!isRow) {
break;
}
if (ordinality) {
data[nodes.length] = ValuePool.getInt(i + 1);
}
Row row = (Row) store.getNewCachedObject(session, data, false);
store.indexRow(session, row);
}
}
}