提交 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 { ...@@ -279,7 +279,7 @@ public class FunctionAlias extends SchemaObjectBase {
* Each method must have a different number of parameters however. * Each method must have a different number of parameters however.
* This helper class represents one such method. * 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 int id;
private final Method method; private final Method method;
private final int dataType; private final int dataType;
...@@ -287,6 +287,11 @@ public class FunctionAlias extends SchemaObjectBase { ...@@ -287,6 +287,11 @@ public class FunctionAlias extends SchemaObjectBase {
private boolean varArgs; private boolean varArgs;
private Class<?> varArgClass; private Class<?> varArgClass;
private int paramCount; 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) { JavaMethod(Method method, int id) {
this.method = method; this.method = method;
...@@ -398,6 +403,11 @@ public class FunctionAlias extends SchemaObjectBase { ...@@ -398,6 +403,11 @@ public class FunctionAlias extends SchemaObjectBase {
params[p] = o; params[p] = o;
} }
} }
if (deterministic) {
if (previousParams != null && Arrays.deepEquals(previousParams, params)) {
return previousReturnValue;
}
}
boolean old = session.getAutoCommit(); boolean old = session.getAutoCommit();
Value identity = session.getLastScopeIdentity(); Value identity = session.getLastScopeIdentity();
boolean defaultConnection = session.getDatabase().getSettings().defaultConnection; boolean defaultConnection = session.getDatabase().getSettings().defaultConnection;
...@@ -409,9 +419,6 @@ public class FunctionAlias extends SchemaObjectBase { ...@@ -409,9 +419,6 @@ public class FunctionAlias extends SchemaObjectBase {
Driver.setDefaultConnection(session.createConnection(columnList)); Driver.setDefaultConnection(session.createConnection(columnList));
} }
returnValue = method.invoke(null, params); returnValue = method.invoke(null, params);
if (returnValue == null) {
return ValueNull.INSTANCE;
}
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
StatementBuilder buff = new StatementBuilder(method.getName()); StatementBuilder buff = new StatementBuilder(method.getName());
buff.append('('); buff.append('(');
...@@ -424,11 +431,21 @@ public class FunctionAlias extends SchemaObjectBase { ...@@ -424,11 +431,21 @@ public class FunctionAlias extends SchemaObjectBase {
} catch (Exception e) { } catch (Exception e) {
throw DbException.convert(e); throw DbException.convert(e);
} }
Value ret;
if (returnValue == null) {
ret = ValueNull.INSTANCE;
} else {
if (Value.class.isAssignableFrom(method.getReturnType())) { if (Value.class.isAssignableFrom(method.getReturnType())) {
return (Value) returnValue; 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;
return ret.convertTo(dataType);
} finally { } finally {
session.setLastScopeIdentity(identity); session.setLastScopeIdentity(identity);
session.setAutoCommit(old); session.setAutoCommit(old);
......
...@@ -80,6 +80,7 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -80,6 +80,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
testNvl2(); testNvl2();
testConcatWs(); testConcatWs();
testTruncate(); testTruncate();
testCachingOfDeterministicFunctionAlias();
deleteDb("functions"); deleteDb("functions");
FileUtils.deleteRecursive(TEMP_DIR, true); FileUtils.deleteRecursive(TEMP_DIR, true);
} }
...@@ -929,6 +930,31 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -929,6 +930,31 @@ public class TestFunctions extends TestBase implements AggregateFunction {
conn.close(); 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 { private void assertCallResult(String expected, Statement stat, String sql) throws SQLException {
ResultSet rs = stat.executeQuery("CALL " + sql); ResultSet rs = stat.executeQuery("CALL " + sql);
rs.next(); rs.next();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论