提交 49ae2b23 authored 作者: Thomas Mueller's avatar Thomas Mueller

SELECT ... FROM CSVREAD no longer creates a temporary file.

上级 079ad67a
......@@ -470,5 +470,4 @@ public class FunctionAlias extends SchemaObjectBase {
}
}
}
......@@ -303,8 +303,8 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotDeterministic("NEXTVAL", NEXTVAL, VAR_ARGS, Value.LONG);
addFunctionNotDeterministic("CURRVAL", CURRVAL, VAR_ARGS, Value.LONG);
addFunction("ARRAY_GET", ARRAY_GET, 2, Value.STRING);
addFunction("CSVREAD", CSVREAD, VAR_ARGS, Value.RESULT_SET, false, false);
addFunction("CSVWRITE", CSVWRITE, VAR_ARGS, Value.INT, false, false);
addFunction("CSVREAD", CSVREAD, VAR_ARGS, Value.RESULT_SET, false, false, true);
addFunction("CSVWRITE", CSVWRITE, VAR_ARGS, Value.INT, false, false, false);
addFunctionNotDeterministic("MEMORY_FREE", MEMORY_FREE, 0, Value.INT);
addFunctionNotDeterministic("MEMORY_USED", MEMORY_USED, 0, Value.INT);
addFunctionNotDeterministic("LOCK_MODE", LOCK_MODE, 0, Value.INT);
......@@ -315,8 +315,8 @@ public class Function extends Expression implements FunctionCall {
addFunctionWithNull("LEAST", LEAST, VAR_ARGS, Value.NULL);
addFunctionWithNull("GREATEST", GREATEST, VAR_ARGS, Value.NULL);
addFunction("CANCEL_SESSION", CANCEL_SESSION, 1, Value.BOOLEAN);
addFunction("SET", SET, 2, Value.NULL, false, false);
addFunction("FILE_READ", FILE_READ, VAR_ARGS, Value.NULL, false, true);
addFunction("SET", SET, 2, Value.NULL, false, false, false);
addFunction("FILE_READ", FILE_READ, VAR_ARGS, Value.NULL, false, true, false);
addFunctionNotDeterministic("TRANSACTION_ID", TRANSACTION_ID, 0, Value.STRING);
// TableFunction
......@@ -335,7 +335,7 @@ public class Function extends Expression implements FunctionCall {
}
private static void addFunction(String name, int type, int parameterCount, int dataType,
boolean nullIfParameterIsNull, boolean deterministic) {
boolean nullIfParameterIsNull, boolean deterministic, boolean fast) {
FunctionInfo info = new FunctionInfo();
info.name = name;
info.type = type;
......@@ -343,19 +343,20 @@ public class Function extends Expression implements FunctionCall {
info.dataType = dataType;
info.nullIfParameterIsNull = nullIfParameterIsNull;
info.deterministic = deterministic;
info.fast = fast;
FUNCTIONS.put(name, info);
}
private static void addFunctionNotDeterministic(String name, int type, int parameterCount, int dataType) {
addFunction(name, type, parameterCount, dataType, true, false);
addFunction(name, type, parameterCount, dataType, true, false, false);
}
private static void addFunction(String name, int type, int parameterCount, int dataType) {
addFunction(name, type, parameterCount, dataType, true, true);
addFunction(name, type, parameterCount, dataType, true, true, false);
}
private static void addFunctionWithNull(String name, int type, int parameterCount, int dataType) {
addFunction(name, type, parameterCount, dataType, false, true);
addFunction(name, type, parameterCount, dataType, false, true, false);
}
/**
......@@ -1224,7 +1225,7 @@ public class Function extends Expression implements FunctionCall {
private static int getDatePart(String part) {
Integer p = DATE_PART.get(StringUtils.toUpperEnglish(part));
if (p == null) {
throw DbException.get(ErrorCode.INVALID_VALUE_2, "date part", part);
throw DbException.getInvalidValueException("date part", part);
}
return p.intValue();
}
......@@ -1986,4 +1987,8 @@ public class Function extends Expression implements FunctionCall {
return info.deterministic;
}
public boolean isFast() {
return info.fast;
}
}
......@@ -82,4 +82,12 @@ public interface FunctionCall {
* @return true if it does
*/
boolean isDeterministic();
/**
* Whether the function is fast, meaning the result shouldn't be cached.
*
* @return true if it is
*/
boolean isFast();
}
......@@ -40,4 +40,10 @@ class FunctionInfo {
* If this function always returns the same value for the same parameters.
*/
boolean deterministic;
/**
* Whether the function is fast, meaning the result shouldn't be cached.
*/
boolean fast;
}
......@@ -164,4 +164,9 @@ public class JavaFunction extends Expression implements FunctionCall {
}
return super.getExpressionColumns(session);
}
public boolean isFast() {
return false;
}
}
......@@ -13,11 +13,11 @@ import org.h2.result.SearchRow;
import org.h2.value.Value;
/**
* A cursor for a function that returns a result set.
* A cursor for a function that returns a result.
*/
public class FunctionCursor implements Cursor {
private ResultInterface result;
private final ResultInterface result;
private Value[] values;
private Row row;
......@@ -41,7 +41,7 @@ public class FunctionCursor implements Cursor {
public boolean next() {
row = null;
if (result.next()) {
if (result != null && result.next()) {
values = result.currentRow();
} else {
values = null;
......
/*
* Copyright 2004-2010 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.index;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.h2.engine.Session;
import org.h2.message.DbException;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.value.DataType;
import org.h2.value.Value;
/**
* A cursor for a function that returns a JDBC result set.
*/
public class FunctionCursorResultSet implements Cursor {
private final Session session;
private final ResultSet result;
private final ResultSetMetaData meta;
private Value[] values;
private Row row;
FunctionCursorResultSet(Session session, ResultSet result) {
this.session = session;
this.result = result;
try {
this.meta = result.getMetaData();
} catch (SQLException e) {
throw DbException.convert(e);
}
}
public Row get() {
if (values == null) {
return null;
}
if (row == null) {
row = new Row(values, 1);
}
return row;
}
public SearchRow getSearchRow() {
return get();
}
public boolean next() {
row = null;
try {
if (result != null && result.next()) {
int columnCount = meta.getColumnCount();
values = new Value[columnCount];
for (int i = 0; i < columnCount; i++) {
int type = DataType.convertSQLTypeToValueType(meta.getColumnType(i + 1));
values[i] = DataType.readValue(session, result, i+1, type);
}
} else {
values = null;
}
} catch (SQLException e) {
throw DbException.convert(e);
}
return values != null;
}
public boolean previous() {
throw DbException.throwInternalError();
}
}
\ No newline at end of file
......@@ -8,7 +8,6 @@ package org.h2.index;
import org.h2.engine.Session;
import org.h2.message.DbException;
import org.h2.result.ResultInterface;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.table.FunctionTable;
......@@ -20,8 +19,7 @@ import org.h2.table.IndexColumn;
*/
public class FunctionIndex extends BaseIndex {
private FunctionTable functionTable;
private ResultInterface result;
private final FunctionTable functionTable;
public FunctionIndex(FunctionTable functionTable, IndexColumn[] columns) {
initBaseIndex(functionTable, 0, null, columns, IndexType.createNonUnique(true));
......@@ -41,10 +39,11 @@ public class FunctionIndex extends BaseIndex {
}
public Cursor find(Session session, SearchRow first, SearchRow last) {
// TODO sometimes result.reset() would be enough (but not when
// parameters are used)
result = functionTable.getResult(session);
return new FunctionCursor(result);
if (functionTable.isFast()) {
return new FunctionCursorResultSet(session, functionTable.getResultSet(session));
} else {
return new FunctionCursor(functionTable.getResult(session));
}
}
public double getCost(Session session, int[] masks) {
......
......@@ -20,6 +20,7 @@ import org.h2.index.Index;
import org.h2.index.IndexType;
import org.h2.message.DbException;
import org.h2.result.LocalResult;
import org.h2.result.ResultInterface;
import org.h2.result.Row;
import org.h2.schema.Schema;
import org.h2.value.DataType;
......@@ -152,24 +153,21 @@ public class FunctionTable extends Table {
}
/**
* Read the result set from the function.
* Read the result from the function. This method caches the result.
*
* @param session the session
* @return the result set
* @return the result
*/
public LocalResult getResult(Session session) {
functionExpr = functionExpr.optimize(session);
Value v = functionExpr.getValue(session);
public ResultInterface getResult(Session session) {
ValueResultSet v = getValueResultSet(session);
if (v == null) {
return null;
}
if (cachedResult != null && cachedValue == v) {
cachedResult.reset();
return cachedResult;
}
if (v == ValueNull.INSTANCE) {
return new LocalResult();
}
ValueResultSet value = (ValueResultSet) v;
ResultSet rs = value.getResultSet();
LocalResult result = LocalResult.read(session, rs, 0);
LocalResult result = LocalResult.read(session, v.getResultSet(), 0);
if (function.isDeterministic()) {
cachedResult = result;
cachedValue = v;
......@@ -177,6 +175,30 @@ public class FunctionTable extends Table {
return result;
}
/**
* Read the result set from the function. This method doesn't cache.
*
* @param session the session
* @return the result set
*/
public ResultSet getResultSet(Session session) {
ValueResultSet v = getValueResultSet(session);
return v == null ? null : v.getResultSet();
}
private ValueResultSet getValueResultSet(Session session) {
functionExpr = functionExpr.optimize(session);
Value v = functionExpr.getValue(session);
if (v == ValueNull.INSTANCE) {
return null;
}
return (ValueResultSet) v;
}
public boolean isFast() {
return function.isFast();
}
public long getMaxDataModificationId() {
// TODO optimization: table-as-a-function currently doesn't know the
// last modified date
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论