提交 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 { ...@@ -470,5 +470,4 @@ public class FunctionAlias extends SchemaObjectBase {
} }
} }
} }
...@@ -303,8 +303,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -303,8 +303,8 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotDeterministic("NEXTVAL", NEXTVAL, VAR_ARGS, Value.LONG); addFunctionNotDeterministic("NEXTVAL", NEXTVAL, VAR_ARGS, Value.LONG);
addFunctionNotDeterministic("CURRVAL", CURRVAL, VAR_ARGS, Value.LONG); addFunctionNotDeterministic("CURRVAL", CURRVAL, VAR_ARGS, Value.LONG);
addFunction("ARRAY_GET", ARRAY_GET, 2, Value.STRING); addFunction("ARRAY_GET", ARRAY_GET, 2, Value.STRING);
addFunction("CSVREAD", CSVREAD, VAR_ARGS, Value.RESULT_SET, false, false); addFunction("CSVREAD", CSVREAD, VAR_ARGS, Value.RESULT_SET, false, false, true);
addFunction("CSVWRITE", CSVWRITE, VAR_ARGS, Value.INT, false, false); addFunction("CSVWRITE", CSVWRITE, VAR_ARGS, Value.INT, false, false, false);
addFunctionNotDeterministic("MEMORY_FREE", MEMORY_FREE, 0, Value.INT); addFunctionNotDeterministic("MEMORY_FREE", MEMORY_FREE, 0, Value.INT);
addFunctionNotDeterministic("MEMORY_USED", MEMORY_USED, 0, Value.INT); addFunctionNotDeterministic("MEMORY_USED", MEMORY_USED, 0, Value.INT);
addFunctionNotDeterministic("LOCK_MODE", LOCK_MODE, 0, Value.INT); addFunctionNotDeterministic("LOCK_MODE", LOCK_MODE, 0, Value.INT);
...@@ -315,8 +315,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -315,8 +315,8 @@ public class Function extends Expression implements FunctionCall {
addFunctionWithNull("LEAST", LEAST, VAR_ARGS, Value.NULL); addFunctionWithNull("LEAST", LEAST, VAR_ARGS, Value.NULL);
addFunctionWithNull("GREATEST", GREATEST, VAR_ARGS, Value.NULL); addFunctionWithNull("GREATEST", GREATEST, VAR_ARGS, Value.NULL);
addFunction("CANCEL_SESSION", CANCEL_SESSION, 1, Value.BOOLEAN); addFunction("CANCEL_SESSION", CANCEL_SESSION, 1, Value.BOOLEAN);
addFunction("SET", SET, 2, Value.NULL, false, false); addFunction("SET", SET, 2, Value.NULL, false, false, false);
addFunction("FILE_READ", FILE_READ, VAR_ARGS, Value.NULL, false, true); addFunction("FILE_READ", FILE_READ, VAR_ARGS, Value.NULL, false, true, false);
addFunctionNotDeterministic("TRANSACTION_ID", TRANSACTION_ID, 0, Value.STRING); addFunctionNotDeterministic("TRANSACTION_ID", TRANSACTION_ID, 0, Value.STRING);
// TableFunction // TableFunction
...@@ -335,7 +335,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -335,7 +335,7 @@ public class Function extends Expression implements FunctionCall {
} }
private static void addFunction(String name, int type, int parameterCount, int dataType, 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(); FunctionInfo info = new FunctionInfo();
info.name = name; info.name = name;
info.type = type; info.type = type;
...@@ -343,19 +343,20 @@ public class Function extends Expression implements FunctionCall { ...@@ -343,19 +343,20 @@ public class Function extends Expression implements FunctionCall {
info.dataType = dataType; info.dataType = dataType;
info.nullIfParameterIsNull = nullIfParameterIsNull; info.nullIfParameterIsNull = nullIfParameterIsNull;
info.deterministic = deterministic; info.deterministic = deterministic;
info.fast = fast;
FUNCTIONS.put(name, info); FUNCTIONS.put(name, info);
} }
private static void addFunctionNotDeterministic(String name, int type, int parameterCount, int dataType) { 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) { 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) { 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 { ...@@ -1224,7 +1225,7 @@ public class Function extends Expression implements FunctionCall {
private static int getDatePart(String part) { private static int getDatePart(String part) {
Integer p = DATE_PART.get(StringUtils.toUpperEnglish(part)); Integer p = DATE_PART.get(StringUtils.toUpperEnglish(part));
if (p == null) { if (p == null) {
throw DbException.get(ErrorCode.INVALID_VALUE_2, "date part", part); throw DbException.getInvalidValueException("date part", part);
} }
return p.intValue(); return p.intValue();
} }
...@@ -1986,4 +1987,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -1986,4 +1987,8 @@ public class Function extends Expression implements FunctionCall {
return info.deterministic; return info.deterministic;
} }
public boolean isFast() {
return info.fast;
}
} }
...@@ -82,4 +82,12 @@ public interface FunctionCall { ...@@ -82,4 +82,12 @@ public interface FunctionCall {
* @return true if it does * @return true if it does
*/ */
boolean isDeterministic(); 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 { ...@@ -40,4 +40,10 @@ class FunctionInfo {
* If this function always returns the same value for the same parameters. * If this function always returns the same value for the same parameters.
*/ */
boolean deterministic; 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 { ...@@ -164,4 +164,9 @@ public class JavaFunction extends Expression implements FunctionCall {
} }
return super.getExpressionColumns(session); return super.getExpressionColumns(session);
} }
public boolean isFast() {
return false;
}
} }
...@@ -13,11 +13,11 @@ import org.h2.result.SearchRow; ...@@ -13,11 +13,11 @@ import org.h2.result.SearchRow;
import org.h2.value.Value; 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 { public class FunctionCursor implements Cursor {
private ResultInterface result; private final ResultInterface result;
private Value[] values; private Value[] values;
private Row row; private Row row;
...@@ -41,7 +41,7 @@ public class FunctionCursor implements Cursor { ...@@ -41,7 +41,7 @@ public class FunctionCursor implements Cursor {
public boolean next() { public boolean next() {
row = null; row = null;
if (result.next()) { if (result != null && result.next()) {
values = result.currentRow(); values = result.currentRow();
} else { } else {
values = null; 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; ...@@ -8,7 +8,6 @@ package org.h2.index;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.table.FunctionTable; import org.h2.table.FunctionTable;
...@@ -20,8 +19,7 @@ import org.h2.table.IndexColumn; ...@@ -20,8 +19,7 @@ import org.h2.table.IndexColumn;
*/ */
public class FunctionIndex extends BaseIndex { public class FunctionIndex extends BaseIndex {
private FunctionTable functionTable; private final FunctionTable functionTable;
private ResultInterface result;
public FunctionIndex(FunctionTable functionTable, IndexColumn[] columns) { public FunctionIndex(FunctionTable functionTable, IndexColumn[] columns) {
initBaseIndex(functionTable, 0, null, columns, IndexType.createNonUnique(true)); initBaseIndex(functionTable, 0, null, columns, IndexType.createNonUnique(true));
...@@ -41,10 +39,11 @@ public class FunctionIndex extends BaseIndex { ...@@ -41,10 +39,11 @@ public class FunctionIndex extends BaseIndex {
} }
public Cursor find(Session session, SearchRow first, SearchRow last) { public Cursor find(Session session, SearchRow first, SearchRow last) {
// TODO sometimes result.reset() would be enough (but not when if (functionTable.isFast()) {
// parameters are used) return new FunctionCursorResultSet(session, functionTable.getResultSet(session));
result = functionTable.getResult(session); } else {
return new FunctionCursor(result); return new FunctionCursor(functionTable.getResult(session));
}
} }
public double getCost(Session session, int[] masks) { public double getCost(Session session, int[] masks) {
......
...@@ -20,6 +20,7 @@ import org.h2.index.Index; ...@@ -20,6 +20,7 @@ import org.h2.index.Index;
import org.h2.index.IndexType; import org.h2.index.IndexType;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.LocalResult; import org.h2.result.LocalResult;
import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.value.DataType; import org.h2.value.DataType;
...@@ -152,24 +153,21 @@ public class FunctionTable extends Table { ...@@ -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 * @param session the session
* @return the result set * @return the result
*/ */
public LocalResult getResult(Session session) { public ResultInterface getResult(Session session) {
functionExpr = functionExpr.optimize(session); ValueResultSet v = getValueResultSet(session);
Value v = functionExpr.getValue(session); if (v == null) {
return null;
}
if (cachedResult != null && cachedValue == v) { if (cachedResult != null && cachedValue == v) {
cachedResult.reset(); cachedResult.reset();
return cachedResult; return cachedResult;
} }
if (v == ValueNull.INSTANCE) { LocalResult result = LocalResult.read(session, v.getResultSet(), 0);
return new LocalResult();
}
ValueResultSet value = (ValueResultSet) v;
ResultSet rs = value.getResultSet();
LocalResult result = LocalResult.read(session, rs, 0);
if (function.isDeterministic()) { if (function.isDeterministic()) {
cachedResult = result; cachedResult = result;
cachedValue = v; cachedValue = v;
...@@ -177,6 +175,30 @@ public class FunctionTable extends Table { ...@@ -177,6 +175,30 @@ public class FunctionTable extends Table {
return result; 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() { public long getMaxDataModificationId() {
// TODO optimization: table-as-a-function currently doesn't know the // TODO optimization: table-as-a-function currently doesn't know the
// last modified date // last modified date
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论