Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
397d3126
提交
397d3126
authored
12月 03, 2013
作者:
noelgrandin
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Issue 528: Add Oracle-compatible TO_CHAR function, patch by Daniel Gredler.
上级
46188bab
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
1142 行增加
和
10 行删除
+1142
-10
help.csv
h2/src/docsrc/help/help.csv
+8
-0
changelog.html
h2/src/docsrc/html/changelog.html
+1
-0
roadmap.html
h2/src/docsrc/html/roadmap.html
+1
-2
ErrorCode.java
h2/src/main/org/h2/constant/ErrorCode.java
+8
-1
Function.java
h2/src/main/org/h2/expression/Function.java
+26
-1
_messages_en.prop
h2/src/main/org/h2/res/_messages_en.prop
+1
-0
help.csv
h2/src/main/org/h2/res/help.csv
+4
-0
ToChar.java
h2/src/main/org/h2/util/ToChar.java
+772
-0
TestBase.java
h2/src/test/org/h2/test/TestBase.java
+18
-2
TestFunctions.java
h2/src/test/org/h2/test/db/TestFunctions.java
+298
-3
dictionary.txt
h2/src/tools/org/h2/build/doc/dictionary.txt
+5
-1
没有找到文件。
h2/src/docsrc/help/help.csv
浏览文件 @
397d3126
...
@@ -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 }
","
","
...
...
h2/src/docsrc/html/changelog.html
浏览文件 @
397d3126
...
@@ -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
<
user
>
" to allow grantee ability to manipulate tables
</li><li>
Extend support of "GRANT ALTER ANY SCHEMA TO
<
user
>
" 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>
...
...
h2/src/docsrc/html/roadmap.html
浏览文件 @
397d3126
...
@@ -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: T
RUNC, NVL2, TO_CHAR, T
O_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.
...
...
h2/src/main/org/h2/constant/ErrorCode.java
浏览文件 @
397d3126
...
@@ -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 9001
0, 9001
1, 90021, 90039,
// next are 90011, 90021, 90039,
// 90051, 90056, 90110, 90122, 90142
// 90051, 90056, 90110, 90122, 90142
private
ErrorCode
()
{
private
ErrorCode
()
{
...
...
h2/src/main/org/h2/expression/Function.java
浏览文件 @
397d3126
...
@@ -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:
...
...
h2/src/main/org/h2/res/_messages_en.prop
浏览文件 @
397d3126
...
@@ -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}
...
...
h2/src/main/org/h2/res/help.csv
浏览文件 @
397d3126
...
@@ -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 }
","
","
...
...
h2/src/main/org/h2/util/ToChar.java
0 → 100644
浏览文件 @
397d3126
/*
* Copyright 2004-2013 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: Daniel Gredler
*/
package
org
.
h2
.
util
;
import
static
java
.
lang
.
Math
.
abs
;
import
java.math.BigDecimal
;
import
java.sql.Date
;
import
java.sql.Timestamp
;
import
java.text.DecimalFormat
;
import
java.text.DecimalFormatSymbols
;
import
java.text.SimpleDateFormat
;
import
java.util.Calendar
;
import
java.util.Currency
;
import
java.util.GregorianCalendar
;
import
java.util.Locale
;
import
java.util.TimeZone
;
import
org.h2.constant.ErrorCode
;
import
org.h2.message.DbException
;
/**
* Emulates Oracle's TO_CHAR function.
*/
public
class
ToChar
{
/** The beginning of the Julian calendar. */
private
static
final
long
JULIAN_EPOCH
;
static
{
GregorianCalendar
epoch
=
new
GregorianCalendar
(
Locale
.
ENGLISH
);
epoch
.
setGregorianChange
(
new
Date
(
Long
.
MAX_VALUE
));
epoch
.
clear
();
epoch
.
set
(
4713
,
Calendar
.
JANUARY
,
1
,
0
,
0
,
0
);
epoch
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
BC
);
JULIAN_EPOCH
=
epoch
.
getTimeInMillis
();
}
private
ToChar
()
{
// utility class
}
/**
* Emulates Oracle's TO_CHAR(number) function.
*
* <p><table border="1">
* <tr><td><b>Input</b></td><td><b>Output</b></td><td><b>Closest {@link DecimalFormat} Equivalent</b></td></tr>
* <tr><td>,</td><td>Grouping separator.</td><td>,</td></tr>
* <tr><td>.</td><td>Decimal separator.</td><td>.</td></tr>
* <tr><td>$</td><td>Leading dollar sign.</td><td>$</td></tr>
* <tr><td>0</td><td>Leading or trailing zeroes.</td><td>0</td></tr>
* <tr><td>9</td><td>Digit.</td><td>#</td></tr>
* <tr><td>B</td><td>Blanks integer part of a fixed point number less than 1.</td><td>#</td></tr>
* <tr><td>C</td><td>ISO currency symbol.</td><td>\u00A4</td></tr>
* <tr><td>D</td><td>Local decimal separator.</td><td>.</td></tr>
* <tr><td>EEEE</td><td>Returns a value in scientific notation.</td><td>E</td></tr>
* <tr><td>FM</td><td>Returns values with no leading or trailing spaces.</td><td>None.</td></tr>
* <tr><td>G</td><td>Local grouping separator.</td><td>,</td></tr>
* <tr><td>L</td><td>Local currency symbol.</td><td>\u00A4</td></tr>
* <tr><td>MI</td><td>Negative values get trailing minus sign, positive get trailing space.</td><td>-</td></tr>
* <tr><td>PR</td><td>Negative values get enclosing angle brackets, positive get spaces.</td><td>None.</td></tr>
* <tr><td>RN</td><td>Returns values in Roman numerals.</td><td>None.</td></tr>
* <tr><td>S</td><td>Returns values with leading/trailing +/- signs.</td><td>None.</td></tr>
* <tr><td>TM</td><td>Returns smallest number of characters possible.</td><td>None.</td></tr>
* <tr><td>U</td><td>Returns the dual currency symbol.</td><td>None.</td></tr>
* <tr><td>V</td><td>Returns a value multiplied by 10^n.</td><td>None.</td></tr>
* <tr><td>X</td><td>Hex value.</td><td>None.</td></tr>
* </table>
*
* @param number the number to format
* @param format the format pattern to use (if any)
* @param nlsParam the NLS parameter (if any)
* @return the formatted number
* @see <a href="http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions181.htm">TO_CHAR(number)</a>
* @see <a href="http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34570">Number format models</a>
*/
public
static
String
toChar
(
BigDecimal
number
,
String
format
,
String
nlsParam
)
{
// short-circuit logic for formats that don't follow common logic below
String
formatUp
=
format
!=
null
?
format
.
toUpperCase
()
:
null
;
if
(
formatUp
==
null
||
formatUp
.
equals
(
"TM"
)
||
formatUp
.
equals
(
"TM9"
))
{
String
s
=
number
.
toPlainString
();
return
s
.
startsWith
(
"0."
)
?
s
.
substring
(
1
)
:
s
;
}
else
if
(
formatUp
.
equals
(
"TME"
))
{
int
pow
=
number
.
precision
()
-
number
.
scale
()
-
1
;
number
=
number
.
movePointLeft
(
pow
);
return
number
.
toPlainString
()
+
"E"
+
(
pow
<
0
?
'-'
:
'+'
)
+
(
abs
(
pow
)
<
10
?
"0"
:
""
)
+
abs
(
pow
);
}
else
if
(
formatUp
.
equals
(
"RN"
))
{
boolean
lowercase
=
format
.
startsWith
(
"r"
);
String
rn
=
StringUtils
.
pad
(
toRomanNumeral
(
number
.
intValue
()),
15
,
" "
,
false
);
return
lowercase
?
rn
.
toLowerCase
()
:
rn
;
}
else
if
(
formatUp
.
equals
(
"FMRN"
))
{
boolean
lowercase
=
format
.
charAt
(
2
)
==
'r'
;
String
rn
=
toRomanNumeral
(
number
.
intValue
());
return
lowercase
?
rn
.
toLowerCase
()
:
rn
;
}
else
if
(
formatUp
.
endsWith
(
"X"
))
{
return
toHex
(
number
,
format
);
}
String
originalFormat
=
format
;
DecimalFormatSymbols
symbols
=
DecimalFormatSymbols
.
getInstance
();
char
localGrouping
=
symbols
.
getGroupingSeparator
();
char
localDecimal
=
symbols
.
getDecimalSeparator
();
boolean
leadingSign
=
formatUp
.
startsWith
(
"S"
);
if
(
leadingSign
)
{
format
=
format
.
substring
(
1
);
}
boolean
trailingSign
=
formatUp
.
endsWith
(
"S"
);
if
(
trailingSign
)
{
format
=
format
.
substring
(
0
,
format
.
length
()
-
1
);
}
boolean
trailingMinus
=
formatUp
.
endsWith
(
"MI"
);
if
(
trailingMinus
)
{
format
=
format
.
substring
(
0
,
format
.
length
()
-
2
);
}
boolean
angleBrackets
=
formatUp
.
endsWith
(
"PR"
);
if
(
angleBrackets
)
{
format
=
format
.
substring
(
0
,
format
.
length
()
-
2
);
}
int
v
=
formatUp
.
indexOf
(
"V"
);
if
(
v
>=
0
)
{
int
digits
=
0
;
for
(
int
i
=
v
+
1
;
i
<
format
.
length
();
i
++)
{
char
c
=
format
.
charAt
(
i
);
if
(
c
==
'0'
||
c
==
'9'
)
{
digits
++;
}
}
number
=
number
.
movePointRight
(
digits
);
format
=
format
.
substring
(
0
,
v
)
+
format
.
substring
(
v
+
1
);
}
Integer
power
;
if
(
format
.
endsWith
(
"EEEE"
))
{
power
=
number
.
precision
()
-
number
.
scale
()
-
1
;
number
=
number
.
movePointLeft
(
power
);
format
=
format
.
substring
(
0
,
format
.
length
()
-
4
);
}
else
{
power
=
null
;
}
int
maxLength
=
1
;
boolean
fillMode
=
!
formatUp
.
startsWith
(
"FM"
);
if
(!
fillMode
)
{
format
=
format
.
substring
(
2
);
}
// blanks flag doesn't seem to actually do anything
format
=
format
.
replaceAll
(
"[Bb]"
,
""
);
// if we need to round the number to fit into the format specified,
// go ahead and do that first
int
separator
=
findDecimalSeparator
(
format
);
int
formatScale
=
calculateScale
(
format
,
separator
);
if
(
formatScale
<
number
.
scale
())
{
number
=
number
.
setScale
(
formatScale
,
BigDecimal
.
ROUND_HALF_UP
);
}
// any 9s to the left of the decimal separator but to the right of a
// 0 behave the same as a 0, e.g. "09999.99" -> "00000.99"
for
(
int
i
=
format
.
indexOf
(
'0'
);
i
>=
0
&&
i
<
separator
;
i
++)
{
if
(
format
.
charAt
(
i
)
==
'9'
)
{
format
=
format
.
substring
(
0
,
i
)
+
"0"
+
format
.
substring
(
i
+
1
);
}
}
StringBuilder
output
=
new
StringBuilder
();
String
unscaled
=
number
.
unscaledValue
().
abs
().
toString
();
// start at the decimal point and fill in the numbers to the left,
// working our way from right to left
int
i
=
separator
-
1
;
int
j
=
unscaled
.
length
()
-
number
.
scale
()
-
1
;
for
(;
i
>=
0
;
i
--)
{
char
c
=
format
.
charAt
(
i
);
maxLength
++;
if
(
c
==
'9'
||
c
==
'0'
)
{
if
(
j
>=
0
)
{
char
digit
=
unscaled
.
charAt
(
j
);
output
.
insert
(
0
,
digit
);
j
--;
}
else
if
(
c
==
'0'
&&
power
==
null
)
{
output
.
insert
(
0
,
'0'
);
}
}
else
if
(
c
==
','
)
{
// only add the grouping separator if we have more numbers
if
(
j
>=
0
||
(
i
>
0
&&
format
.
charAt
(
i
-
1
)
==
'0'
))
{
output
.
insert
(
0
,
c
);
}
}
else
if
(
c
==
'G'
||
c
==
'g'
)
{
// only add the grouping separator if we have more numbers
if
(
j
>=
0
||
(
i
>
0
&&
format
.
charAt
(
i
-
1
)
==
'0'
))
{
output
.
insert
(
0
,
localGrouping
);
}
}
else
if
(
c
==
'C'
||
c
==
'c'
)
{
Currency
currency
=
Currency
.
getInstance
(
Locale
.
getDefault
());
output
.
insert
(
0
,
currency
.
getCurrencyCode
());
maxLength
+=
6
;
}
else
if
(
c
==
'L'
||
c
==
'l'
||
c
==
'U'
||
c
==
'u'
)
{
Currency
currency
=
Currency
.
getInstance
(
Locale
.
getDefault
());
output
.
insert
(
0
,
currency
.
getSymbol
());
maxLength
+=
9
;
}
else
if
(
c
==
'$'
)
{
output
.
insert
(
0
,
c
);
}
else
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_TO_CHAR_FORMAT
,
originalFormat
);
}
}
// if the format (to the left of the decimal point) was too small
// to hold the number, return a big "######" string
if
(
j
>=
0
)
{
return
StringUtils
.
pad
(
""
,
format
.
length
()
+
1
,
"#"
,
true
);
}
if
(
separator
<
format
.
length
())
{
// add the decimal point
maxLength
++;
char
pt
=
format
.
charAt
(
separator
);
if
(
pt
==
'd'
||
pt
==
'D'
)
{
output
.
append
(
localDecimal
);
}
else
{
output
.
append
(
pt
);
}
// start at the decimal point and fill in the numbers to the right,
// working our way from left to right
i
=
separator
+
1
;
j
=
unscaled
.
length
()
-
number
.
scale
();
for
(;
i
<
format
.
length
();
i
++)
{
char
c
=
format
.
charAt
(
i
);
maxLength
++;
if
(
c
==
'9'
||
c
==
'0'
)
{
if
(
j
<
unscaled
.
length
())
{
char
digit
=
unscaled
.
charAt
(
j
);
output
.
append
(
digit
);
j
++;
}
else
{
if
(
c
==
'0'
||
fillMode
)
{
output
.
append
(
'0'
);
}
}
}
else
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_TO_CHAR_FORMAT
,
originalFormat
);
}
}
}
addSign
(
output
,
number
.
signum
(),
leadingSign
,
trailingSign
,
trailingMinus
,
angleBrackets
,
fillMode
);
if
(
power
!=
null
)
{
output
.
append
(
'E'
);
output
.
append
(
power
<
0
?
'-'
:
'+'
);
output
.
append
(
Math
.
abs
(
power
)
<
10
?
"0"
:
""
);
output
.
append
(
Math
.
abs
(
power
));
}
if
(
fillMode
)
{
if
(
power
!=
null
)
{
output
.
insert
(
0
,
' '
);
}
else
{
while
(
output
.
length
()
<
maxLength
)
{
output
.
insert
(
0
,
' '
);
}
}
}
return
output
.
toString
();
}
private
static
void
addSign
(
StringBuilder
output
,
int
signum
,
boolean
leadingSign
,
boolean
trailingSign
,
boolean
trailingMinus
,
boolean
angleBrackets
,
boolean
fillMode
)
{
if
(
angleBrackets
)
{
if
(
signum
<
0
)
{
output
.
insert
(
0
,
'<'
);
output
.
append
(
'>'
);
}
else
if
(
fillMode
)
{
output
.
insert
(
0
,
' '
);
output
.
append
(
' '
);
}
}
else
{
String
sign
;
if
(
signum
==
0
)
{
sign
=
""
;
}
else
if
(
signum
<
0
)
{
sign
=
"-"
;
}
else
{
if
(
leadingSign
||
trailingSign
)
{
sign
=
"+"
;
}
else
if
(
fillMode
)
{
sign
=
" "
;
}
else
{
sign
=
""
;
}
}
if
(
trailingMinus
||
trailingSign
)
{
output
.
append
(
sign
);
}
else
{
output
.
insert
(
0
,
sign
);
}
}
}
private
static
int
findDecimalSeparator
(
String
format
)
{
int
index
=
format
.
indexOf
(
'.'
);
if
(
index
==
-
1
)
{
index
=
format
.
indexOf
(
'D'
);
if
(
index
==
-
1
)
{
index
=
format
.
indexOf
(
'd'
);
if
(
index
==
-
1
)
{
index
=
format
.
length
();
}
}
}
return
index
;
}
private
static
int
calculateScale
(
String
format
,
int
separator
)
{
int
scale
=
0
;
for
(
int
i
=
separator
;
i
<
format
.
length
();
i
++)
{
char
c
=
format
.
charAt
(
i
);
if
(
c
==
'0'
||
c
==
'9'
)
{
scale
++;
}
}
return
scale
;
}
private
static
String
toRomanNumeral
(
int
number
)
{
int
[]
values
=
new
int
[]
{
1000
,
900
,
500
,
400
,
100
,
90
,
50
,
40
,
10
,
9
,
5
,
4
,
1
};
String
[]
numerals
=
new
String
[]
{
"M"
,
"CM"
,
"D"
,
"CD"
,
"C"
,
"XC"
,
"L"
,
"XL"
,
"X"
,
"IX"
,
"V"
,
"IV"
,
"I"
};
StringBuilder
result
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
values
.
length
;
i
++)
{
int
value
=
values
[
i
];
String
numeral
=
numerals
[
i
];
while
(
number
>=
value
)
{
result
.
append
(
numeral
);
number
-=
value
;
}
}
return
result
.
toString
();
}
private
static
String
toHex
(
BigDecimal
number
,
String
format
)
{
boolean
fillMode
=
!
format
.
toUpperCase
().
startsWith
(
"FM"
);
boolean
uppercase
=
!
format
.
contains
(
"x"
);
boolean
zeroPadded
=
format
.
startsWith
(
"0"
);
int
digits
=
0
;
for
(
int
i
=
0
;
i
<
format
.
length
();
i
++)
{
char
c
=
format
.
charAt
(
i
);
if
(
c
==
'0'
||
c
==
'X'
||
c
==
'x'
)
{
digits
++;
}
}
int
i
=
number
.
setScale
(
0
,
BigDecimal
.
ROUND_HALF_UP
).
intValue
();
String
hex
=
Integer
.
toHexString
(
i
);
if
(
digits
<
hex
.
length
())
{
hex
=
StringUtils
.
pad
(
""
,
digits
+
1
,
"#"
,
true
);
}
else
{
if
(
uppercase
)
{
hex
=
hex
.
toUpperCase
();
}
if
(
zeroPadded
)
{
hex
=
StringUtils
.
pad
(
hex
,
digits
,
"0"
,
false
);
}
if
(
fillMode
)
{
hex
=
StringUtils
.
pad
(
hex
,
format
.
length
()
+
1
,
" "
,
false
);
}
}
return
hex
;
}
/**
* Emulates Oracle's TO_CHAR(datetime) function.
*
* <p><table border="1">
* <tr><td><b>Input</b></td><td><b>Output</b></td><td><b>Closest {@link SimpleDateFormat} Equivalent</b></td></tr>
* <tr><td>- / , . ; : "text"</td><td>Reproduced verbatim.</td><td>'text'</td></tr>
* <tr><td>A.D. AD B.C. BC</td><td>Era designator, with or without periods.</td><td>G</td></tr>
* <tr><td>A.M. AM P.M. PM</td><td>AM/PM marker.</td><td>a</td></tr>
* <tr><td>CC SCC</td><td>Century.</td><td>None.</td></tr>
* <tr><td>D</td><td>Day of week.</td><td>u</td></tr>
* <tr><td>DAY</td><td>Name of day.</td><td>EEEE</td></tr>
* <tr><td>DY</td><td>Abbreviated day name.</td><td>EEE</td></tr>
* <tr><td>DD</td><td>Day of month.</td><td>d</td></tr>
* <tr><td>DDD</td><td>Day of year.</td><td>D</td></tr>
* <tr><td>DL</td><td>Long date format.</td><td>EEEE, MMMM d, yyyy</td></tr>
* <tr><td>DS</td><td>Short date format.</td><td>MM/dd/yyyy</td></tr>
* <tr><td>E</td><td>Abbreviated era name (Japanese, Chinese, Thai)</td><td>None.</td></tr>
* <tr><td>EE</td><td>Full era name (Japanese, Chinese, Thai)</td><td>None.</td></tr>
* <tr><td>FF[1-9]</td><td>Fractional seconds.</td><td>S</td></tr>
* <tr><td>FM</td><td>Returns values with no leading or trailing spaces.</td><td>None.</td></tr>
* <tr><td>FX</td><td>Requires exact matches between character data and format model.</td><td>None.</td></tr>
* <tr><td>HH HH12</td><td>Hour in AM/PM (1-12).</td><td>hh</td></tr>
* <tr><td>HH24</td><td>Hour in day (0-23).</td><td>HH</td></tr>
* <tr><td>IW</td><td>Week in year.</td><td>w</td></tr>
* <tr><td>WW</td><td>Week in year.</td><td>w</td></tr>
* <tr><td>W</td><td>Week in month.</td><td>W</td></tr>
* <tr><td>IYYY IYY IY I</td><td>Last 4/3/2/1 digit(s) of ISO year.</td><td>yyyy yyy yy y</td></tr>
* <tr><td>RRRR RR</td><td>Last 4/2 digits of year.</td><td>yyyy yy</td></tr>
* <tr><td>Y,YYY</td><td>Year with comma.</td><td>None.</td></tr>
* <tr><td>YEAR SYEAR</td><td>Year spelled out (S prefixes BC years with minus sign).</td><td>None.</td></tr>
* <tr><td>YYYY SYYYY</td><td>4-digit year (S prefixes BC years with minus sign).</td><td>yyyy</td></tr>
* <tr><td>YYY YY Y</td><td>Last 3/2/1 digit(s) of year.</td><td>yyy yy y</td></tr>
* <tr><td>J</td><td>Julian day (number of days since January 1, 4712 BC).</td><td>None.</td></tr>
* <tr><td>MI</td><td>Minute in hour.</td><td>mm</td></tr>
* <tr><td>MM</td><td>Month in year.</td><td>MM</td></tr>
* <tr><td>MON</td><td>Abbreviated name of month.</td><td>MMM</td></tr>
* <tr><td>MONTH</td><td>Name of month, padded with spaces.</td><td>MMMM</td></tr>
* <tr><td>RM</td><td>Roman numeral month (I-XII).</td><td>None.</td></tr>
* <tr><td>Q</td><td>Quarter of year.</td><td>None.</td></tr>
* <tr><td>SS</td><td>Seconds in minute.</td><td>ss</td></tr>
* <tr><td>SSSSS</td><td>Seconds in day.</td><td>None.</td></tr>
* <tr><td>TS</td><td>Short time format.</td><td>h:mm:ss aa</td></tr>
* <tr><td>TZD</td><td>Daylight savings time zone abbreviation.</td><td>z</td></tr>
* <tr><td>TZR</td><td>Time zone region information.</td><td>zzzz</td></tr>
* <tr><td>X</td><td>Local radix character.</td><td>None.</td></tr>
* </table>
*
* @param ts the timestamp to format
* @param format the format pattern to use (if any)
* @param nlsParam the NLS parameter (if any)
* @return the formatted timestamp
* @see <a href="http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions180.htm">TO_CHAR(datetime)</a>
* @see <a href="http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34924">Datetime format models</a>
*/
public
static
String
toChar
(
Timestamp
ts
,
String
format
,
String
nlsParam
)
{
if
(
format
==
null
)
{
format
=
"DD-MON-YY HH.MI.SS.FF PM"
;
}
GregorianCalendar
cal
=
new
GregorianCalendar
(
Locale
.
ENGLISH
);
cal
.
setTimeInMillis
(
ts
.
getTime
());
StringBuilder
output
=
new
StringBuilder
();
boolean
fillMode
=
true
;
for
(
int
i
=
0
;
i
<
format
.
length
();)
{
Capitalization
cap
;
// AD / BC
if
((
cap
=
containsAt
(
format
,
i
,
"A.D."
,
"B.C."
))
!=
null
)
{
String
era
=
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
AD
?
"A.D."
:
"B.C."
;
output
.
append
(
cap
.
apply
(
era
));
i
+=
4
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"AD"
,
"BC"
))
!=
null
)
{
String
era
=
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
AD
?
"AD"
:
"BC"
;
output
.
append
(
cap
.
apply
(
era
));
i
+=
2
;
// AM / PM
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"A.M."
,
"P.M."
))
!=
null
)
{
String
am
=
cal
.
get
(
Calendar
.
AM_PM
)
==
Calendar
.
AM
?
"A.M."
:
"P.M."
;
output
.
append
(
cap
.
apply
(
am
));
i
+=
4
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"AM"
,
"PM"
))
!=
null
)
{
String
am
=
cal
.
get
(
Calendar
.
AM_PM
)
==
Calendar
.
AM
?
"AM"
:
"PM"
;
output
.
append
(
cap
.
apply
(
am
));
i
+=
2
;
// Long/short date/time format
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DL"
))
!=
null
)
{
output
.
append
(
new
SimpleDateFormat
(
"EEEE, MMMM d, yyyy"
).
format
(
ts
));
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DS"
))
!=
null
)
{
output
.
append
(
new
SimpleDateFormat
(
"MM/dd/yyyy"
).
format
(
ts
));
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"TS"
))
!=
null
)
{
output
.
append
(
new
SimpleDateFormat
(
"h:mm:ss aa"
).
format
(
ts
));
i
+=
2
;
// Day
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DDD"
))
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
DAY_OF_YEAR
));
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DD"
))
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
DAY_OF_MONTH
));
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DY"
))
!=
null
)
{
String
day
=
new
SimpleDateFormat
(
"EEE"
).
format
(
ts
).
toUpperCase
();
output
.
append
(
cap
.
apply
(
day
));
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DAY"
))
!=
null
)
{
String
day
=
new
SimpleDateFormat
(
"EEEE"
).
format
(
ts
);
if
(
fillMode
)
{
day
=
StringUtils
.
pad
(
day
,
"Wednesday"
.
length
(),
" "
,
true
);
}
output
.
append
(
cap
.
apply
(
day
));
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"D"
))
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
DAY_OF_WEEK
));
i
+=
1
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"J"
))
!=
null
)
{
long
millis
=
ts
.
getTime
()
-
JULIAN_EPOCH
;
long
days
=
(
long
)
Math
.
floor
(
millis
/
(
1000
*
60
*
60
*
24
));
output
.
append
(
days
);
i
+=
1
;
// Hours
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"HH24"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
HOUR_OF_DAY
)));
i
+=
4
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"HH12"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
HOUR
)));
i
+=
4
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"HH"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
HOUR
)));
i
+=
2
;
// Minutes
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MI"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
MINUTE
)));
i
+=
2
;
// Seconds
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"SSSSS"
))
!=
null
)
{
int
seconds
=
cal
.
get
(
Calendar
.
HOUR_OF_DAY
)
*
60
*
60
;
seconds
+=
cal
.
get
(
Calendar
.
MINUTE
)
*
60
;
seconds
+=
cal
.
get
(
Calendar
.
SECOND
);
output
.
append
(
seconds
);
i
+=
5
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"SS"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
SECOND
)));
i
+=
2
;
// Fractional seconds
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"FF1"
,
"FF2"
,
"FF3"
,
"FF4"
,
"FF5"
,
"FF6"
,
"FF7"
,
"FF8"
,
"FF9"
))
!=
null
)
{
int
x
=
Integer
.
parseInt
(
format
.
substring
(
i
+
2
,
i
+
3
));
int
ff
=
(
int
)
(
cal
.
get
(
Calendar
.
MILLISECOND
)
*
Math
.
pow
(
10
,
x
-
3
));
output
.
append
(
ff
);
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"FF"
))
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
MILLISECOND
)
*
1000
);
i
+=
2
;
// Time zone
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"TZR"
))
!=
null
)
{
TimeZone
tz
=
TimeZone
.
getDefault
();
output
.
append
(
tz
.
getID
());
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"TZD"
))
!=
null
)
{
TimeZone
tz
=
TimeZone
.
getDefault
();
boolean
daylight
=
tz
.
inDaylightTime
(
new
java
.
util
.
Date
());
output
.
append
(
tz
.
getDisplayName
(
daylight
,
TimeZone
.
SHORT
));
i
+=
3
;
// Week
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"IW"
,
"WW"
))
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
WEEK_OF_YEAR
));
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"W"
))
!=
null
)
{
int
w
=
(
int
)
(
1
+
Math
.
floor
(
cal
.
get
(
Calendar
.
DAY_OF_MONTH
)
/
7
));
output
.
append
(
w
);
i
+=
1
;
// Year
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"Y,YYY"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"#,###"
).
format
(
getYear
(
cal
)));
i
+=
5
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"SYYYY"
))
!=
null
)
{
if
(
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
BC
)
{
output
.
append
(
'-'
);
}
output
.
append
(
new
DecimalFormat
(
"0000"
).
format
(
getYear
(
cal
)));
i
+=
5
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"YYYY"
,
"IYYY"
,
"RRRR"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"0000"
).
format
(
getYear
(
cal
)));
i
+=
4
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"YYY"
,
"IYY"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"000"
).
format
(
getYear
(
cal
)
%
1000
));
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"YY"
,
"IY"
,
"RR"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
getYear
(
cal
)
%
100
));
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"I"
,
"Y"
))
!=
null
)
{
output
.
append
(
getYear
(
cal
)
%
10
);
i
+=
1
;
// Month / quarter
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MONTH"
))
!=
null
)
{
String
month
=
new
SimpleDateFormat
(
"MMMM"
).
format
(
ts
);
if
(
fillMode
)
{
month
=
StringUtils
.
pad
(
month
,
"September"
.
length
(),
" "
,
true
);
}
output
.
append
(
cap
.
apply
(
month
));
i
+=
5
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MON"
))
!=
null
)
{
String
month
=
new
SimpleDateFormat
(
"MMM"
).
format
(
ts
);
output
.
append
(
cap
.
apply
(
month
));
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MM"
))
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
MONTH
)
+
1
);
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"RM"
))
!=
null
)
{
int
month
=
cal
.
get
(
Calendar
.
MONTH
)
+
1
;
output
.
append
(
cap
.
apply
(
toRomanNumeral
(
month
)));
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"Q"
))
!=
null
)
{
int
q
=
(
int
)
(
1
+
Math
.
floor
(
cal
.
get
(
Calendar
.
MONTH
)
/
3
));
output
.
append
(
q
);
i
+=
1
;
// Local radix character
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"X"
))
!=
null
)
{
char
c
=
DecimalFormatSymbols
.
getInstance
().
getDecimalSeparator
();
output
.
append
(
c
);
i
+=
1
;
// Format modifiers
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"FM"
))
!=
null
)
{
fillMode
=
!
fillMode
;
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"FX"
))
!=
null
)
{
i
+=
2
;
// Literal text
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"\""
))
!=
null
)
{
for
(
i
=
i
+
1
;
i
<
format
.
length
();
i
++)
{
char
c
=
format
.
charAt
(
i
);
if
(
c
!=
'"'
)
{
output
.
append
(
c
);
}
else
{
i
++;
break
;
}
}
}
else
if
(
format
.
charAt
(
i
)
==
'-'
||
format
.
charAt
(
i
)
==
'/'
||
format
.
charAt
(
i
)
==
','
||
format
.
charAt
(
i
)
==
'.'
||
format
.
charAt
(
i
)
==
';'
||
format
.
charAt
(
i
)
==
':'
||
format
.
charAt
(
i
)
==
' '
)
{
output
.
append
(
format
.
charAt
(
i
));
i
+=
1
;
// Anything else
}
else
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_TO_CHAR_FORMAT
,
format
);
}
}
return
output
.
toString
();
}
private
static
int
getYear
(
Calendar
cal
)
{
int
year
=
cal
.
get
(
Calendar
.
YEAR
);
if
(
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
BC
)
{
year
--;
}
return
year
;
}
/**
* Returns a capitalization strategy if the specified string contains any of the specified substrings at the
* specified index. The capitalization strategy indicates the casing of the substring that was found. If none
* of the specified substrings are found, this method returns <code>null</code>.
*
* @param s the string to check
* @param index the index to check at
* @param substrings the substrings to check for within the string
* @return a capitalization strategy if the specified string contains any of the specified substrings at the
* specified index, <code>null</code> otherwise
*/
private
static
Capitalization
containsAt
(
String
s
,
int
index
,
String
...
substrings
)
{
for
(
String
substring
:
substrings
)
{
if
(
index
+
substring
.
length
()
<=
s
.
length
())
{
boolean
found
=
true
;
Boolean
up1
=
null
;
Boolean
up2
=
null
;
for
(
int
i
=
0
;
i
<
substring
.
length
();
i
++)
{
char
c1
=
s
.
charAt
(
index
+
i
);
char
c2
=
substring
.
charAt
(
i
);
if
(
c1
!=
c2
&&
Character
.
toUpperCase
(
c1
)
!=
Character
.
toUpperCase
(
c2
))
{
found
=
false
;
break
;
}
else
if
(
Character
.
isLetter
(
c1
))
{
if
(
up1
==
null
)
{
up1
=
Character
.
isUpperCase
(
c1
);
}
else
if
(
up2
==
null
)
{
up2
=
Character
.
isUpperCase
(
c1
);
}
}
}
if
(
found
)
{
return
Capitalization
.
toCapitalization
(
up1
,
up2
);
}
}
}
return
null
;
}
/** Represents a capitalization / casing strategy. */
private
enum
Capitalization
{
/** All letters are uppercased. */
UPPERCASE
,
/** All letters are lowercased. */
LOWERCASE
,
/** The string is capitalized (first letter uppercased, subsequent letters lowercased). */
CAPITALIZE
;
/**
* Returns the capitalization / casing strategy which should be used when the first and second letters have
* the specified casing.
*
* @param up1 whether or not the first letter is uppercased
* @param up2 whether or not the second letter is uppercased
* @return the capitalization / casing strategy which should be used when the first and second letters have
* the specified casing
*/
public
static
Capitalization
toCapitalization
(
Boolean
up1
,
Boolean
up2
)
{
if
(
up1
==
null
)
{
return
Capitalization
.
CAPITALIZE
;
}
else
if
(
up2
==
null
)
{
return
up1
?
Capitalization
.
UPPERCASE
:
Capitalization
.
LOWERCASE
;
}
else
if
(
up1
)
{
return
up2
?
Capitalization
.
UPPERCASE
:
Capitalization
.
CAPITALIZE
;
}
else
{
return
Capitalization
.
LOWERCASE
;
}
}
/**
* Applies this capitalization strategy to the specified string.
*
* @param s the string to apply this strategy to
* @return the resultant string
*/
public
String
apply
(
String
s
)
{
if
(
s
==
null
||
s
.
isEmpty
())
{
return
s
;
}
switch
(
this
)
{
case
UPPERCASE:
return
s
.
toUpperCase
();
case
LOWERCASE:
return
s
.
toLowerCase
();
case
CAPITALIZE:
return
Character
.
toUpperCase
(
s
.
charAt
(
0
))
+
(
s
.
length
()
>
1
?
s
.
toLowerCase
().
substring
(
1
)
:
""
);
default
:
throw
new
IllegalArgumentException
(
"Unknown capitalization strategy: "
+
this
);
}
}
}
}
h2/src/test/org/h2/test/TestBase.java
浏览文件 @
397d3126
...
@@ -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.
*
*
...
...
h2/src/test/org/h2/test/db/TestFunctions.java
浏览文件 @
397d3126
...
@@ -26,7 +26,11 @@ import java.sql.Statement;
...
@@ -26,7 +26,11 @@ import java.sql.Statement;
import
java.sql.Types
;
import
java.sql.Types
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Calendar
;
import
java.util.Calendar
;
import
java.util.Currency
;
import
java.util.Date
;
import
java.util.Locale
;
import
java.util.Properties
;
import
java.util.Properties
;
import
java.util.TimeZone
;
import
java.util.UUID
;
import
java.util.UUID
;
import
org.h2.api.AggregateFunction
;
import
org.h2.api.AggregateFunction
;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.ErrorCode
;
...
@@ -82,6 +86,9 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -82,6 +86,9 @@ public class TestFunctions extends TestBase implements AggregateFunction {
testNvl2
();
testNvl2
();
testConcatWs
();
testConcatWs
();
testTruncate
();
testTruncate
();
testToCharFromDateTime
();
testToCharFromNumber
();
testToCharFromText
();
// TODO
// TODO
// testCachingOfDeterministicFunctionAlias();
// testCachingOfDeterministicFunctionAlias();
...
@@ -217,11 +224,11 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -217,11 +224,11 @@ public class TestFunctions extends TestBase implements AggregateFunction {
Connection
conn
=
getConnection
(
"functions"
);
Connection
conn
=
getConnection
(
"functions"
);
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
ResultSet
rs
;
ResultSet
rs
;
stat
.
execute
(
"create alias TO_CHAR for \""
+
getClass
().
getName
()
+
".toChar\""
);
stat
.
execute
(
"create alias TO_CHAR
_2
for \""
+
getClass
().
getName
()
+
".toChar\""
);
rs
=
stat
.
executeQuery
(
"call TO_CHAR(TIMESTAMP '2001-02-03 04:05:06', 'format')"
);
rs
=
stat
.
executeQuery
(
"call TO_CHAR
_2
(TIMESTAMP '2001-02-03 04:05:06', 'format')"
);
rs
.
next
();
rs
.
next
();
assertEquals
(
"2001-02-03 04:05:06.0"
,
rs
.
getString
(
1
));
assertEquals
(
"2001-02-03 04:05:06.0"
,
rs
.
getString
(
1
));
stat
.
execute
(
"drop alias TO_CHAR"
);
stat
.
execute
(
"drop alias TO_CHAR
_2
"
);
conn
.
close
();
conn
.
close
();
}
}
...
@@ -935,6 +942,294 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -935,6 +942,294 @@ public class TestFunctions extends TestBase implements AggregateFunction {
conn
.
close
();
conn
.
close
();
}
}
private
void
testToCharFromDateTime
()
throws
SQLException
{
deleteDb
(
"functions"
);
Connection
conn
=
getConnection
(
"functions"
);
Statement
stat
=
conn
.
createStatement
();
TimeZone
tz
=
TimeZone
.
getDefault
();
boolean
daylight
=
tz
.
inDaylightTime
(
new
Date
());
String
tzShortName
=
tz
.
getDisplayName
(
daylight
,
TimeZone
.
SHORT
);
String
tzLongName
=
tz
.
getID
();
stat
.
executeUpdate
(
"CREATE TABLE T (X TIMESTAMP(6))"
);
stat
.
executeUpdate
(
"INSERT INTO T VALUES (TIMESTAMP '1979-11-12 08:12:34.560')"
);
stat
.
executeUpdate
(
"CREATE TABLE U (X TIMESTAMP(6))"
);
stat
.
executeUpdate
(
"INSERT INTO U VALUES (TIMESTAMP '-100-01-15 14:04:02.120')"
);
assertResult
(
"1979-11-12 08:12:34.56"
,
stat
,
"SELECT X FROM T"
);
assertResult
(
"-100-01-15 14:04:02.12"
,
stat
,
"SELECT X FROM U"
);
assertResult
(
"12-NOV-79 08.12.34.560000 AM"
,
stat
,
"SELECT TO_CHAR(X) FROM T"
);
assertResult
(
"- / , . ; : text - /"
,
stat
,
"SELECT TO_CHAR(X, '- / , . ; : \"text\" - /') FROM T"
);
assertResult
(
"1979-11-12"
,
stat
,
"SELECT TO_CHAR(X, 'YYYY-MM-DD') FROM T"
);
assertResult
(
"1979/11/12"
,
stat
,
"SELECT TO_CHAR(X, 'YYYY/MM/DD') FROM T"
);
assertResult
(
"1979,11,12"
,
stat
,
"SELECT TO_CHAR(X, 'YYYY,MM,DD') FROM T"
);
assertResult
(
"1979.11.12"
,
stat
,
"SELECT TO_CHAR(X, 'YYYY.MM.DD') FROM T"
);
assertResult
(
"1979;11;12"
,
stat
,
"SELECT TO_CHAR(X, 'YYYY;MM;DD') FROM T"
);
assertResult
(
"1979:11:12"
,
stat
,
"SELECT TO_CHAR(X, 'YYYY:MM:DD') FROM T"
);
assertResult
(
"year 1979!"
,
stat
,
"SELECT TO_CHAR(X, '\"year \"YYYY\"!\"') FROM T"
);
assertResult
(
"1979 AD"
,
stat
,
"SELECT TO_CHAR(X, 'YYYY AD') FROM T"
);
assertResult
(
"1979 A.D."
,
stat
,
"SELECT TO_CHAR(X, 'YYYY A.D.') FROM T"
);
assertResult
(
"0100 B.C."
,
stat
,
"SELECT TO_CHAR(X, 'YYYY A.D.') FROM U"
);
assertResult
(
"1979 AD"
,
stat
,
"SELECT TO_CHAR(X, 'YYYY BC') FROM T"
);
assertResult
(
"100 BC"
,
stat
,
"SELECT TO_CHAR(X, 'YYY BC') FROM U"
);
assertResult
(
"00 BC"
,
stat
,
"SELECT TO_CHAR(X, 'YY BC') FROM U"
);
assertResult
(
"0 BC"
,
stat
,
"SELECT TO_CHAR(X, 'Y BC') FROM U"
);
assertResult
(
"1979 A.D."
,
stat
,
"SELECT TO_CHAR(X, 'YYYY B.C.') FROM T"
);
assertResult
(
"08:12 AM"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI AM') FROM T"
);
assertResult
(
"08:12 A.M."
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI A.M.') FROM T"
);
assertResult
(
"02:04 P.M."
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI A.M.') FROM U"
);
assertResult
(
"08:12 AM"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI PM') FROM T"
);
assertResult
(
"02:04 PM"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI PM') FROM U"
);
assertResult
(
"08:12 A.M."
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI P.M.') FROM T"
);
assertResult
(
"A.M."
,
stat
,
"SELECT TO_CHAR(X, 'P.M.') FROM T"
);
assertResult
(
"a.m."
,
stat
,
"SELECT TO_CHAR(X, 'p.M.') FROM T"
);
assertResult
(
"a.m."
,
stat
,
"SELECT TO_CHAR(X, 'p.m.') FROM T"
);
assertResult
(
"AM"
,
stat
,
"SELECT TO_CHAR(X, 'PM') FROM T"
);
assertResult
(
"Am"
,
stat
,
"SELECT TO_CHAR(X, 'Pm') FROM T"
);
assertResult
(
"am"
,
stat
,
"SELECT TO_CHAR(X, 'pM') FROM T"
);
assertResult
(
"am"
,
stat
,
"SELECT TO_CHAR(X, 'pm') FROM T"
);
assertResult
(
"2"
,
stat
,
"SELECT TO_CHAR(X, 'D') FROM T"
);
assertResult
(
"2"
,
stat
,
"SELECT TO_CHAR(X, 'd') FROM T"
);
assertResult
(
"MONDAY "
,
stat
,
"SELECT TO_CHAR(X, 'DAY') FROM T"
);
assertResult
(
"Monday "
,
stat
,
"SELECT TO_CHAR(X, 'Day') FROM T"
);
assertResult
(
"monday "
,
stat
,
"SELECT TO_CHAR(X, 'day') FROM T"
);
assertResult
(
"monday "
,
stat
,
"SELECT TO_CHAR(X, 'dAY') FROM T"
);
assertResult
(
"Monday"
,
stat
,
"SELECT TO_CHAR(X, 'fmDay') FROM T"
);
assertResult
(
"monday -monday-monday-monday -monday"
,
stat
,
"SELECT TO_CHAR(X, 'day-fmday-day-fmday-fmday') FROM T"
);
assertResult
(
"12"
,
stat
,
"SELECT TO_CHAR(X, 'DD') FROM T"
);
assertResult
(
"316"
,
stat
,
"SELECT TO_CHAR(X, 'DDD') FROM T"
);
assertResult
(
"316"
,
stat
,
"SELECT TO_CHAR(X, 'DdD') FROM T"
);
assertResult
(
"316"
,
stat
,
"SELECT TO_CHAR(X, 'dDD') FROM T"
);
assertResult
(
"316"
,
stat
,
"SELECT TO_CHAR(X, 'ddd') FROM T"
);
assertResult
(
"Monday, November 12, 1979"
,
stat
,
"SELECT TO_CHAR(X, 'DL') FROM T"
);
assertResult
(
"Monday, November 12, 1979"
,
stat
,
"SELECT TO_CHAR(X, 'DL', 'NLS_DATE_LANGUAGE = English') FROM T"
);
assertResult
(
"11/12/1979"
,
stat
,
"SELECT TO_CHAR(X, 'DS') FROM T"
);
assertResult
(
"11/12/1979"
,
stat
,
"SELECT TO_CHAR(X, 'Ds') FROM T"
);
assertResult
(
"11/12/1979"
,
stat
,
"SELECT TO_CHAR(X, 'dS') FROM T"
);
assertResult
(
"11/12/1979"
,
stat
,
"SELECT TO_CHAR(X, 'ds') FROM T"
);
assertResult
(
"MON"
,
stat
,
"SELECT TO_CHAR(X, 'DY') FROM T"
);
assertResult
(
"Mon"
,
stat
,
"SELECT TO_CHAR(X, 'Dy') FROM T"
);
assertResult
(
"mon"
,
stat
,
"SELECT TO_CHAR(X, 'dy') FROM T"
);
assertResult
(
"mon"
,
stat
,
"SELECT TO_CHAR(X, 'dY') FROM T"
);
assertResult
(
"08:12:34.560000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF') FROM T"
);
assertResult
(
"08:12:34.5"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF1') FROM T"
);
assertResult
(
"08:12:34.56"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF2') FROM T"
);
assertResult
(
"08:12:34.560"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF3') FROM T"
);
assertResult
(
"08:12:34.5600"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF4') FROM T"
);
assertResult
(
"08:12:34.56000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF5') FROM T"
);
assertResult
(
"08:12:34.560000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF6') FROM T"
);
assertResult
(
"08:12:34.5600000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF7') FROM T"
);
assertResult
(
"08:12:34.56000000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF8') FROM T"
);
assertResult
(
"08:12:34.560000000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF9') FROM T"
);
assertResult
(
"08:12:34.560000000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.ff9') FROM T"
);
assertResult
(
"08:12:34.560000000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.fF9') FROM T"
);
assertResult
(
"08:12"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI') FROM T"
);
assertResult
(
"08:12"
,
stat
,
"SELECT TO_CHAR(X, 'HH12:MI') FROM T"
);
assertResult
(
"08:12"
,
stat
,
"SELECT TO_CHAR(X, 'HH24:MI') FROM T"
);
assertResult
(
"46"
,
stat
,
"SELECT TO_CHAR(X, 'IW') FROM T"
);
assertResult
(
"46"
,
stat
,
"SELECT TO_CHAR(X, 'WW') FROM T"
);
assertResult
(
"2"
,
stat
,
"SELECT TO_CHAR(X, 'W') FROM T"
);
assertResult
(
"9"
,
stat
,
"SELECT TO_CHAR(X, 'I') FROM T"
);
assertResult
(
"79"
,
stat
,
"SELECT TO_CHAR(X, 'IY') FROM T"
);
assertResult
(
"979"
,
stat
,
"SELECT TO_CHAR(X, 'IYY') FROM T"
);
assertResult
(
"1979"
,
stat
,
"SELECT TO_CHAR(X, 'IYYY') FROM T"
);
assertResult
(
"2444190"
,
stat
,
"SELECT TO_CHAR(X, 'J') FROM T"
);
assertResult
(
"12"
,
stat
,
"SELECT TO_CHAR(X, 'MI') FROM T"
);
assertResult
(
"11"
,
stat
,
"SELECT TO_CHAR(X, 'MM') FROM T"
);
assertResult
(
"11"
,
stat
,
"SELECT TO_CHAR(X, 'Mm') FROM T"
);
assertResult
(
"11"
,
stat
,
"SELECT TO_CHAR(X, 'mM') FROM T"
);
assertResult
(
"11"
,
stat
,
"SELECT TO_CHAR(X, 'mm') FROM T"
);
assertResult
(
"NOV"
,
stat
,
"SELECT TO_CHAR(X, 'MON') FROM T"
);
assertResult
(
"Nov"
,
stat
,
"SELECT TO_CHAR(X, 'Mon') FROM T"
);
assertResult
(
"nov"
,
stat
,
"SELECT TO_CHAR(X, 'mon') FROM T"
);
assertResult
(
"NOVEMBER "
,
stat
,
"SELECT TO_CHAR(X, 'MONTH') FROM T"
);
assertResult
(
"November "
,
stat
,
"SELECT TO_CHAR(X, 'Month') FROM T"
);
assertResult
(
"november "
,
stat
,
"SELECT TO_CHAR(X, 'month') FROM T"
);
assertResult
(
"November"
,
stat
,
"SELECT TO_CHAR(X, 'fmMonth') FROM T"
);
assertResult
(
"4"
,
stat
,
"SELECT TO_CHAR(X, 'Q') FROM T"
);
assertResult
(
"XI"
,
stat
,
"SELECT TO_CHAR(X, 'RM') FROM T"
);
assertResult
(
"xi"
,
stat
,
"SELECT TO_CHAR(X, 'rm') FROM T"
);
assertResult
(
"Xi"
,
stat
,
"SELECT TO_CHAR(X, 'Rm') FROM T"
);
assertResult
(
"79"
,
stat
,
"SELECT TO_CHAR(X, 'RR') FROM T"
);
assertResult
(
"1979"
,
stat
,
"SELECT TO_CHAR(X, 'RRRR') FROM T"
);
assertResult
(
"34"
,
stat
,
"SELECT TO_CHAR(X, 'SS') FROM T"
);
assertResult
(
"29554"
,
stat
,
"SELECT TO_CHAR(X, 'SSSSS') FROM T"
);
assertResult
(
"8:12:34 AM"
,
stat
,
"SELECT TO_CHAR(X, 'TS') FROM T"
);
assertResult
(
tzLongName
,
stat
,
"SELECT TO_CHAR(X, 'TZR') FROM T"
);
assertResult
(
tzShortName
,
stat
,
"SELECT TO_CHAR(X, 'TZD') FROM T"
);
assertResult
(
"."
,
stat
,
"SELECT TO_CHAR(X, 'X') FROM T"
);
assertResult
(
"1,979"
,
stat
,
"SELECT TO_CHAR(X, 'Y,YYY') FROM T"
);
assertResult
(
"1979"
,
stat
,
"SELECT TO_CHAR(X, 'YYYY') FROM T"
);
assertResult
(
"1979"
,
stat
,
"SELECT TO_CHAR(X, 'SYYYY') FROM T"
);
assertResult
(
"-0100"
,
stat
,
"SELECT TO_CHAR(X, 'SYYYY') FROM U"
);
assertResult
(
"979"
,
stat
,
"SELECT TO_CHAR(X, 'YYY') FROM T"
);
assertResult
(
"79"
,
stat
,
"SELECT TO_CHAR(X, 'YY') FROM T"
);
assertResult
(
"9"
,
stat
,
"SELECT TO_CHAR(X, 'Y') FROM T"
);
assertResult
(
"7979"
,
stat
,
"SELECT TO_CHAR(X, 'yyfxyy') FROM T"
);
assertThrows
(
""
,
stat
,
"SELECT TO_CHAR(X, 'A') FROM T"
);
conn
.
close
();
}
private
void
testToCharFromNumber
()
throws
SQLException
{
deleteDb
(
"functions"
);
Connection
conn
=
getConnection
(
"functions"
);
Statement
stat
=
conn
.
createStatement
();
Currency
currency
=
Currency
.
getInstance
(
Locale
.
getDefault
());
String
cc
=
currency
.
getCurrencyCode
();
String
cs
=
currency
.
getSymbol
();
assertResult
(
".45"
,
stat
,
"SELECT TO_CHAR(0.45) FROM DUAL"
);
assertResult
(
"12923"
,
stat
,
"SELECT TO_CHAR(12923) FROM DUAL"
);
assertResult
(
" 12923.00"
,
stat
,
"SELECT TO_CHAR(12923, '99999.99', 'NLS_CURRENCY = BTC') FROM DUAL"
);
assertResult
(
"12923."
,
stat
,
"SELECT TO_CHAR(12923, 'FM99999.99', 'NLS_CURRENCY = BTC') FROM DUAL"
);
assertResult
(
"######"
,
stat
,
"SELECT TO_CHAR(12345, '9,999') FROM DUAL"
);
assertResult
(
"######"
,
stat
,
"SELECT TO_CHAR(1234567, '9,999') FROM DUAL"
);
assertResult
(
" 12,345"
,
stat
,
"SELECT TO_CHAR(12345, '99,999') FROM DUAL"
);
assertResult
(
" 123,45"
,
stat
,
"SELECT TO_CHAR(12345, '999,99') FROM DUAL"
);
assertResult
(
"######"
,
stat
,
"SELECT TO_CHAR(12345, '9.999') FROM DUAL"
);
assertResult
(
"#######"
,
stat
,
"SELECT TO_CHAR(12345, '99.999') FROM DUAL"
);
assertResult
(
"########"
,
stat
,
"SELECT TO_CHAR(12345, '999.999') FROM DUAL"
);
assertResult
(
"#########"
,
stat
,
"SELECT TO_CHAR(12345, '9999.999') FROM DUAL"
);
assertResult
(
" 12345.000"
,
stat
,
"SELECT TO_CHAR(12345, '99999.999') FROM DUAL"
);
assertResult
(
"###"
,
stat
,
"SELECT TO_CHAR(12345, '$9') FROM DUAL"
);
assertResult
(
"#####"
,
stat
,
"SELECT TO_CHAR(12345, '$999') FROM DUAL"
);
assertResult
(
"######"
,
stat
,
"SELECT TO_CHAR(12345, '$9999') FROM DUAL"
);
assertResult
(
" "
+
cs
+
"12345"
,
stat
,
"SELECT TO_CHAR(12345, '$99999999') FROM DUAL"
);
assertResult
(
" "
+
cs
+
"12,345.35"
,
stat
,
"SELECT TO_CHAR(12345.345, '$99,999,999.99') FROM DUAL"
);
assertResult
(
" "
+
cs
+
"12,345"
,
stat
,
"SELECT TO_CHAR(12345.345, '$99g999g999') FROM DUAL"
);
assertResult
(
" 12,345.35"
,
stat
,
"SELECT TO_CHAR(12345.345, '99,999,999.99') FROM DUAL"
);
assertResult
(
"12,345.35"
,
stat
,
"SELECT TO_CHAR(12345.345, 'FM99,999,999.99') FROM DUAL"
);
assertResult
(
" 00,012,345.35"
,
stat
,
"SELECT TO_CHAR(12345.345, '00,000,000.00') FROM DUAL"
);
assertResult
(
"00,012,345.35"
,
stat
,
"SELECT TO_CHAR(12345.345, 'FM00,000,000.00') FROM DUAL"
);
assertResult
(
"###"
,
stat
,
"SELECT TO_CHAR(12345, '09') FROM DUAL"
);
assertResult
(
"#####"
,
stat
,
"SELECT TO_CHAR(12345, '0999') FROM DUAL"
);
assertResult
(
" 00012345"
,
stat
,
"SELECT TO_CHAR(12345, '09999999') FROM DUAL"
);
assertResult
(
" 0000012345"
,
stat
,
"SELECT TO_CHAR(12345, '0009999999') FROM DUAL"
);
assertResult
(
"###"
,
stat
,
"SELECT TO_CHAR(12345, '90') FROM DUAL"
);
assertResult
(
"#####"
,
stat
,
"SELECT TO_CHAR(12345, '9990') FROM DUAL"
);
assertResult
(
" 12345"
,
stat
,
"SELECT TO_CHAR(12345, '99999990') FROM DUAL"
);
assertResult
(
" 12345"
,
stat
,
"SELECT TO_CHAR(12345, '9999999000') FROM DUAL"
);
assertResult
(
" 12345"
,
stat
,
"SELECT TO_CHAR(12345, '9999999990') FROM DUAL"
);
assertResult
(
"12345"
,
stat
,
"SELECT TO_CHAR(12345, 'FM9999999990') FROM DUAL"
);
assertResult
(
" 12345.2300"
,
stat
,
"SELECT TO_CHAR(12345.23, '9999999.9000') FROM DUAL"
);
assertResult
(
" 12345"
,
stat
,
"SELECT TO_CHAR(12345, '9999999') FROM DUAL"
);
assertResult
(
" 12345"
,
stat
,
"SELECT TO_CHAR(12345, '999999') FROM DUAL"
);
assertResult
(
" 12345"
,
stat
,
"SELECT TO_CHAR(12345, '99999') FROM DUAL"
);
assertResult
(
" 12345"
,
stat
,
"SELECT TO_CHAR(12345, '00000') FROM DUAL"
);
assertResult
(
"#####"
,
stat
,
"SELECT TO_CHAR(12345, '9999') FROM DUAL"
);
assertResult
(
"#####"
,
stat
,
"SELECT TO_CHAR(12345, '0000') FROM DUAL"
);
assertResult
(
" -12345"
,
stat
,
"SELECT TO_CHAR(-12345, '99999999') FROM DUAL"
);
assertResult
(
" -12345"
,
stat
,
"SELECT TO_CHAR(-12345, '9999999') FROM DUAL"
);
assertResult
(
" -12345"
,
stat
,
"SELECT TO_CHAR(-12345, '999999') FROM DUAL"
);
assertResult
(
"-12345"
,
stat
,
"SELECT TO_CHAR(-12345, '99999') FROM DUAL"
);
assertResult
(
"#####"
,
stat
,
"SELECT TO_CHAR(-12345, '9999') FROM DUAL"
);
assertResult
(
"####"
,
stat
,
"SELECT TO_CHAR(-12345, '999') FROM DUAL"
);
assertResult
(
" 0"
,
stat
,
"SELECT TO_CHAR(0, '9999999') FROM DUAL"
);
assertResult
(
" 00.30"
,
stat
,
"SELECT TO_CHAR(0.3, '00.99') FROM DUAL"
);
assertResult
(
"00.3"
,
stat
,
"SELECT TO_CHAR(0.3, 'FM00.99') FROM DUAL"
);
assertResult
(
" 00.30"
,
stat
,
"SELECT TO_CHAR(0.3, '00.00') FROM DUAL"
);
assertResult
(
" .30000"
,
stat
,
"SELECT TO_CHAR(0.3, '99.00000') FROM DUAL"
);
assertResult
(
".30000"
,
stat
,
"SELECT TO_CHAR(0.3, 'FM99.00000') FROM DUAL"
);
assertResult
(
" 00.30"
,
stat
,
"SELECT TO_CHAR(0.3, 'B00.99') FROM DUAL"
);
assertResult
(
" .30"
,
stat
,
"SELECT TO_CHAR(0.3, 'B99.99') FROM DUAL"
);
assertResult
(
" .30"
,
stat
,
"SELECT TO_CHAR(0.3, '99.99') FROM DUAL"
);
assertResult
(
".3"
,
stat
,
"SELECT TO_CHAR(0.3, 'FMB99.99') FROM DUAL"
);
assertResult
(
" 00.30"
,
stat
,
"SELECT TO_CHAR(0.3, 'B09.99') FROM DUAL"
);
assertResult
(
" 00.30"
,
stat
,
"SELECT TO_CHAR(0.3, 'B00.00') FROM DUAL"
);
assertResult
(
" "
+
cc
+
"123.45"
,
stat
,
"SELECT TO_CHAR(123.45, 'C999.99') FROM DUAL"
);
assertResult
(
" -"
+
cc
+
"123.45"
,
stat
,
"SELECT TO_CHAR(-123.45, 'C999.99') FROM DUAL"
);
assertResult
(
" "
+
cc
+
"123.45"
,
stat
,
"SELECT TO_CHAR(123.45, 'C999,999.99') FROM DUAL"
);
assertResult
(
" "
+
cc
+
"123"
,
stat
,
"SELECT TO_CHAR(123.45, 'C999g999') FROM DUAL"
);
assertResult
(
cc
+
"123.45"
,
stat
,
"SELECT TO_CHAR(123.45, 'FMC999,999.99') FROM DUAL"
);
assertResult
(
" "
+
cs
+
"123.45"
,
stat
,
"SELECT TO_CHAR(123.45, 'L999.99') FROM DUAL"
);
assertResult
(
" -"
+
cs
+
"123.45"
,
stat
,
"SELECT TO_CHAR(-123.45, 'L999.99') FROM DUAL"
);
assertResult
(
cs
+
"123.45"
,
stat
,
"SELECT TO_CHAR(123.45, 'FML999.99') FROM DUAL"
);
assertResult
(
" "
+
cs
+
"123.45"
,
stat
,
"SELECT TO_CHAR(123.45, 'U999.99') FROM DUAL"
);
assertResult
(
" "
+
cs
+
"123.45"
,
stat
,
"SELECT TO_CHAR(123.45, 'u999.99') FROM DUAL"
);
assertResult
(
" .33"
,
stat
,
"SELECT TO_CHAR(0.326, '99D99') FROM DUAL"
);
assertResult
(
" 1.2E+02"
,
stat
,
"SELECT TO_CHAR(123.456, '9.9EEEE') FROM DUAL"
);
assertResult
(
" 1.2E+14"
,
stat
,
"SELECT TO_CHAR(123456789012345, '9.9EEEE') FROM DUAL"
);
assertResult
(
" 1E+02"
,
stat
,
"SELECT TO_CHAR(123.456, '9EEEE') FROM DUAL"
);
assertResult
(
" 1E+02"
,
stat
,
"SELECT TO_CHAR(123.456, '999EEEE') FROM DUAL"
);
assertResult
(
" 1E-03"
,
stat
,
"SELECT TO_CHAR(.00123456, '999EEEE') FROM DUAL"
);
assertResult
(
" 1E+00"
,
stat
,
"SELECT TO_CHAR(1, '999EEEE') FROM DUAL"
);
assertResult
(
" -1E+00"
,
stat
,
"SELECT TO_CHAR(-1, '999EEEE') FROM DUAL"
);
assertResult
(
" 1.23456000E+02"
,
stat
,
"SELECT TO_CHAR(123.456, '00.00000000EEEE') FROM DUAL"
);
assertResult
(
"1.23456000E+02"
,
stat
,
"SELECT TO_CHAR(123.456, 'fm00.00000000EEEE') FROM DUAL"
);
assertResult
(
" 1,234,567"
,
stat
,
"SELECT TO_CHAR(1234567, '9G999G999') FROM DUAL"
);
assertResult
(
"-1,234,567"
,
stat
,
"SELECT TO_CHAR(-1234567, '9G999G999') FROM DUAL"
);
assertResult
(
"123.45-"
,
stat
,
"SELECT TO_CHAR(-123.45, '999.99MI') FROM DUAL"
);
assertResult
(
"123.45-"
,
stat
,
"SELECT TO_CHAR(-123.45, '999.99mi') FROM DUAL"
);
assertResult
(
"123.45-"
,
stat
,
"SELECT TO_CHAR(-123.45, '999.99mI') FROM DUAL"
);
assertResult
(
"230.00-"
,
stat
,
"SELECT TO_CHAR(-230, '999.99MI') FROM DUAL"
);
assertResult
(
"230-"
,
stat
,
"SELECT TO_CHAR(-230, '999MI') FROM DUAL"
);
assertResult
(
"123.45 "
,
stat
,
"SELECT TO_CHAR(123.45, '999.99MI') FROM DUAL"
);
assertResult
(
"230.00 "
,
stat
,
"SELECT TO_CHAR(230, '999.99MI') FROM DUAL"
);
assertResult
(
"230 "
,
stat
,
"SELECT TO_CHAR(230, '999MI') FROM DUAL"
);
assertResult
(
"230"
,
stat
,
"SELECT TO_CHAR(230, 'FM999MI') FROM DUAL"
);
assertResult
(
"<230>"
,
stat
,
"SELECT TO_CHAR(-230, '999PR') FROM DUAL"
);
assertResult
(
"<230>"
,
stat
,
"SELECT TO_CHAR(-230, '999pr') FROM DUAL"
);
assertResult
(
"<230>"
,
stat
,
"SELECT TO_CHAR(-230, 'fm999pr') FROM DUAL"
);
assertResult
(
" 230 "
,
stat
,
"SELECT TO_CHAR(230, '999PR') FROM DUAL"
);
assertResult
(
"230"
,
stat
,
"SELECT TO_CHAR(230, 'FM999PR') FROM DUAL"
);
assertResult
(
"0"
,
stat
,
"SELECT TO_CHAR(0, 'fm999pr') FROM DUAL"
);
assertResult
(
" CCXXXVIII"
,
stat
,
"SELECT TO_CHAR(238, 'RN') FROM DUAL"
);
assertResult
(
"CCXXXVIII"
,
stat
,
"SELECT TO_CHAR(238, 'FMRN') FROM DUAL"
);
assertResult
(
"cxlix"
,
stat
,
"SELECT TO_CHAR(149, 'FMrN') FROM DUAL"
);
assertResult
(
" MCMLXXIX"
,
stat
,
"SELECT TO_CHAR(1979, 'RN') FROM DUAL;"
);
assertResult
(
" xliv"
,
stat
,
"SELECT TO_CHAR(44, 'rN') FROM DUAL"
);
assertResult
(
" mdcclxxvi"
,
stat
,
"SELECT TO_CHAR(1776, 'rn') FROM DUAL"
);
assertResult
(
" +42"
,
stat
,
"SELECT TO_CHAR(42, 'S999') FROM DUAL"
);
assertResult
(
" +42"
,
stat
,
"SELECT TO_CHAR(42, 's999') FROM DUAL"
);
assertResult
(
" 42+"
,
stat
,
"SELECT TO_CHAR(42, '999S') FROM DUAL"
);
assertResult
(
" -42"
,
stat
,
"SELECT TO_CHAR(-42, 'S999') FROM DUAL"
);
assertResult
(
" 42-"
,
stat
,
"SELECT TO_CHAR(-42, '999S') FROM DUAL"
);
assertResult
(
"42"
,
stat
,
"SELECT TO_CHAR(42, 'TM') FROM DUAL"
);
assertResult
(
"-42"
,
stat
,
"SELECT TO_CHAR(-42, 'TM') FROM DUAL"
);
assertResult
(
"4212341241234.23412342"
,
stat
,
"SELECT TO_CHAR(4212341241234.23412342, 'tm') FROM DUAL"
);
assertResult
(
".23412342"
,
stat
,
"SELECT TO_CHAR(0.23412342, 'tm') FROM DUAL"
);
assertResult
(
" 12300"
,
stat
,
"SELECT TO_CHAR(123, '999V99') FROM DUAL"
);
assertResult
(
"######"
,
stat
,
"SELECT TO_CHAR(1234, '999V99') FROM DUAL"
);
assertResult
(
"123400"
,
stat
,
"SELECT TO_CHAR(1234, 'FM9999v99') FROM DUAL"
);
assertResult
(
"1234"
,
stat
,
"SELECT TO_CHAR(123.4, 'FM9999V9') FROM DUAL"
);
assertResult
(
"123"
,
stat
,
"SELECT TO_CHAR(123.4, 'FM9999V') FROM DUAL"
);
assertResult
(
"123400000"
,
stat
,
"SELECT TO_CHAR(123.4, 'FM9999V090909') FROM DUAL"
);
assertResult
(
"##"
,
stat
,
"SELECT TO_CHAR(123, 'X') FROM DUAL"
);
assertResult
(
" 7B"
,
stat
,
"SELECT TO_CHAR(123, 'XX') FROM DUAL"
);
assertResult
(
" 7b"
,
stat
,
"SELECT TO_CHAR(123, 'Xx') FROM DUAL"
);
assertResult
(
" 7b"
,
stat
,
"SELECT TO_CHAR(123, 'xX') FROM DUAL"
);
assertResult
(
" 7B"
,
stat
,
"SELECT TO_CHAR(123, 'XXXX') FROM DUAL"
);
assertResult
(
" 007B"
,
stat
,
"SELECT TO_CHAR(123, '000X') FROM DUAL"
);
assertResult
(
" 007B"
,
stat
,
"SELECT TO_CHAR(123, '0XXX') FROM DUAL"
);
assertResult
(
"####"
,
stat
,
"SELECT TO_CHAR(123456789, 'FMXXX') FROM DUAL"
);
assertResult
(
"7B"
,
stat
,
"SELECT TO_CHAR(123, 'FMXX') FROM DUAL"
);
assertResult
(
"C6"
,
stat
,
"SELECT TO_CHAR(197.6, 'FMXX') FROM DUAL"
);
assertResult
(
" 7"
,
stat
,
"SELECT TO_CHAR(7, 'XX') FROM DUAL"
);
assertResult
(
"123"
,
stat
,
"SELECT TO_CHAR(123, 'TM') FROM DUAL"
);
assertResult
(
"123"
,
stat
,
"SELECT TO_CHAR(123, 'tm') FROM DUAL"
);
assertResult
(
"123"
,
stat
,
"SELECT TO_CHAR(123, 'tM9') FROM DUAL"
);
assertResult
(
"1.23E+02"
,
stat
,
"SELECT TO_CHAR(123, 'TME') FROM DUAL"
);
assertResult
(
"1.23456789012345E+14"
,
stat
,
"SELECT TO_CHAR(123456789012345, 'TME') FROM DUAL"
);
assertResult
(
"4.5E-01"
,
stat
,
"SELECT TO_CHAR(0.45, 'TME') FROM DUAL"
);
assertResult
(
"4.5E-01"
,
stat
,
"SELECT TO_CHAR(0.45, 'tMe') FROM DUAL"
);
assertThrows
(
"Invalid format \"999.99q\""
,
stat
,
"SELECT TO_CHAR(123.45, '999.99q') FROM DUAL"
);
assertThrows
(
"Invalid format \"fm999.99q\""
,
stat
,
"SELECT TO_CHAR(123.45, 'fm999.99q') FROM DUAL"
);
assertThrows
(
"Invalid format \"q999.99\""
,
stat
,
"SELECT TO_CHAR(123.45, 'q999.99') FROM DUAL"
);
conn
.
close
();
}
private
void
testToCharFromText
()
throws
SQLException
{
deleteDb
(
"functions"
);
Connection
conn
=
getConnection
(
"functions"
);
Statement
stat
=
conn
.
createStatement
();
assertResult
(
"abc"
,
stat
,
"SELECT TO_CHAR('abc') FROM DUAL"
);
conn
.
close
();
}
private
void
testCachingOfDeterministicFunctionAlias
()
throws
SQLException
{
private
void
testCachingOfDeterministicFunctionAlias
()
throws
SQLException
{
deleteDb
(
"functions"
);
deleteDb
(
"functions"
);
Connection
conn
=
getConnection
(
"functions"
);
Connection
conn
=
getConnection
(
"functions"
);
...
...
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
397d3126
...
@@ -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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论