提交 cbb01f60 authored 作者: noelgrandin's avatar noelgrandin

Add a single-value cache for DETERMINISTIC ALIAS method calls, reduces unnecessary calls

上级 7163157b
......@@ -279,7 +279,7 @@ public class FunctionAlias extends SchemaObjectBase {
* Each method must have a different number of parameters however.
* This helper class represents one such method.
*/
public static class JavaMethod implements Comparable<JavaMethod> {
public class JavaMethod implements Comparable<JavaMethod> {
private final int id;
private final Method method;
private final int dataType;
......@@ -287,6 +287,11 @@ public class FunctionAlias extends SchemaObjectBase {
private boolean varArgs;
private Class<?> varArgClass;
private int paramCount;
/**
* Cache the value of the last call if the function is deterministic.
*/
private Object[] previousParams;
private Value previousReturnValue;
JavaMethod(Method method, int id) {
this.method = method;
......@@ -398,6 +403,11 @@ public class FunctionAlias extends SchemaObjectBase {
params[p] = o;
}
}
if (deterministic) {
if (previousParams != null && Arrays.deepEquals(previousParams, params)) {
return previousReturnValue;
}
}
boolean old = session.getAutoCommit();
Value identity = session.getLastScopeIdentity();
boolean defaultConnection = session.getDatabase().getSettings().defaultConnection;
......@@ -409,9 +419,6 @@ public class FunctionAlias extends SchemaObjectBase {
Driver.setDefaultConnection(session.createConnection(columnList));
}
returnValue = method.invoke(null, params);
if (returnValue == null) {
return ValueNull.INSTANCE;
}
} catch (InvocationTargetException e) {
StatementBuilder buff = new StatementBuilder(method.getName());
buff.append('(');
......@@ -424,11 +431,21 @@ public class FunctionAlias extends SchemaObjectBase {
} catch (Exception e) {
throw DbException.convert(e);
}
if (Value.class.isAssignableFrom(method.getReturnType())) {
return (Value) returnValue;
Value ret;
if (returnValue == null) {
ret = ValueNull.INSTANCE;
} else {
if (Value.class.isAssignableFrom(method.getReturnType())) {
ret = (Value) returnValue;
} else {
ret = DataType.convertToValue(session, returnValue, dataType);
}
}
if (deterministic) {
previousParams = params;
previousReturnValue = ret;
}
Value ret = DataType.convertToValue(session, returnValue, dataType);
return ret.convertTo(dataType);
return ret;
} finally {
session.setLastScopeIdentity(identity);
session.setAutoCommit(old);
......
......@@ -80,6 +80,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
testNvl2();
testConcatWs();
testTruncate();
testCachingOfDeterministicFunctionAlias();
deleteDb("functions");
FileUtils.deleteRecursive(TEMP_DIR, true);
}
......@@ -929,6 +930,31 @@ public class TestFunctions extends TestBase implements AggregateFunction {
conn.close();
}
private static int countOfCallsToTestCache;
private void testCachingOfDeterministicFunctionAlias() throws SQLException {
deleteDb("functions");
Connection conn = getConnection("functions");
Statement stat = conn.createStatement();
stat.execute("create alias MYTF2 deterministic for \"" + TestFunctions.class.getName() + ".testCache\"");
stat.execute("create view MVIEW2 as select * from MYTF2()");
countOfCallsToTestCache = 0;
stat.executeQuery("select * from MVIEW2");
assertEquals(0, countOfCallsToTestCache);
conn.close();
}
/**
* This method is called via reflection from the database.
*/
public static synchronized ResultSet testCache() {
countOfCallsToTestCache++;
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("ID", Types.INTEGER, 10, 0);
rs.addRow(0);
return rs;
}
private void assertCallResult(String expected, Statement stat, String sql) throws SQLException {
ResultSet rs = stat.executeQuery("CALL " + sql);
rs.next();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论