提交 6ecfc2ce authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Use FunctionsMySQL in MySQL mode

上级 394ac43a
...@@ -29,6 +29,7 @@ import org.h2.engine.Mode; ...@@ -29,6 +29,7 @@ import org.h2.engine.Mode;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mode.FunctionsMSSQLServer; import org.h2.mode.FunctionsMSSQLServer;
import org.h2.mode.FunctionsMySQL;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
import org.h2.security.BlockCipher; import org.h2.security.BlockCipher;
...@@ -144,7 +145,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -144,7 +145,7 @@ public class Function extends Expression implements FunctionCall {
public static final int ROW_NUMBER = 300; public static final int ROW_NUMBER = 300;
private static final int VAR_ARGS = -1; protected static final int VAR_ARGS = -1;
private static final long PRECISION_UNKNOWN = -1; private static final long PRECISION_UNKNOWN = -1;
private static final HashMap<String, FunctionInfo> FUNCTIONS = new HashMap<>(256); private static final HashMap<String, FunctionInfo> FUNCTIONS = new HashMap<>(256);
...@@ -152,11 +153,13 @@ public class Function extends Expression implements FunctionCall { ...@@ -152,11 +153,13 @@ public class Function extends Expression implements FunctionCall {
protected Expression[] args; protected Expression[] args;
private final FunctionInfo info; protected final FunctionInfo info;
private ArrayList<Expression> varArgs; private ArrayList<Expression> varArgs;
private int dataType, scale; protected int dataType;
private long precision = PRECISION_UNKNOWN;
private int displaySize; protected int scale;
protected long precision = PRECISION_UNKNOWN;
protected int displaySize;
private final Database database; private final Database database;
static { static {
...@@ -524,6 +527,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -524,6 +527,8 @@ public class Function extends Expression implements FunctionCall {
switch (database.getMode().getEnum()) { switch (database.getMode().getEnum()) {
case MSSQLServer: case MSSQLServer:
return FunctionsMSSQLServer.getFunction(database, name); return FunctionsMSSQLServer.getFunction(database, name);
case MySQL:
return FunctionsMySQL.getFunction(database, name);
default: default:
return null; return null;
} }
...@@ -1098,7 +1103,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1098,7 +1103,7 @@ public class Function extends Expression implements FunctionCall {
return table.getDiskSpaceUsed(); return table.getDiskSpaceUsed();
} }
private static Value getNullOrValue(Session session, Expression[] args, protected static Value getNullOrValue(Session session, Expression[] args,
Value[] values, int i) { Value[] values, int i) {
if (i >= args.length) { if (i >= args.length) {
return null; return null;
...@@ -1114,7 +1119,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -1114,7 +1119,7 @@ public class Function extends Expression implements FunctionCall {
return v; return v;
} }
private Value getValueWithArgs(Session session, Expression[] args) { protected Value getValueWithArgs(Session session, Expression[] args) {
Value[] values = new Value[args.length]; Value[] values = new Value[args.length];
if (info.nullIfParameterIsNull) { if (info.nullIfParameterIsNull) {
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
......
...@@ -13,12 +13,12 @@ public final class FunctionInfo { ...@@ -13,12 +13,12 @@ public final class FunctionInfo {
/** /**
* The name of the function. * The name of the function.
*/ */
final String name; public final String name;
/** /**
* The function type. * The function type.
*/ */
final int type; public final int type;
/** /**
* The number of parameters. * The number of parameters.
...@@ -28,7 +28,7 @@ public final class FunctionInfo { ...@@ -28,7 +28,7 @@ public final class FunctionInfo {
/** /**
* The data type of the return value. * The data type of the return value.
*/ */
final int returnDataType; public final int returnDataType;
/** /**
* If the result of the function is NULL if any of the parameters is NULL. * If the result of the function is NULL if any of the parameters is NULL.
...@@ -38,7 +38,7 @@ public final class FunctionInfo { ...@@ -38,7 +38,7 @@ public final 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.
*/ */
final boolean deterministic; public final boolean deterministic;
/** /**
* Should the return value ResultSet be buffered in a local temporary file? * Should the return value ResultSet be buffered in a local temporary file?
...@@ -66,7 +66,7 @@ public final class FunctionInfo { ...@@ -66,7 +66,7 @@ public final class FunctionInfo {
* should the return value ResultSet be buffered in a local * should the return value ResultSet be buffered in a local
* temporary file? * temporary file?
*/ */
FunctionInfo(String name, int type, int parameterCount, int returnDataType, boolean nullIfParameterIsNull, public FunctionInfo(String name, int type, int parameterCount, int returnDataType, boolean nullIfParameterIsNull,
boolean deterministic, boolean bufferResultSetToLocalTemp) { boolean deterministic, boolean bufferResultSetToLocalTemp) {
this.name = name; this.name = name;
this.type = type; this.type = type;
......
...@@ -7,13 +7,18 @@ package org.h2.mode; ...@@ -7,13 +7,18 @@ package org.h2.mode;
import java.util.HashMap; import java.util.HashMap;
import org.h2.engine.Database;
import org.h2.expression.Function; import org.h2.expression.Function;
import org.h2.expression.FunctionInfo; import org.h2.expression.FunctionInfo;
/** /**
* Base class for mode-specific functions. * Base class for mode-specific functions.
*/ */
abstract class FunctionsBase { abstract class FunctionsBase extends Function {
FunctionsBase(Database database, FunctionInfo info) {
super(database, info);
}
/** /**
* Copy a standard function to a mode functions with a different name. * Copy a standard function to a mode functions with a different name.
......
...@@ -39,6 +39,7 @@ public final class FunctionsMSSQLServer extends FunctionsBase { ...@@ -39,6 +39,7 @@ public final class FunctionsMSSQLServer extends FunctionsBase {
return info != null ? new Function(database, info) : null; return info != null ? new Function(database, info) : null;
} }
private FunctionsMSSQLServer() { private FunctionsMSSQLServer(Database database, FunctionInfo info) {
super(database, info);
} }
} }
...@@ -5,14 +5,24 @@ ...@@ -5,14 +5,24 @@
*/ */
package org.h2.mode; package org.h2.mode;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import org.h2.api.ErrorCode;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.expression.Expression;
import org.h2.expression.Function;
import org.h2.expression.FunctionInfo;
import org.h2.expression.ValueExpression;
import org.h2.message.DbException;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueInt;
import org.h2.value.ValueString;
/** /**
* This class implements some MySQL-specific functions. * This class implements some MySQL-specific functions.
...@@ -20,7 +30,20 @@ import org.h2.util.StringUtils; ...@@ -20,7 +30,20 @@ import org.h2.util.StringUtils;
* @author Jason Brittain * @author Jason Brittain
* @author Thomas Mueller * @author Thomas Mueller
*/ */
public class FunctionsMySQL { public class FunctionsMySQL extends FunctionsBase {
private static final int UNIX_TIMESTAMP = 1001, FROM_UNIXTIME = 1002, DATE = 1003;
private static final HashMap<String, FunctionInfo> FUNCTIONS = new HashMap<>();
static {
FUNCTIONS.put("UNIX_TIMESTAMP", new FunctionInfo("UNIX_TIMESTAMP", UNIX_TIMESTAMP,
VAR_ARGS, Value.INT, false, false, false));
FUNCTIONS.put("FROM_UNIXTIME", new FunctionInfo("FROM_UNIXTIME", FROM_UNIXTIME,
VAR_ARGS, Value.STRING, false, true, false));
FUNCTIONS.put("DATE", new FunctionInfo("DATE", DATE,
1, Value.DATE, false, true, false));
}
/** /**
* The date format of a MySQL formatted date/time. * The date format of a MySQL formatted date/time.
...@@ -60,27 +83,6 @@ public class FunctionsMySQL { ...@@ -60,27 +83,6 @@ public class FunctionsMySQL {
"%%", "%", "%%", "%",
}; };
/**
* Register the functionality in the database.
* Nothing happens if the functions are already registered.
*
* @param conn the connection
*/
public static void register(Connection conn) throws SQLException {
String[] init = {
"UNIX_TIMESTAMP", "unixTimestamp",
"FROM_UNIXTIME", "fromUnixTime",
"DATE", "date",
};
Statement stat = conn.createStatement();
for (int i = 0; i < init.length; i += 2) {
String alias = init[i], method = init[i + 1];
stat.execute(
"CREATE ALIAS IF NOT EXISTS " + alias +
" FOR \"" + FunctionsMySQL.class.getName() + "." + method + "\"");
}
}
/** /**
* Get the seconds since 1970-01-01 00:00:00 UTC. * Get the seconds since 1970-01-01 00:00:00 UTC.
* See * See
...@@ -140,24 +142,104 @@ public class FunctionsMySQL { ...@@ -140,24 +142,104 @@ public class FunctionsMySQL {
} }
/** /**
* See * Returns mode-specific function for a given name, or {@code null}.
* http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#function_date
* This function is dependent on the exact formatting of the MySQL date/time
* string.
* *
* @param dateTime The date/time String from which to extract just the date * @param database
* part. * the database
* @return the date part of the given date/time String argument. * @param upperName
* the upper-case name of a function
* @return the function with specified name or {@code null}
*/ */
public static String date(String dateTime) { public static Function getFunction(Database database, String upperName) {
if (dateTime == null) { FunctionInfo info = FUNCTIONS.get(upperName);
return null; return info != null ? new FunctionsMySQL(database, info) : null;
}
FunctionsMySQL(Database database, FunctionInfo info) {
super(database, info);
}
@Override
protected void checkParameterCount(int len) {
int min, max;
switch (info.type) {
case UNIX_TIMESTAMP:
min = 0;
max = 2;
break;
case FROM_UNIXTIME:
min = 1;
max = 2;
break;
case DATE:
min = 1;
max = 1;
break;
default:
DbException.throwInternalError("type=" + info.type);
return;
}
if (len < min || len > max) {
throw DbException.get(ErrorCode.INVALID_PARAMETER_COUNT_2, info.name, min + ".." + max);
}
}
@Override
public Expression optimize(Session session) {
boolean allConst = info.deterministic;
for (int i = 0; i < args.length; i++) {
Expression e = args[i];
if (e == null) {
continue;
}
e = e.optimize(session);
args[i] = e;
if (!e.isConstant()) {
allConst = false;
}
}
if (allConst) {
return ValueExpression.get(getValue(session));
}
dataType = info.returnDataType;
DataType dt = DataType.getDataType(dataType);
precision = dt.defaultPrecision;
scale = dt.defaultScale;
displaySize = dt.defaultDisplaySize;
return this;
}
@Override
protected Value getValueWithArgs(Session session, Expression[] args) {
Value[] values = new Value[args.length];
Value v0 = getNullOrValue(session, args, values, 0);
Value v1 = getNullOrValue(session, args, values, 1);
Value result;
switch (info.type) {
case UNIX_TIMESTAMP:
result = ValueInt.get(v0 == null ? unixTimestamp() : unixTimestamp(v0.getTimestamp()));
break;
case FROM_UNIXTIME:
result = ValueString.get(
v1 == null ? fromUnixTime(v0.getInt()) : fromUnixTime(v0.getInt(), v1.getString()));
break;
case DATE:
switch (v0.getType()) {
case Value.DATE:
result = v0;
break;
default:
v0 = v0.convertTo(Value.TIMESTAMP);
//$FALL-THROUGH$
case Value.TIMESTAMP:
case Value.TIMESTAMP_TZ:
result = v0.convertTo(Value.DATE);
} }
int index = dateTime.indexOf(' '); break;
if (index != -1) { default:
return dateTime.substring(0, index); throw DbException.throwInternalError("type=" + info.type);
} }
return dateTime; return result;
} }
} }
...@@ -307,7 +307,6 @@ public class TestCompatibility extends TestDb { ...@@ -307,7 +307,6 @@ public class TestCompatibility extends TestDb {
stat.execute("DROP TABLE IF EXISTS TEST"); stat.execute("DROP TABLE IF EXISTS TEST");
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)"); stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
stat.execute("INSERT INTO TEST VALUES(1, 'Hello'), (2, 'World')"); stat.execute("INSERT INTO TEST VALUES(1, 'Hello'), (2, 'World')");
org.h2.mode.FunctionsMySQL.register(conn);
assertResult("0", stat, "SELECT UNIX_TIMESTAMP('1970-01-01 00:00:00Z')"); assertResult("0", stat, "SELECT UNIX_TIMESTAMP('1970-01-01 00:00:00Z')");
assertResult("1196418619", stat, assertResult("1196418619", stat,
"SELECT UNIX_TIMESTAMP('2007-11-30 10:30:19Z')"); "SELECT UNIX_TIMESTAMP('2007-11-30 10:30:19Z')");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论