Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
9e5d9644
提交
9e5d9644
authored
2月 18, 2018
作者:
Evgenij Ryazanov
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' into generated_keys
上级
0581dbd0
8556fd23
显示空白字符变更
内嵌
并排
正在显示
30 个修改的文件
包含
1116 行增加
和
644 行删除
+1116
-644
help.csv
h2/src/docsrc/help/help.csv
+39
-5
Constraint.java
h2/src/main/org/h2/constraint/Constraint.java
+0
-1
AggregateDataMedian.java
h2/src/main/org/h2/expression/AggregateDataMedian.java
+2
-1
Function.java
h2/src/main/org/h2/expression/Function.java
+96
-74
IndexCursor.java
h2/src/main/org/h2/index/IndexCursor.java
+3
-4
MVStore.java
h2/src/main/org/h2/mvstore/MVStore.java
+22
-20
DataReader.java
h2/src/main/org/h2/store/DataReader.java
+1
-1
MetaTable.java
h2/src/main/org/h2/table/MetaTable.java
+1
-1
ChangeFileEncryption.java
h2/src/main/org/h2/tools/ChangeFileEncryption.java
+2
-1
DateTimeUtils.java
h2/src/main/org/h2/util/DateTimeUtils.java
+41
-39
ToChar.java
h2/src/main/org/h2/util/ToChar.java
+180
-106
ToDateParser.java
h2/src/main/org/h2/util/ToDateParser.java
+202
-42
ToDateTokenizer.java
h2/src/main/org/h2/util/ToDateTokenizer.java
+82
-111
Transfer.java
h2/src/main/org/h2/value/Transfer.java
+1
-17
ValueLobDb.java
h2/src/main/org/h2/value/ValueLobDb.java
+10
-0
ValueTimestampTimeZone.java
h2/src/main/org/h2/value/ValueTimestampTimeZone.java
+24
-42
TestBase.java
h2/src/test/org/h2/test/TestBase.java
+66
-10
TestFunctions.java
h2/src/test/org/h2/test/db/TestFunctions.java
+92
-70
TestOutOfMemory.java
h2/src/test/org/h2/test/db/TestOutOfMemory.java
+88
-60
TestLobApi.java
h2/src/test/org/h2/test/jdbc/TestLobApi.java
+27
-4
TestScript.java
h2/src/test/org/h2/test/scripts/TestScript.java
+1
-1
dateadd.sql
...est/org/h2/test/scripts/functions/timeanddate/dateadd.sql
+12
-0
datediff.sql
...st/org/h2/test/scripts/functions/timeanddate/datediff.sql
+16
-0
extract.sql
...est/org/h2/test/scripts/functions/timeanddate/extract.sql
+14
-0
TestMVStoreBenchmark.java
h2/src/test/org/h2/test/store/TestMVStoreBenchmark.java
+0
-8
TestFuzzOptimizations.java
h2/src/test/org/h2/test/synth/TestFuzzOptimizations.java
+22
-17
TestClearReferences.java
h2/src/test/org/h2/test/unit/TestClearReferences.java
+3
-0
TestDateTimeUtils.java
h2/src/test/org/h2/test/unit/TestDateTimeUtils.java
+58
-4
TestTimeStampWithTimeZone.java
h2/src/test/org/h2/test/unit/TestTimeStampWithTimeZone.java
+9
-3
dictionary.txt
h2/src/tools/org/h2/build/doc/dictionary.txt
+2
-2
没有找到文件。
h2/src/docsrc/help/help.csv
浏览文件 @
9e5d9644
...
@@ -2300,9 +2300,9 @@ Each table has a pseudo-column named ""_ROWID_"" that contains the unique row id
...
@@ -2300,9 +2300,9 @@ Each table has a pseudo-column named ""_ROWID_"" that contains the unique row id
"
"
"Other Grammar","Time","
"Other Grammar","Time","
TIME 'hh:mm:ss'
TIME 'hh:mm:ss
[.nnnnnnnnn]
'
","
","
A time literal. A value is between
plus and minus 2 million hours
A time literal. A value is between
0:00:00 and 23:59:59.999999999
and has nanosecond resolution.
and has nanosecond resolution.
","
","
TIME '23:59:59'
TIME '23:59:59'
...
@@ -2318,6 +2318,19 @@ minimum and maximum years are 0001 and 9999.
...
@@ -2318,6 +2318,19 @@ minimum and maximum years are 0001 and 9999.
TIMESTAMP '2005-12-31 23:59:59'
TIMESTAMP '2005-12-31 23:59:59'
"
"
"Other Grammar","Timestamp with time zone","
TIMESTAMP 'yyyy-MM-dd hh:mm:ss[.nnnnnnnnn]
[Z | { - | + } timeZoneOffsetString | timeZoneNameString ]'
","
A timestamp with time zone literal.
If name of time zone is specified it will be converted to time zone offset.
","
TIMESTAMP WITH TIME ZONE '2005-12-31 23:59:59Z'
TIMESTAMP WITH TIME ZONE '2005-12-31 23:59:59-10:00'
TIMESTAMP WITH TIME ZONE '2005-12-31 23:59:59.123+05'
TIMESTAMP WITH TIME ZONE '2005-12-31 23:59:59.123456789 Europe/London'
"
"Other Grammar","Value","
"Other Grammar","Value","
string | dollarQuotedString | numeric | date | time | timestamp | boolean | bytes | array | null
string | dollarQuotedString | numeric | date | time | timestamp | boolean | bytes | array | null
","
","
...
@@ -3671,7 +3684,7 @@ CURRENT_TIMESTAMP()
...
@@ -3671,7 +3684,7 @@ CURRENT_TIMESTAMP()
Adds units to a date-time value. The string indicates the unit.
Adds units to a date-time value. The string indicates the unit.
Use negative values to subtract units.
Use negative values to subtract units.
addIntLong may be a long value when manipulating milliseconds,
addIntLong may be a long value when manipulating milliseconds,
otherwise it'
s range is restricted to int.
microseconds, or nanoseconds otherwise it
s range is restricted to int.
The same units as in the EXTRACT function are supported.
The same units as in the EXTRACT function are supported.
This method returns a value with the same type as specified value if unit is compatible with this value.
This method returns a value with the same type as specified value if unit is compatible with this value.
If specified unit is a HOUR, MINUTE, SECOND, MILLISECOND, etc and value is a DATE value DATEADD returns combined TIMESTAMP.
If specified unit is a HOUR, MINUTE, SECOND, MILLISECOND, etc and value is a DATE value DATEADD returns combined TIMESTAMP.
...
@@ -3727,11 +3740,13 @@ DAY_OF_YEAR(CREATED)
...
@@ -3727,11 +3740,13 @@ DAY_OF_YEAR(CREATED)
"Functions (Time and Date)","EXTRACT","
"Functions (Time and Date)","EXTRACT","
EXTRACT ( { YEAR | YY | MONTH | MM | QUARTER | WEEK | ISO_WEEK
EXTRACT ( { YEAR | YY | MONTH | MM | QUARTER | WEEK | ISO_WEEK
| DAY | DD | DAY_OF_YEAR | DOY
| DAY | DD | DAY_OF_YEAR | DOY
| HOUR | HH | MINUTE | MI | SECOND | SS | MILLISECOND | MS }
| HOUR | HH | MINUTE | MI | SECOND | SS | EPOCH
| MILLISECOND | MS | MICROSECOND | MCS | NANOSECOND | NS }
FROM timestamp )
FROM timestamp )
","
","
Returns a specific value from a timestamps.
Returns a specific value from a timestamps.
This method returns an int.
This method returns a numeric value with EPOCH unit and
an int for all other time units.
","
","
EXTRACT(SECOND FROM CURRENT_TIMESTAMP)
EXTRACT(SECOND FROM CURRENT_TIMESTAMP)
"
"
...
@@ -3820,6 +3835,17 @@ This method uses the current system locale.
...
@@ -3820,6 +3835,17 @@ This method uses the current system locale.
WEEK(CREATED)
WEEK(CREATED)
"
"
"Functions (Time and Date)","ISO_WEEK","
ISO_WEEK(timestamp)
","
Returns the week (1-53) from a timestamp.
This method uses the ISO definition when
first week of year should have at least four days
and week is started with Monday.
","
ISO_WEEK(CREATED)
"
"Functions (Time and Date)","YEAR","
"Functions (Time and Date)","YEAR","
YEAR(timestamp)
YEAR(timestamp)
","
","
...
@@ -3828,6 +3854,14 @@ Returns the year from a timestamp.
...
@@ -3828,6 +3854,14 @@ Returns the year from a timestamp.
YEAR(CREATED)
YEAR(CREATED)
"
"
"Functions (Time and Date)","ISO_YEAR","
ISO_YEAR(timestamp)
","
Returns the ISO week year from a timestamp.
","
ISO_YEAR(CREATED)
"
"Functions (System)","ARRAY_GET","
"Functions (System)","ARRAY_GET","
ARRAY_GET(arrayExpression, indexExpression)
ARRAY_GET(arrayExpression, indexExpression)
","
","
...
...
h2/src/main/org/h2/constraint/Constraint.java
浏览文件 @
9e5d9644
...
@@ -10,7 +10,6 @@ import org.h2.engine.DbObject;
...
@@ -10,7 +10,6 @@ import org.h2.engine.DbObject;
import
org.h2.engine.Session
;
import
org.h2.engine.Session
;
import
org.h2.expression.ExpressionVisitor
;
import
org.h2.expression.ExpressionVisitor
;
import
org.h2.index.Index
;
import
org.h2.index.Index
;
import
org.h2.message.DbException
;
import
org.h2.message.Trace
;
import
org.h2.message.Trace
;
import
org.h2.result.Row
;
import
org.h2.result.Row
;
import
org.h2.schema.Schema
;
import
org.h2.schema.Schema
;
...
...
h2/src/main/org/h2/expression/AggregateDataMedian.java
浏览文件 @
9e5d9644
...
@@ -224,7 +224,8 @@ class AggregateDataMedian extends AggregateData {
...
@@ -224,7 +224,8 @@ class AggregateDataMedian extends AggregateData {
case
Value
.
DOUBLE
:
case
Value
.
DOUBLE
:
return
ValueDouble
.
get
((
v0
.
getFloat
()
+
v1
.
getDouble
())
/
2
);
return
ValueDouble
.
get
((
v0
.
getFloat
()
+
v1
.
getDouble
())
/
2
);
case
Value
.
TIME
:
{
case
Value
.
TIME
:
{
return
ValueTime
.
fromMillis
((
v0
.
getTime
().
getTime
()
+
v1
.
getTime
().
getTime
())
/
2
);
ValueTime
t0
=
(
ValueTime
)
v0
.
convertTo
(
Value
.
TIME
),
t1
=
(
ValueTime
)
v1
.
convertTo
(
Value
.
TIME
);
return
ValueTime
.
fromNanos
((
t0
.
getNanos
()
+
t1
.
getNanos
())
/
2
);
}
}
case
Value
.
DATE
:
{
case
Value
.
DATE
:
{
ValueDate
d0
=
(
ValueDate
)
v0
.
convertTo
(
Value
.
DATE
),
d1
=
(
ValueDate
)
v1
.
convertTo
(
Value
.
DATE
);
ValueDate
d0
=
(
ValueDate
)
v0
.
convertTo
(
Value
.
DATE
),
d1
=
(
ValueDate
)
v1
.
convertTo
(
Value
.
DATE
);
...
...
h2/src/main/org/h2/expression/Function.java
浏览文件 @
9e5d9644
...
@@ -15,9 +15,8 @@ import java.nio.charset.StandardCharsets;
...
@@ -15,9 +15,8 @@ import java.nio.charset.StandardCharsets;
import
java.sql.Connection
;
import
java.sql.Connection
;
import
java.sql.ResultSet
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.text.
SimpleDateFormat
;
import
java.text.
DateFormatSymbols
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
import
java.util.GregorianCalendar
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.Locale
;
import
java.util.Locale
;
...
@@ -99,7 +98,7 @@ public class Function extends Expression implements FunctionCall {
...
@@ -99,7 +98,7 @@ public class Function extends Expression implements FunctionCall {
XMLATTR
=
83
,
XMLNODE
=
84
,
XMLCOMMENT
=
85
,
XMLCDATA
=
86
,
XMLATTR
=
83
,
XMLNODE
=
84
,
XMLCOMMENT
=
85
,
XMLCDATA
=
86
,
XMLSTARTDOC
=
87
,
XMLTEXT
=
88
,
REGEXP_REPLACE
=
89
,
RPAD
=
90
,
XMLSTARTDOC
=
87
,
XMLTEXT
=
88
,
REGEXP_REPLACE
=
89
,
RPAD
=
90
,
LPAD
=
91
,
CONCAT_WS
=
92
,
TO_CHAR
=
93
,
TRANSLATE
=
94
,
ORA_HASH
=
95
,
LPAD
=
91
,
CONCAT_WS
=
92
,
TO_CHAR
=
93
,
TRANSLATE
=
94
,
ORA_HASH
=
95
,
TO_DATE
=
96
,
TO_TIMESTAMP
=
97
,
ADD_MONTHS
=
98
;
TO_DATE
=
96
,
TO_TIMESTAMP
=
97
,
ADD_MONTHS
=
98
,
TO_TIMESTAMP_TZ
=
99
;
public
static
final
int
CURDATE
=
100
,
CURTIME
=
101
,
DATE_ADD
=
102
,
public
static
final
int
CURDATE
=
100
,
CURTIME
=
101
,
DATE_ADD
=
102
,
DATE_DIFF
=
103
,
DAY_NAME
=
104
,
DAY_OF_MONTH
=
105
,
DATE_DIFF
=
103
,
DAY_NAME
=
104
,
DAY_OF_MONTH
=
105
,
...
@@ -111,14 +110,9 @@ public class Function extends Expression implements FunctionCall {
...
@@ -111,14 +110,9 @@ public class Function extends Expression implements FunctionCall {
ISO_WEEK
=
124
,
ISO_DAY_OF_WEEK
=
125
;
ISO_WEEK
=
124
,
ISO_DAY_OF_WEEK
=
125
;
/**
/**
* Pseudo function
for {@code EXTRACT(MILLISECOND FROM ...)}
.
* Pseudo function
s for DATEADD, DATEDIFF, and EXTRACT
.
*/
*/
public
static
final
int
MILLISECOND
=
126
;
public
static
final
int
MILLISECOND
=
126
,
EPOCH
=
127
,
MICROSECOND
=
128
,
NANOSECOND
=
129
;
/**
* Pseudo function for {@code EXTRACT(EPOCH FROM ...)}.
*/
public
static
final
int
EPOCH
=
127
;
public
static
final
int
DATABASE
=
150
,
USER
=
151
,
CURRENT_USER
=
152
,
public
static
final
int
DATABASE
=
150
,
USER
=
151
,
CURRENT_USER
=
152
,
IDENTITY
=
153
,
SCOPE_IDENTITY
=
154
,
AUTOCOMMIT
=
155
,
IDENTITY
=
153
,
SCOPE_IDENTITY
=
154
,
AUTOCOMMIT
=
155
,
...
@@ -159,6 +153,11 @@ public class Function extends Expression implements FunctionCall {
...
@@ -159,6 +153,11 @@ public class Function extends Expression implements FunctionCall {
private
static
final
HashMap
<
String
,
Integer
>
DATE_PART
=
new
HashMap
<>();
private
static
final
HashMap
<
String
,
Integer
>
DATE_PART
=
new
HashMap
<>();
private
static
final
char
[]
SOUNDEX_INDEX
=
new
char
[
128
];
private
static
final
char
[]
SOUNDEX_INDEX
=
new
char
[
128
];
/**
* English names of months and week days.
*/
private
static
volatile
String
[][]
MONTHS_AND_WEEKS
;
protected
Expression
[]
args
;
protected
Expression
[]
args
;
private
final
FunctionInfo
info
;
private
final
FunctionInfo
info
;
...
@@ -206,6 +205,10 @@ public class Function extends Expression implements FunctionCall {
...
@@ -206,6 +205,10 @@ public class Function extends Expression implements FunctionCall {
DATE_PART
.
put
(
"MILLISECOND"
,
MILLISECOND
);
DATE_PART
.
put
(
"MILLISECOND"
,
MILLISECOND
);
DATE_PART
.
put
(
"MS"
,
MILLISECOND
);
DATE_PART
.
put
(
"MS"
,
MILLISECOND
);
DATE_PART
.
put
(
"EPOCH"
,
EPOCH
);
DATE_PART
.
put
(
"EPOCH"
,
EPOCH
);
DATE_PART
.
put
(
"MICROSECOND"
,
MICROSECOND
);
DATE_PART
.
put
(
"MCS"
,
MICROSECOND
);
DATE_PART
.
put
(
"NANOSECOND"
,
NANOSECOND
);
DATE_PART
.
put
(
"NS"
,
NANOSECOND
);
// SOUNDEX_INDEX
// SOUNDEX_INDEX
String
index
=
"7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R"
;
String
index
=
"7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R"
;
...
@@ -337,6 +340,7 @@ public class Function extends Expression implements FunctionCall {
...
@@ -337,6 +340,7 @@ public class Function extends Expression implements FunctionCall {
addFunction
(
"TO_DATE"
,
TO_DATE
,
VAR_ARGS
,
Value
.
TIMESTAMP
);
addFunction
(
"TO_DATE"
,
TO_DATE
,
VAR_ARGS
,
Value
.
TIMESTAMP
);
addFunction
(
"TO_TIMESTAMP"
,
TO_TIMESTAMP
,
VAR_ARGS
,
Value
.
TIMESTAMP
);
addFunction
(
"TO_TIMESTAMP"
,
TO_TIMESTAMP
,
VAR_ARGS
,
Value
.
TIMESTAMP
);
addFunction
(
"ADD_MONTHS"
,
ADD_MONTHS
,
2
,
Value
.
TIMESTAMP
);
addFunction
(
"ADD_MONTHS"
,
ADD_MONTHS
,
2
,
Value
.
TIMESTAMP
);
addFunction
(
"TO_TIMESTAMP_TZ"
,
TO_TIMESTAMP_TZ
,
VAR_ARGS
,
Value
.
TIMESTAMP_TZ
);
// alias for MSSQLServer
// alias for MSSQLServer
addFunctionNotDeterministic
(
"GETDATE"
,
CURDATE
,
addFunctionNotDeterministic
(
"GETDATE"
,
CURDATE
,
0
,
Value
.
DATE
);
0
,
Value
.
DATE
);
...
@@ -845,9 +849,8 @@ public class Function extends Expression implements FunctionCall {
...
@@ -845,9 +849,8 @@ public class Function extends Expression implements FunctionCall {
database
.
getMode
().
treatEmptyStringsAsNull
);
database
.
getMode
().
treatEmptyStringsAsNull
);
break
;
break
;
case
DAY_NAME:
{
case
DAY_NAME:
{
SimpleDateFormat
dayName
=
new
SimpleDateFormat
(
int
dayOfWeek
=
DateTimeUtils
.
getSundayDayOfWeek
(
DateTimeUtils
.
dateAndTimeFromValue
(
v0
)[
0
]);
"EEEE"
,
Locale
.
ENGLISH
);
result
=
ValueString
.
get
(
getMonthsAndWeeks
(
1
)[
dayOfWeek
],
result
=
ValueString
.
get
(
dayName
.
format
(
v0
.
getDate
()),
database
.
getMode
().
treatEmptyStringsAsNull
);
database
.
getMode
().
treatEmptyStringsAsNull
);
break
;
break
;
}
}
...
@@ -864,12 +867,11 @@ public class Function extends Expression implements FunctionCall {
...
@@ -864,12 +867,11 @@ public class Function extends Expression implements FunctionCall {
case
SECOND:
case
SECOND:
case
WEEK:
case
WEEK:
case
YEAR:
case
YEAR:
result
=
ValueInt
.
get
(
getDatePart
(
v0
,
info
.
type
));
result
=
ValueInt
.
get
(
get
Int
DatePart
(
v0
,
info
.
type
));
break
;
break
;
case
MONTH_NAME:
{
case
MONTH_NAME:
{
SimpleDateFormat
monthName
=
new
SimpleDateFormat
(
"MMMM"
,
int
month
=
DateTimeUtils
.
monthFromDateValue
(
DateTimeUtils
.
dateAndTimeFromValue
(
v0
)[
0
]);
Locale
.
ENGLISH
);
result
=
ValueString
.
get
(
getMonthsAndWeeks
(
0
)[
month
-
1
],
result
=
ValueString
.
get
(
monthName
.
format
(
v0
.
getDate
()),
database
.
getMode
().
treatEmptyStringsAsNull
);
database
.
getMode
().
treatEmptyStringsAsNull
);
break
;
break
;
}
}
...
@@ -1234,32 +1236,16 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1234,32 +1236,16 @@ public class Function extends Expression implements FunctionCall {
}
}
case
TRUNCATE:
{
case
TRUNCATE:
{
if
(
v0
.
getType
()
==
Value
.
TIMESTAMP
)
{
if
(
v0
.
getType
()
==
Value
.
TIMESTAMP
)
{
java
.
sql
.
Timestamp
d
=
v0
.
getTimestamp
();
result
=
ValueTimestamp
.
fromDateValueAndNanos
(((
ValueTimestamp
)
v0
).
getDateValue
(),
0
);
Calendar
c
=
DateTimeUtils
.
createGregorianCalendar
();
c
.
setTime
(
d
);
c
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
c
.
set
(
Calendar
.
MINUTE
,
0
);
c
.
set
(
Calendar
.
SECOND
,
0
);
c
.
set
(
Calendar
.
MILLISECOND
,
0
);
result
=
ValueTimestamp
.
fromMillis
(
c
.
getTimeInMillis
());
}
else
if
(
v0
.
getType
()
==
Value
.
DATE
)
{
}
else
if
(
v0
.
getType
()
==
Value
.
DATE
)
{
ValueDate
vd
=
(
ValueDate
)
v0
;
result
=
ValueTimestamp
.
fromDateValueAndNanos
(((
ValueDate
)
v0
).
getDateValue
(),
0
);
Calendar
c
=
DateTimeUtils
.
createGregorianCalendar
();
}
else
if
(
v0
.
getType
()
==
Value
.
TIMESTAMP_TZ
)
{
c
.
setTime
(
vd
.
getDate
());
ValueTimestampTimeZone
ts
=
(
ValueTimestampTimeZone
)
v0
;
c
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
result
=
ValueTimestampTimeZone
.
fromDateValueAndNanos
(
ts
.
getDateValue
(),
0
,
c
.
set
(
Calendar
.
MINUTE
,
0
);
ts
.
getTimeZoneOffsetMins
());
c
.
set
(
Calendar
.
SECOND
,
0
);
c
.
set
(
Calendar
.
MILLISECOND
,
0
);
result
=
ValueTimestamp
.
fromMillis
(
c
.
getTimeInMillis
());
}
else
if
(
v0
.
getType
()
==
Value
.
STRING
)
{
}
else
if
(
v0
.
getType
()
==
Value
.
STRING
)
{
ValueString
vd
=
(
ValueString
)
v0
;
ValueTimestamp
ts
=
ValueTimestamp
.
parse
(
v0
.
getString
(),
session
.
getDatabase
().
getMode
());
Calendar
c
=
DateTimeUtils
.
createGregorianCalendar
();
result
=
ValueTimestamp
.
fromDateValueAndNanos
(
ts
.
getDateValue
(),
0
);
c
.
setTime
(
ValueTimestamp
.
parse
(
vd
.
getString
(),
session
.
getDatabase
().
getMode
()).
getDate
());
c
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
c
.
set
(
Calendar
.
MINUTE
,
0
);
c
.
set
(
Calendar
.
SECOND
,
0
);
c
.
set
(
Calendar
.
MILLISECOND
,
0
);
result
=
ValueTimestamp
.
fromMillis
(
c
.
getTimeInMillis
());
}
else
{
}
else
{
double
d
=
v0
.
getDouble
();
double
d
=
v0
.
getDouble
();
int
p
=
v1
==
null
?
0
:
v1
.
getInt
();
int
p
=
v1
==
null
?
0
:
v1
.
getInt
();
...
@@ -1450,7 +1436,8 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1450,7 +1436,8 @@ public class Function extends Expression implements FunctionCall {
case
Value
.
TIME
:
case
Value
.
TIME
:
case
Value
.
DATE
:
case
Value
.
DATE
:
case
Value
.
TIMESTAMP
:
case
Value
.
TIMESTAMP
:
result
=
ValueString
.
get
(
ToChar
.
toChar
(
v0
.
getTimestamp
(),
case
Value
.
TIMESTAMP_TZ
:
result
=
ValueString
.
get
(
ToChar
.
toCharDateTime
(
v0
,
v1
==
null
?
null
:
v1
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
(),
v2
==
null
?
null
:
v2
.
getString
()),
v2
==
null
?
null
:
v2
.
getString
()),
database
.
getMode
().
treatEmptyStringsAsNull
);
database
.
getMode
().
treatEmptyStringsAsNull
);
...
@@ -1472,16 +1459,20 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1472,16 +1459,20 @@ public class Function extends Expression implements FunctionCall {
}
}
break
;
break
;
case
TO_DATE:
case
TO_DATE:
result
=
ValueTimestamp
.
get
(
ToDateParser
.
toDate
(
v0
.
getString
(),
result
=
ToDateParser
.
toDate
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
())
)
;
v1
==
null
?
null
:
v1
.
getString
());
break
;
break
;
case
TO_TIMESTAMP:
case
TO_TIMESTAMP:
result
=
ValueTimestamp
.
get
(
ToDateParser
.
toTimestamp
(
v0
.
getString
(),
result
=
ToDateParser
.
toTimestamp
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
())
)
;
v1
==
null
?
null
:
v1
.
getString
());
break
;
break
;
case
ADD_MONTHS:
case
ADD_MONTHS:
result
=
dateadd
(
"MONTH"
,
v1
.
getInt
(),
v0
);
result
=
dateadd
(
"MONTH"
,
v1
.
getInt
(),
v0
);
break
;
break
;
case
TO_TIMESTAMP_TZ:
result
=
ToDateParser
.
toTimestampTz
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
());
break
;
case
TRANSLATE:
{
case
TRANSLATE:
{
String
matching
=
v1
.
getString
();
String
matching
=
v1
.
getString
();
String
replacement
=
v2
.
getString
();
String
replacement
=
v2
.
getString
();
...
@@ -1502,12 +1493,8 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1502,12 +1493,8 @@ public class Function extends Expression implements FunctionCall {
break
;
break
;
case
EXTRACT:
{
case
EXTRACT:
{
int
field
=
getDatePart
(
v0
.
getString
());
int
field
=
getDatePart
(
v0
.
getString
());
// Normal case when we don't retrieve the EPOCH time
if
(
field
!=
EPOCH
)
{
if
(
field
!=
EPOCH
)
{
result
=
ValueInt
.
get
(
getIntDatePart
(
v1
,
field
));
result
=
ValueInt
.
get
(
getDatePart
(
v1
,
field
));
}
else
{
}
else
{
// Case where we retrieve the EPOCH time.
// Case where we retrieve the EPOCH time.
...
@@ -1530,27 +1517,30 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1530,27 +1517,30 @@ public class Function extends Expression implements FunctionCall {
}
else
if
(
v1
instanceof
ValueDate
)
{
}
else
if
(
v1
instanceof
ValueDate
)
{
// Case where the value is of type date '2000:01:01', we have to retrieve the
total
// Case where the value is of type date '2000:01:01', we have to retrieve the
// number of days and multiply it by the number of seconds in a day.
//
total
number of days and multiply it by the number of seconds in a day.
result
=
ValueDecimal
.
get
(
numberOfDays
.
multiply
(
secondsPerDay
));
result
=
ValueDecimal
.
get
(
numberOfDays
.
multiply
(
secondsPerDay
));
}
else
if
(
v1
instanceof
ValueTimestampTimeZone
)
{
}
else
if
(
v1
instanceof
ValueTimestampTimeZone
)
{
// Case where the value is a of type ValueTimestampTimeZone ('2000:01:01 10:00:00+05).
// Case where the value is a of type ValueTimestampTimeZone
// We retrieve the time zone offset in minute
// ('2000:01:01 10:00:00+05').
// We retrieve the time zone offset in minutes
ValueTimestampTimeZone
v
=
(
ValueTimestampTimeZone
)
v1
;
ValueTimestampTimeZone
v
=
(
ValueTimestampTimeZone
)
v1
;
BigDecimal
timeZoneOffsetSeconds
=
new
BigDecimal
(
v
.
getTimeZoneOffsetMins
()
*
60
);
BigDecimal
timeZoneOffsetSeconds
=
new
BigDecimal
(
v
.
getTimeZoneOffsetMins
()
*
60
);
// Sum the time in nanoseconds and the total number of days in seconds
// Sum the time in nanoseconds and the total number of days in seconds
// and adding the timeZone offset in seconds.
// and adding the timeZone offset in seconds.
result
=
ValueDecimal
.
get
(
timeNanosBigDecimal
.
divide
(
nanosSeconds
)
result
=
ValueDecimal
.
get
(
timeNanosBigDecimal
.
divide
(
nanosSeconds
)
.
add
(
numberOfDays
.
multiply
(
secondsPerDay
))
.
add
(
numberOfDays
.
multiply
(
secondsPerDay
)).
subtract
(
timeZoneOffsetSeconds
));
.
subtract
(
timeZoneOffsetSeconds
));
}
else
{
}
else
{
// By default, we have the date and the time ('2000:01:01 10:00:00) if no type is given.
// By default, we have the date and the time ('2000:01:01 10:00:00') if no type
// We just have to sum the time in nanoseconds and the total number of days in seconds.
// is given.
result
=
ValueDecimal
.
get
(
timeNanosBigDecimal
.
divide
(
nanosSeconds
).
add
(
numberOfDays
.
multiply
(
secondsPerDay
)));
// We just have to sum the time in nanoseconds and the total number of days in
// seconds.
result
=
ValueDecimal
.
get
(
timeNanosBigDecimal
.
divide
(
nanosSeconds
).
add
(
numberOfDays
.
multiply
(
secondsPerDay
)));
}
}
}
}
break
;
break
;
...
@@ -1866,8 +1856,7 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1866,8 +1856,7 @@ public class Function extends Expression implements FunctionCall {
private
static
Value
dateadd
(
String
part
,
long
count
,
Value
v
)
{
private
static
Value
dateadd
(
String
part
,
long
count
,
Value
v
)
{
int
field
=
getDatePart
(
part
);
int
field
=
getDatePart
(
part
);
//v = v.convertTo(Value.TIMESTAMP);
if
(
field
!=
MILLISECOND
&&
field
!=
MICROSECOND
&&
field
!=
NANOSECOND
&&
if
(
field
!=
MILLISECOND
&&
(
count
>
Integer
.
MAX_VALUE
||
count
<
Integer
.
MIN_VALUE
))
{
(
count
>
Integer
.
MAX_VALUE
||
count
<
Integer
.
MIN_VALUE
))
{
throw
DbException
.
getInvalidValueException
(
"DATEADD count"
,
count
);
throw
DbException
.
getInvalidValueException
(
"DATEADD count"
,
count
);
}
}
...
@@ -1917,11 +1906,17 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1917,11 +1906,17 @@ public class Function extends Expression implements FunctionCall {
count
*=
60_000_000_000L
;
count
*=
60_000_000_000L
;
break
;
break
;
case
SECOND:
case
SECOND:
case
EPOCH:
count
*=
1_000_000_000
;
count
*=
1_000_000_000
;
break
;
break
;
case
MILLISECOND:
case
MILLISECOND:
count
*=
1_000_000
;
count
*=
1_000_000
;
break
;
break
;
case
MICROSECOND:
count
*=
1_000
;
break
;
case
NANOSECOND:
break
;
default
:
default
:
throw
DbException
.
getUnsupportedException
(
"DATEADD "
+
part
);
throw
DbException
.
getUnsupportedException
(
"DATEADD "
+
part
);
}
}
...
@@ -1966,17 +1961,27 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1966,17 +1961,27 @@ public class Function extends Expression implements FunctionCall {
long
dateValue2
=
a2
[
0
];
long
dateValue2
=
a2
[
0
];
long
absolute2
=
DateTimeUtils
.
absoluteDayFromDateValue
(
dateValue2
);
long
absolute2
=
DateTimeUtils
.
absoluteDayFromDateValue
(
dateValue2
);
switch
(
field
)
{
switch
(
field
)
{
case
NANOSECOND:
case
MICROSECOND:
case
MILLISECOND:
case
MILLISECOND:
case
SECOND:
case
SECOND:
case
EPOCH:
case
MINUTE:
case
MINUTE:
case
HOUR:
case
HOUR:
long
timeNanos1
=
a1
[
1
];
long
timeNanos1
=
a1
[
1
];
long
timeNanos2
=
a2
[
1
];
long
timeNanos2
=
a2
[
1
];
switch
(
field
)
{
switch
(
field
)
{
case
NANOSECOND:
return
(
absolute2
-
absolute1
)
*
DateTimeUtils
.
NANOS_PER_DAY
+
(
timeNanos2
-
timeNanos1
);
case
MICROSECOND:
return
(
absolute2
-
absolute1
)
*
(
DateTimeUtils
.
MILLIS_PER_DAY
*
1_000
)
+
(
timeNanos2
/
1_000
-
timeNanos1
/
1_000
);
case
MILLISECOND:
case
MILLISECOND:
return
(
absolute2
-
absolute1
)
*
DateTimeUtils
.
MILLIS_PER_DAY
return
(
absolute2
-
absolute1
)
*
DateTimeUtils
.
MILLIS_PER_DAY
+
(
timeNanos2
/
1_000_000
-
timeNanos1
/
1_000_000
);
+
(
timeNanos2
/
1_000_000
-
timeNanos1
/
1_000_000
);
case
SECOND:
case
SECOND:
case
EPOCH:
return
(
absolute2
-
absolute1
)
*
86_400
return
(
absolute2
-
absolute1
)
*
86_400
+
(
timeNanos2
/
1_000_000_000
-
timeNanos1
/
1_000_000_000
);
+
(
timeNanos2
/
1_000_000_000
-
timeNanos1
/
1_000_000_000
);
case
MINUTE:
case
MINUTE:
...
@@ -2023,6 +2028,18 @@ public class Function extends Expression implements FunctionCall {
...
@@ -2023,6 +2028,18 @@ public class Function extends Expression implements FunctionCall {
return
r2
-
r1
;
return
r2
-
r1
;
}
}
private
static
String
[]
getMonthsAndWeeks
(
int
field
)
{
String
[][]
result
=
MONTHS_AND_WEEKS
;
if
(
result
==
null
)
{
result
=
new
String
[
2
][];
DateFormatSymbols
dfs
=
DateFormatSymbols
.
getInstance
(
Locale
.
ENGLISH
);
result
[
0
]
=
dfs
.
getMonths
();
result
[
1
]
=
dfs
.
getWeekdays
();
MONTHS_AND_WEEKS
=
result
;
}
return
result
[
field
];
}
private
static
String
substring
(
String
s
,
int
start
,
int
length
)
{
private
static
String
substring
(
String
s
,
int
start
,
int
length
)
{
int
len
=
s
.
length
();
int
len
=
s
.
length
();
start
--;
start
--;
...
@@ -2310,6 +2327,7 @@ public class Function extends Expression implements FunctionCall {
...
@@ -2310,6 +2327,7 @@ public class Function extends Expression implements FunctionCall {
case
XMLTEXT:
case
XMLTEXT:
case
TRUNCATE:
case
TRUNCATE:
case
TO_TIMESTAMP:
case
TO_TIMESTAMP:
case
TO_TIMESTAMP_TZ:
min
=
1
;
min
=
1
;
max
=
2
;
max
=
2
;
break
;
break
;
...
@@ -2859,7 +2877,7 @@ public class Function extends Expression implements FunctionCall {
...
@@ -2859,7 +2877,7 @@ public class Function extends Expression implements FunctionCall {
* @param field the field type, see {@link Function} for constants
* @param field the field type, see {@link Function} for constants
* @return the value
* @return the value
*/
*/
public
static
int
getDatePart
(
Value
date
,
int
field
)
{
public
static
int
get
Int
DatePart
(
Value
date
,
int
field
)
{
long
[]
a
=
DateTimeUtils
.
dateAndTimeFromValue
(
date
);
long
[]
a
=
DateTimeUtils
.
dateAndTimeFromValue
(
date
);
long
dateValue
=
a
[
0
];
long
dateValue
=
a
[
0
];
long
timeNanos
=
a
[
1
];
long
timeNanos
=
a
[
1
];
...
@@ -2878,6 +2896,10 @@ public class Function extends Expression implements FunctionCall {
...
@@ -2878,6 +2896,10 @@ public class Function extends Expression implements FunctionCall {
return
(
int
)
(
timeNanos
/
1_000_000_000
%
60
);
return
(
int
)
(
timeNanos
/
1_000_000_000
%
60
);
case
Function
.
MILLISECOND
:
case
Function
.
MILLISECOND
:
return
(
int
)
(
timeNanos
/
1_000_000
%
1_000
);
return
(
int
)
(
timeNanos
/
1_000_000
%
1_000
);
case
Function
.
MICROSECOND
:
return
(
int
)
(
timeNanos
/
1_000
%
1_000_000
);
case
Function
.
NANOSECOND
:
return
(
int
)
(
timeNanos
%
1_000_000_000
);
case
Function
.
DAY_OF_YEAR
:
case
Function
.
DAY_OF_YEAR
:
return
DateTimeUtils
.
getDayOfYear
(
dateValue
);
return
DateTimeUtils
.
getDayOfYear
(
dateValue
);
case
Function
.
DAY_OF_WEEK
:
case
Function
.
DAY_OF_WEEK
:
...
...
h2/src/main/org/h2/index/IndexCursor.java
浏览文件 @
9e5d9644
...
@@ -148,6 +148,9 @@ public class IndexCursor implements Cursor {
...
@@ -148,6 +148,9 @@ public class IndexCursor implements Cursor {
}
}
}
}
}
}
if
(
inColumn
!=
null
)
{
start
=
table
.
getTemplateRow
();
}
}
}
/**
/**
...
@@ -326,7 +329,6 @@ public class IndexCursor implements Cursor {
...
@@ -326,7 +329,6 @@ public class IndexCursor implements Cursor {
while
(
inResult
.
next
())
{
while
(
inResult
.
next
())
{
Value
v
=
inResult
.
currentRow
()[
0
];
Value
v
=
inResult
.
currentRow
()[
0
];
if
(
v
!=
ValueNull
.
INSTANCE
)
{
if
(
v
!=
ValueNull
.
INSTANCE
)
{
v
=
inColumn
.
convert
(
v
);
if
(
inResultTested
==
null
)
{
if
(
inResultTested
==
null
)
{
inResultTested
=
new
HashSet
<>();
inResultTested
=
new
HashSet
<>();
}
}
...
@@ -342,9 +344,6 @@ public class IndexCursor implements Cursor {
...
@@ -342,9 +344,6 @@ public class IndexCursor implements Cursor {
private
void
find
(
Value
v
)
{
private
void
find
(
Value
v
)
{
v
=
inColumn
.
convert
(
v
);
v
=
inColumn
.
convert
(
v
);
int
id
=
inColumn
.
getColumnId
();
int
id
=
inColumn
.
getColumnId
();
if
(
start
==
null
)
{
start
=
table
.
getTemplateRow
();
}
start
.
setValue
(
id
,
v
);
start
.
setValue
(
id
,
v
);
cursor
=
index
.
find
(
tableFilter
,
start
,
start
);
cursor
=
index
.
find
(
tableFilter
,
start
,
start
);
}
}
...
...
h2/src/main/org/h2/mvstore/MVStore.java
浏览文件 @
9e5d9644
...
@@ -2450,6 +2450,7 @@ public final class MVStore {
...
@@ -2450,6 +2450,7 @@ public final class MVStore {
* needed.
* needed.
*/
*/
void
writeInBackground
()
{
void
writeInBackground
()
{
try
{
if
(
closed
)
{
if
(
closed
)
{
return
;
return
;
}
}
...
@@ -2470,7 +2471,6 @@ public final class MVStore {
...
@@ -2470,7 +2471,6 @@ public final class MVStore {
}
}
}
}
if
(
autoCompactFillRate
>
0
)
{
if
(
autoCompactFillRate
>
0
)
{
try
{
// whether there were file read or write operations since
// whether there were file read or write operations since
// the last time
// the last time
boolean
fileOps
;
boolean
fileOps
;
...
@@ -2486,21 +2486,23 @@ public final class MVStore {
...
@@ -2486,21 +2486,23 @@ public final class MVStore {
// in the bookkeeping?
// in the bookkeeping?
compact
(
fillRate
,
autoCommitMemory
);
compact
(
fillRate
,
autoCommitMemory
);
autoCompactLastFileOpCount
=
fileStore
.
getWriteCount
()
+
fileStore
.
getReadCount
();
autoCompactLastFileOpCount
=
fileStore
.
getWriteCount
()
+
fileStore
.
getReadCount
();
}
}
catch
(
Throwable
e
)
{
}
catch
(
Throwable
e
)
{
handleException
(
e
);
handleException
(
e
);
}
}
}
}
}
private
void
handleException
(
Throwable
ex
)
{
private
void
handleException
(
Throwable
ex
)
{
if
(
backgroundExceptionHandler
!=
null
)
{
if
(
backgroundExceptionHandler
!=
null
)
{
try
{
try
{
backgroundExceptionHandler
.
uncaughtException
(
null
,
ex
);
backgroundExceptionHandler
.
uncaughtException
(
null
,
ex
);
}
catch
(
Throwable
ignore
)
{
}
catch
(
Throwable
ignore
)
{
if
(
ex
!=
ignore
)
{
// OOME may be the same
ex
.
addSuppressed
(
ignore
);
ex
.
addSuppressed
(
ignore
);
}
}
}
}
}
}
}
/**
/**
* Set the read cache size in MB.
* Set the read cache size in MB.
...
...
h2/src/main/org/h2/store/DataReader.java
浏览文件 @
9e5d9644
...
@@ -171,7 +171,7 @@ public class DataReader extends Reader {
...
@@ -171,7 +171,7 @@ public class DataReader extends Reader {
int
i
=
0
;
int
i
=
0
;
try
{
try
{
for
(;
i
<
len
;
i
++)
{
for
(;
i
<
len
;
i
++)
{
buff
[
i
]
=
readChar
();
buff
[
off
+
i
]
=
readChar
();
}
}
return
len
;
return
len
;
}
catch
(
EOFException
e
)
{
}
catch
(
EOFException
e
)
{
...
...
h2/src/main/org/h2/table/MetaTable.java
浏览文件 @
9e5d9644
h2/src/main/org/h2/tools/ChangeFileEncryption.java
浏览文件 @
9e5d9644
...
@@ -224,7 +224,8 @@ public class ChangeFileEncryption extends Tool {
...
@@ -224,7 +224,8 @@ public class ChangeFileEncryption extends Tool {
try
(
FileChannel
fileIn
=
getFileChannel
(
fileName
,
"r"
,
decryptKey
)){
try
(
FileChannel
fileIn
=
getFileChannel
(
fileName
,
"r"
,
decryptKey
)){
try
(
InputStream
inStream
=
new
FileChannelInputStream
(
fileIn
,
true
))
{
try
(
InputStream
inStream
=
new
FileChannelInputStream
(
fileIn
,
true
))
{
FileUtils
.
delete
(
temp
);
FileUtils
.
delete
(
temp
);
try
(
OutputStream
outStream
=
new
FileChannelOutputStream
(
getFileChannel
(
temp
,
"rw"
,
encryptKey
),
true
))
{
try
(
OutputStream
outStream
=
new
FileChannelOutputStream
(
getFileChannel
(
temp
,
"rw"
,
encryptKey
),
true
))
{
byte
[]
buffer
=
new
byte
[
4
*
1024
];
byte
[]
buffer
=
new
byte
[
4
*
1024
];
long
remaining
=
fileIn
.
size
();
long
remaining
=
fileIn
.
size
();
long
total
=
remaining
;
long
total
=
remaining
;
...
...
h2/src/main/org/h2/util/DateTimeUtils.java
浏览文件 @
9e5d9644
...
@@ -85,6 +85,11 @@ public class DateTimeUtils {
...
@@ -85,6 +85,11 @@ public class DateTimeUtils {
private
static
final
ThreadLocal
<
GregorianCalendar
>
CACHED_CALENDAR_NON_DEFAULT_TIMEZONE
=
private
static
final
ThreadLocal
<
GregorianCalendar
>
CACHED_CALENDAR_NON_DEFAULT_TIMEZONE
=
new
ThreadLocal
<>();
new
ThreadLocal
<>();
/**
* Cached local time zone.
*/
private
static
volatile
TimeZone
timeZone
;
/**
/**
* Observed JVM behaviour is that if the timezone of the host computer is
* Observed JVM behaviour is that if the timezone of the host computer is
* changed while the JVM is running, the zone offset does not change but
* changed while the JVM is running, the zone offset does not change but
...
@@ -100,12 +105,26 @@ public class DateTimeUtils {
...
@@ -100,12 +105,26 @@ public class DateTimeUtils {
// utility class
// utility class
}
}
/**
* Returns local time zone.
*
* @return local time zone
*/
private
static
TimeZone
getTimeZone
()
{
TimeZone
tz
=
timeZone
;
if
(
tz
==
null
)
{
timeZone
=
tz
=
TimeZone
.
getDefault
();
}
return
tz
;
}
/**
/**
* Reset the cached calendar for default timezone, for example after
* Reset the cached calendar for default timezone, for example after
* changing the default timezone.
* changing the default timezone.
*/
*/
public
static
void
resetCalendar
()
{
public
static
void
resetCalendar
()
{
CACHED_CALENDAR
.
remove
();
CACHED_CALENDAR
.
remove
();
timeZone
=
null
;
zoneOffsetMillis
=
DateTimeUtils
.
createGregorianCalendar
().
get
(
Calendar
.
ZONE_OFFSET
);
zoneOffsetMillis
=
DateTimeUtils
.
createGregorianCalendar
().
get
(
Calendar
.
ZONE_OFFSET
);
}
}
...
@@ -628,20 +647,6 @@ public class DateTimeUtils {
...
@@ -628,20 +647,6 @@ public class DateTimeUtils {
return
ValueTimestamp
.
fromDateValueAndNanos
(
dateValue
,
timeNanos
);
return
ValueTimestamp
.
fromDateValueAndNanos
(
dateValue
,
timeNanos
);
}
}
/**
* Get the year (positive or negative) from a calendar.
*
* @param calendar the calendar
* @return the year
*/
private
static
int
getYear
(
Calendar
calendar
)
{
int
year
=
calendar
.
get
(
Calendar
.
YEAR
);
if
(
calendar
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
BC
)
{
year
=
1
-
year
;
}
return
year
;
}
/**
/**
* Get the number of milliseconds since 1970-01-01 in the local timezone,
* Get the number of milliseconds since 1970-01-01 in the local timezone,
* but without daylight saving time into account.
* but without daylight saving time into account.
...
@@ -921,19 +926,6 @@ public class DateTimeUtils {
...
@@ -921,19 +926,6 @@ public class DateTimeUtils {
return
new
Date
(
millis
);
return
new
Date
(
millis
);
}
}
/**
* Convert an encoded date value to millis, using the supplied timezone.
*
* @param tz the timezone
* @param dateValue the date value
* @return the date
*/
public
static
long
convertDateValueToMillis
(
TimeZone
tz
,
long
dateValue
)
{
return
getMillis
(
tz
,
yearFromDateValue
(
dateValue
),
monthFromDateValue
(
dateValue
),
dayFromDateValue
(
dateValue
),
0
,
0
,
0
,
0
);
}
/**
/**
* Convert an encoded date-time value to millis, using the supplied timezone.
* Convert an encoded date-time value to millis, using the supplied timezone.
*
*
...
@@ -1070,9 +1062,13 @@ public class DateTimeUtils {
...
@@ -1070,9 +1062,13 @@ public class DateTimeUtils {
* @return the date value
* @return the date value
*/
*/
public
static
long
dateValueFromDate
(
long
ms
)
{
public
static
long
dateValueFromDate
(
long
ms
)
{
Calendar
cal
=
getCalendar
();
ms
+=
getTimeZone
().
getOffset
(
ms
);
cal
.
setTimeInMillis
(
ms
);
long
absoluteDay
=
ms
/
MILLIS_PER_DAY
;
return
dateValueFromCalendar
(
cal
);
// Round toward negative infinity
if
(
ms
<
0
&&
(
absoluteDay
*
MILLIS_PER_DAY
!=
ms
))
{
absoluteDay
--;
}
return
dateValueFromAbsoluteDay
(
absoluteDay
);
}
}
/**
/**
...
@@ -1082,10 +1078,12 @@ public class DateTimeUtils {
...
@@ -1082,10 +1078,12 @@ public class DateTimeUtils {
* @return the date value
* @return the date value
*/
*/
private
static
long
dateValueFromCalendar
(
Calendar
cal
)
{
private
static
long
dateValueFromCalendar
(
Calendar
cal
)
{
int
year
,
month
,
day
;
int
year
=
cal
.
get
(
Calendar
.
YEAR
);
year
=
getYear
(
cal
);
if
(
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
BC
)
{
month
=
cal
.
get
(
Calendar
.
MONTH
)
+
1
;
year
=
1
-
year
;
day
=
cal
.
get
(
Calendar
.
DAY_OF_MONTH
);
}
int
month
=
cal
.
get
(
Calendar
.
MONTH
)
+
1
;
int
day
=
cal
.
get
(
Calendar
.
DAY_OF_MONTH
);
return
((
long
)
year
<<
SHIFT_YEAR
)
|
(
month
<<
SHIFT_MONTH
)
|
day
;
return
((
long
)
year
<<
SHIFT_YEAR
)
|
(
month
<<
SHIFT_MONTH
)
|
day
;
}
}
...
@@ -1097,9 +1095,13 @@ public class DateTimeUtils {
...
@@ -1097,9 +1095,13 @@ public class DateTimeUtils {
* @return the nanoseconds
* @return the nanoseconds
*/
*/
public
static
long
nanosFromDate
(
long
ms
)
{
public
static
long
nanosFromDate
(
long
ms
)
{
Calendar
cal
=
getCalendar
();
ms
+=
getTimeZone
().
getOffset
(
ms
);
cal
.
setTimeInMillis
(
ms
);
long
absoluteDay
=
ms
/
MILLIS_PER_DAY
;
return
nanosFromCalendar
(
cal
);
// Round toward negative infinity
if
(
ms
<
0
&&
(
absoluteDay
*
MILLIS_PER_DAY
!=
ms
))
{
absoluteDay
--;
}
return
(
ms
-
absoluteDay
*
MILLIS_PER_DAY
)
*
1_000_000
;
}
}
/**
/**
...
@@ -1154,7 +1156,7 @@ public class DateTimeUtils {
...
@@ -1154,7 +1156,7 @@ public class DateTimeUtils {
m
+=
12
;
m
+=
12
;
}
}
long
a
=
((
y
*
2922L
)
>>
3
)
+
DAYS_OFFSET
[
m
-
3
]
+
d
-
719484
;
long
a
=
((
y
*
2922L
)
>>
3
)
+
DAYS_OFFSET
[
m
-
3
]
+
d
-
719484
;
if
(
y
<=
1582
&&
((
y
<
1582
)
||
(
m
*
100
+
d
<
10
0
5
)))
{
if
(
y
<=
1582
&&
((
y
<
1582
)
||
(
m
*
100
+
d
<
10
1
5
)))
{
// Julian calendar (cutover at 1582-10-04 / 1582-10-15)
// Julian calendar (cutover at 1582-10-04 / 1582-10-15)
a
+=
13
;
a
+=
13
;
}
else
if
(
y
<
1901
||
y
>
2099
)
{
}
else
if
(
y
<
1901
||
y
>
2099
)
{
...
...
h2/src/main/org/h2/util/ToChar.java
浏览文件 @
9e5d9644
...
@@ -6,20 +6,19 @@
...
@@ -6,20 +6,19 @@
package
org
.
h2
.
util
;
package
org
.
h2
.
util
;
import
java.math.BigDecimal
;
import
java.math.BigDecimal
;
import
java.sql.Date
;
import
java.text.DateFormatSymbols
;
import
java.sql.Timestamp
;
import
java.text.DecimalFormat
;
import
java.text.DecimalFormat
;
import
java.text.DecimalFormatSymbols
;
import
java.text.DecimalFormatSymbols
;
import
java.text.SimpleDateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.Calendar
;
import
java.util.Currency
;
import
java.util.Currency
;
import
java.util.GregorianCalendar
;
import
java.util.Locale
;
import
java.util.Locale
;
import
java.util.TimeZone
;
import
java.util.TimeZone
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.value.Value
;
import
org.h2.value.ValueTimestampTimeZone
;
/**
/**
* Emulates Oracle's TO_CHAR function.
* Emulates Oracle's TO_CHAR function.
...
@@ -29,7 +28,7 @@ public class ToChar {
...
@@ -29,7 +28,7 @@ public class ToChar {
/**
/**
* The beginning of the Julian calendar.
* The beginning of the Julian calendar.
*/
*/
private
static
final
long
JULIAN_EPOCH
;
static
final
int
JULIAN_EPOCH
=
-
2_440_588
;
private
static
final
int
[]
ROMAN_VALUES
=
{
1000
,
900
,
500
,
400
,
100
,
90
,
50
,
40
,
10
,
9
,
private
static
final
int
[]
ROMAN_VALUES
=
{
1000
,
900
,
500
,
400
,
100
,
90
,
50
,
40
,
10
,
9
,
5
,
4
,
1
};
5
,
4
,
1
};
...
@@ -37,14 +36,9 @@ public class ToChar {
...
@@ -37,14 +36,9 @@ public class ToChar {
private
static
final
String
[]
ROMAN_NUMERALS
=
{
"M"
,
"CM"
,
"D"
,
"CD"
,
"C"
,
"XC"
,
private
static
final
String
[]
ROMAN_NUMERALS
=
{
"M"
,
"CM"
,
"D"
,
"CD"
,
"C"
,
"XC"
,
"L"
,
"XL"
,
"X"
,
"IX"
,
"V"
,
"IV"
,
"I"
};
"L"
,
"XL"
,
"X"
,
"IX"
,
"V"
,
"IV"
,
"I"
};
static
{
static
final
int
MONTHS
=
0
,
SHORT_MONTHS
=
1
,
WEEKDAYS
=
2
,
SHORT_WEEKDAYS
=
3
,
AM_PM
=
4
;
GregorianCalendar
epoch
=
new
GregorianCalendar
(
Locale
.
ENGLISH
);
epoch
.
setGregorianChange
(
new
Date
(
Long
.
MAX_VALUE
));
private
static
volatile
String
[][]
NAMES
;
epoch
.
clear
();
epoch
.
set
(
4713
,
Calendar
.
JANUARY
,
1
,
0
,
0
,
0
);
epoch
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
BC
);
JULIAN_EPOCH
=
epoch
.
getTimeInMillis
();
}
private
ToChar
()
{
private
ToChar
()
{
// utility class
// utility class
...
@@ -460,6 +454,66 @@ public class ToChar {
...
@@ -460,6 +454,66 @@ public class ToChar {
return
hex
;
return
hex
;
}
}
static
String
[]
getNames
(
int
names
)
{
String
[][]
result
=
NAMES
;
if
(
result
==
null
)
{
result
=
new
String
[
5
][];
DateFormatSymbols
dfs
=
DateFormatSymbols
.
getInstance
();
result
[
MONTHS
]
=
dfs
.
getMonths
();
String
[]
months
=
dfs
.
getShortMonths
();
for
(
int
i
=
0
;
i
<
12
;
i
++)
{
String
month
=
months
[
i
];
if
(
month
.
endsWith
(
"."
))
{
months
[
i
]
=
month
.
substring
(
0
,
month
.
length
()
-
1
);
}
}
result
[
SHORT_MONTHS
]
=
months
;
result
[
WEEKDAYS
]
=
dfs
.
getWeekdays
();
result
[
SHORT_WEEKDAYS
]
=
dfs
.
getShortWeekdays
();
result
[
AM_PM
]
=
dfs
.
getAmPmStrings
();
NAMES
=
result
;
}
return
result
[
names
];
}
/**
* Returns time zone display name or ID for the specified date-time value.
*
* @param value
* value
* @param tzd
* if {@code true} return TZD (time zone region with Daylight Saving
* Time information included), if {@code false} return TZR (time zone
* region)
* @return time zone display name or ID
*/
private
static
String
getTimeZone
(
Value
value
,
boolean
tzd
)
{
if
(!(
value
instanceof
ValueTimestampTimeZone
))
{
TimeZone
tz
=
TimeZone
.
getDefault
();
if
(
tzd
)
{
boolean
daylight
=
tz
.
inDaylightTime
(
value
.
getTimestamp
());
return
tz
.
getDisplayName
(
daylight
,
TimeZone
.
SHORT
);
}
return
tz
.
getID
();
}
int
offset
=
((
ValueTimestampTimeZone
)
value
).
getTimeZoneOffsetMins
();
if
(
offset
==
0
)
{
return
"UTC"
;
}
StringBuilder
b
=
new
StringBuilder
(
9
);
b
.
append
(
"GMT"
);
if
(
offset
<
0
)
{
b
.
append
(
'-'
);
offset
=
-
offset
;
}
else
{
b
.
append
(
'+'
);
}
StringUtils
.
appendZeroPadded
(
b
,
2
,
offset
/
60
);
b
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
b
,
2
,
offset
%
60
);
return
b
.
toString
();
}
/**
/**
* Emulates Oracle's TO_CHAR(datetime) function.
* Emulates Oracle's TO_CHAR(datetime) function.
*
*
...
@@ -592,19 +646,31 @@ public class ToChar {
...
@@ -592,19 +646,31 @@ public class ToChar {
* See also TO_CHAR(datetime) and datetime format models
* See also TO_CHAR(datetime) and datetime format models
* in the Oracle documentation.
* in the Oracle documentation.
*
*
* @param
ts the timestamp
to format
* @param
value the date-time value
to format
* @param format the format pattern to use (if any)
* @param format the format pattern to use (if any)
* @param nlsParam the NLS parameter (if any)
* @param nlsParam the NLS parameter (if any)
* @return the formatted timestamp
* @return the formatted timestamp
*/
*/
public
static
String
toChar
(
Timestamp
ts
,
String
format
,
@SuppressWarnings
(
"unused"
)
String
nlsParam
)
{
public
static
String
toCharDateTime
(
Value
value
,
String
format
,
@SuppressWarnings
(
"unused"
)
String
nlsParam
)
{
long
[]
a
=
DateTimeUtils
.
dateAndTimeFromValue
(
value
);
long
dateValue
=
a
[
0
];
long
timeNanos
=
a
[
1
];
int
year
=
DateTimeUtils
.
yearFromDateValue
(
dateValue
);
int
monthOfYear
=
DateTimeUtils
.
monthFromDateValue
(
dateValue
);
int
dayOfMonth
=
DateTimeUtils
.
dayFromDateValue
(
dateValue
);
int
posYear
=
Math
.
abs
(
year
);
long
second
=
timeNanos
/
1_000_000_000
;
int
nanos
=
(
int
)
(
timeNanos
-
second
*
1_000_000_000
);
int
minute
=
(
int
)
(
second
/
60
);
second
-=
minute
*
60
;
int
hour
=
minute
/
60
;
minute
-=
hour
*
60
;
int
h12
=
(
hour
+
11
)
%
12
+
1
;
boolean
isAM
=
hour
<
12
;
if
(
format
==
null
)
{
if
(
format
==
null
)
{
format
=
"DD-MON-YY HH.MI.SS.FF PM"
;
format
=
"DD-MON-YY HH.MI.SS.FF PM"
;
}
}
GregorianCalendar
cal
=
new
GregorianCalendar
(
Locale
.
ENGLISH
);
cal
.
setTimeInMillis
(
ts
.
getTime
());
StringBuilder
output
=
new
StringBuilder
();
StringBuilder
output
=
new
StringBuilder
();
boolean
fillMode
=
true
;
boolean
fillMode
=
true
;
...
@@ -615,197 +681,213 @@ public class ToChar {
...
@@ -615,197 +681,213 @@ public class ToChar {
// AD / BC
// AD / BC
if
((
cap
=
containsAt
(
format
,
i
,
"A.D."
,
"B.C."
))
!=
null
)
{
if
((
cap
=
containsAt
(
format
,
i
,
"A.D."
,
"B.C."
))
!=
null
)
{
String
era
=
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
AD
?
"A.D."
:
"B.C."
;
String
era
=
year
>
0
?
"A.D."
:
"B.C."
;
output
.
append
(
cap
.
apply
(
era
));
output
.
append
(
cap
.
apply
(
era
));
i
+=
4
;
i
+=
4
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"AD"
,
"BC"
))
!=
null
)
{
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"AD"
,
"BC"
))
!=
null
)
{
String
era
=
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
AD
?
"AD"
:
"BC"
;
String
era
=
year
>
0
?
"AD"
:
"BC"
;
output
.
append
(
cap
.
apply
(
era
));
output
.
append
(
cap
.
apply
(
era
));
i
+=
2
;
i
+=
2
;
// AM / PM
// AM / PM
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"A.M."
,
"P.M."
))
!=
null
)
{
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"A.M."
,
"P.M."
))
!=
null
)
{
String
am
=
cal
.
get
(
Calendar
.
AM_PM
)
==
Calendar
.
AM
?
"A.M."
:
"P.M."
;
String
am
=
is
AM
?
"A.M."
:
"P.M."
;
output
.
append
(
cap
.
apply
(
am
));
output
.
append
(
cap
.
apply
(
am
));
i
+=
4
;
i
+=
4
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"AM"
,
"PM"
))
!=
null
)
{
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"AM"
,
"PM"
))
!=
null
)
{
String
am
=
cal
.
get
(
Calendar
.
AM_PM
)
==
Calendar
.
AM
?
"AM"
:
"PM"
;
String
am
=
is
AM
?
"AM"
:
"PM"
;
output
.
append
(
cap
.
apply
(
am
));
output
.
append
(
cap
.
apply
(
am
));
i
+=
2
;
i
+=
2
;
// Long/short date/time format
// Long/short date/time format
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DL"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"DL"
)
!=
null
)
{
output
.
append
(
new
SimpleDateFormat
(
"EEEE, MMMM d, yyyy"
).
format
(
ts
));
String
day
=
getNames
(
WEEKDAYS
)[
DateTimeUtils
.
getSundayDayOfWeek
(
dateValue
)];
String
month
=
getNames
(
MONTHS
)[
monthOfYear
-
1
];
output
.
append
(
day
).
append
(
", "
).
append
(
month
).
append
(
' '
).
append
(
dayOfMonth
).
append
(
", "
);
StringUtils
.
appendZeroPadded
(
output
,
4
,
posYear
);
i
+=
2
;
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DS"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"DS"
)
!=
null
)
{
output
.
append
(
new
SimpleDateFormat
(
"MM/dd/yyyy"
).
format
(
ts
));
StringUtils
.
appendZeroPadded
(
output
,
2
,
monthOfYear
);
output
.
append
(
'/'
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
dayOfMonth
);
output
.
append
(
'/'
);
StringUtils
.
appendZeroPadded
(
output
,
4
,
posYear
);
i
+=
2
;
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"TS"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"TS"
)
!=
null
)
{
output
.
append
(
new
SimpleDateFormat
(
"h:mm:ss aa"
).
format
(
ts
));
output
.
append
(
h12
).
append
(
':'
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
minute
);
output
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
second
);
output
.
append
(
' '
);
output
.
append
(
getNames
(
AM_PM
)[
isAM
?
0
:
1
]);
i
+=
2
;
i
+=
2
;
// Day
// Day
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"DDD"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"DDD"
)
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
DAY_OF_YEAR
));
output
.
append
(
DateTimeUtils
.
getDayOfYear
(
dateValue
));
i
+=
3
;
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DD"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"DD"
)
!=
null
)
{
output
.
append
(
String
.
format
(
"%02d"
,
StringUtils
.
appendZeroPadded
(
output
,
2
,
dayOfMonth
);
cal
.
get
(
Calendar
.
DAY_OF_MONTH
)));
i
+=
2
;
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DY"
))
!=
null
)
{
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DY"
))
!=
null
)
{
String
day
=
new
SimpleDateFormat
(
"EEE"
).
format
(
ts
)
;
String
day
=
getNames
(
SHORT_WEEKDAYS
)[
DateTimeUtils
.
getSundayDayOfWeek
(
dateValue
)]
;
output
.
append
(
cap
.
apply
(
day
));
output
.
append
(
cap
.
apply
(
day
));
i
+=
2
;
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DAY"
))
!=
null
)
{
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DAY"
))
!=
null
)
{
String
day
=
new
SimpleDateFormat
(
"EEEE"
).
format
(
ts
)
;
String
day
=
getNames
(
WEEKDAYS
)[
DateTimeUtils
.
getSundayDayOfWeek
(
dateValue
)]
;
if
(
fillMode
)
{
if
(
fillMode
)
{
day
=
StringUtils
.
pad
(
day
,
"Wednesday"
.
length
(),
" "
,
true
);
day
=
StringUtils
.
pad
(
day
,
"Wednesday"
.
length
(),
" "
,
true
);
}
}
output
.
append
(
cap
.
apply
(
day
));
output
.
append
(
cap
.
apply
(
day
));
i
+=
3
;
i
+=
3
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"D"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"D"
)
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
DAY_OF_WEEK
));
output
.
append
(
DateTimeUtils
.
getSundayDayOfWeek
(
dateValue
));
i
+=
1
;
i
+=
1
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"J"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"J"
)
!=
null
)
{
long
millis
=
ts
.
getTime
()
-
JULIAN_EPOCH
;
output
.
append
(
DateTimeUtils
.
absoluteDayFromDateValue
(
dateValue
)
-
JULIAN_EPOCH
);
long
days
=
(
long
)
Math
.
floor
(
millis
/
(
1000
*
60
*
60
*
24
));
output
.
append
(
days
);
i
+=
1
;
i
+=
1
;
// Hours
// Hours
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"HH24"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"HH24"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
HOUR_OF_DAY
))
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
hour
);
i
+=
4
;
i
+=
4
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"HH12"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"HH12"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
HOUR
))
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
h12
);
i
+=
4
;
i
+=
4
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"HH"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"HH"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
HOUR
))
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
h12
);
i
+=
2
;
i
+=
2
;
// Minutes
// Minutes
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"MI"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"MI"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
MINUTE
))
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
minute
);
i
+=
2
;
i
+=
2
;
// Seconds
// Seconds
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"SSSSS"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"SSSSS"
)
!=
null
)
{
int
seconds
=
cal
.
get
(
Calendar
.
HOUR_OF_DAY
)
*
60
*
60
;
int
seconds
=
(
int
)
(
timeNanos
/
1_000_000_000
);
seconds
+=
cal
.
get
(
Calendar
.
MINUTE
)
*
60
;
seconds
+=
cal
.
get
(
Calendar
.
SECOND
);
output
.
append
(
seconds
);
output
.
append
(
seconds
);
i
+=
5
;
i
+=
5
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"SS"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"SS"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
SECOND
))
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
second
);
i
+=
2
;
i
+=
2
;
// Fractional seconds
// Fractional seconds
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"FF1"
,
"FF2"
,
}
else
if
(
containsAt
(
format
,
i
,
"FF1"
,
"FF2"
,
"FF3"
,
"FF4"
,
"FF5"
,
"FF6"
,
"FF7"
,
"FF8"
,
"FF9"
)
)
!=
null
)
{
"FF3"
,
"FF4"
,
"FF5"
,
"FF6"
,
"FF7"
,
"FF8"
,
"FF9"
)
!=
null
)
{
int
x
=
Integer
.
parseInt
(
format
.
substring
(
i
+
2
,
i
+
3
))
;
int
x
=
format
.
charAt
(
i
+
2
)
-
'0'
;
int
ff
=
(
int
)
(
cal
.
get
(
Calendar
.
MILLISECOND
)
*
Math
.
pow
(
10
,
x
-
3
));
int
ff
=
(
int
)
(
nanos
*
Math
.
pow
(
10
,
x
-
9
));
output
.
append
(
ff
);
StringUtils
.
appendZeroPadded
(
output
,
x
,
ff
);
i
+=
3
;
i
+=
3
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"FF"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"FF"
)
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
MILLISECOND
)
*
1000
);
StringUtils
.
appendZeroPadded
(
output
,
9
,
nanos
);
i
+=
2
;
i
+=
2
;
// Time zone
// Time zone
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"TZR"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"TZR"
)
!=
null
)
{
TimeZone
tz
=
TimeZone
.
getDefault
();
output
.
append
(
getTimeZone
(
value
,
false
));
output
.
append
(
tz
.
getID
());
i
+=
3
;
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"TZD"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"TZD"
)
!=
null
)
{
TimeZone
tz
=
TimeZone
.
getDefault
();
output
.
append
(
getTimeZone
(
value
,
true
));
boolean
daylight
=
tz
.
inDaylightTime
(
new
java
.
util
.
Date
());
output
.
append
(
tz
.
getDisplayName
(
daylight
,
TimeZone
.
SHORT
));
i
+=
3
;
i
+=
3
;
// Week
// Week
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"IW"
,
"WW"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"IW"
,
"WW"
)
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
WEEK_OF_YEAR
));
output
.
append
(
DateTimeUtils
.
getWeekOfYear
(
dateValue
,
0
,
1
));
i
+=
2
;
i
+=
2
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"W"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"W"
)
!=
null
)
{
int
w
=
(
int
)
(
1
+
Math
.
floor
(
cal
.
get
(
Calendar
.
DAY_OF_MONTH
)
/
7
))
;
int
w
=
1
+
dayOfMonth
/
7
;
output
.
append
(
w
);
output
.
append
(
w
);
i
+=
1
;
i
+=
1
;
// Year
// Year
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"Y,YYY"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"Y,YYY"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"#,###"
).
format
(
getYear
(
cal
)
));
output
.
append
(
new
DecimalFormat
(
"#,###"
).
format
(
posYear
));
i
+=
5
;
i
+=
5
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"SYYYY"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"SYYYY"
)
!=
null
)
{
if
(
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
BC
)
{
// Should be <= 0, but Oracle prints negative years with off-by-one difference
if
(
year
<
0
)
{
output
.
append
(
'-'
);
output
.
append
(
'-'
);
}
}
output
.
append
(
new
DecimalFormat
(
"0000"
).
format
(
getYear
(
cal
))
);
StringUtils
.
appendZeroPadded
(
output
,
4
,
posYear
);
i
+=
5
;
i
+=
5
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"YYYY"
,
"IYYY"
,
"RRRR"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"YYYY"
,
"RRRR"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"0000"
).
format
(
getYear
(
cal
))
);
StringUtils
.
appendZeroPadded
(
output
,
4
,
posYear
);
i
+=
4
;
i
+=
4
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"YYY"
,
"IYY"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"IYYY"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"000"
).
format
(
getYear
(
cal
)
%
1000
));
StringUtils
.
appendZeroPadded
(
output
,
4
,
Math
.
abs
(
DateTimeUtils
.
getIsoWeekYear
(
dateValue
)));
i
+=
4
;
}
else
if
(
containsAt
(
format
,
i
,
"YYY"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
3
,
posYear
%
1000
);
i
+=
3
;
}
else
if
(
containsAt
(
format
,
i
,
"IYY"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
3
,
Math
.
abs
(
DateTimeUtils
.
getIsoWeekYear
(
dateValue
))
%
1000
);
i
+=
3
;
i
+=
3
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"YY"
,
"IY"
,
"RR"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"YY"
,
"RR"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
getYear
(
cal
)
%
100
)
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
posYear
%
100
);
i
+=
2
;
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"I"
,
"Y"
))
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"IY"
)
!=
null
)
{
output
.
append
(
getYear
(
cal
)
%
10
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
Math
.
abs
(
DateTimeUtils
.
getIsoWeekYear
(
dateValue
))
%
100
);
i
+=
2
;
}
else
if
(
containsAt
(
format
,
i
,
"Y"
)
!=
null
)
{
output
.
append
(
posYear
%
10
);
i
+=
1
;
}
else
if
(
containsAt
(
format
,
i
,
"I"
)
!=
null
)
{
output
.
append
(
Math
.
abs
(
DateTimeUtils
.
getIsoWeekYear
(
dateValue
))
%
10
);
i
+=
1
;
i
+=
1
;
// Month / quarter
// Month / quarter
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MONTH"
))
!=
null
)
{
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MONTH"
))
!=
null
)
{
String
month
=
new
SimpleDateFormat
(
"MMMM"
).
format
(
ts
)
;
String
month
=
getNames
(
MONTHS
)[
monthOfYear
-
1
]
;
if
(
fillMode
)
{
if
(
fillMode
)
{
month
=
StringUtils
.
pad
(
month
,
"September"
.
length
(),
" "
,
true
);
month
=
StringUtils
.
pad
(
month
,
"September"
.
length
(),
" "
,
true
);
}
}
output
.
append
(
cap
.
apply
(
month
));
output
.
append
(
cap
.
apply
(
month
));
i
+=
5
;
i
+=
5
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MON"
))
!=
null
)
{
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MON"
))
!=
null
)
{
String
month
=
new
SimpleDateFormat
(
"MMM"
).
format
(
ts
)
;
String
month
=
getNames
(
SHORT_MONTHS
)[
monthOfYear
-
1
]
;
output
.
append
(
cap
.
apply
(
month
));
output
.
append
(
cap
.
apply
(
month
));
i
+=
3
;
i
+=
3
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"MM"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"MM"
)
!=
null
)
{
output
.
append
(
String
.
format
(
"%02d"
,
cal
.
get
(
Calendar
.
MONTH
)
+
1
)
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
monthOfYear
);
i
+=
2
;
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"RM"
))
!=
null
)
{
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"RM"
))
!=
null
)
{
int
month
=
cal
.
get
(
Calendar
.
MONTH
)
+
1
;
output
.
append
(
cap
.
apply
(
toRomanNumeral
(
monthOfYear
)));
output
.
append
(
cap
.
apply
(
toRomanNumeral
(
month
)));
i
+=
2
;
i
+=
2
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"Q"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"Q"
)
!=
null
)
{
int
q
=
(
int
)
(
1
+
Math
.
floor
(
cal
.
get
(
Calendar
.
MONTH
)
/
3
)
);
int
q
=
1
+
((
monthOfYear
-
1
)
/
3
);
output
.
append
(
q
);
output
.
append
(
q
);
i
+=
1
;
i
+=
1
;
// Local radix character
// Local radix character
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"X"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"X"
)
!=
null
)
{
char
c
=
DecimalFormatSymbols
.
getInstance
().
getDecimalSeparator
();
char
c
=
DecimalFormatSymbols
.
getInstance
().
getDecimalSeparator
();
output
.
append
(
c
);
output
.
append
(
c
);
i
+=
1
;
i
+=
1
;
// Format modifiers
// Format modifiers
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"FM"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"FM"
)
!=
null
)
{
fillMode
=
!
fillMode
;
fillMode
=
!
fillMode
;
i
+=
2
;
i
+=
2
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"FX"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"FX"
)
!=
null
)
{
i
+=
2
;
i
+=
2
;
// Literal text
// Literal text
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"\""
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"\""
)
!=
null
)
{
for
(
i
=
i
+
1
;
i
<
format
.
length
();
i
++)
{
for
(
i
=
i
+
1
;
i
<
format
.
length
();
i
++)
{
char
c
=
format
.
charAt
(
i
);
char
c
=
format
.
charAt
(
i
);
if
(
c
!=
'"'
)
{
if
(
c
!=
'"'
)
{
...
@@ -835,14 +917,6 @@ public class ToChar {
...
@@ -835,14 +917,6 @@ public class ToChar {
return
output
.
toString
();
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
* Returns a capitalization strategy if the specified string contains any of
* the specified substrings at the specified index. The capitalization
* the specified substrings at the specified index. The capitalization
...
...
h2/src/main/org/h2/util/ToDateParser.java
浏览文件 @
9e5d9644
...
@@ -7,9 +7,13 @@ package org.h2.util;
...
@@ -7,9 +7,13 @@ package org.h2.util;
import
static
java
.
lang
.
String
.
format
;
import
static
java
.
lang
.
String
.
format
;
import
java.sql.Timestamp
;
import
java.util.Calendar
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
import
java.util.List
;
import
java.util.List
;
import
java.util.TimeZone
;
import
org.h2.value.ValueTimestamp
;
import
org.h2.value.ValueTimestampTimeZone
;
/**
/**
* Emulates Oracle's TO_DATE function.<br>
* Emulates Oracle's TO_DATE function.<br>
...
@@ -21,8 +25,29 @@ public class ToDateParser {
...
@@ -21,8 +25,29 @@ public class ToDateParser {
private
final
ConfigParam
functionName
;
private
final
ConfigParam
functionName
;
private
String
inputStr
;
private
String
inputStr
;
private
String
formatStr
;
private
String
formatStr
;
private
final
Calendar
resultCalendar
=
DateTimeUtils
.
createGregorianCalendar
();
private
Integer
nanos
;
private
boolean
doyValid
=
false
,
absoluteDayValid
=
false
,
hour12Valid
=
false
,
timeZoneHMValid
=
false
;
private
boolean
bc
;
private
long
absoluteDay
;
private
int
year
,
month
,
day
=
1
;
private
int
dayOfYear
;
private
int
hour
,
minute
,
second
,
nanos
;
private
int
hour12
;
boolean
isAM
=
true
;
private
TimeZone
timeZone
;
private
int
timeZoneHour
,
timeZoneMinute
;
private
int
currentYear
,
currentMonth
;
/**
/**
* @param input the input date with the date-time info
* @param input the input date with the date-time info
...
@@ -31,20 +56,6 @@ public class ToDateParser {
...
@@ -31,20 +56,6 @@ public class ToDateParser {
* code)
* code)
*/
*/
private
ToDateParser
(
ConfigParam
functionName
,
String
input
,
String
format
)
{
private
ToDateParser
(
ConfigParam
functionName
,
String
input
,
String
format
)
{
// reset calendar - default oracle behaviour
resultCalendar
.
set
(
Calendar
.
YEAR
,
1970
);
resultCalendar
.
set
(
Calendar
.
MONTH
,
DateTimeUtils
.
createGregorianCalendar
().
get
(
Calendar
.
MONTH
));
resultCalendar
.
clear
(
Calendar
.
DAY_OF_YEAR
);
resultCalendar
.
clear
(
Calendar
.
DAY_OF_WEEK
);
resultCalendar
.
clear
(
Calendar
.
DAY_OF_WEEK_IN_MONTH
);
resultCalendar
.
set
(
Calendar
.
DAY_OF_MONTH
,
1
);
resultCalendar
.
set
(
Calendar
.
HOUR
,
0
);
resultCalendar
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
resultCalendar
.
set
(
Calendar
.
MINUTE
,
0
);
resultCalendar
.
set
(
Calendar
.
SECOND
,
0
);
resultCalendar
.
set
(
Calendar
.
MILLISECOND
,
0
);
resultCalendar
.
set
(
Calendar
.
AM_PM
,
Calendar
.
AM
);
this
.
functionName
=
functionName
;
this
.
functionName
=
functionName
;
inputStr
=
input
.
trim
();
inputStr
=
input
.
trim
();
// Keep a copy
// Keep a copy
...
@@ -59,30 +70,65 @@ public class ToDateParser {
...
@@ -59,30 +70,65 @@ public class ToDateParser {
unmodifiedFormatStr
=
formatStr
;
unmodifiedFormatStr
=
formatStr
;
}
}
private
static
ToDateParser
get
DateParser
(
String
input
,
String
format
)
{
private
static
ToDateParser
get
TimestampParser
(
ConfigParam
param
,
String
input
,
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_DATE
,
input
,
format
);
ToDateParser
result
=
new
ToDateParser
(
param
,
input
,
format
);
parse
(
result
);
parse
(
result
);
return
result
;
return
result
;
}
}
private
static
ToDateParser
getTimestampParser
(
String
input
,
String
format
)
{
private
ValueTimestamp
getResultingValue
()
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_TIMESTAMP
,
input
,
format
);
long
dateValue
;
parse
(
result
);
if
(
absoluteDayValid
)
{
return
result
;
dateValue
=
DateTimeUtils
.
dateValueFromAbsoluteDay
(
absoluteDay
);
}
else
{
int
year
=
this
.
year
;
if
(
year
==
0
)
{
year
=
getCurrentYear
();
}
}
if
(
bc
)
{
private
Timestamp
getResultingTimestamp
()
{
year
=
1
-
year
;
Calendar
cal
=
(
Calendar
)
getResultCalendar
().
clone
();
}
int
nanosToSet
=
nanos
==
null
?
if
(
doyValid
)
{
cal
.
get
(
Calendar
.
MILLISECOND
)
*
1000000
:
nanos
.
intValue
();
dateValue
=
DateTimeUtils
.
dateValueFromAbsoluteDay
(
cal
.
set
(
Calendar
.
MILLISECOND
,
0
);
DateTimeUtils
.
absoluteDayFromDateValue
(
DateTimeUtils
.
dateValue
(
year
,
1
,
1
))
Timestamp
ts
=
new
Timestamp
(
cal
.
getTimeInMillis
());
+
dayOfYear
-
1
);
ts
.
setNanos
(
nanosToSet
);
}
else
{
return
ts
;
int
month
=
this
.
month
;
if
(
month
==
0
)
{
// Oracle uses current month as default
month
=
getCurrentMonth
();
}
dateValue
=
DateTimeUtils
.
dateValue
(
year
,
month
,
day
);
}
}
int
hour
;
if
(
hour12Valid
)
{
hour
=
hour12
%
12
;
if
(!
isAM
)
{
hour
+=
12
;
}
}
else
{
hour
=
this
.
hour
;
}
long
timeNanos
=
((((
hour
*
60
)
+
minute
)
*
60
)
+
second
)
*
1_000_000_000L
+
nanos
;
return
ValueTimestamp
.
fromDateValueAndNanos
(
dateValue
,
timeNanos
);
}
}
Calendar
getResultCalendar
()
{
private
ValueTimestampTimeZone
getResultingValueWithTimeZone
()
{
return
resultCalendar
;
ValueTimestamp
ts
=
getResultingValue
();
long
dateValue
=
ts
.
getDateValue
();
short
offset
;
if
(
timeZoneHMValid
)
{
offset
=
(
short
)
(
timeZoneHour
*
60
+
((
timeZoneHour
>=
0
)
?
timeZoneMinute
:
-
timeZoneMinute
));
}
else
{
TimeZone
timeZone
=
this
.
timeZone
;
if
(
timeZone
==
null
)
{
timeZone
=
TimeZone
.
getDefault
();
}
long
millis
=
DateTimeUtils
.
convertDateTimeValueToMillis
(
timeZone
,
dateValue
,
nanos
/
1000000
);
offset
=
(
short
)
(
timeZone
.
getOffset
(
millis
)
/
1000
/
60
);
}
return
ValueTimestampTimeZone
.
fromDateValueAndNanos
(
dateValue
,
ts
.
getTimeNanos
(),
offset
);
}
}
String
getInputStr
()
{
String
getInputStr
()
{
...
@@ -97,10 +143,111 @@ public class ToDateParser {
...
@@ -97,10 +143,111 @@ public class ToDateParser {
return
functionName
.
name
();
return
functionName
.
name
();
}
}
private
void
queryCurrentYearAndMonth
()
{
GregorianCalendar
gc
=
DateTimeUtils
.
getCalendar
();
gc
.
setTimeInMillis
(
System
.
currentTimeMillis
());
currentYear
=
gc
.
get
(
Calendar
.
YEAR
);
currentMonth
=
gc
.
get
(
Calendar
.
MONTH
)
+
1
;
}
int
getCurrentYear
()
{
if
(
currentYear
==
0
)
{
queryCurrentYearAndMonth
();
}
return
currentYear
;
}
int
getCurrentMonth
()
{
if
(
currentMonth
==
0
)
{
queryCurrentYearAndMonth
();
}
return
currentMonth
;
}
void
setAbsoluteDay
(
int
absoluteDay
)
{
doyValid
=
false
;
absoluteDayValid
=
true
;
this
.
absoluteDay
=
absoluteDay
;
}
void
setBC
(
boolean
bc
)
{
doyValid
=
false
;
absoluteDayValid
=
false
;
this
.
bc
=
bc
;
}
void
setYear
(
int
year
)
{
doyValid
=
false
;
absoluteDayValid
=
false
;
this
.
year
=
year
;
}
void
setMonth
(
int
month
)
{
doyValid
=
false
;
absoluteDayValid
=
false
;
this
.
month
=
month
;
if
(
year
==
0
)
{
year
=
1970
;
}
}
void
setDay
(
int
day
)
{
doyValid
=
false
;
absoluteDayValid
=
false
;
this
.
day
=
day
;
if
(
year
==
0
)
{
year
=
1970
;
}
}
void
setDayOfYear
(
int
dayOfYear
)
{
doyValid
=
true
;
absoluteDayValid
=
false
;
this
.
dayOfYear
=
dayOfYear
;
}
void
setHour
(
int
hour
)
{
hour12Valid
=
false
;
this
.
hour
=
hour
;
}
void
setMinute
(
int
minute
)
{
this
.
minute
=
minute
;
}
void
setSecord
(
int
second
)
{
this
.
second
=
second
;
}
void
setNanos
(
int
nanos
)
{
void
setNanos
(
int
nanos
)
{
this
.
nanos
=
nanos
;
this
.
nanos
=
nanos
;
}
}
void
setAmPm
(
boolean
isAM
)
{
hour12Valid
=
true
;
this
.
isAM
=
isAM
;
}
void
setHour12
(
int
hour12
)
{
hour12Valid
=
true
;
this
.
hour12
=
hour12
;
}
void
setTimeZone
(
TimeZone
timeZone
)
{
timeZoneHMValid
=
false
;
this
.
timeZone
=
timeZone
;
}
void
setTimeZoneHour
(
int
timeZoneHour
)
{
timeZoneHMValid
=
true
;
this
.
timeZoneHour
=
timeZoneHour
;
}
void
setTimeZoneMinute
(
int
timeZoneMinute
)
{
timeZoneHMValid
=
true
;
this
.
timeZoneMinute
=
timeZoneMinute
;
}
private
boolean
hasToParseData
()
{
private
boolean
hasToParseData
()
{
return
formatStr
.
length
()
>
0
;
return
formatStr
.
length
()
>
0
;
}
}
...
@@ -180,9 +327,21 @@ public class ToDateParser {
...
@@ -180,9 +327,21 @@ public class ToDateParser {
* @param format the format
* @param format the format
* @return the timestamp
* @return the timestamp
*/
*/
public
static
Timestamp
toTimestamp
(
String
input
,
String
format
)
{
public
static
ValueTimestamp
toTimestamp
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getTimestampParser
(
input
,
format
);
ToDateParser
parser
=
getTimestampParser
(
ConfigParam
.
TO_TIMESTAMP
,
input
,
format
);
return
parser
.
getResultingTimestamp
();
return
parser
.
getResultingValue
();
}
/**
* Parse a string as a timestamp with the given format.
*
* @param input the input
* @param format the format
* @return the timestamp
*/
public
static
ValueTimestampTimeZone
toTimestampTz
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getTimestampParser
(
ConfigParam
.
TO_TIMESTAMP_TZ
,
input
,
format
);
return
parser
.
getResultingValueWithTimeZone
();
}
}
/**
/**
...
@@ -192,9 +351,9 @@ public class ToDateParser {
...
@@ -192,9 +351,9 @@ public class ToDateParser {
* @param format the format
* @param format the format
* @return the date as a timestamp
* @return the date as a timestamp
*/
*/
public
static
Timestamp
toDate
(
String
input
,
String
format
)
{
public
static
Value
Timestamp
toDate
(
String
input
,
String
format
)
{
ToDateParser
parser
=
get
DateParser
(
input
,
format
);
ToDateParser
parser
=
get
TimestampParser
(
ConfigParam
.
TO_DATE
,
input
,
format
);
return
parser
.
getResulting
Timestamp
();
return
parser
.
getResulting
Value
();
}
}
/**
/**
...
@@ -202,7 +361,8 @@ public class ToDateParser {
...
@@ -202,7 +361,8 @@ public class ToDateParser {
*/
*/
private
enum
ConfigParam
{
private
enum
ConfigParam
{
TO_DATE
(
"DD MON YYYY"
),
TO_DATE
(
"DD MON YYYY"
),
TO_TIMESTAMP
(
"DD MON YYYY HH:MI:SS"
);
TO_TIMESTAMP
(
"DD MON YYYY HH:MI:SS"
),
TO_TIMESTAMP_TZ
(
"DD MON YYYY HH:MI:SS TZR"
);
private
final
String
defaultFormatStr
;
private
final
String
defaultFormatStr
;
ConfigParam
(
String
defaultFormatStr
)
{
ConfigParam
(
String
defaultFormatStr
)
{
...
...
h2/src/main/org/h2/util/ToDateTokenizer.java
浏览文件 @
9e5d9644
...
@@ -6,17 +6,12 @@
...
@@ -6,17 +6,12 @@
package
org
.
h2
.
util
;
package
org
.
h2
.
util
;
import
static
java
.
lang
.
String
.
format
;
import
static
java
.
lang
.
String
.
format
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.Calendar
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.Date
;
import
java.util.GregorianCalendar
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Locale
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.TimeZone
;
import
java.util.TimeZone
;
import
java.util.regex.Matcher
;
import
java.util.regex.Matcher
;
...
@@ -144,38 +139,36 @@ class ToDateTokenizer {
...
@@ -144,38 +139,36 @@ class ToDateTokenizer {
* Parslet responsible for parsing year parameter
* Parslet responsible for parsing year parameter
*/
*/
static
class
YearParslet
implements
ToDateParslet
{
static
class
YearParslet
implements
ToDateParslet
{
@Override
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
switch
(
formatTokenEnum
)
{
case
SYYYY:
case
SYYYY:
case
YYYY:
case
YYYY:
case
IYYY:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_FOUR_DIGITS
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_FOUR_DIGITS
,
params
,
formatTokenEnum
);
params
,
formatTokenEnum
);
// only necessary for Java1.6
if
(
inputFragmentStr
.
startsWith
(
"+"
))
{
inputFragmentStr
=
inputFragmentStr
.
substring
(
1
);
}
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
// Gregorian calendar does not have a year 0.
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
if
(
dateNr
==
0
)
{
if
(
dateNr
==
0
)
{
throwException
(
params
,
"Year may not be zero"
);
throwException
(
params
,
"Year may not be zero"
);
}
}
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
params
.
setYear
(
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
break
;
case
YYY:
case
YYY:
case
IYY:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_THREE_DIGITS
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_THREE_DIGITS
,
params
,
formatTokenEnum
);
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
if
(
dateNr
>
999
)
{
throwException
(
params
,
"Year may have only three digits with specified format"
);
}
dateNr
+=
(
params
.
getCurrentYear
()
/
1_000
)
*
1_000
;
// Gregorian calendar does not have a year 0.
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
params
.
setYear
(
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
break
;
case
RRRR:
case
RRRR:
inputFragmentStr
=
matchStringOrThrow
(
inputFragmentStr
=
matchStringOrThrow
(
...
@@ -191,15 +184,14 @@ class ToDateTokenizer {
...
@@ -191,15 +184,14 @@ class ToDateTokenizer {
if
(
dateNr
==
0
)
{
if
(
dateNr
==
0
)
{
throwException
(
params
,
"Year may not be zero"
);
throwException
(
params
,
"Year may not be zero"
);
}
}
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
params
.
setYear
(
dateNr
);
break
;
break
;
case
RR:
case
RR:
Calendar
calendar
=
DateTimeUtils
.
createGregorianCalendar
();
int
cc
=
params
.
getCurrentYear
()
/
100
;
int
cc
=
calendar
.
get
(
Calendar
.
YEAR
)
/
100
;
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
)
+
cc
*
100
;
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
)
+
cc
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
params
.
setYear
(
dateNr
);
break
;
break
;
case
EE
/* NOT supported yet */
:
case
EE
/* NOT supported yet */
:
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
...
@@ -210,38 +202,40 @@ class ToDateTokenizer {
...
@@ -210,38 +202,40 @@ class ToDateTokenizer {
formatTokenEnum
.
name
()));
formatTokenEnum
.
name
()));
break
;
break
;
case
YY:
case
YY:
case
IY:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
if
(
dateNr
>
99
)
{
throwException
(
params
,
"Year may have only two digits with specified format"
);
}
dateNr
+=
(
params
.
getCurrentYear
()
/
100
)
*
100
;
// Gregorian calendar does not have a year 0.
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
params
.
setYear
(
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
break
;
case
SCC:
case
SCC:
case
CC:
case
CC:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
)
*
100
;
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
)
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
params
.
setYear
(
dateNr
);
break
;
break
;
case
Y:
case
Y:
case
I:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
if
(
dateNr
>
9
)
{
throwException
(
params
,
"Year may have only two digits with specified format"
);
}
dateNr
+=
(
params
.
getCurrentYear
()
/
10
)
*
10
;
// Gregorian calendar does not have a year 0.
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
params
.
setYear
(
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
break
;
case
BC_AD:
case
BC_AD:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_BC_AD
,
params
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_BC_AD
,
params
,
formatTokenEnum
);
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
))
{
params
.
setBC
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
));
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
BC
);
}
else
{
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
AD
);
}
break
;
break
;
default
:
default
:
throw
new
IllegalArgumentException
(
format
(
throw
new
IllegalArgumentException
(
format
(
...
@@ -262,29 +256,26 @@ class ToDateTokenizer {
...
@@ -262,29 +256,26 @@ class ToDateTokenizer {
@Override
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
s
=
params
.
getInputStr
();
String
s
=
params
.
getInputStr
();
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
switch
(
formatTokenEnum
)
{
case
MONTH:
case
MONTH:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
inputFragmentStr
=
setByName
(
params
,
ToChar
.
MONTHS
);
Calendar
.
LONG
);
break
;
break
;
case
Q
/* NOT supported yet */
:
case
Q
/* NOT supported yet */
:
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
formatTokenEnum
.
name
()));
break
;
break
;
case
MON:
case
MON:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
inputFragmentStr
=
setByName
(
params
,
ToChar
.
SHORT_MONTHS
);
Calendar
.
SHORT
);
break
;
break
;
case
MM:
case
MM:
// Note: In Calendar Month go from 0 - 11
// Note: In Calendar Month go from 0 - 11
inputFragmentStr
=
matchStringOrThrow
(
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MONTH
,
dateNr
-
1
);
params
.
setMonth
(
dateNr
);
break
;
break
;
case
RM:
case
RM:
dateNr
=
0
;
dateNr
=
0
;
...
@@ -293,7 +284,7 @@ class ToDateTokenizer {
...
@@ -293,7 +284,7 @@ class ToDateTokenizer {
int
len
=
monthName
.
length
();
int
len
=
monthName
.
length
();
if
(
s
.
length
()
>=
len
&&
monthName
if
(
s
.
length
()
>=
len
&&
monthName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
result
.
set
(
Calendar
.
MONTH
,
dateNr
);
params
.
setMonth
(
dateNr
+
1
);
inputFragmentStr
=
monthName
;
inputFragmentStr
=
monthName
;
break
;
break
;
}
}
...
@@ -322,7 +313,6 @@ class ToDateTokenizer {
...
@@ -322,7 +313,6 @@ class ToDateTokenizer {
@Override
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
switch
(
formatTokenEnum
)
{
...
@@ -330,40 +320,31 @@ class ToDateTokenizer {
...
@@ -330,40 +320,31 @@ class ToDateTokenizer {
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_YEAR
,
dateNr
);
params
.
setDayOfYear
(
dateNr
);
break
;
break
;
case
DD:
case
DD:
inputFragmentStr
=
matchStringOrThrow
(
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
params
.
setDay
(
dateNr
);
break
;
break
;
case
D:
case
D:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
params
.
setDay
(
dateNr
);
break
;
break
;
case
DAY:
case
DAY:
inputFragmentStr
=
setByName
(
result
,
params
,
inputFragmentStr
=
setByName
(
params
,
ToChar
.
WEEKDAYS
);
Calendar
.
DAY_OF_WEEK
,
Calendar
.
LONG
);
break
;
break
;
case
DY:
case
DY:
inputFragmentStr
=
setByName
(
result
,
params
,
inputFragmentStr
=
setByName
(
params
,
ToChar
.
SHORT_WEEKDAYS
);
Calendar
.
DAY_OF_WEEK
,
Calendar
.
SHORT
);
break
;
break
;
case
J:
case
J:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
formatTokenEnum
);
try
{
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
Date
date
=
new
SimpleDateFormat
(
"Myydd"
)
params
.
setAbsoluteDay
(
dateNr
+
ToChar
.
JULIAN_EPOCH
);
.
parse
(
inputFragmentStr
);
result
.
setTime
(
date
);
}
catch
(
ParseException
e
)
{
throwException
(
params
,
format
(
"Failed to parse Julian date: %s"
,
inputFragmentStr
));
}
break
;
break
;
default
:
default
:
throw
new
IllegalArgumentException
(
format
(
throw
new
IllegalArgumentException
(
format
(
...
@@ -382,7 +363,6 @@ class ToDateTokenizer {
...
@@ -382,7 +363,6 @@ class ToDateTokenizer {
@Override
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
switch
(
formatTokenEnum
)
{
...
@@ -390,97 +370,76 @@ class ToDateTokenizer {
...
@@ -390,97 +370,76 @@ class ToDateTokenizer {
inputFragmentStr
=
matchStringOrThrow
(
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
dateNr
);
params
.
setHour
(
dateNr
);
break
;
break
;
case
HH12:
case
HH12:
case
HH:
case
HH:
inputFragmentStr
=
matchStringOrThrow
(
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR
,
dateNr
);
params
.
setHour12
(
dateNr
);
break
;
break
;
case
MI:
case
MI:
inputFragmentStr
=
matchStringOrThrow
(
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MINUTE
,
dateNr
);
params
.
setMinute
(
dateNr
);
break
;
break
;
case
SS:
case
SS:
inputFragmentStr
=
matchStringOrThrow
(
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
params
.
setSecord
(
dateNr
);
break
;
break
;
case
SSSSS:
case
SSSSS:
{
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
int
second
=
dateNr
%
60
;
result
.
set
(
Calendar
.
MINUTE
,
0
);
dateNr
/=
60
;
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
int
minute
=
dateNr
%
60
;
dateNr
/=
60
;
int
hour
=
dateNr
%
24
;
params
.
setHour
(
hour
);
params
.
setMinute
(
minute
);
params
.
setSecord
(
second
);
break
;
break
;
}
case
FF:
case
FF:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
formatTokenEnum
);
String
paddedRightNrStr
=
format
(
"%-9s"
,
inputFragmentStr
)
String
paddedRightNrStr
=
format
(
"%-9s"
,
inputFragmentStr
)
.
replace
(
' '
,
'0'
);
.
replace
(
' '
,
'0'
);
paddedRightNrStr
=
paddedRightNrStr
.
substring
(
0
,
9
);
paddedRightNrStr
=
paddedRightNrStr
.
substring
(
0
,
9
);
Double
nineDigits
=
Double
.
parseDouble
(
paddedRightNrStr
);
double
nineDigits
=
Double
.
parseDouble
(
paddedRightNrStr
);
params
.
setNanos
(
nineDigits
.
intValue
());
params
.
setNanos
((
int
)
nineDigits
);
dateNr
=
(
int
)
Math
.
round
(
nineDigits
/
1000000.0
);
result
.
set
(
Calendar
.
MILLISECOND
,
dateNr
);
break
;
break
;
case
AM_PM:
case
AM_PM:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_AM_PM
,
params
,
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_AM_PM
,
params
,
formatTokenEnum
);
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"A"
))
{
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"A"
))
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
AM
);
params
.
setAmPm
(
true
);
}
else
{
}
else
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
PM
);
params
.
setAmPm
(
false
);
}
}
break
;
break
;
case
TZH:
case
TZH:
inputFragmentStr
=
matchStringOrThrow
(
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
TimeZone
tz
=
result
.
getTimeZone
();
params
.
setTimeZoneHour
(
dateNr
);
int
offsetMillis
=
tz
.
getRawOffset
();
// purge min and sec
offsetMillis
=
(
offsetMillis
/
MILLIS_IN_HOUR
)
*
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
offsetMillis
+
dateNr
);
result
.
setTimeZone
(
tz
);
break
;
break
;
case
TZM:
case
TZM:
inputFragmentStr
=
matchStringOrThrow
(
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
tz
=
result
.
getTimeZone
();
params
.
setTimeZoneMinute
(
dateNr
);
offsetMillis
=
tz
.
getRawOffset
();
// purge hour
offsetMillis
=
offsetMillis
%
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
dateNr
*
MILLIS_IN_HOUR
+
offsetMillis
);
result
.
setTimeZone
(
tz
);
break
;
break
;
case
TZR:
case
TZR:
// Example: US/Pacific
String
s
=
params
.
getInputStr
();
tz
=
result
.
getTimeZone
();
for
(
String
tzName
:
TimeZone
.
getAvailableIDs
())
{
int
length
=
tzName
.
length
();
if
(
s
.
length
()
>=
length
&&
tzName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
length
)))
{
tz
.
setID
(
tzName
);
result
.
setTimeZone
(
tz
);
inputFragmentStr
=
tzName
;
break
;
}
}
break
;
case
TZD:
case
TZD:
// Must correspond with TZR region. Example: PST (for US/Pacific
String
tzName
=
params
.
getInputStr
();
// standard time)
params
.
setTimeZone
(
TimeZone
.
getTimeZone
(
tzName
));
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
inputFragmentStr
=
tzName
;
formatTokenEnum
.
name
()));
break
;
break
;
default
:
default
:
throw
new
IllegalArgumentException
(
format
(
throw
new
IllegalArgumentException
(
format
(
...
@@ -535,22 +494,33 @@ class ToDateTokenizer {
...
@@ -535,22 +494,33 @@ class ToDateTokenizer {
/**
/**
* Set the given field in the calendar.
* Set the given field in the calendar.
*
*
* @param c the calendar
* @param params the parameters with the input string
* @param params the parameters with the input string
* @param field the field to set
* @param field the field to set
* @param style the data type
* @return the matched value
* @return the matched value
*/
*/
static
String
setByName
(
Calendar
c
,
ToDateParser
params
,
int
field
,
static
String
setByName
(
ToDateParser
params
,
int
field
)
{
int
style
)
{
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
String
s
=
params
.
getInputStr
();
String
s
=
params
.
getInputStr
();
Map
<
String
,
Integer
>
timeStringMap
=
c
.
getDisplayNames
(
field
,
style
,
String
[]
values
=
ToChar
.
getNames
(
field
);
Locale
.
getDefault
());
for
(
int
i
=
0
;
i
<
values
.
length
;
i
++)
{
for
(
String
dayName
:
timeStringMap
.
keySet
())
{
String
dayName
=
values
[
i
];
if
(
dayName
==
null
)
{
continue
;
}
int
len
=
dayName
.
length
();
int
len
=
dayName
.
length
();
if
(
dayName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
if
(
dayName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
c
.
set
(
field
,
timeStringMap
.
get
(
dayName
));
switch
(
field
)
{
case
ToChar
.
MONTHS
:
case
ToChar
.
SHORT_MONTHS
:
params
.
setMonth
(
i
+
1
);
break
;
case
ToChar
.
WEEKDAYS
:
case
ToChar
.
SHORT_WEEKDAYS
:
// TODO
break
;
default
:
throw
new
IllegalArgumentException
();
}
inputFragmentStr
=
dayName
;
inputFragmentStr
=
dayName
;
break
;
break
;
}
}
...
@@ -558,7 +528,7 @@ class ToDateTokenizer {
...
@@ -558,7 +528,7 @@ class ToDateTokenizer {
if
(
inputFragmentStr
==
null
||
inputFragmentStr
.
isEmpty
())
{
if
(
inputFragmentStr
==
null
||
inputFragmentStr
.
isEmpty
())
{
throwException
(
params
,
format
(
throwException
(
params
,
format
(
"Tried to parse one of '%s' but failed (may be an internal error?)"
,
"Tried to parse one of '%s' but failed (may be an internal error?)"
,
timeStringMap
.
keySet
(
)));
Arrays
.
toString
(
values
)));
}
}
return
inputFragmentStr
;
return
inputFragmentStr
;
}
}
...
@@ -583,9 +553,10 @@ class ToDateTokenizer {
...
@@ -583,9 +553,10 @@ class ToDateTokenizer {
YYYY
(
PARSLET_YEAR
),
YYYY
(
PARSLET_YEAR
),
// 4-digit year with sign (- = B.C.)
// 4-digit year with sign (- = B.C.)
SYYYY
(
PARSLET_YEAR
),
SYYYY
(
PARSLET_YEAR
),
// 4-digit year based on the ISO standard (?)
// 3-digit year
IYYY
(
PARSLET_YEAR
),
YYY
(
PARSLET_YEAR
),
IYY
(
PARSLET_YEAR
),
YY
(
YYY
(
PARSLET_YEAR
),
PARSLET_YEAR
),
IY
(
PARSLET_YEAR
),
// 2-digit year
YY
(
PARSLET_YEAR
),
// Two-digit century with with sign (- = B.C.)
// Two-digit century with with sign (- = B.C.)
SCC
(
PARSLET_YEAR
),
SCC
(
PARSLET_YEAR
),
// Two-digit century.
// Two-digit century.
...
@@ -638,7 +609,7 @@ class ToDateTokenizer {
...
@@ -638,7 +609,7 @@ class ToDateTokenizer {
// NOT supported yet -
// NOT supported yet -
// Abbreviated era name (Japanese Imperial,
// Abbreviated era name (Japanese Imperial,
// ROC Official, and Thai Buddha calendars).
// ROC Official, and Thai Buddha calendars).
E
(
PARSLET_YEAR
),
Y
(
PARSLET_YEAR
),
I
(
PARSLET_YEAR
),
E
(
PARSLET_YEAR
),
Y
(
PARSLET_YEAR
),
// Quarter of year (1, 2, 3, 4; JAN-MAR = 1).
// Quarter of year (1, 2, 3, 4; JAN-MAR = 1).
Q
(
PARSLET_MONTH
),
Q
(
PARSLET_MONTH
),
// Day of week (1-7).
// Day of week (1-7).
...
...
h2/src/main/org/h2/value/Transfer.java
浏览文件 @
9e5d9644
...
@@ -14,7 +14,6 @@ import java.io.Reader;
...
@@ -14,7 +14,6 @@ import java.io.Reader;
import
java.math.BigDecimal
;
import
java.math.BigDecimal
;
import
java.net.InetAddress
;
import
java.net.InetAddress
;
import
java.net.Socket
;
import
java.net.Socket
;
import
java.nio.charset.StandardCharsets
;
import
java.sql.ResultSet
;
import
java.sql.ResultSet
;
import
java.sql.ResultSetMetaData
;
import
java.sql.ResultSetMetaData
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
...
@@ -463,10 +462,6 @@ public class Transfer {
...
@@ -463,10 +462,6 @@ public class Transfer {
throw
DbException
.
get
(
throw
DbException
.
get
(
ErrorCode
.
CONNECTION_BROKEN_1
,
"length="
+
length
);
ErrorCode
.
CONNECTION_BROKEN_1
,
"length="
+
length
);
}
}
if
(
length
>
Integer
.
MAX_VALUE
)
{
throw
DbException
.
get
(
ErrorCode
.
CONNECTION_BROKEN_1
,
"length="
+
length
);
}
writeLong
(
length
);
writeLong
(
length
);
Reader
reader
=
v
.
getReader
();
Reader
reader
=
v
.
getReader
();
Data
.
copyString
(
reader
,
out
);
Data
.
copyString
(
reader
,
out
);
...
@@ -652,21 +647,10 @@ public class Transfer {
...
@@ -652,21 +647,10 @@ public class Transfer {
return
ValueLobDb
.
create
(
return
ValueLobDb
.
create
(
Value
.
CLOB
,
session
.
getDataHandler
(),
tableId
,
id
,
hmac
,
precision
);
Value
.
CLOB
,
session
.
getDataHandler
(),
tableId
,
id
,
hmac
,
precision
);
}
}
if
(
length
<
0
||
length
>
Integer
.
MAX_VALUE
)
{
if
(
length
<
0
)
{
throw
DbException
.
get
(
throw
DbException
.
get
(
ErrorCode
.
CONNECTION_BROKEN_1
,
"length="
+
length
);
ErrorCode
.
CONNECTION_BROKEN_1
,
"length="
+
length
);
}
}
DataReader
reader
=
new
DataReader
(
in
);
int
len
=
(
int
)
length
;
char
[]
buff
=
new
char
[
len
];
IOUtils
.
readFully
(
reader
,
buff
,
len
);
int
magic
=
readInt
();
if
(
magic
!=
LOB_MAGIC
)
{
throw
DbException
.
get
(
ErrorCode
.
CONNECTION_BROKEN_1
,
"magic="
+
magic
);
}
byte
[]
small
=
new
String
(
buff
).
getBytes
(
StandardCharsets
.
UTF_8
);
return
ValueLobDb
.
createSmallLob
(
Value
.
CLOB
,
small
,
length
);
}
}
Value
v
=
session
.
getDataHandler
().
getLobStorage
().
Value
v
=
session
.
getDataHandler
().
getLobStorage
().
createClob
(
new
DataReader
(
in
),
length
);
createClob
(
new
DataReader
(
in
),
length
);
...
...
h2/src/main/org/h2/value/ValueLobDb.java
浏览文件 @
9e5d9644
...
@@ -26,6 +26,7 @@ import org.h2.store.FileStoreInputStream;
...
@@ -26,6 +26,7 @@ import org.h2.store.FileStoreInputStream;
import
org.h2.store.FileStoreOutputStream
;
import
org.h2.store.FileStoreOutputStream
;
import
org.h2.store.LobStorageFrontend
;
import
org.h2.store.LobStorageFrontend
;
import
org.h2.store.LobStorageInterface
;
import
org.h2.store.LobStorageInterface
;
import
org.h2.store.RangeReader
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.MathUtils
;
import
org.h2.util.MathUtils
;
...
@@ -544,6 +545,15 @@ public class ValueLobDb extends Value implements Value.ValueClob,
...
@@ -544,6 +545,15 @@ public class ValueLobDb extends Value implements Value.ValueClob,
*/
*/
public
static
ValueLobDb
createTempClob
(
Reader
in
,
long
length
,
public
static
ValueLobDb
createTempClob
(
Reader
in
,
long
length
,
DataHandler
handler
)
{
DataHandler
handler
)
{
if
(
length
>=
0
)
{
// Otherwise BufferedReader may try to read more data than needed and that
// blocks the network level
try
{
in
=
new
RangeReader
(
in
,
0
,
length
);
}
catch
(
IOException
e
)
{
throw
DbException
.
convert
(
e
);
}
}
BufferedReader
reader
;
BufferedReader
reader
;
if
(
in
instanceof
BufferedReader
)
{
if
(
in
instanceof
BufferedReader
)
{
reader
=
(
BufferedReader
)
in
;
reader
=
(
BufferedReader
)
in
;
...
...
h2/src/main/org/h2/value/ValueTimestampTimeZone.java
浏览文件 @
9e5d9644
...
@@ -9,8 +9,6 @@ import java.math.BigDecimal;
...
@@ -9,8 +9,6 @@ import java.math.BigDecimal;
import
java.sql.PreparedStatement
;
import
java.sql.PreparedStatement
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
java.util.SimpleTimeZone
;
import
java.util.TimeZone
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.TimestampWithTimeZone
;
import
org.h2.api.TimestampWithTimeZone
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
...
@@ -148,19 +146,6 @@ public class ValueTimestampTimeZone extends Value {
...
@@ -148,19 +146,6 @@ public class ValueTimestampTimeZone extends Value {
return
timeZoneOffsetMins
;
return
timeZoneOffsetMins
;
}
}
/**
* Returns compatible offset-based time zone with no DST schedule.
*
* @return compatible offset-based time zone
*/
public
TimeZone
getTimeZone
()
{
int
offset
=
timeZoneOffsetMins
;
if
(
offset
==
0
)
{
return
DateTimeUtils
.
UTC
;
}
return
new
SimpleTimeZone
(
offset
*
60000
,
Integer
.
toString
(
offset
));
}
@Override
@Override
public
Timestamp
getTimestamp
()
{
public
Timestamp
getTimestamp
()
{
throw
new
UnsupportedOperationException
(
"unimplemented"
);
throw
new
UnsupportedOperationException
(
"unimplemented"
);
...
@@ -219,34 +204,31 @@ public class ValueTimestampTimeZone extends Value {
...
@@ -219,34 +204,31 @@ public class ValueTimestampTimeZone extends Value {
@Override
@Override
protected
int
compareSecure
(
Value
o
,
CompareMode
mode
)
{
protected
int
compareSecure
(
Value
o
,
CompareMode
mode
)
{
ValueTimestampTimeZone
t
=
(
ValueTimestampTimeZone
)
o
;
ValueTimestampTimeZone
t
=
(
ValueTimestampTimeZone
)
o
;
// We are pretending that the dateValue is in UTC because that gives us
// Maximum time zone offset is +/-18 hours so difference in days between local
// a stable sort even if the DST database changes.
// and UTC cannot be more than one day
long
daysA
=
DateTimeUtils
.
absoluteDayFromDateValue
(
dateValue
);
// convert to minutes and add timezone offset
long
timeA
=
timeNanos
-
timeZoneOffsetMins
*
60_000_000_000L
;
long
a
=
DateTimeUtils
.
convertDateValueToMillis
(
if
(
timeA
<
0
)
{
DateTimeUtils
.
UTC
,
dateValue
)
/
timeA
+=
DateTimeUtils
.
NANOS_PER_DAY
;
(
1000L
*
60L
);
daysA
--;
long
ma
=
timeNanos
/
(
1000L
*
1000L
*
1000L
*
60L
);
}
else
if
(
timeA
>=
DateTimeUtils
.
NANOS_PER_DAY
)
{
a
+=
ma
;
timeA
-=
DateTimeUtils
.
NANOS_PER_DAY
;
a
-=
timeZoneOffsetMins
;
daysA
++;
}
// convert to minutes and add timezone offset
long
daysB
=
DateTimeUtils
.
absoluteDayFromDateValue
(
t
.
dateValue
);
long
b
=
DateTimeUtils
.
convertDateValueToMillis
(
long
timeB
=
t
.
timeNanos
-
t
.
timeZoneOffsetMins
*
60_000_000_000L
;
DateTimeUtils
.
UTC
,
t
.
dateValue
)
/
if
(
timeB
<
0
)
{
(
1000L
*
60L
);
timeB
+=
DateTimeUtils
.
NANOS_PER_DAY
;
long
mb
=
t
.
timeNanos
/
(
1000L
*
1000L
*
1000L
*
60L
);
daysB
--;
b
+=
mb
;
}
else
if
(
timeB
>=
DateTimeUtils
.
NANOS_PER_DAY
)
{
b
-=
t
.
timeZoneOffsetMins
;
timeB
-=
DateTimeUtils
.
NANOS_PER_DAY
;
daysB
++;
// compare date
}
int
c
=
Long
.
compare
(
a
,
b
);
int
cmp
=
Long
.
compare
(
daysA
,
daysB
);
if
(
c
!=
0
)
{
if
(
cmp
!=
0
)
{
return
c
;
return
cmp
;
}
}
// compare time
return
Long
.
compare
(
timeA
,
timeB
);
long
na
=
timeNanos
-
(
ma
*
1000L
*
1000L
*
1000L
*
60L
);
long
nb
=
t
.
timeNanos
-
(
mb
*
1000L
*
1000L
*
1000L
*
60L
);
return
Long
.
compare
(
na
,
nb
);
}
}
@Override
@Override
...
...
h2/src/test/org/h2/test/TestBase.java
浏览文件 @
9e5d9644
...
@@ -6,6 +6,7 @@
...
@@ -6,6 +6,7 @@
package
org
.
h2
.
test
;
package
org
.
h2
.
test
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayInputStream
;
import
java.io.File
;
import
java.io.FileWriter
;
import
java.io.FileWriter
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
...
@@ -30,7 +31,9 @@ import java.sql.Types;
...
@@ -30,7 +31,9 @@ import java.sql.Types;
import
java.text.DateFormat
;
import
java.text.DateFormat
;
import
java.text.SimpleDateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.LinkedList
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Objects
;
import
java.util.SimpleTimeZone
;
import
java.util.SimpleTimeZone
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeUnit
;
...
@@ -40,6 +43,7 @@ import org.h2.store.fs.FilePath;
...
@@ -40,6 +43,7 @@ import org.h2.store.fs.FilePath;
import
org.h2.store.fs.FileUtils
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.utils.ProxyCodeGenerator
;
import
org.h2.test.utils.ProxyCodeGenerator
;
import
org.h2.test.utils.ResultVerifier
;
import
org.h2.test.utils.ResultVerifier
;
import
org.h2.test.utils.SelfDestructor
;
import
org.h2.tools.DeleteDbFiles
;
import
org.h2.tools.DeleteDbFiles
;
/**
/**
...
@@ -1444,6 +1448,16 @@ public abstract class TestBase {
...
@@ -1444,6 +1448,16 @@ public abstract class TestBase {
return
System
.
getProperty
(
"java.class.path"
);
return
System
.
getProperty
(
"java.class.path"
);
}
}
/**
* Get the path to a java executable of the current process
*
* @return the path to java
*/
private
String
getJVM
()
{
return
System
.
getProperty
(
"java.home"
)
+
File
.
separatorChar
+
"bin"
+
File
.
separator
+
"java"
;
}
/**
/**
* Use up almost all memory.
* Use up almost all memory.
*
*
...
@@ -1687,4 +1701,46 @@ public abstract class TestBase {
...
@@ -1687,4 +1701,46 @@ public abstract class TestBase {
return
getClass
().
getSimpleName
();
return
getClass
().
getSimpleName
();
}
}
public
ProcessBuilder
buildChild
(
String
name
,
Class
<?
extends
TestBase
>
childClass
,
String
...
jvmArgs
)
{
List
<
String
>
args
=
new
ArrayList
<>(
16
);
args
.
add
(
getJVM
());
Collections
.
addAll
(
args
,
jvmArgs
);
Collections
.
addAll
(
args
,
"-cp"
,
getClassPath
(),
SelfDestructor
.
getPropertyString
(
1
),
childClass
.
getName
(),
"-url"
,
getURL
(
name
,
true
),
"-user"
,
getUser
(),
"-password"
,
getPassword
());
ProcessBuilder
processBuilder
=
new
ProcessBuilder
()
// .redirectError(ProcessBuilder.Redirect.INHERIT)
.
redirectErrorStream
(
true
)
.
redirectOutput
(
ProcessBuilder
.
Redirect
.
INHERIT
)
.
command
(
args
);
return
processBuilder
;
}
public
abstract
static
class
Child
extends
TestBase
{
private
String
url
;
private
String
user
;
private
String
password
;
public
Child
(
String
...
args
)
{
for
(
int
i
=
0
;
i
<
args
.
length
;
i
++)
{
if
(
"-url"
.
equals
(
args
[
i
]))
{
url
=
args
[++
i
];
}
else
if
(
"-user"
.
equals
(
args
[
i
]))
{
user
=
args
[++
i
];
}
else
if
(
"-password"
.
equals
(
args
[
i
]))
{
password
=
args
[++
i
];
}
SelfDestructor
.
startCountdown
(
60
);
}
}
public
Connection
getConnection
()
throws
SQLException
{
return
getConnection
(
url
,
user
,
password
);
}
}
}
}
h2/src/test/org/h2/test/db/TestFunctions.java
浏览文件 @
9e5d9644
...
@@ -34,6 +34,7 @@ import java.util.ArrayList;
...
@@ -34,6 +34,7 @@ import java.util.ArrayList;
import
java.util.Calendar
;
import
java.util.Calendar
;
import
java.util.Currency
;
import
java.util.Currency
;
import
java.util.Date
;
import
java.util.Date
;
import
java.util.GregorianCalendar
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.Locale
;
import
java.util.Locale
;
import
java.util.Properties
;
import
java.util.Properties
;
...
@@ -56,6 +57,8 @@ import org.h2.util.StringUtils;
...
@@ -56,6 +57,8 @@ import org.h2.util.StringUtils;
import
org.h2.util.ToChar.Capitalization
;
import
org.h2.util.ToChar.Capitalization
;
import
org.h2.util.ToDateParser
;
import
org.h2.util.ToDateParser
;
import
org.h2.value.Value
;
import
org.h2.value.Value
;
import
org.h2.value.ValueTimestamp
;
import
org.h2.value.ValueTimestampTimeZone
;
/**
/**
* Tests for user defined functions and aggregates.
* Tests for user defined functions and aggregates.
...
@@ -1296,10 +1299,13 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1296,10 +1299,13 @@ public class TestFunctions extends TestBase implements AggregateFunction {
}
}
private
void
testToDate
()
throws
ParseException
{
private
void
testToDate
()
throws
ParseException
{
final
int
month
=
DateTimeUtils
.
createGregorianCalendar
().
get
(
Calendar
.
MONTH
);
GregorianCalendar
calendar
=
DateTimeUtils
.
createGregorianCalendar
();
int
year
=
calendar
.
get
(
Calendar
.
YEAR
);
Date
date
=
null
;
int
month
=
calendar
.
get
(
Calendar
.
MONTH
)
+
1
;
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1979-11-12"
);
// Default date in Oracle is the first day of the current month
String
defDate
=
year
+
"-"
+
month
+
"-1 "
;
ValueTimestamp
date
=
null
;
date
=
ValueTimestamp
.
parse
(
"1979-11-12"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979-11-12T00:00:00Z"
,
"YYYY-MM-DD\"T\"HH24:MI:SS\"Z\""
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979-11-12T00:00:00Z"
,
"YYYY-MM-DD\"T\"HH24:MI:SS\"Z\""
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979*foo*1112"
,
"YYYY\"*foo*\"MM\"\"DD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979*foo*1112"
,
"YYYY\"*foo*\"MM\"\"DD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979-11-12"
,
"YYYY-MM-DD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979-11-12"
,
"YYYY-MM-DD"
));
...
@@ -1309,126 +1315,124 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1309,126 +1315,124 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979;11;12"
,
"YYYY;MM;DD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979;11;12"
,
"YYYY;MM;DD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979:11:12"
,
"YYYY:MM:DD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979:11:12"
,
"YYYY:MM:DD"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"1979"
);
date
=
ValueTimestamp
.
parse
(
"1979-"
+
month
+
"-01"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979"
,
"YYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979"
,
"YYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979 AD"
,
"YYYY AD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979 AD"
,
"YYYY AD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979 A.D."
,
"YYYY A.D."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979 A.D."
,
"YYYY A.D."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979 A.D."
,
"YYYY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979 A.D."
,
"YYYY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979"
,
"IYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"+1979"
,
"SYYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"+1979"
,
"SYYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"RRRR"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"RRRR"
));
date
=
new
SimpleDateFormat
(
"yyyy-mm"
).
parse
(
"1970-12"
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"00:12:00"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"12"
,
"MI"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"12"
,
"MI"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM"
).
parse
(
"1970-1
1"
);
date
=
ValueTimestamp
.
parse
(
"1970-11-0
1"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"MM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"MM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"Mm"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"Mm"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"mM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"mM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"mm"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"mm"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"XI"
,
"RM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"XI"
,
"RM"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"9"
)
;
int
y
=
(
year
/
10
)
*
10
+
9
;
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"9"
,
"Y"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"9"
,
"Y"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"9"
,
"I"
));
y
=
(
year
/
100
)
*
100
+
79
;
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"79"
);
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"YY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"YY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"IY"
));
y
=
(
year
/
1_000
)
*
1_000
+
979
;
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"979"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"979"
,
"YYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"979"
,
"YYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"979"
,
"IYY"
));
// Gregorian calendar does not have a year 0.
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date
=
new
SimpleDateFormat
(
"yyy"
).
parse
(
"-99"
);
date
=
ValueTimestamp
.
parse
(
"-99-"
+
month
+
"-01"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"0100 BC"
,
"YYYY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"0100 BC"
,
"YYYY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"0100 B.C."
,
"YYYY B.C."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"0100 B.C."
,
"YYYY B.C."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"100 BC"
,
"YYY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"-0100"
,
"SYYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"-0100"
,
"SYYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"-0100"
,
"YYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"-0100"
,
"YYYY"
));
// Gregorian calendar does not have a year 0.
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date
=
new
SimpleDateFormat
(
"y"
).
parse
(
"0"
);
y
=
-((
year
/
1_000
)
*
1_000
+
99
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"100 BC"
,
"YYY BC"
));
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
y
=
-((
year
/
100
)
*
100
);
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"01 BC"
,
"YY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"01 BC"
,
"YY BC"
));
y
=
-((
year
/
10
)
*
10
);
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1 BC"
,
"Y BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1 BC"
,
"Y BC"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:00"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12 AM"
,
"HH:MI AM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12 AM"
,
"HH:MI AM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12 A.M."
,
"HH:MI A.M."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12 A.M."
,
"HH:MI A.M."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH24:MI"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH24:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:00"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH:MI"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH:MI"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH12:MI"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH12:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:34"
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:34"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34"
,
"HH:MI:SS"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34"
,
"HH:MI:SS"
));
date
=
new
SimpleDateFormat
(
"ss"
).
parse
(
"34"
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"12:00:00"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"12:00:00 PM"
,
"HH12:MI:SS AM"
));
date
=
ValueTimestamp
.
parse
(
defDate
+
"00:00:00"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"12:00:00 AM"
,
"HH12:MI:SS AM"
));
date
=
ValueTimestamp
.
parse
(
defDate
+
"00:00:34"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"34"
,
"SS"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"34"
,
"SS"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss"
).
parse
(
"1970 08:12:34"
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:34"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"29554"
,
"SSSSS"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"29554"
,
"SSSSS"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss SSS"
).
parse
(
"1970 08:12:34 550"
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:34.550"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34 550"
,
"HH:MI:SS FF"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34 550"
,
"HH:MI:SS FF"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34 55"
,
"HH:MI:SS FF2"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34 55"
,
"HH:MI:SS FF2"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"14:04:00"
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"14:04:00"
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"02:04 P.M."
,
"HH:MI p.M."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"02:04 P.M."
,
"HH:MI p.M."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"02:04 PM"
,
"HH:MI PM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"02:04 PM"
,
"HH:MI PM"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-12-12"
);
date
=
ValueTimestamp
.
parse
(
"1970-"
+
month
+
"-12"
);
// does not work in all timezones
assertEquals
(
date
,
ToDateParser
.
toDate
(
"12"
,
"DD"
));
// assertEquals(date, ToDateParser.toDate("12", "DD"));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-11-12"
);
date
=
ValueTimestamp
.
parse
(
year
+
(
calendar
.
isLeapYear
(
year
)
?
"11-11"
:
"-11-12"
)
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"DDD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"DDD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"DdD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"DdD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"dDD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"dDD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"ddd"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"ddd"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
)
.
parse
(
"2013-01-29"
);
date
=
ValueTimestamp
.
parse
(
"2013-01-29"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"
113029
"
,
"J"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"
2456322
"
,
"J"
));
if
(
Locale
.
getDefault
()
==
Locale
.
ENGLISH
)
{
if
(
Locale
.
getDefault
()
.
getLanguage
().
equals
(
"en"
)
)
{
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd'T'HH:mm:ss"
).
parse
(
"9999-12-31T
23:59:59"
);
date
=
ValueTimestamp
.
parse
(
"9999-12-31
23:59:59"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"31-DEC-9999 23:59:59"
,
"DD-MON-YYYY HH24:MI:SS"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"31-DEC-9999 23:59:59"
,
"DD-MON-YYYY HH24:MI:SS"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"31-DEC-9999 23:59:59"
,
"DD-MON-RRRR HH24:MI:SS"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"31-DEC-9999 23:59:59"
,
"DD-MON-RRRR HH24:MI:SS"
));
SimpleDateFormat
ymd
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
);
assertEquals
(
ValueTimestamp
.
parse
(
"0001-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-0001"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"0001-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-0001"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"9999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-9999"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"9999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-9999"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-000"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-000"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-099"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-099"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"0100-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-100"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"0100-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-100"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-00"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-00"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"2049-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-49"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"2049-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-49"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"1950-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-50"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"1950-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-50"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-99"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-99"
,
"DD-MON-RRRR"
));
}
}
}
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-05-10 10:11:12-08:15"
),
ToDateParser
.
toTimestampTz
(
"2000-05-10 10:11:12 -8:15"
,
"YYYY-MM-DD HH24:MI:SS TZH:TZM"
));
private
static
void
setMonth
(
Date
date
,
int
month
)
{
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-05-10 10:11:12-08:15"
),
Calendar
c
=
DateTimeUtils
.
createGregorianCalendar
();
ToDateParser
.
toTimestampTz
(
"2000-05-10 10:11:12 GMT-08:15"
,
"YYYY-MM-DD HH24:MI:SS TZR"
));
c
.
setTime
(
date
);
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-02-10 10:11:12-08"
),
c
.
set
(
Calendar
.
MONTH
,
month
);
ToDateParser
.
toTimestampTz
(
"2000-02-10 10:11:12 US/Pacific"
,
"YYYY-MM-DD HH24:MI:SS TZR"
));
date
.
setTime
(
c
.
getTimeInMillis
());
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-02-10 10:11:12-08"
),
ToDateParser
.
toTimestampTz
(
"2000-02-10 10:11:12 PST"
,
"YYYY-MM-DD HH24:MI:SS TZD"
));
}
}
private
void
testToCharFromDateTime
()
throws
SQLException
{
private
void
testToCharFromDateTime
()
throws
SQLException
{
...
@@ -1453,7 +1457,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1453,7 +1457,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertResult
(
"-100-01-15 14:04:02.12"
,
stat
,
"SELECT X FROM U"
);
assertResult
(
"-100-01-15 14:04:02.12"
,
stat
,
"SELECT X FROM U"
);
String
expected
=
String
.
format
(
"%tb"
,
timestamp1979
).
toUpperCase
();
String
expected
=
String
.
format
(
"%tb"
,
timestamp1979
).
toUpperCase
();
expected
=
stripTrailingPeriod
(
expected
);
expected
=
stripTrailingPeriod
(
expected
);
assertResult
(
"12-"
+
expected
+
"-79 08.12.34.560000 AM"
,
stat
,
assertResult
(
"12-"
+
expected
+
"-79 08.12.34.560000
000
AM"
,
stat
,
"SELECT TO_CHAR(X) FROM T"
);
"SELECT TO_CHAR(X) FROM T"
);
assertResult
(
"- / , . ; : text - /"
,
stat
,
assertResult
(
"- / , . ; : text - /"
,
stat
,
"SELECT TO_CHAR(X, '- / , . ; : \"text\" - /') FROM T"
);
"SELECT TO_CHAR(X, '- / , . ; : \"text\" - /') FROM T"
);
...
@@ -1486,12 +1490,25 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1486,12 +1490,25 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertResult
(
"0 BC"
,
stat
,
assertResult
(
"0 BC"
,
stat
,
"SELECT TO_CHAR(X, 'Y BC') FROM U"
);
"SELECT TO_CHAR(X, 'Y BC') FROM U"
);
assertResult
(
"1979 A.D."
,
stat
,
"SELECT TO_CHAR(X, 'YYYY B.C.') FROM T"
);
assertResult
(
"1979 A.D."
,
stat
,
"SELECT TO_CHAR(X, 'YYYY B.C.') FROM T"
);
assertResult
(
"2013"
,
stat
,
"SELECT TO_CHAR(DATE '2013-12-30', 'YYYY') FROM DUAL"
);
assertResult
(
"013"
,
stat
,
"SELECT TO_CHAR(DATE '2013-12-30', 'YYY') FROM DUAL"
);
assertResult
(
"13"
,
stat
,
"SELECT TO_CHAR(DATE '2013-12-30', 'YY') FROM DUAL"
);
assertResult
(
"3"
,
stat
,
"SELECT TO_CHAR(DATE '2013-12-30', 'Y') FROM DUAL"
);
// ISO week year
assertResult
(
"2014"
,
stat
,
"SELECT TO_CHAR(DATE '2013-12-30', 'IYYY') FROM DUAL"
);
assertResult
(
"014"
,
stat
,
"SELECT TO_CHAR(DATE '2013-12-30', 'IYY') FROM DUAL"
);
assertResult
(
"14"
,
stat
,
"SELECT TO_CHAR(DATE '2013-12-30', 'IY') FROM DUAL"
);
assertResult
(
"4"
,
stat
,
"SELECT TO_CHAR(DATE '2013-12-30', 'I') FROM DUAL"
);
assertResult
(
"0001"
,
stat
,
"SELECT TO_CHAR(DATE '-0001-01-01', 'IYYY') FROM DUAL"
);
assertResult
(
"0005"
,
stat
,
"SELECT TO_CHAR(DATE '-0004-01-01', 'IYYY') FROM DUAL"
);
assertResult
(
"08:12 AM"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI AM') 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
(
"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
(
"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
(
"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
(
"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
(
"08:12 A.M."
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI P.M.') FROM T"
);
assertResult
(
"12 PM"
,
stat
,
"SELECT TO_CHAR(TIME '12:00:00', 'HH AM')"
);
assertResult
(
"12 AM"
,
stat
,
"SELECT TO_CHAR(TIME '00:00:00', 'HH AM')"
);
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
(
"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"
);
...
@@ -1532,7 +1549,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1532,7 +1549,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertResult
(
Capitalization
.
CAPITALIZE
.
apply
(
expected
),
stat
,
"SELECT TO_CHAR(X, 'Dy') FROM T"
);
assertResult
(
Capitalization
.
CAPITALIZE
.
apply
(
expected
),
stat
,
"SELECT TO_CHAR(X, 'Dy') FROM T"
);
assertResult
(
expected
.
toLowerCase
(),
stat
,
"SELECT TO_CHAR(X, 'dy') FROM T"
);
assertResult
(
expected
.
toLowerCase
(),
stat
,
"SELECT TO_CHAR(X, 'dy') FROM T"
);
assertResult
(
expected
.
toLowerCase
(),
stat
,
"SELECT TO_CHAR(X, 'dY') FROM T"
);
assertResult
(
expected
.
toLowerCase
(),
stat
,
"SELECT TO_CHAR(X, 'dY') FROM T"
);
assertResult
(
"08:12:34.560000"
,
stat
,
assertResult
(
"08:12:34.560000
000
"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF') FROM T"
);
"SELECT TO_CHAR(X, 'HH:MI:SS.FF') FROM T"
);
assertResult
(
"08:12:34.5"
,
stat
,
assertResult
(
"08:12:34.5"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF1') FROM T"
);
"SELECT TO_CHAR(X, 'HH:MI:SS.FF1') FROM T"
);
...
@@ -1552,10 +1569,10 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1552,10 +1569,10 @@ public class TestFunctions extends TestBase implements AggregateFunction {
"SELECT TO_CHAR(X, 'HH:MI:SS.FF8') FROM T"
);
"SELECT TO_CHAR(X, 'HH:MI:SS.FF8') FROM T"
);
assertResult
(
"08:12:34.560000000"
,
stat
,
assertResult
(
"08:12:34.560000000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF9') FROM T"
);
"SELECT TO_CHAR(X, 'HH:MI:SS.FF9') FROM T"
);
assertResult
(
"0
8:12:34.560000000
"
,
stat
,
assertResult
(
"0
12345678
"
,
stat
,
"SELECT TO_CHAR(
X, 'HH:MI:SS.ff9
') FROM T"
);
"SELECT TO_CHAR(
TIME '0:00:00.012345678', 'FF
') FROM T"
);
assertResult
(
"0
8:12:34.56000000
0"
,
stat
,
assertResult
(
"00"
,
stat
,
"SELECT TO_CHAR(
X, 'HH:MI:SS.fF9
') FROM T"
);
"SELECT TO_CHAR(
TIME '0:00:00.000', 'FF2
') FROM T"
);
assertResult
(
"08:12"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI') 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, 'HH12:MI') FROM T"
);
assertResult
(
"08:12"
,
stat
,
"SELECT TO_CHAR(X, 'HH24:MI') FROM T"
);
assertResult
(
"08:12"
,
stat
,
"SELECT TO_CHAR(X, 'HH24:MI') FROM T"
);
...
@@ -1606,6 +1623,10 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1606,6 +1623,10 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertResult
(
expected
,
stat
,
"SELECT TO_CHAR(X, 'TS') FROM T"
);
assertResult
(
expected
,
stat
,
"SELECT TO_CHAR(X, 'TS') FROM T"
);
assertResult
(
tzLongName
,
stat
,
"SELECT TO_CHAR(X, 'TZR') FROM T"
);
assertResult
(
tzLongName
,
stat
,
"SELECT TO_CHAR(X, 'TZR') FROM T"
);
assertResult
(
tzShortName
,
stat
,
"SELECT TO_CHAR(X, 'TZD') FROM T"
);
assertResult
(
tzShortName
,
stat
,
"SELECT TO_CHAR(X, 'TZD') FROM T"
);
assertResult
(
"GMT+10:30"
,
stat
,
"SELECT TO_CHAR(TIMESTAMP WITH TIME ZONE '2010-01-01 0:00:00+10:30', 'TZR')"
);
assertResult
(
"GMT+10:30"
,
stat
,
"SELECT TO_CHAR(TIMESTAMP WITH TIME ZONE '2010-01-01 0:00:00+10:30', 'TZD')"
);
expected
=
String
.
format
(
"%f"
,
1.1
).
substring
(
1
,
2
);
expected
=
String
.
format
(
"%f"
,
1.1
).
substring
(
1
,
2
);
assertResult
(
expected
,
stat
,
"SELECT TO_CHAR(X, 'X') FROM T"
);
assertResult
(
expected
,
stat
,
"SELECT TO_CHAR(X, 'X') FROM T"
);
expected
=
String
.
format
(
"%,d"
,
1979
);
expected
=
String
.
format
(
"%,d"
,
1979
);
...
@@ -1903,7 +1924,8 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1903,7 +1924,8 @@ public class TestFunctions extends TestBase implements AggregateFunction {
final
String
twoDecimals
=
"0"
+
decimalSeparator
+
"00"
;
final
String
twoDecimals
=
"0"
+
decimalSeparator
+
"00"
;
assertResult
(
oneDecimal
,
stat
,
"select to_char(0, 'FM0D099') from dual;"
);
assertResult
(
oneDecimal
,
stat
,
"select to_char(0, 'FM0D099') from dual;"
);
assertResult
(
twoDecimals
,
stat
,
"select to_char(0., 'FM0D009') from dual;"
);
assertResult
(
twoDecimals
,
stat
,
"select to_char(0., 'FM0D009') from dual;"
);
assertResult
(
"0.000000000"
,
stat
,
"select to_char(0.000000000, 'FM0D999999999') from dual;"
);
assertResult
(
"0"
+
decimalSeparator
+
"000000000"
,
stat
,
"select to_char(0.000000000, 'FM0D999999999') from dual;"
);
assertResult
(
"0"
+
decimalSeparator
,
stat
,
"select to_char(0, 'FM0D9') from dual;"
);
assertResult
(
"0"
+
decimalSeparator
,
stat
,
"select to_char(0, 'FM0D9') from dual;"
);
assertResult
(
oneDecimal
,
stat
,
"select to_char(0.0, 'FM0D099') from dual;"
);
assertResult
(
oneDecimal
,
stat
,
"select to_char(0.0, 'FM0D099') from dual;"
);
assertResult
(
twoDecimals
,
stat
,
"select to_char(0.00, 'FM0D009') from dual;"
);
assertResult
(
twoDecimals
,
stat
,
"select to_char(0.00, 'FM0D009') from dual;"
);
...
...
h2/src/test/org/h2/test/db/TestOutOfMemory.java
浏览文件 @
9e5d9644
...
@@ -15,7 +15,6 @@ import java.util.Map;
...
@@ -15,7 +15,6 @@ import java.util.Map;
import
java.util.Random
;
import
java.util.Random
;
import
java.util.concurrent.atomic.AtomicReference
;
import
java.util.concurrent.atomic.AtomicReference
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.message.DbException
;
import
org.h2.mvstore.MVStore
;
import
org.h2.mvstore.MVStore
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePathMem
;
import
org.h2.store.fs.FilePathMem
;
...
@@ -28,6 +27,8 @@ import org.h2.test.TestBase;
...
@@ -28,6 +27,8 @@ import org.h2.test.TestBase;
*/
*/
public
class
TestOutOfMemory
extends
TestBase
{
public
class
TestOutOfMemory
extends
TestBase
{
private
static
final
String
DB_NAME
=
"outOfMemory"
;
/**
/**
* Run just this test.
* Run just this test.
*
*
...
@@ -38,16 +39,18 @@ public class TestOutOfMemory extends TestBase {
...
@@ -38,16 +39,18 @@ public class TestOutOfMemory extends TestBase {
}
}
@Override
@Override
public
void
test
()
throws
SQLException
,
Interrupted
Exception
{
public
void
test
()
throws
Exception
{
if
(
config
.
vmlens
)
{
if
(
config
.
vmlens
)
{
// running out of memory will cause the vmlens agent to stop working
// running out of memory will cause the vmlens agent to stop working
return
;
return
;
}
}
try
{
try
{
if
(!
config
.
travis
)
{
System
.
gc
();
System
.
gc
();
testMVStoreUsingInMemoryFileSystem
();
testMVStoreUsingInMemoryFileSystem
();
System
.
gc
();
System
.
gc
();
testDatabaseUsingInMemoryFileSystem
();
testDatabaseUsingInMemoryFileSystem
();
}
System
.
gc
();
System
.
gc
();
testUpdateWhenNearlyOutOfMemory
();
testUpdateWhenNearlyOutOfMemory
();
}
finally
{
}
finally
{
...
@@ -147,67 +150,92 @@ public class TestOutOfMemory extends TestBase {
...
@@ -147,67 +150,92 @@ public class TestOutOfMemory extends TestBase {
}
}
}
}
private
void
testUpdateWhenNearlyOutOfMemory
()
throws
SQLException
,
Interrupted
Exception
{
private
void
testUpdateWhenNearlyOutOfMemory
()
throws
Exception
{
if
(
config
.
memory
)
{
if
(
config
.
memory
)
{
return
;
return
;
}
}
recoverAfterOOM
();
deleteDb
(
DB_NAME
);
deleteDb
(
"outOfMemory"
);
Connection
conn
=
getConnection
(
"outOfMemory;MAX_OPERATION_MEMORY=1000000"
);
ProcessBuilder
processBuilder
=
buildChild
(
DB_NAME
+
";MAX_OPERATION_MEMORY=1000000"
,
MyChild
.
class
,
"-XX:+UseParallelGC"
,
// "-XX:+UseG1GC",
"-Xmx128m"
);
//*
processBuilder
.
start
().
waitFor
();
/*/
List<String> args = processBuilder.command();
for (Iterator<String> iter = args.iterator(); iter.hasNext(); ) {
String arg = iter.next();
if(arg.equals(MyChild.class.getName())) {
iter.remove();
break;
}
iter.remove();
}
MyChild.main(args.toArray(new String[0]));
//*/
try
(
Connection
conn
=
getConnection
(
DB_NAME
))
{
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"drop all objects"
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT count(*) FROM stuff"
);
stat
.
execute
(
"create table stuff (id int, text varchar as space(100) || id)"
);
assertTrue
(
rs
.
next
());
stat
.
execute
(
"insert into stuff(id) select x from system_range(1, 3000)"
);
assertEquals
(
3000
,
rs
.
getInt
(
1
));
rs
=
stat
.
executeQuery
(
"SELECT * FROM stuff WHERE id = 3000"
);
assertTrue
(
rs
.
next
());
String
text
=
rs
.
getString
(
2
);
assertFalse
(
rs
.
wasNull
());
assertEquals
(
1004
,
text
.
length
());
// TODO: there are intermittent failures here
// where number is about 1000 short of expected value.
// This indicates a real problem - durability failure
// and need to be looked at.
rs
=
stat
.
executeQuery
(
"SELECT sum(length(text)) FROM stuff"
);
assertTrue
(
rs
.
next
());
int
totalSize
=
rs
.
getInt
(
1
);
if
(
3010893
>
totalSize
)
{
TestBase
.
logErrorMessage
(
"Durability failure - expected: 3010893, actual: "
+
totalSize
);
}
}
finally
{
deleteDb
(
DB_NAME
);
}
}
public
static
final
class
MyChild
extends
TestBase
.
Child
{
public
static
void
main
(
String
...
args
)
throws
Exception
{
new
MyChild
(
args
).
init
().
test
();
}
private
MyChild
(
String
...
args
)
{
super
(
args
);
}
@Override
public
void
test
()
{
try
(
Connection
conn
=
getConnection
())
{
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"DROP ALL OBJECTS"
);
stat
.
execute
(
"CREATE TABLE stuff (id INT, text VARCHAR)"
);
stat
.
execute
(
"INSERT INTO stuff(id) SELECT x FROM system_range(1, 3000)"
);
PreparedStatement
prep
=
conn
.
prepareStatement
(
PreparedStatement
prep
=
conn
.
prepareStatement
(
"update stuff set text = text
|| space(1000) || id"
);
"UPDATE stuff SET text = IFNULL(text,'')
|| space(1000) || id"
);
prep
.
execute
();
prep
.
execute
();
stat
.
execute
(
"checkpoint"
);
stat
.
execute
(
"CHECKPOINT"
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT sum(length(text)) FROM stuff"
);
assertTrue
(
rs
.
next
());
assertEquals
(
3010893
,
rs
.
getInt
(
1
));
eatMemory
(
80
);
eatMemory
(
80
);
try
{
try
{
prep
.
execute
();
prep
.
execute
();
fail
();
fail
();
}
catch
(
DbException
ex
)
{
}
catch
(
SQLException
ignore
)
{
freeMemory
();
assertTrue
(
ErrorCode
.
OUT_OF_MEMORY
==
ex
.
getErrorCode
()
||
ErrorCode
.
GENERAL_ERROR_1
==
ex
.
getErrorCode
());
}
catch
(
SQLException
ex
)
{
freeMemory
();
assertTrue
(
ErrorCode
.
OUT_OF_MEMORY
==
ex
.
getErrorCode
()
||
ErrorCode
.
GENERAL_ERROR_1
==
ex
.
getErrorCode
());
}
recoverAfterOOM
();
try
{
conn
.
close
();
fail
();
}
catch
(
DbException
ex
)
{
freeMemory
();
assertEquals
(
ErrorCode
.
DATABASE_IS_CLOSED
,
ex
.
getErrorCode
());
}
catch
(
SQLException
ex
)
{
freeMemory
();
assertEquals
(
ErrorCode
.
DATABASE_IS_CLOSED
,
ex
.
getErrorCode
());
}
freeMemory
();
conn
=
null
;
conn
=
getConnection
(
"outOfMemory"
);
stat
=
conn
.
createStatement
();
ResultSet
rs
=
stat
.
executeQuery
(
"select count(*) from stuff"
);
rs
.
next
();
assertEquals
(
3000
,
rs
.
getInt
(
1
));
}
catch
(
OutOfMemoryError
e
)
{
freeMemory
();
// out of memory not detected
throw
new
AssertionError
(
"Out of memory not detected"
,
e
);
}
finally
{
}
finally
{
freeMemory
();
freeMemory
();
if
(
conn
!=
null
)
{
try
{
conn
.
close
();
}
catch
(
SQLException
e
)
{
// out of memory will / may close the database
assertKnownException
(
e
);
}
}
}
}
}
}
deleteDb
(
"outOfMemory"
);
}
}
}
h2/src/test/org/h2/test/jdbc/TestLobApi.java
浏览文件 @
9e5d9644
...
@@ -119,7 +119,20 @@ public class TestLobApi extends TestBase {
...
@@ -119,7 +119,20 @@ public class TestLobApi extends TestBase {
prep
.
setString
(
1
,
""
);
prep
.
setString
(
1
,
""
);
prep
.
setBytes
(
2
,
new
byte
[
0
]);
prep
.
setBytes
(
2
,
new
byte
[
0
]);
prep
.
execute
();
prep
.
execute
();
Random
r
=
new
Random
(
1
);
Random
r
=
new
Random
(
1
);
char
[]
charsSmall
=
new
char
[
20
];
for
(
int
i
=
0
;
i
<
charsSmall
.
length
;
i
++)
{
charsSmall
[
i
]
=
(
char
)
r
.
nextInt
(
10000
);
}
String
dSmall
=
new
String
(
charsSmall
);
prep
.
setCharacterStream
(
1
,
new
StringReader
(
dSmall
),
-
1
);
byte
[]
bytesSmall
=
new
byte
[
20
];
r
.
nextBytes
(
bytesSmall
);
prep
.
setBinaryStream
(
2
,
new
ByteArrayInputStream
(
bytesSmall
),
-
1
);
prep
.
execute
();
char
[]
chars
=
new
char
[
100000
];
char
[]
chars
=
new
char
[
100000
];
for
(
int
i
=
0
;
i
<
chars
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
chars
.
length
;
i
++)
{
chars
[
i
]
=
(
char
)
r
.
nextInt
(
10000
);
chars
[
i
]
=
(
char
)
r
.
nextInt
(
10000
);
...
@@ -130,6 +143,7 @@ public class TestLobApi extends TestBase {
...
@@ -130,6 +143,7 @@ public class TestLobApi extends TestBase {
r
.
nextBytes
(
bytes
);
r
.
nextBytes
(
bytes
);
prep
.
setBinaryStream
(
2
,
new
ByteArrayInputStream
(
bytes
),
-
1
);
prep
.
setBinaryStream
(
2
,
new
ByteArrayInputStream
(
bytes
),
-
1
);
prep
.
execute
();
prep
.
execute
();
conn
.
setAutoCommit
(
false
);
conn
.
setAutoCommit
(
false
);
ResultSet
rs
=
stat
.
executeQuery
(
"select * from test order by id"
);
ResultSet
rs
=
stat
.
executeQuery
(
"select * from test order by id"
);
rs
.
next
();
rs
.
next
();
...
@@ -138,18 +152,27 @@ public class TestLobApi extends TestBase {
...
@@ -138,18 +152,27 @@ public class TestLobApi extends TestBase {
rs
.
next
();
rs
.
next
();
Clob
c2
=
rs
.
getClob
(
2
);
Clob
c2
=
rs
.
getClob
(
2
);
Blob
b2
=
rs
.
getBlob
(
3
);
Blob
b2
=
rs
.
getBlob
(
3
);
rs
.
next
();
Clob
c3
=
rs
.
getClob
(
2
);
Blob
b3
=
rs
.
getBlob
(
3
);
assertFalse
(
rs
.
next
());
assertFalse
(
rs
.
next
());
// now close
// now close
rs
.
close
();
rs
.
close
();
// but the LOBs must stay open
// but the LOBs must stay open
assertEquals
(
0
,
c1
.
length
());
assertEquals
(
0
,
c1
.
length
());
assertEquals
(
0
,
b1
.
length
());
assertEquals
(
0
,
b1
.
length
());
assertEquals
(
chars
.
length
,
c2
.
length
());
assertEquals
(
bytes
.
length
,
b2
.
length
());
assertEquals
(
""
,
c1
.
getSubString
(
1
,
0
));
assertEquals
(
""
,
c1
.
getSubString
(
1
,
0
));
assertEquals
(
new
byte
[
0
],
b1
.
getBytes
(
1
,
0
));
assertEquals
(
new
byte
[
0
],
b1
.
getBytes
(
1
,
0
));
assertEquals
(
d
,
c2
.
getSubString
(
1
,
(
int
)
c2
.
length
()));
assertEquals
(
bytes
,
b2
.
getBytes
(
1
,
(
int
)
b2
.
length
()));
assertEquals
(
charsSmall
.
length
,
c2
.
length
());
assertEquals
(
bytesSmall
.
length
,
b2
.
length
());
assertEquals
(
dSmall
,
c2
.
getSubString
(
1
,
(
int
)
c2
.
length
()));
assertEquals
(
bytesSmall
,
b2
.
getBytes
(
1
,
(
int
)
b2
.
length
()));
assertEquals
(
chars
.
length
,
c3
.
length
());
assertEquals
(
bytes
.
length
,
b3
.
length
());
assertEquals
(
d
,
c3
.
getSubString
(
1
,
(
int
)
c3
.
length
()));
assertEquals
(
bytes
,
b3
.
getBytes
(
1
,
(
int
)
b3
.
length
()));
stat
.
execute
(
"drop table test"
);
stat
.
execute
(
"drop table test"
);
conn
.
close
();
conn
.
close
();
}
}
...
...
h2/src/test/org/h2/test/scripts/TestScript.java
浏览文件 @
9e5d9644
h2/src/test/org/h2/test/scripts/functions/timeanddate/dateadd.sql
浏览文件 @
9e5d9644
...
@@ -105,6 +105,18 @@ call dateadd('MS', 1, TIMESTAMP '2001-02-03 04:05:06.789001');
...
@@ -105,6 +105,18 @@ call dateadd('MS', 1, TIMESTAMP '2001-02-03 04:05:06.789001');
>
2001
-
02
-
03
04
:
05
:
06
.
790001
>
2001
-
02
-
03
04
:
05
:
06
.
790001
>
rows
:
1
>
rows
:
1
SELECT
DATEADD
(
'MICROSECOND'
,
1
,
TIME
'10:00:01'
),
DATEADD
(
'MCS'
,
1
,
TIMESTAMP
'2010-10-20 10:00:01.1'
);
>
TIME
'10:00:01.000001'
TIMESTAMP
'2010-10-20 10:00:01.100001'
>
---------------------- --------------------------------------
>
10
:
00
:
01
.
000001
2010
-
10
-
20
10
:
00
:
01
.
100001
>
rows
:
1
SELECT
DATEADD
(
'NANOSECOND'
,
1
,
TIME
'10:00:01'
),
DATEADD
(
'NS'
,
1
,
TIMESTAMP
'2010-10-20 10:00:01.1'
);
>
TIME
'10:00:01.000000001'
TIMESTAMP
'2010-10-20 10:00:01.100000001'
>
------------------------- -----------------------------------------
>
10
:
00
:
01
.
000000001
2010
-
10
-
20
10
:
00
:
01
.
100000001
>
rows
:
1
SELECT
DATEADD
(
'HOUR'
,
1
,
DATE
'2010-01-20'
);
SELECT
DATEADD
(
'HOUR'
,
1
,
DATE
'2010-01-20'
);
>
TIMESTAMP
'2010-01-20 01:00:00.0'
>
TIMESTAMP
'2010-01-20 01:00:00.0'
>
---------------------------------
>
---------------------------------
...
...
h2/src/test/org/h2/test/scripts/functions/timeanddate/datediff.sql
浏览文件 @
9e5d9644
...
@@ -159,6 +159,22 @@ call datediff('MS', TIMESTAMP '1900-01-01 00:00:01.000', TIMESTAMP '2008-01-01 0
...
@@ -159,6 +159,22 @@ call datediff('MS', TIMESTAMP '1900-01-01 00:00:01.000', TIMESTAMP '2008-01-01 0
>
3408134399000
>
3408134399000
>
rows
:
1
>
rows
:
1
SELECT
DATEDIFF
(
'MICROSECOND'
,
'2006-01-01 00:00:00.0000000'
,
'2006-01-01 00:00:00.123456789'
),
DATEDIFF
(
'MCS'
,
'2006-01-01 00:00:00.0000000'
,
'2006-01-01 00:00:00.123456789'
),
DATEDIFF
(
'MCS'
,
'2006-01-01 00:00:00.0000000'
,
'2006-01-02 00:00:00.123456789'
);
>
123456
123456
86400123456
>
------ ------ -----------
>
123456
123456
86400123456
>
rows
:
1
SELECT
DATEDIFF
(
'NANOSECOND'
,
'2006-01-01 00:00:00.0000000'
,
'2006-01-01 00:00:00.123456789'
),
DATEDIFF
(
'NS'
,
'2006-01-01 00:00:00.0000000'
,
'2006-01-01 00:00:00.123456789'
),
DATEDIFF
(
'NS'
,
'2006-01-01 00:00:00.0000000'
,
'2006-01-02 00:00:00.123456789'
);
>
123456789
123456789
86400123456789
>
--------- --------- --------------
>
123456789
123456789
86400123456789
>
rows
:
1
SELECT
DATEDIFF
(
'WEEK'
,
DATE
'2018-02-02'
,
DATE
'2018-02-03'
),
DATEDIFF
(
'ISO_WEEK'
,
DATE
'2018-02-02'
,
DATE
'2018-02-03'
);
SELECT
DATEDIFF
(
'WEEK'
,
DATE
'2018-02-02'
,
DATE
'2018-02-03'
),
DATEDIFF
(
'ISO_WEEK'
,
DATE
'2018-02-02'
,
DATE
'2018-02-03'
);
>
0
0
>
0
0
>
-
-
>
-
-
...
...
h2/src/test/org/h2/test/scripts/functions/timeanddate/extract.sql
浏览文件 @
9e5d9644
...
@@ -3,6 +3,20 @@
...
@@ -3,6 +3,20 @@
-- Initial Developer: H2 Group
-- Initial Developer: H2 Group
--
--
SELECT
EXTRACT
(
MICROSECOND
FROM
TIME
'10:00:00.123456789'
),
EXTRACT
(
MCS
FROM
TIMESTAMP
'2015-01-01 11:22:33.987654321'
);
>
123456
987654
>
------ ------
>
123456
987654
>
rows
:
1
SELECT
EXTRACT
(
NANOSECOND
FROM
TIME
'10:00:00.123456789'
),
EXTRACT
(
NS
FROM
TIMESTAMP
'2015-01-01 11:22:33.987654321'
);
>
123456789
987654321
>
--------- ---------
>
123456789
987654321
>
rows
:
1
select
EXTRACT
(
EPOCH
from
time
'00:00:00'
);
select
EXTRACT
(
EPOCH
from
time
'00:00:00'
);
>
0
>
0
...
...
h2/src/test/org/h2/test/store/TestMVStoreBenchmark.java
浏览文件 @
9e5d9644
...
@@ -124,14 +124,6 @@ public class TestMVStoreBenchmark extends TestBase {
...
@@ -124,14 +124,6 @@ public class TestMVStoreBenchmark extends TestBase {
}
}
static
long
getMemory
()
{
static
long
getMemory
()
{
try
{
LinkedList
<
byte
[]>
list
=
new
LinkedList
<>();
while
(
true
)
{
list
.
add
(
new
byte
[
1024
]);
}
}
catch
(
OutOfMemoryError
e
)
{
// ok
}
for
(
int
i
=
0
;
i
<
16
;
i
++)
{
for
(
int
i
=
0
;
i
<
16
;
i
++)
{
System
.
gc
();
System
.
gc
();
try
{
try
{
...
...
h2/src/test/org/h2/test/synth/TestFuzzOptimizations.java
浏览文件 @
9e5d9644
...
@@ -10,6 +10,7 @@ import java.sql.PreparedStatement;
...
@@ -10,6 +10,7 @@ import java.sql.PreparedStatement;
import
java.sql.ResultSet
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.Random
;
import
java.util.Random
;
...
@@ -107,7 +108,22 @@ public class TestFuzzOptimizations extends TestBase {
...
@@ -107,7 +108,22 @@ public class TestFuzzOptimizations extends TestBase {
ArrayList
<
String
>
params
=
New
.
arrayList
();
ArrayList
<
String
>
params
=
New
.
arrayList
();
String
condition
=
getRandomCondition
(
random
,
params
,
columns
,
String
condition
=
getRandomCondition
(
random
,
params
,
columns
,
compares
,
values
);
compares
,
values
);
// System.out.println(condition + " " + params);
String
message
=
"seed: "
+
seed
+
" "
+
condition
;
executeAndCompare
(
condition
,
params
,
message
);
if
(
params
.
size
()
>
0
)
{
for
(
int
j
=
0
;
j
<
params
.
size
();
j
++)
{
String
value
=
values
[
random
.
nextInt
(
values
.
length
-
2
)];
params
.
set
(
j
,
value
);
}
executeAndCompare
(
condition
,
params
,
message
);
}
}
executeAndCompare
(
"a >=0 and b in(?, 2) and a in(1, ?, null)"
,
Arrays
.
asList
(
"10"
,
"2"
),
"seed=-6191135606105920350L"
);
db
.
execute
(
"drop table test0, test1"
);
}
private
void
executeAndCompare
(
String
condition
,
List
<
String
>
params
,
String
message
)
throws
SQLException
{
PreparedStatement
prep0
=
conn
.
prepareStatement
(
PreparedStatement
prep0
=
conn
.
prepareStatement
(
"select * from test0 where "
+
condition
"select * from test0 where "
+
condition
+
" order by 1, 2, 3"
);
+
" order by 1, 2, 3"
);
...
@@ -120,18 +136,7 @@ public class TestFuzzOptimizations extends TestBase {
...
@@ -120,18 +136,7 @@ public class TestFuzzOptimizations extends TestBase {
}
}
ResultSet
rs0
=
prep0
.
executeQuery
();
ResultSet
rs0
=
prep0
.
executeQuery
();
ResultSet
rs1
=
prep1
.
executeQuery
();
ResultSet
rs1
=
prep1
.
executeQuery
();
assertEquals
(
"seed: "
+
seed
+
" "
+
condition
,
rs0
,
rs1
);
assertEquals
(
message
,
rs0
,
rs1
);
if
(
params
.
size
()
>
0
)
{
for
(
int
j
=
0
;
j
<
params
.
size
();
j
++)
{
String
value
=
values
[
random
.
nextInt
(
values
.
length
-
2
)];
params
.
set
(
j
,
value
);
prep0
.
setString
(
j
+
1
,
value
);
prep1
.
setString
(
j
+
1
,
value
);
}
assertEquals
(
"seed: "
+
seed
+
" "
+
condition
,
rs0
,
rs1
);
}
}
db
.
execute
(
"drop table test0, test1"
);
}
}
private
String
getRandomCondition
(
Random
random
,
ArrayList
<
String
>
params
,
private
String
getRandomCondition
(
Random
random
,
ArrayList
<
String
>
params
,
...
...
h2/src/test/org/h2/test/unit/TestClearReferences.java
浏览文件 @
9e5d9644
...
@@ -26,6 +26,7 @@ public class TestClearReferences extends TestBase {
...
@@ -26,6 +26,7 @@ public class TestClearReferences extends TestBase {
"org.h2.compress.CompressLZF.cachedHashTable"
,
"org.h2.compress.CompressLZF.cachedHashTable"
,
"org.h2.engine.DbSettings.defaultSettings"
,
"org.h2.engine.DbSettings.defaultSettings"
,
"org.h2.engine.SessionRemote.sessionFactory"
,
"org.h2.engine.SessionRemote.sessionFactory"
,
"org.h2.expression.Function.MONTHS_AND_WEEKS"
,
"org.h2.jdbcx.JdbcDataSourceFactory.cachedTraceSystem"
,
"org.h2.jdbcx.JdbcDataSourceFactory.cachedTraceSystem"
,
"org.h2.store.RecoverTester.instance"
,
"org.h2.store.RecoverTester.instance"
,
"org.h2.store.fs.FilePath.defaultProvider"
,
"org.h2.store.fs.FilePath.defaultProvider"
,
...
@@ -36,6 +37,7 @@ public class TestClearReferences extends TestBase {
...
@@ -36,6 +37,7 @@ public class TestClearReferences extends TestBase {
"org.h2.tools.CompressTool.cachedBuffer"
,
"org.h2.tools.CompressTool.cachedBuffer"
,
"org.h2.util.CloseWatcher.queue"
,
"org.h2.util.CloseWatcher.queue"
,
"org.h2.util.CloseWatcher.refs"
,
"org.h2.util.CloseWatcher.refs"
,
"org.h2.util.DateTimeUtils.timeZone"
,
"org.h2.util.MathUtils.cachedSecureRandom"
,
"org.h2.util.MathUtils.cachedSecureRandom"
,
"org.h2.util.NetUtils.cachedLocalAddress"
,
"org.h2.util.NetUtils.cachedLocalAddress"
,
"org.h2.util.StringUtils.softCache"
,
"org.h2.util.StringUtils.softCache"
,
...
@@ -43,6 +45,7 @@ public class TestClearReferences extends TestBase {
...
@@ -43,6 +45,7 @@ public class TestClearReferences extends TestBase {
"org.h2.util.JdbcUtils.allowedClassNamePrefixes"
,
"org.h2.util.JdbcUtils.allowedClassNamePrefixes"
,
"org.h2.util.JdbcUtils.userClassFactories"
,
"org.h2.util.JdbcUtils.userClassFactories"
,
"org.h2.util.Task.counter"
,
"org.h2.util.Task.counter"
,
"org.h2.util.ToChar.NAMES"
,
"org.h2.value.CompareMode.lastUsed"
,
"org.h2.value.CompareMode.lastUsed"
,
"org.h2.value.Value.softCache"
,
"org.h2.value.Value.softCache"
,
};
};
...
...
h2/src/test/org/h2/test/unit/TestDateTimeUtils.java
浏览文件 @
9e5d9644
...
@@ -5,13 +5,16 @@
...
@@ -5,13 +5,16 @@
*/
*/
package
org
.
h2
.
test
.
unit
;
package
org
.
h2
.
test
.
unit
;
import
static
org
.
h2
.
util
.
DateTimeUtils
.
dateValue
;
import
java.sql.Timestamp
;
import
java.util.Calendar
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
import
java.util.GregorianCalendar
;
import
java.util.TimeZone
;
import
org.h2.test.TestBase
;
import
org.h2.test.TestBase
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.value.ValueTimestamp
;
import
static
org
.
h2
.
util
.
DateTimeUtils
.
dateValue
;
/**
/**
* Unit tests for the DateTimeUtils class
* Unit tests for the DateTimeUtils class
...
@@ -21,9 +24,18 @@ public class TestDateTimeUtils extends TestBase {
...
@@ -21,9 +24,18 @@ public class TestDateTimeUtils extends TestBase {
/**
/**
* Run just this test.
* Run just this test.
*
*
* @param a ignored
* @param a
* if {@code "testUtc2Value"} only {@link #testUTC2Value(boolean)}
* will be executed with all time zones (slow). Otherwise all tests
* in this test unit will be executed with local time zone.
*/
*/
public
static
void
main
(
String
...
a
)
throws
Exception
{
public
static
void
main
(
String
...
a
)
throws
Exception
{
if
(
a
.
length
==
1
)
{
if
(
"testUtc2Value"
.
equals
(
a
[
0
]))
{
new
TestDateTimeUtils
().
testUTC2Value
(
true
);
return
;
}
}
TestBase
.
createCaller
().
init
().
test
();
TestBase
.
createCaller
().
init
().
test
();
}
}
...
@@ -33,6 +45,7 @@ public class TestDateTimeUtils extends TestBase {
...
@@ -33,6 +45,7 @@ public class TestDateTimeUtils extends TestBase {
testDayOfWeek
();
testDayOfWeek
();
testWeekOfYear
();
testWeekOfYear
();
testDateValueFromDenormalizedDate
();
testDateValueFromDenormalizedDate
();
testUTC2Value
(
false
);
}
}
private
void
testParseTimeNanosDB2Format
()
{
private
void
testParseTimeNanosDB2Format
()
{
...
@@ -44,7 +57,7 @@ public class TestDateTimeUtils extends TestBase {
...
@@ -44,7 +57,7 @@ public class TestDateTimeUtils extends TestBase {
}
}
/**
/**
* Test for {@link DateTimeUtils#getSundayDayOfWeek()} and
* Test for {@link DateTimeUtils#getSundayDayOfWeek(
long
)} and
* {@link DateTimeUtils#getIsoDayOfWeek(long)}.
* {@link DateTimeUtils#getIsoDayOfWeek(long)}.
*/
*/
private
void
testDayOfWeek
()
{
private
void
testDayOfWeek
()
{
...
@@ -106,4 +119,45 @@ public class TestDateTimeUtils extends TestBase {
...
@@ -106,4 +119,45 @@ public class TestDateTimeUtils extends TestBase {
assertEquals
(
dateValue
(-
100
,
2
,
29
),
DateTimeUtils
.
dateValueFromDenormalizedDate
(-
100
,
2
,
30
));
assertEquals
(
dateValue
(-
100
,
2
,
29
),
DateTimeUtils
.
dateValueFromDenormalizedDate
(-
100
,
2
,
30
));
}
}
private
void
testUTC2Value
(
boolean
allTimeZones
)
{
TimeZone
def
=
TimeZone
.
getDefault
();
GregorianCalendar
gc
=
new
GregorianCalendar
();
if
(
allTimeZones
)
{
try
{
for
(
String
id
:
TimeZone
.
getAvailableIDs
())
{
System
.
out
.
println
(
id
);
TimeZone
tz
=
TimeZone
.
getTimeZone
(
id
);
TimeZone
.
setDefault
(
tz
);
DateTimeUtils
.
resetCalendar
();
testUTC2ValueImpl
(
tz
,
gc
);
}
}
finally
{
TimeZone
.
setDefault
(
def
);
DateTimeUtils
.
resetCalendar
();
}
}
else
{
testUTC2ValueImpl
(
def
,
gc
);
}
}
private
void
testUTC2ValueImpl
(
TimeZone
tz
,
GregorianCalendar
gc
)
{
gc
.
setTimeZone
(
tz
);
gc
.
set
(
Calendar
.
MILLISECOND
,
0
);
long
absoluteStart
=
DateTimeUtils
.
absoluteDayFromDateValue
(
DateTimeUtils
.
dateValue
(
1950
,
01
,
01
));
long
absoluteEnd
=
DateTimeUtils
.
absoluteDayFromDateValue
(
DateTimeUtils
.
dateValue
(
2050
,
01
,
01
));
for
(
long
i
=
absoluteStart
;
i
<
absoluteEnd
;
i
++)
{
long
dateValue
=
DateTimeUtils
.
dateValueFromAbsoluteDay
(
i
);
int
year
=
DateTimeUtils
.
yearFromDateValue
(
dateValue
);
int
month
=
DateTimeUtils
.
monthFromDateValue
(
dateValue
);
int
day
=
DateTimeUtils
.
dayFromDateValue
(
dateValue
);
for
(
int
j
=
0
;
j
<
48
;
j
++)
{
gc
.
set
(
year
,
month
-
1
,
day
,
j
/
2
,
(
j
&
1
)
*
30
,
0
);
long
timeMillis
=
gc
.
getTimeInMillis
();
ValueTimestamp
ts
=
DateTimeUtils
.
convertTimestamp
(
new
Timestamp
(
timeMillis
),
gc
);
assertEquals
(
ts
.
getDateValue
(),
DateTimeUtils
.
dateValueFromDate
(
timeMillis
));
assertEquals
(
ts
.
getTimeNanos
(),
DateTimeUtils
.
nanosFromDate
(
timeMillis
));
}
}
}
}
}
h2/src/test/org/h2/test/unit/TestTimeStampWithTimeZone.java
浏览文件 @
9e5d9644
...
@@ -126,21 +126,27 @@ public class TestTimeStampWithTimeZone extends TestBase {
...
@@ -126,21 +126,27 @@ public class TestTimeStampWithTimeZone extends TestBase {
ValueTimestampTimeZone
a
=
ValueTimestampTimeZone
.
parse
(
"1970-01-01 12:00:00.00+00:15"
);
ValueTimestampTimeZone
a
=
ValueTimestampTimeZone
.
parse
(
"1970-01-01 12:00:00.00+00:15"
);
ValueTimestampTimeZone
b
=
ValueTimestampTimeZone
.
parse
(
"1970-01-01 12:00:01.00+01:15"
);
ValueTimestampTimeZone
b
=
ValueTimestampTimeZone
.
parse
(
"1970-01-01 12:00:01.00+01:15"
);
int
c
=
a
.
compareTo
(
b
,
null
);
int
c
=
a
.
compareTo
(
b
,
null
);
assertEquals
(
c
,
1
);
assertEquals
(
1
,
c
);
c
=
b
.
compareTo
(
a
,
null
);
assertEquals
(-
1
,
c
);
}
}
private
void
test3
()
{
private
void
test3
()
{
ValueTimestampTimeZone
a
=
ValueTimestampTimeZone
.
parse
(
"1970-01-02 00:00:02.00+01:15"
);
ValueTimestampTimeZone
a
=
ValueTimestampTimeZone
.
parse
(
"1970-01-02 00:00:02.00+01:15"
);
ValueTimestampTimeZone
b
=
ValueTimestampTimeZone
.
parse
(
"1970-01-01 23:00:01.00+00:15"
);
ValueTimestampTimeZone
b
=
ValueTimestampTimeZone
.
parse
(
"1970-01-01 23:00:01.00+00:15"
);
int
c
=
a
.
compareTo
(
b
,
null
);
int
c
=
a
.
compareTo
(
b
,
null
);
assertEquals
(
c
,
1
);
assertEquals
(
1
,
c
);
c
=
b
.
compareTo
(
a
,
null
);
assertEquals
(-
1
,
c
);
}
}
private
void
test4
()
{
private
void
test4
()
{
ValueTimestampTimeZone
a
=
ValueTimestampTimeZone
.
parse
(
"1970-01-02 00:00:01.00+01:15"
);
ValueTimestampTimeZone
a
=
ValueTimestampTimeZone
.
parse
(
"1970-01-02 00:00:01.00+01:15"
);
ValueTimestampTimeZone
b
=
ValueTimestampTimeZone
.
parse
(
"1970-01-01 23:00:01.00+00:15"
);
ValueTimestampTimeZone
b
=
ValueTimestampTimeZone
.
parse
(
"1970-01-01 23:00:01.00+00:15"
);
int
c
=
a
.
compareTo
(
b
,
null
);
int
c
=
a
.
compareTo
(
b
,
null
);
assertEquals
(
c
,
0
);
assertEquals
(
0
,
c
);
c
=
b
.
compareTo
(
a
,
null
);
assertEquals
(
0
,
c
);
}
}
private
void
test5
()
throws
SQLException
{
private
void
test5
()
throws
SQLException
{
...
...
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
9e5d9644
...
@@ -764,5 +764,5 @@ mdy destfile hclf forbids spellchecking selfdestruct expects accident jacocoagen
...
@@ -764,5 +764,5 @@ mdy destfile hclf forbids spellchecking selfdestruct expects accident jacocoagen
jacoco xdata invokes sourcefiles classfiles duplication crypto stacktraces prt directions handled overly asm hardcoded
jacoco xdata invokes sourcefiles classfiles duplication crypto stacktraces prt directions handled overly asm hardcoded
interpolated thead
interpolated thead
die weekdiff osx subprocess dow proleptic
die weekdiff osx subprocess dow proleptic
microsecond microseconds divisible cmp denormalized suppressed saturated mcs
london
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论