提交 b0b00641 authored 作者: Thomas Mueller's avatar Thomas Mueller

User defined functions can now be deterministic.

上级 2ae49669
...@@ -965,7 +965,7 @@ public class Parser { ...@@ -965,7 +965,7 @@ public class Parser {
if (!(func instanceof FunctionCall)) { if (!(func instanceof FunctionCall)) {
throw getSyntaxError(); throw getSyntaxError();
} }
table = new FunctionTable(mainSchema, session, (FunctionCall) func); table = new FunctionTable(mainSchema, session, func, (FunctionCall) func);
} }
} else if ("DUAL".equals(tableName)) { } else if ("DUAL".equals(tableName)) {
table = getDualTable(); table = getDualTable();
...@@ -3765,6 +3765,7 @@ public class Parser { ...@@ -3765,6 +3765,7 @@ public class Parser {
} }
command.setAliasName(name); command.setAliasName(name);
command.setIfNotExists(ifNotExists); command.setIfNotExists(ifNotExists);
command.setDeterministic(readIf("DETERMINISTIC"));
read("FOR"); read("FOR");
command.setJavaClassMethod(readUniqueIdentifier()); command.setJavaClassMethod(readUniqueIdentifier());
return command; return command;
......
...@@ -22,6 +22,7 @@ public class CreateFunctionAlias extends DefineCommand { ...@@ -22,6 +22,7 @@ public class CreateFunctionAlias extends DefineCommand {
private String aliasName; private String aliasName;
private String javaClassMethod; private String javaClassMethod;
private boolean deterministic;
private boolean ifNotExists; private boolean ifNotExists;
private boolean force; private boolean force;
...@@ -40,6 +41,7 @@ public class CreateFunctionAlias extends DefineCommand { ...@@ -40,6 +41,7 @@ public class CreateFunctionAlias extends DefineCommand {
} else { } else {
int id = getObjectId(false, true); int id = getObjectId(false, true);
FunctionAlias functionAlias = new FunctionAlias(db, id, aliasName, javaClassMethod, force); FunctionAlias functionAlias = new FunctionAlias(db, id, aliasName, javaClassMethod, force);
functionAlias.setDeterministic(deterministic);
db.addDatabaseObject(session, functionAlias); db.addDatabaseObject(session, functionAlias);
} }
return 0; return 0;
...@@ -61,4 +63,8 @@ public class CreateFunctionAlias extends DefineCommand { ...@@ -61,4 +63,8 @@ public class CreateFunctionAlias extends DefineCommand {
this.force = force; this.force = force;
} }
public void setDeterministic(boolean deterministic) {
this.deterministic = deterministic;
}
} }
...@@ -36,6 +36,7 @@ public class FunctionAlias extends DbObjectBase { ...@@ -36,6 +36,7 @@ public class FunctionAlias extends DbObjectBase {
private String className; private String className;
private String methodName; private String methodName;
private JavaMethod[] javaMethods; private JavaMethod[] javaMethods;
private boolean deterministic;
public FunctionAlias(Database db, int id, String name, String javaClassMethod, boolean force) throws SQLException { public FunctionAlias(Database db, int id, String name, String javaClassMethod, boolean force) throws SQLException {
initDbObjectBase(db, id, name, Trace.FUNCTION); initDbObjectBase(db, id, name, Trace.FUNCTION);
...@@ -130,6 +131,9 @@ public class FunctionAlias extends DbObjectBase { ...@@ -130,6 +131,9 @@ public class FunctionAlias extends DbObjectBase {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
buff.append("CREATE FORCE ALIAS "); buff.append("CREATE FORCE ALIAS ");
buff.append(getSQL()); buff.append(getSQL());
if (deterministic) {
buff.append(" DETERMINISTIC");
}
buff.append(" FOR "); buff.append(" FOR ");
buff.append(Parser.quoteIdentifier(className + "." + methodName)); buff.append(Parser.quoteIdentifier(className + "." + methodName));
return buff.toString(); return buff.toString();
...@@ -350,4 +354,12 @@ public class FunctionAlias extends DbObjectBase { ...@@ -350,4 +354,12 @@ public class FunctionAlias extends DbObjectBase {
} }
public void setDeterministic(boolean deterministic) {
this.deterministic = deterministic;
}
public boolean isDeterministic() {
return deterministic;
}
} }
...@@ -72,8 +72,6 @@ import org.h2.value.ValueUuid; ...@@ -72,8 +72,6 @@ import org.h2.value.ValueUuid;
* This class implements most built-in functions of this database. * This class implements most built-in functions of this database.
*/ */
public class Function extends Expression implements FunctionCall { public class Function extends Expression implements FunctionCall {
// TODO functions: add function hashcode(value)
public static final int ABS = 0, ACOS = 1, ASIN = 2, ATAN = 3, ATAN2 = 4, BITAND = 5, BITOR = 6, BITXOR = 7, public static final int ABS = 0, ACOS = 1, ASIN = 2, ATAN = 3, ATAN2 = 4, BITAND = 5, BITOR = 6, BITXOR = 7,
CEILING = 8, COS = 9, COT = 10, DEGREES = 11, EXP = 12, FLOOR = 13, LOG = 14, LOG10 = 15, MOD = 16, CEILING = 8, COS = 9, COT = 10, DEGREES = 11, EXP = 12, FLOOR = 13, LOG = 14, LOG10 = 15, MOD = 16,
PI = 17, POWER = 18, RADIANS = 19, RAND = 20, ROUND = 21, ROUNDMAGIC = 22, SIGN = 23, SIN = 24, SQRT = 25, PI = 17, POWER = 18, RADIANS = 19, RAND = 20, ROUND = 21, ROUNDMAGIC = 22, SIGN = 23, SIN = 24, SQRT = 25,
...@@ -183,7 +181,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -183,7 +181,7 @@ public class Function extends Expression implements FunctionCall {
addFunction("RADIANS", RADIANS, 1, Value.DOUBLE); addFunction("RADIANS", RADIANS, 1, Value.DOUBLE);
// RAND without argument: get the next value // RAND without argument: get the next value
// RAND with one argument: seed the random generator // RAND with one argument: seed the random generator
addFunctionNotConst("RAND", RAND, VAR_ARGS, Value.DOUBLE); addFunctionNotDeterministic("RAND", RAND, VAR_ARGS, Value.DOUBLE);
addFunction("ROUND", ROUND, 2, Value.DOUBLE); addFunction("ROUND", ROUND, 2, Value.DOUBLE);
addFunction("ROUNDMAGIC", ROUNDMAGIC, 1, Value.DOUBLE); addFunction("ROUNDMAGIC", ROUNDMAGIC, 1, Value.DOUBLE);
addFunction("SIGN", SIGN, 1, Value.INT); addFunction("SIGN", SIGN, 1, Value.INT);
...@@ -194,12 +192,12 @@ public class Function extends Expression implements FunctionCall { ...@@ -194,12 +192,12 @@ public class Function extends Expression implements FunctionCall {
addFunction("HASH", HASH, 3, Value.BYTES); addFunction("HASH", HASH, 3, Value.BYTES);
addFunction("ENCRYPT", ENCRYPT, 3, Value.BYTES); addFunction("ENCRYPT", ENCRYPT, 3, Value.BYTES);
addFunction("DECRYPT", DECRYPT, 3, Value.BYTES); addFunction("DECRYPT", DECRYPT, 3, Value.BYTES);
addFunctionNotConst("SECURE_RAND", SECURE_RAND, 1, Value.BYTES); addFunctionNotDeterministic("SECURE_RAND", SECURE_RAND, 1, Value.BYTES);
addFunction("COMPRESS", COMPRESS, VAR_ARGS, Value.BYTES); addFunction("COMPRESS", COMPRESS, VAR_ARGS, Value.BYTES);
addFunction("EXPAND", EXPAND, 1, Value.BYTES); addFunction("EXPAND", EXPAND, 1, Value.BYTES);
addFunction("ZERO", ZERO, 0, Value.INT); addFunction("ZERO", ZERO, 0, Value.INT);
addFunctionNotConst("RANDOM_UUID", RANDOM_UUID, 0, Value.UUID); addFunctionNotDeterministic("RANDOM_UUID", RANDOM_UUID, 0, Value.UUID);
addFunctionNotConst("SYS_GUID", RANDOM_UUID, 0, Value.UUID); addFunctionNotDeterministic("SYS_GUID", RANDOM_UUID, 0, Value.UUID);
// string // string
addFunction("ASCII", ASCII, 1, Value.INT); addFunction("ASCII", ASCII, 1, Value.INT);
addFunction("BIT_LENGTH", BIT_LENGTH, 1, Value.INT); addFunction("BIT_LENGTH", BIT_LENGTH, 1, Value.INT);
...@@ -251,12 +249,12 @@ public class Function extends Expression implements FunctionCall { ...@@ -251,12 +249,12 @@ public class Function extends Expression implements FunctionCall {
addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING); addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING);
// date // date
addFunctionNotConst("CURRENT_DATE", CURRENT_DATE, 0, Value.DATE); addFunctionNotDeterministic("CURRENT_DATE", CURRENT_DATE, 0, Value.DATE);
addFunctionNotConst("CURDATE", CURDATE, 0, Value.DATE); addFunctionNotDeterministic("CURDATE", CURDATE, 0, Value.DATE);
addFunctionNotConst("CURRENT_TIME", CURRENT_TIME, 0, Value.TIME); addFunctionNotDeterministic("CURRENT_TIME", CURRENT_TIME, 0, Value.TIME);
addFunctionNotConst("CURTIME", CURTIME, 0, Value.TIME); addFunctionNotDeterministic("CURTIME", CURTIME, 0, Value.TIME);
addFunctionNotConst("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP, VAR_ARGS, Value.TIMESTAMP); addFunctionNotDeterministic("CURRENT_TIMESTAMP", CURRENT_TIMESTAMP, VAR_ARGS, Value.TIMESTAMP);
addFunctionNotConst("NOW", NOW, VAR_ARGS, Value.TIMESTAMP); addFunctionNotDeterministic("NOW", NOW, VAR_ARGS, Value.TIMESTAMP);
addFunction("DATEADD", DATE_ADD, 3, Value.TIMESTAMP); addFunction("DATEADD", DATE_ADD, 3, Value.TIMESTAMP);
addFunction("DATEDIFF", DATE_DIFF, 3, Value.LONG); addFunction("DATEDIFF", DATE_DIFF, 3, Value.LONG);
addFunction("DAYNAME", DAY_NAME, 1, Value.STRING); addFunction("DAYNAME", DAY_NAME, 1, Value.STRING);
...@@ -283,14 +281,14 @@ public class Function extends Expression implements FunctionCall { ...@@ -283,14 +281,14 @@ public class Function extends Expression implements FunctionCall {
addFunction("ISO_WEEK", ISO_WEEK, 1, Value.INT); addFunction("ISO_WEEK", ISO_WEEK, 1, Value.INT);
addFunction("ISO_DAY_OF_WEEK", ISO_DAY_OF_WEEK, 1, Value.INT); addFunction("ISO_DAY_OF_WEEK", ISO_DAY_OF_WEEK, 1, Value.INT);
// system // system
addFunctionNotConst("DATABASE", DATABASE, 0, Value.STRING); addFunctionNotDeterministic("DATABASE", DATABASE, 0, Value.STRING);
addFunctionNotConst("USER", USER, 0, Value.STRING); addFunctionNotDeterministic("USER", USER, 0, Value.STRING);
addFunctionNotConst("CURRENT_USER", CURRENT_USER, 0, Value.STRING); addFunctionNotDeterministic("CURRENT_USER", CURRENT_USER, 0, Value.STRING);
addFunctionNotConst("IDENTITY", IDENTITY, 0, Value.LONG); addFunctionNotDeterministic("IDENTITY", IDENTITY, 0, Value.LONG);
addFunctionNotConst("IDENTITY_VAL_LOCAL", IDENTITY, 0, Value.LONG); addFunctionNotDeterministic("IDENTITY_VAL_LOCAL", IDENTITY, 0, Value.LONG);
addFunctionNotConst("LAST_INSERT_ID", IDENTITY, 0, Value.LONG); addFunctionNotDeterministic("LAST_INSERT_ID", IDENTITY, 0, Value.LONG);
addFunctionNotConst("AUTOCOMMIT", AUTOCOMMIT, 0, Value.BOOLEAN); addFunctionNotDeterministic("AUTOCOMMIT", AUTOCOMMIT, 0, Value.BOOLEAN);
addFunctionNotConst("READONLY", READONLY, 0, Value.BOOLEAN); addFunctionNotDeterministic("READONLY", READONLY, 0, Value.BOOLEAN);
addFunction("DATABASE_PATH", DATABASE_PATH, 0, Value.STRING); addFunction("DATABASE_PATH", DATABASE_PATH, 0, Value.STRING);
addFunction("LOCK_TIMEOUT", LOCK_TIMEOUT, 0, Value.INT); addFunction("LOCK_TIMEOUT", LOCK_TIMEOUT, 0, Value.INT);
addFunctionWithNull("IFNULL", IFNULL, 2, Value.NULL); addFunctionWithNull("IFNULL", IFNULL, 2, Value.NULL);
...@@ -301,16 +299,16 @@ public class Function extends Expression implements FunctionCall { ...@@ -301,16 +299,16 @@ public class Function extends Expression implements FunctionCall {
addFunctionWithNull("NVL", COALESCE, VAR_ARGS, Value.NULL); addFunctionWithNull("NVL", COALESCE, VAR_ARGS, Value.NULL);
addFunctionWithNull("NULLIF", NULLIF, 2, Value.NULL); addFunctionWithNull("NULLIF", NULLIF, 2, Value.NULL);
addFunctionWithNull("CASE", CASE, VAR_ARGS, Value.NULL); addFunctionWithNull("CASE", CASE, VAR_ARGS, Value.NULL);
addFunctionNotConst("NEXTVAL", NEXTVAL, VAR_ARGS, Value.LONG); addFunctionNotDeterministic("NEXTVAL", NEXTVAL, VAR_ARGS, Value.LONG);
addFunctionNotConst("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);
addFunction("CSVWRITE", CSVWRITE, VAR_ARGS, Value.INT, false, false); addFunction("CSVWRITE", CSVWRITE, VAR_ARGS, Value.INT, false, false);
addFunctionNotConst("MEMORY_FREE", MEMORY_FREE, 0, Value.INT); addFunctionNotDeterministic("MEMORY_FREE", MEMORY_FREE, 0, Value.INT);
addFunctionNotConst("MEMORY_USED", MEMORY_USED, 0, Value.INT); addFunctionNotDeterministic("MEMORY_USED", MEMORY_USED, 0, Value.INT);
addFunctionNotConst("LOCK_MODE", LOCK_MODE, 0, Value.INT); addFunctionNotDeterministic("LOCK_MODE", LOCK_MODE, 0, Value.INT);
addFunctionNotConst("SCHEMA", SCHEMA, 0, Value.STRING); addFunctionNotDeterministic("SCHEMA", SCHEMA, 0, Value.STRING);
addFunctionNotConst("SESSION_ID", SESSION_ID, 0, Value.INT); addFunctionNotDeterministic("SESSION_ID", SESSION_ID, 0, Value.INT);
addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT); addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT);
addFunction("LINK_SCHEMA", LINK_SCHEMA, 6, Value.RESULT_SET); addFunction("LINK_SCHEMA", LINK_SCHEMA, 6, Value.RESULT_SET);
addFunctionWithNull("LEAST", LEAST, VAR_ARGS, Value.NULL); addFunctionWithNull("LEAST", LEAST, VAR_ARGS, Value.NULL);
...@@ -318,7 +316,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -318,7 +316,7 @@ public class Function extends Expression implements FunctionCall {
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);
addFunction("FILE_READ", FILE_READ, VAR_ARGS, Value.NULL, false, true); addFunction("FILE_READ", FILE_READ, VAR_ARGS, Value.NULL, false, true);
addFunctionNotConst("TRANSACTION_ID", TRANSACTION_ID, 0, Value.STRING); addFunctionNotDeterministic("TRANSACTION_ID", TRANSACTION_ID, 0, Value.STRING);
// TableFunction // TableFunction
addFunctionWithNull("TABLE", TABLE, VAR_ARGS, Value.RESULT_SET); addFunctionWithNull("TABLE", TABLE, VAR_ARGS, Value.RESULT_SET);
...@@ -336,18 +334,18 @@ public class Function extends Expression implements FunctionCall { ...@@ -336,18 +334,18 @@ 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 isDeterm) { boolean nullIfParameterIsNull, boolean deterministic) {
FunctionInfo info = new FunctionInfo(); FunctionInfo info = new FunctionInfo();
info.name = name; info.name = name;
info.type = type; info.type = type;
info.parameterCount = parameterCount; info.parameterCount = parameterCount;
info.dataType = dataType; info.dataType = dataType;
info.nullIfParameterIsNull = nullIfParameterIsNull; info.nullIfParameterIsNull = nullIfParameterIsNull;
info.isDeterministic = isDeterm; info.deterministic = deterministic;
FUNCTIONS.put(name, info); FUNCTIONS.put(name, info);
} }
private static void addFunctionNotConst(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);
} }
...@@ -1606,7 +1604,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1606,7 +1604,7 @@ public class Function extends Expression implements FunctionCall {
} }
public Expression optimize(Session session) throws SQLException { public Expression optimize(Session session) throws SQLException {
boolean allConst = info.isDeterministic; boolean allConst = info.deterministic;
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
Expression e = args[i].optimize(session); Expression e = args[i].optimize(session);
args[i] = e; args[i] = e;
...@@ -1919,7 +1917,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1919,7 +1917,7 @@ public class Function extends Expression implements FunctionCall {
} }
public boolean isEverything(ExpressionVisitor visitor) { public boolean isEverything(ExpressionVisitor visitor) {
if (visitor.getType() == ExpressionVisitor.DETERMINISTIC && !info.isDeterministic) { if (visitor.getType() == ExpressionVisitor.DETERMINISTIC && !info.deterministic) {
return false; return false;
} }
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
...@@ -1939,4 +1937,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -1939,4 +1937,8 @@ public class Function extends Expression implements FunctionCall {
return cost; return cost;
} }
public boolean isDeterministic() {
return info.deterministic;
}
} }
...@@ -78,4 +78,10 @@ public interface FunctionCall { ...@@ -78,4 +78,10 @@ public interface FunctionCall {
*/ */
String getSQL(); String getSQL();
/**
* Whether the function always returns the same result for the same parameters.
*
* @return true if it does
*/
boolean isDeterministic();
} }
...@@ -39,5 +39,5 @@ class FunctionInfo { ...@@ -39,5 +39,5 @@ 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 isDeterministic; boolean deterministic;
} }
...@@ -52,6 +52,9 @@ public class JavaFunction extends Expression implements FunctionCall { ...@@ -52,6 +52,9 @@ public class JavaFunction extends Expression implements FunctionCall {
Expression e = args[i].optimize(session); Expression e = args[i].optimize(session);
args[i] = e; args[i] = e;
} }
if (isEverything(ExpressionVisitor.DETERMINISTIC)) {
return ValueExpression.get(getValue(session));
}
return this; return this;
} }
...@@ -120,9 +123,12 @@ public class JavaFunction extends Expression implements FunctionCall { ...@@ -120,9 +123,12 @@ public class JavaFunction extends Expression implements FunctionCall {
public boolean isEverything(ExpressionVisitor visitor) { public boolean isEverything(ExpressionVisitor visitor) {
switch(visitor.getType()) { switch(visitor.getType()) {
case ExpressionVisitor.DETERMINISTIC: case ExpressionVisitor.DETERMINISTIC:
// TODO optimization: some functions are deterministic, but we don't if (!isDeterministic()) {
// know (no setting for that) return false;
return false; } else {
// only if all parameters are deterministic as well
break;
}
case ExpressionVisitor.GET_DEPENDENCIES: case ExpressionVisitor.GET_DEPENDENCIES:
visitor.addDependency(functionAlias); visitor.addDependency(functionAlias);
break; break;
...@@ -145,4 +151,8 @@ public class JavaFunction extends Expression implements FunctionCall { ...@@ -145,4 +151,8 @@ public class JavaFunction extends Expression implements FunctionCall {
return cost; return cost;
} }
public boolean isDeterministic() {
return functionAlias.isDeterministic();
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论