提交 51386e8e authored 作者: noelgrandin's avatar noelgrandin

Support TRUNC(timestamp) to make Oracle users happy.

上级 db6a0c91
......@@ -2799,6 +2799,7 @@ CALL HASH('SHA256', STRINGTOUTF8('Password'), 1000)
","
Truncates to a number of digits (to the next value closer to 0).
This method returns a double.
There is also a TRUNCATE function that operates on numbers.
","
TRUNCATE(VALUE, 2)
"
......@@ -3366,6 +3367,16 @@ Returns the second (0-59) from a timestamp.
SECOND(CREATED)
"
"Functions (Time and Date)","TRUNCATE","
{ TRUNC | TRUNCATE } (timestamp)
","
Truncates a timestamp to a date (day) value.
This method returns a date.
There is also a TRUNCATE function that operates on numbers.
","
TRUNCATE(CREATED)
"
"Functions (Time and Date)","WEEK","
WEEK(timestamp)
","
......
......@@ -18,7 +18,7 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>-
<ul><li>Support TRUNC(timestamp) to make Oracle users happy.
</li></ul>
<h2>Version 1.3.171 (2013-03-17)</h2>
......
......@@ -204,9 +204,9 @@ public class Function extends Expression implements FunctionCall {
addFunction("SQRT", SQRT, 1, Value.DOUBLE);
addFunction("TAN", TAN, 1, Value.DOUBLE);
addFunction("TANH", TANH, 1, Value.DOUBLE);
addFunction("TRUNCATE", TRUNCATE, 2, Value.DOUBLE);
addFunction("TRUNCATE", TRUNCATE, VAR_ARGS, Value.NULL);
// same as TRUNCATE
addFunction("TRUNC", TRUNCATE, 2, Value.DOUBLE);
addFunction("TRUNC", TRUNCATE, VAR_ARGS, Value.NULL);
addFunction("HASH", HASH, 3, Value.BYTES);
addFunction("ENCRYPT", ENCRYPT, 3, Value.BYTES);
addFunction("DECRYPT", DECRYPT, 3, Value.BYTES);
......@@ -1016,11 +1016,22 @@ public class Function extends Expression implements FunctionCall {
break;
}
case TRUNCATE: {
double d = v0.getDouble();
int p = v1.getInt();
double f = Math.pow(10., p);
double g = d * f;
result = ValueDouble.get(((d < 0) ? Math.ceil(g) : Math.floor(g)) / f);
if (v0.getType() == Value.TIMESTAMP) {
java.sql.Timestamp d = v0.getTimestamp();
Calendar c = Calendar.getInstance();
c.setTime(d);
c.set(Calendar.HOUR, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
result = ValueTimestamp.get(new java.sql.Timestamp(c.getTimeInMillis()));
} else {
double d = v0.getDouble();
int p = v1.getInt();
double f = Math.pow(10., p);
double g = d * f;
result = ValueDouble.get(((d < 0) ? Math.ceil(g) : Math.floor(g)) / f);
}
break;
}
case HASH:
......@@ -1699,6 +1710,7 @@ public class Function extends Expression implements FunctionCall {
case FILE_READ:
case ROUND:
case XMLTEXT:
case TRUNCATE:
min = 1;
max = 2;
break;
......@@ -1858,11 +1870,27 @@ public class Function extends Expression implements FunctionCall {
s = scale;
d = displaySize;
break;
case TRUNCATE:
t = p0.getType();
s = p0.getScale();
p = p0.getPrecision();
d = p0.getDisplaySize();
if (t == Value.NULL) {
t = Value.INT;
p = ValueInt.PRECISION;
d = ValueInt.DISPLAY_SIZE;
s = 0;
} else if (t == Value.TIMESTAMP) {
t = Value.DATE;
p = ValueDate.PRECISION;
s = 0;
d = ValueDate.DISPLAY_SIZE;
}
break;
case ABS:
case FLOOR:
case RADIANS:
case ROUND:
case TRUNCATE:
case POWER:
t = p0.getType();
s = p0.getScale();
......@@ -2004,6 +2032,7 @@ public class Function extends Expression implements FunctionCall {
case TRIM:
case STRINGDECODE:
case UTF8TOSTRING:
case TRUNCATE:
precision = args[0].getPrecision();
displaySize = args[0].getDisplaySize();
break;
......
......@@ -1223,6 +1223,10 @@ Returns the quarter (1-4) from a timestamp."
SECOND(timestamp)
","
Returns the second (0-59) from a timestamp."
"Functions (Time and Date)","TRUNCATE","
TRUNCATE(timestamp)
","
Truncates a timestamp to a date (day) value."
"Functions (Time and Date)","WEEK","
WEEK(timestamp)
","
......
......@@ -29,7 +29,7 @@ public class ValueDate extends Value {
* The display size of the textual representation of a date.
* Example: 2000-01-02
*/
static final int DISPLAY_SIZE = 10;
public static final int DISPLAY_SIZE = 10;
private final long dateValue;
......
......@@ -25,9 +25,11 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.SimpleTimeZone;
import org.h2.jdbc.JdbcConnection;
import org.h2.message.DbException;
import org.h2.message.TraceSystem;
......@@ -589,6 +591,22 @@ public abstract class TestBase {
}
}
/**
* Check if two values are equal, and if not throw an exception.
*
* @param expected the expected value
* @param actual the actual value
* @throws AssertionError if the values are not equal
*/
public void assertEquals(java.util.Date expected, java.util.Date actual) {
if (expected != actual && !expected.equals(actual)) {
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
final SimpleTimeZone GMT_TIMEZONE = new SimpleTimeZone(0, "Z");
df.setTimeZone(GMT_TIMEZONE);
fail("Expected: " + df.format(expected) + " actual: " + df.format(actual));
}
}
/**
* Check if two values are equal, and if not throw an exception.
*
......
......@@ -17,6 +17,7 @@ import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
......@@ -25,6 +26,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Properties;
import java.util.UUID;
import org.h2.api.AggregateFunction;
......@@ -75,6 +77,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
testValue();
testNvl2();
testConcatWs();
testTruncate();
deleteDb("functions");
FileUtils.deleteRecursive(TEMP_DIR, true);
}
......@@ -860,6 +863,46 @@ public class TestFunctions extends TestBase implements AggregateFunction {
conn.close();
}
private void testTruncate() throws SQLException {
deleteDb("functions");
Connection conn = getConnection("functions");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT TRUNCATE(1.234, 2) FROM dual");
rs.next();
assertEquals(1.23d, rs.getDouble(1));
rs = stat.executeQuery("SELECT CURRENT_TIMESTAMP(), TRUNCATE(CURRENT_TIMESTAMP()) FROM dual");
rs.next();
Calendar c = Calendar.getInstance();
c.setTime(rs.getTimestamp(1));
c.set(Calendar.HOUR, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
java.util.Date nowDate = c.getTime();
assertEquals(nowDate, rs.getTimestamp(2));
try {
rs = stat.executeQuery("SELECT TRUNCATE('bad', 1) FROM dual");
fail("expected exception");
} catch (SQLException ex) {}
// check for passing wrong data type
try {
rs = stat.executeQuery("SELECT TRUNCATE('bad') FROM dual");
fail("expected exception");
} catch (SQLException ex) {}
// check for too many parameters
try {
rs = stat.executeQuery("SELECT TRUNCATE(1,2,3) FROM dual");
fail("expected exception");
} catch (SQLException ex) {}
conn.close();
}
private void assertCallResult(String expected, Statement stat, String sql) throws SQLException {
ResultSet rs = stat.executeQuery("CALL " + sql);
rs.next();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论