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

Use FunctionsMySQL in MySQL mode

上级 394ac43a
......@@ -29,6 +29,7 @@ import org.h2.engine.Mode;
import org.h2.engine.Session;
import org.h2.message.DbException;
import org.h2.mode.FunctionsMSSQLServer;
import org.h2.mode.FunctionsMySQL;
import org.h2.schema.Schema;
import org.h2.schema.Sequence;
import org.h2.security.BlockCipher;
......@@ -144,7 +145,7 @@ public class Function extends Expression implements FunctionCall {
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 HashMap<String, FunctionInfo> FUNCTIONS = new HashMap<>(256);
......@@ -152,11 +153,13 @@ public class Function extends Expression implements FunctionCall {
protected Expression[] args;
private final FunctionInfo info;
protected final FunctionInfo info;
private ArrayList<Expression> varArgs;
private int dataType, scale;
private long precision = PRECISION_UNKNOWN;
private int displaySize;
protected int dataType;
protected int scale;
protected long precision = PRECISION_UNKNOWN;
protected int displaySize;
private final Database database;
static {
......@@ -524,6 +527,8 @@ public class Function extends Expression implements FunctionCall {
switch (database.getMode().getEnum()) {
case MSSQLServer:
return FunctionsMSSQLServer.getFunction(database, name);
case MySQL:
return FunctionsMySQL.getFunction(database, name);
default:
return null;
}
......@@ -1098,7 +1103,7 @@ public class Function extends Expression implements FunctionCall {
return table.getDiskSpaceUsed();
}
private static Value getNullOrValue(Session session, Expression[] args,
protected static Value getNullOrValue(Session session, Expression[] args,
Value[] values, int i) {
if (i >= args.length) {
return null;
......@@ -1114,7 +1119,7 @@ public class Function extends Expression implements FunctionCall {
return v;
}
private Value getValueWithArgs(Session session, Expression[] args) {
protected Value getValueWithArgs(Session session, Expression[] args) {
Value[] values = new Value[args.length];
if (info.nullIfParameterIsNull) {
for (int i = 0; i < args.length; i++) {
......
......@@ -13,12 +13,12 @@ public final class FunctionInfo {
/**
* The name of the function.
*/
final String name;
public final String name;
/**
* The function type.
*/
final int type;
public final int type;
/**
* The number of parameters.
......@@ -28,7 +28,7 @@ public final class FunctionInfo {
/**
* 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.
......@@ -38,7 +38,7 @@ public final class FunctionInfo {
/**
* 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?
......@@ -66,7 +66,7 @@ public final class FunctionInfo {
* should the return value ResultSet be buffered in a local
* 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) {
this.name = name;
this.type = type;
......
......@@ -7,13 +7,18 @@ package org.h2.mode;
import java.util.HashMap;
import org.h2.engine.Database;
import org.h2.expression.Function;
import org.h2.expression.FunctionInfo;
/**
* 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.
......
......@@ -39,6 +39,7 @@ public final class FunctionsMSSQLServer extends FunctionsBase {
return info != null ? new Function(database, info) : null;
}
private FunctionsMSSQLServer() {
private FunctionsMSSQLServer(Database database, FunctionInfo info) {
super(database, info);
}
}
......@@ -5,14 +5,24 @@
*/
package org.h2.mode;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
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.value.DataType;
import org.h2.value.Value;
import org.h2.value.ValueInt;
import org.h2.value.ValueString;
/**
* This class implements some MySQL-specific functions.
......@@ -20,7 +30,20 @@ import org.h2.util.StringUtils;
* @author Jason Brittain
* @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.
......@@ -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.
* See
......@@ -140,24 +142,104 @@ public class FunctionsMySQL {
}
/**
* See
* 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.
* Returns mode-specific function for a given name, or {@code null}.
*
* @param dateTime The date/time String from which to extract just the date
* part.
* @return the date part of the given date/time String argument.
* @param database
* the database
* @param upperName
* the upper-case name of a function
* @return the function with specified name or {@code null}
*/
public static String date(String dateTime) {
if (dateTime == null) {
return null;
public static Function getFunction(Database database, String upperName) {
FunctionInfo info = FUNCTIONS.get(upperName);
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);
}
int index = dateTime.indexOf(' ');
if (index != -1) {
return dateTime.substring(0, index);
}
@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);
}
break;
default:
throw DbException.throwInternalError("type=" + info.type);
}
return dateTime;
return result;
}
}
......@@ -307,7 +307,6 @@ public class TestCompatibility extends TestDb {
stat.execute("DROP TABLE IF EXISTS TEST");
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
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("1196418619", stat,
"SELECT UNIX_TIMESTAMP('2007-11-30 10:30:19Z')");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论