提交 397d3126 authored 作者: noelgrandin's avatar noelgrandin

Issue 528: Add Oracle-compatible TO_CHAR function, patch by Daniel Gredler.

上级 46188bab
...@@ -3346,6 +3346,14 @@ This method returns a string. ...@@ -3346,6 +3346,14 @@ This method returns a string.
CALL XMLTEXT('test') CALL XMLTEXT('test')
" "
"Functions (String)","TO_CHAR","
TO_CHAR(value [, format[, nlsParam]])
","
Oracle-compatible TO_CHAR function that can format a timestamp, a number, or text.
","
CALL TO_CHAR(TIMESTAMP '2010-01-01 00:00:00', 'DD MON, YYYY')
"
"Functions (Time and Date)","CURRENT_DATE"," "Functions (Time and Date)","CURRENT_DATE","
{ CURRENT_DATE [ () ] | CURDATE() | SYSDATE | TODAY } { CURRENT_DATE [ () ] | CURDATE() | SYSDATE | TODAY }
"," ","
......
...@@ -44,6 +44,7 @@ Change Log ...@@ -44,6 +44,7 @@ Change Log
</li><li>Slightly reduce the memory cost of View metadata. </li><li>Slightly reduce the memory cost of View metadata.
</li><li>Extend support of "GRANT ALTER ANY SCHEMA TO &lt;user&gt;" to allow grantee ability to manipulate tables </li><li>Extend support of "GRANT ALTER ANY SCHEMA TO &lt;user&gt;" to allow grantee ability to manipulate tables
</li><li>Issue 532: Javadoc for ErrorCode.ROLES_AND_RIGHT_CANNOT_BE_MIXED looks wrong </li><li>Issue 532: Javadoc for ErrorCode.ROLES_AND_RIGHT_CANNOT_BE_MIXED looks wrong
</li><li>Issue 528: Add Oracle-compatible TO_CHAR function, patch by Daniel Gredler.
</li></ul> </li></ul>
<h2>Version 1.3.174 (2013-10-19)</h2> <h2>Version 1.3.174 (2013-10-19)</h2>
......
...@@ -72,7 +72,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -72,7 +72,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Store all temp files in the temp directory. </li><li>Store all temp files in the temp directory.
</li><li>Don't use temp files, specially not deleteOnExit (bug 4513817: File.deleteOnExit consumes memory). </li><li>Don't use temp files, specially not deleteOnExit (bug 4513817: File.deleteOnExit consumes memory).
Also to allow opening client / server (remote) connections when using LOBs. Also to allow opening client / server (remote) connections when using LOBs.
</li><li>Sequence: add features [NO] MINVALUE, MAXVALUE, CYCLE.
</li><li>Make DDL (Data Definition) operations transactional. </li><li>Make DDL (Data Definition) operations transactional.
</li><li>Deferred integrity checking (DEFERRABLE INITIALLY DEFERRED). </li><li>Deferred integrity checking (DEFERRABLE INITIALLY DEFERRED).
</li><li>Groovy Stored Procedures: http://groovy.codehaus.org/GSQL </li><li>Groovy Stored Procedures: http://groovy.codehaus.org/GSQL
...@@ -122,7 +121,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -122,7 +121,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Custom class loader to reload functions on demand. </li><li>Custom class loader to reload functions on demand.
</li><li>Test http://mysql-je.sourceforge.net/ </li><li>Test http://mysql-je.sourceforge.net/
</li><li>H2 Console: the webclient could support more features like phpMyAdmin. </li><li>H2 Console: the webclient could support more features like phpMyAdmin.
</li><li>Support Oracle functions: TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER. </li><li>Support Oracle functions: TO_DATE, TO_NUMBER.
</li><li>Work on the Java to C converter. </li><li>Work on the Java to C converter.
</li><li>The HELP information schema can be directly exposed in the Console. </li><li>The HELP information schema can be directly exposed in the Console.
</li><li>Maybe use the 0x1234 notation for binary fields, see MS SQL Server. </li><li>Maybe use the 0x1234 notation for binary fields, see MS SQL Server.
......
...@@ -488,6 +488,13 @@ public class ErrorCode { ...@@ -488,6 +488,13 @@ public class ErrorCode {
*/ */
public static final int SEQUENCE_ATTRIBUTES_INVALID = 90009; public static final int SEQUENCE_ATTRIBUTES_INVALID = 90009;
/**
* The error with code <code>90010</code> is thrown when
* trying to format a timestamp or number using TO_CHAR
* with an invalid format.
*/
public static final int INVALID_TO_CHAR_FORMAT = 90010;
/** /**
* The error with code <code>22007</code> is thrown when * The error with code <code>22007</code> is thrown when
* a text can not be converted to a date, time, or timestamp constant. * a text can not be converted to a date, time, or timestamp constant.
...@@ -1884,7 +1891,7 @@ public class ErrorCode { ...@@ -1884,7 +1891,7 @@ public class ErrorCode {
public static final int JAVA_OBJECT_SERIALIZER_CHANGE_WITH_DATA_TABLE = 90141; public static final int JAVA_OBJECT_SERIALIZER_CHANGE_WITH_DATA_TABLE = 90141;
// next are 90010, 90011, 90021, 90039, // next are 90011, 90021, 90039,
// 90051, 90056, 90110, 90122, 90142 // 90051, 90056, 90110, 90122, 90142
private ErrorCode() { private ErrorCode() {
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
package org.h2.expression; package org.h2.expression;
import static org.h2.util.ToChar.toChar;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
...@@ -85,7 +86,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -85,7 +86,7 @@ public class Function extends Expression implements FunctionCall {
SPACE = 71, SUBSTR = 72, SUBSTRING = 73, UCASE = 74, LOWER = 75, UPPER = 76, POSITION = 77, TRIM = 78, SPACE = 71, SUBSTR = 72, SUBSTRING = 73, UCASE = 74, LOWER = 75, UPPER = 76, POSITION = 77, TRIM = 78,
STRINGENCODE = 79, STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82, XMLATTR = 83, XMLNODE = 84, STRINGENCODE = 79, STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82, XMLATTR = 83, XMLNODE = 84,
XMLCOMMENT = 85, XMLCDATA = 86, XMLSTARTDOC = 87, XMLTEXT = 88, REGEXP_REPLACE = 89, RPAD = 90, LPAD = 91, XMLCOMMENT = 85, XMLCDATA = 86, XMLSTARTDOC = 87, XMLTEXT = 88, REGEXP_REPLACE = 89, RPAD = 90, LPAD = 91,
CONCAT_WS = 92; CONCAT_WS = 92, TO_CHAR = 93;
public static final int CURDATE = 100, CURTIME = 101, DATE_ADD = 102, DATE_DIFF = 103, DAY_NAME = 104, public static final int CURDATE = 100, CURTIME = 101, DATE_ADD = 102, DATE_DIFF = 103, DAY_NAME = 104,
DAY_OF_MONTH = 105, DAY_OF_WEEK = 106, DAY_OF_YEAR = 107, HOUR = 108, MINUTE = 109, MONTH = 110, MONTH_NAME = 111, DAY_OF_MONTH = 105, DAY_OF_WEEK = 106, DAY_OF_YEAR = 107, HOUR = 108, MINUTE = 109, MONTH = 110, MONTH_NAME = 111,
...@@ -280,6 +281,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -280,6 +281,7 @@ public class Function extends Expression implements FunctionCall {
addFunction("REGEXP_REPLACE", REGEXP_REPLACE, 3, Value.STRING); addFunction("REGEXP_REPLACE", REGEXP_REPLACE, 3, Value.STRING);
addFunction("RPAD", RPAD, VAR_ARGS, Value.STRING); addFunction("RPAD", RPAD, VAR_ARGS, Value.STRING);
addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING); addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING);
addFunction("TO_CHAR", TO_CHAR, VAR_ARGS, Value.STRING);
// date // date
addFunctionNotDeterministic("CURRENT_DATE", CURRENT_DATE, 0, Value.DATE); addFunctionNotDeterministic("CURRENT_DATE", CURRENT_DATE, 0, Value.DATE);
...@@ -1191,6 +1193,25 @@ public class Function extends Expression implements FunctionCall { ...@@ -1191,6 +1193,25 @@ public class Function extends Expression implements FunctionCall {
case LPAD: case LPAD:
result = ValueString.get(StringUtils.pad(v0.getString(), v1.getInt(), v2 == null ? null : v2.getString(), false), database.getMode().treatEmptyStringsAsNull); result = ValueString.get(StringUtils.pad(v0.getString(), v1.getInt(), v2 == null ? null : v2.getString(), false), database.getMode().treatEmptyStringsAsNull);
break; break;
case TO_CHAR:
switch(v0.getType()){
case Value.TIME:
case Value.DATE:
case Value.TIMESTAMP:
result = ValueString.get(toChar(v0.getTimestamp(), v1 == null ? null : v1.getString(), v2 == null ? null : v2.getString()), database.getMode().treatEmptyStringsAsNull);
break;
case Value.SHORT:
case Value.INT:
case Value.LONG:
case Value.DECIMAL:
case Value.DOUBLE:
case Value.FLOAT:
result = ValueString.get(toChar(v0.getBigDecimal(), v1 == null ? null : v1.getString(), v2 == null ? null : v2.getString()), database.getMode().treatEmptyStringsAsNull);
break;
default:
result = ValueString.get(v0.getString(), database.getMode().treatEmptyStringsAsNull);
}
break;
case H2VERSION: case H2VERSION:
result = ValueString.get(Constants.getVersion(), database.getMode().treatEmptyStringsAsNull); result = ValueString.get(Constants.getVersion(), database.getMode().treatEmptyStringsAsNull);
break; break;
...@@ -1777,6 +1798,10 @@ public class Function extends Expression implements FunctionCall { ...@@ -1777,6 +1798,10 @@ public class Function extends Expression implements FunctionCall {
min = 1; min = 1;
max = 2; max = 2;
break; break;
case TO_CHAR:
min = 1;
max = 3;
break;
case REPLACE: case REPLACE:
case LOCATE: case LOCATE:
case INSTR: case INSTR:
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
90007=The object is already closed 90007=The object is already closed
90008=Invalid value {0} for parameter {1} 90008=Invalid value {0} for parameter {1}
90009=Unable to create or alter sequence {0} because of invalid attributes (start value {1}, min value {2}, max value {3}, increment {4}) 90009=Unable to create or alter sequence {0} because of invalid attributes (start value {1}, min value {2}, max value {3}, increment {4})
90010=Invalid TO_CHAR format {0}
90012=Parameter {0} is not set 90012=Parameter {0} is not set
90013=Database {0} not found 90013=Database {0} not found
90014=Error parsing {0} 90014=Error parsing {0}
......
...@@ -1183,6 +1183,10 @@ Returns the XML declaration." ...@@ -1183,6 +1183,10 @@ Returns the XML declaration."
XMLTEXT(valueString [, escapeNewlineBoolean]) XMLTEXT(valueString [, escapeNewlineBoolean])
"," ","
Creates an XML text element." Creates an XML text element."
"Functions (String)","TO_CHAR","
TO_CHAR(value [, format[, nlsParam]])
","
Oracle-compatible TO_CHAR function that can format a timestamp, a number, or text."
"Functions (Time and Date)","CURRENT_DATE"," "Functions (Time and Date)","CURRENT_DATE","
{ CURRENT_DATE [ () ] | CURDATE() | SYSDATE | TODAY } { CURRENT_DATE [ () ] | CURDATE() | SYSDATE | TODAY }
"," ","
......
差异被折叠。
...@@ -712,6 +712,8 @@ public abstract class TestBase { ...@@ -712,6 +712,8 @@ public abstract class TestBase {
} else if (expected == null || actual == null) { } else if (expected == null || actual == null) {
fail("Expected: " + expected + " Actual: " + actual + " " + message); fail("Expected: " + expected + " Actual: " + actual + " " + message);
} else if (!expected.equals(actual)) { } else if (!expected.equals(actual)) {
int al = expected.length();
int bl = actual.length();
for (int i = 0; i < expected.length(); i++) { for (int i = 0; i < expected.length(); i++) {
String s = expected.substring(0, i); String s = expected.substring(0, i);
if (!actual.startsWith(s)) { if (!actual.startsWith(s)) {
...@@ -719,8 +721,6 @@ public abstract class TestBase { ...@@ -719,8 +721,6 @@ public abstract class TestBase {
break; break;
} }
} }
int al = expected.length();
int bl = actual.length();
if (al > 4000) { if (al > 4000) {
expected = expected.substring(0, 4000); expected = expected.substring(0, 4000);
} }
...@@ -970,6 +970,22 @@ public abstract class TestBase { ...@@ -970,6 +970,22 @@ public abstract class TestBase {
} }
} }
/**
* Check that executing the specified query results in the specified error.
*
* @param expectedErrorMessage the expected error message
* @param stat the statement
* @param sql the SQL statement to execute
*/
protected void assertThrows(String expectedErrorMessage, Statement stat, String sql) {
try {
stat.executeQuery(sql);
fail("Expected error: " + expectedErrorMessage);
} catch (SQLException e) {
assertTrue(e.getMessage().startsWith(expectedErrorMessage));
}
}
/** /**
* Check if the result set meta data is correct. * Check if the result set meta data is correct.
* *
......
...@@ -743,4 +743,8 @@ lives pauses allocates kicks introduction straightforward getenv ...@@ -743,4 +743,8 @@ lives pauses allocates kicks introduction straightforward getenv
ordinate tweaking fetching rfe yates cookie btrfs cookies ordinate tweaking fetching rfe yates cookie btrfs cookies
nocycle nomaxvalue nominvalue cycling proceed prospective exhausted contingent nocycle nomaxvalue nominvalue cycling proceed prospective exhausted contingent
validities hang degenerates freezes emulation gredler cemo koc blanked validities hang degenerates freezes emulation gredler cemo koc blanked
reverting blanked jump reverting blanked jump capitalization capitalize symbol symbols verbatim
\ No newline at end of file closest resultant savings designator numeral numerals lowercased uppercased
casing epoch century abbreviation scientific circuit emulates blanks substrings
thai tme fmrn fmxxx fmday fml syyyy nov iyy iyyy syear scc fmc fmb fmxx tzr tzd
btc mcmlxxix xliv mdcclxxvi ccxxxviii xii cxlix yyfxyy
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论