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
"
"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.
","
TIME '23:59:59'
...
...
@@ -2318,6 +2318,19 @@ minimum and maximum years are 0001 and 9999.
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","
string | dollarQuotedString | numeric | date | time | timestamp | boolean | bytes | array | null
","
...
...
@@ -3671,7 +3684,7 @@ CURRENT_TIMESTAMP()
Adds units to a date-time value. The string indicates the unit.
Use negative values to subtract units.
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.
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.
...
...
@@ -3727,11 +3740,13 @@ DAY_OF_YEAR(CREATED)
"Functions (Time and Date)","EXTRACT","
EXTRACT ( { YEAR | YY | MONTH | MM | QUARTER | WEEK | ISO_WEEK
| 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 )
","
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)
"
...
...
@@ -3820,6 +3835,17 @@ This method uses the current system locale.
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","
YEAR(timestamp)
","
...
...
@@ -3828,6 +3854,14 @@ Returns the year from a timestamp.
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","
ARRAY_GET(arrayExpression, indexExpression)
","
...
...
h2/src/main/org/h2/constraint/Constraint.java
浏览文件 @
9e5d9644
...
...
@@ -10,7 +10,6 @@ import org.h2.engine.DbObject;
import
org.h2.engine.Session
;
import
org.h2.expression.ExpressionVisitor
;
import
org.h2.index.Index
;
import
org.h2.message.DbException
;
import
org.h2.message.Trace
;
import
org.h2.result.Row
;
import
org.h2.schema.Schema
;
...
...
h2/src/main/org/h2/expression/AggregateDataMedian.java
浏览文件 @
9e5d9644
...
...
@@ -224,7 +224,8 @@ class AggregateDataMedian extends AggregateData {
case
Value
.
DOUBLE
:
return
ValueDouble
.
get
((
v0
.
getFloat
()
+
v1
.
getDouble
())
/
2
);
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
:
{
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;
import
java.sql.Connection
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.text.
SimpleDateFormat
;
import
java.text.
DateFormatSymbols
;
import
java.util.ArrayList
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
import
java.util.HashMap
;
import
java.util.Locale
;
...
...
@@ -99,7 +98,7 @@ public class Function extends Expression implements FunctionCall {
XMLATTR
=
83
,
XMLNODE
=
84
,
XMLCOMMENT
=
85
,
XMLCDATA
=
86
,
XMLSTARTDOC
=
87
,
XMLTEXT
=
88
,
REGEXP_REPLACE
=
89
,
RPAD
=
90
,
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
,
DATE_DIFF
=
103
,
DAY_NAME
=
104
,
DAY_OF_MONTH
=
105
,
...
...
@@ -111,14 +110,9 @@ public class Function extends Expression implements FunctionCall {
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
;
/**
* Pseudo function for {@code EXTRACT(EPOCH FROM ...)}.
*/
public
static
final
int
EPOCH
=
127
;
public
static
final
int
MILLISECOND
=
126
,
EPOCH
=
127
,
MICROSECOND
=
128
,
NANOSECOND
=
129
;
public
static
final
int
DATABASE
=
150
,
USER
=
151
,
CURRENT_USER
=
152
,
IDENTITY
=
153
,
SCOPE_IDENTITY
=
154
,
AUTOCOMMIT
=
155
,
...
...
@@ -159,6 +153,11 @@ public class Function extends Expression implements FunctionCall {
private
static
final
HashMap
<
String
,
Integer
>
DATE_PART
=
new
HashMap
<>();
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
;
private
final
FunctionInfo
info
;
...
...
@@ -206,6 +205,10 @@ public class Function extends Expression implements FunctionCall {
DATE_PART
.
put
(
"MILLISECOND"
,
MILLISECOND
);
DATE_PART
.
put
(
"MS"
,
MILLISECOND
);
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
String
index
=
"7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R"
;
...
...
@@ -337,6 +340,7 @@ public class Function extends Expression implements FunctionCall {
addFunction
(
"TO_DATE"
,
TO_DATE
,
VAR_ARGS
,
Value
.
TIMESTAMP
);
addFunction
(
"TO_TIMESTAMP"
,
TO_TIMESTAMP
,
VAR_ARGS
,
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
addFunctionNotDeterministic
(
"GETDATE"
,
CURDATE
,
0
,
Value
.
DATE
);
...
...
@@ -845,9 +849,8 @@ public class Function extends Expression implements FunctionCall {
database
.
getMode
().
treatEmptyStringsAsNull
);
break
;
case
DAY_NAME:
{
SimpleDateFormat
dayName
=
new
SimpleDateFormat
(
"EEEE"
,
Locale
.
ENGLISH
);
result
=
ValueString
.
get
(
dayName
.
format
(
v0
.
getDate
()),
int
dayOfWeek
=
DateTimeUtils
.
getSundayDayOfWeek
(
DateTimeUtils
.
dateAndTimeFromValue
(
v0
)[
0
]);
result
=
ValueString
.
get
(
getMonthsAndWeeks
(
1
)[
dayOfWeek
],
database
.
getMode
().
treatEmptyStringsAsNull
);
break
;
}
...
...
@@ -864,12 +867,11 @@ public class Function extends Expression implements FunctionCall {
case
SECOND:
case
WEEK:
case
YEAR:
result
=
ValueInt
.
get
(
getDatePart
(
v0
,
info
.
type
));
result
=
ValueInt
.
get
(
get
Int
DatePart
(
v0
,
info
.
type
));
break
;
case
MONTH_NAME:
{
SimpleDateFormat
monthName
=
new
SimpleDateFormat
(
"MMMM"
,
Locale
.
ENGLISH
);
result
=
ValueString
.
get
(
monthName
.
format
(
v0
.
getDate
()),
int
month
=
DateTimeUtils
.
monthFromDateValue
(
DateTimeUtils
.
dateAndTimeFromValue
(
v0
)[
0
]);
result
=
ValueString
.
get
(
getMonthsAndWeeks
(
0
)[
month
-
1
],
database
.
getMode
().
treatEmptyStringsAsNull
);
break
;
}
...
...
@@ -1234,32 +1236,16 @@ public class Function extends Expression implements FunctionCall {
}
case
TRUNCATE:
{
if
(
v0
.
getType
()
==
Value
.
TIMESTAMP
)
{
java
.
sql
.
Timestamp
d
=
v0
.
getTimestamp
();
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
());
result
=
ValueTimestamp
.
fromDateValueAndNanos
(((
ValueTimestamp
)
v0
).
getDateValue
(),
0
);
}
else
if
(
v0
.
getType
()
==
Value
.
DATE
)
{
ValueDate
vd
=
(
ValueDate
)
v0
;
Calendar
c
=
DateTimeUtils
.
createGregorianCalendar
();
c
.
setTime
(
vd
.
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
());
result
=
ValueTimestamp
.
fromDateValueAndNanos
(((
ValueDate
)
v0
).
getDateValue
(),
0
);
}
else
if
(
v0
.
getType
()
==
Value
.
TIMESTAMP_TZ
)
{
ValueTimestampTimeZone
ts
=
(
ValueTimestampTimeZone
)
v0
;
result
=
ValueTimestampTimeZone
.
fromDateValueAndNanos
(
ts
.
getDateValue
(),
0
,
ts
.
getTimeZoneOffsetMins
());
}
else
if
(
v0
.
getType
()
==
Value
.
STRING
)
{
ValueString
vd
=
(
ValueString
)
v0
;
Calendar
c
=
DateTimeUtils
.
createGregorianCalendar
();
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
());
ValueTimestamp
ts
=
ValueTimestamp
.
parse
(
v0
.
getString
(),
session
.
getDatabase
().
getMode
());
result
=
ValueTimestamp
.
fromDateValueAndNanos
(
ts
.
getDateValue
(),
0
);
}
else
{
double
d
=
v0
.
getDouble
();
int
p
=
v1
==
null
?
0
:
v1
.
getInt
();
...
...
@@ -1450,7 +1436,8 @@ public class Function extends Expression implements FunctionCall {
case
Value
.
TIME
:
case
Value
.
DATE
:
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
(),
v2
==
null
?
null
:
v2
.
getString
()),
database
.
getMode
().
treatEmptyStringsAsNull
);
...
...
@@ -1472,16 +1459,20 @@ public class Function extends Expression implements FunctionCall {
}
break
;
case
TO_DATE:
result
=
ValueTimestamp
.
get
(
ToDateParser
.
toDate
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
())
)
;
result
=
ToDateParser
.
toDate
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
());
break
;
case
TO_TIMESTAMP:
result
=
ValueTimestamp
.
get
(
ToDateParser
.
toTimestamp
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
())
)
;
result
=
ToDateParser
.
toTimestamp
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
());
break
;
case
ADD_MONTHS:
result
=
dateadd
(
"MONTH"
,
v1
.
getInt
(),
v0
);
break
;
case
TO_TIMESTAMP_TZ:
result
=
ToDateParser
.
toTimestampTz
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
());
break
;
case
TRANSLATE:
{
String
matching
=
v1
.
getString
();
String
replacement
=
v2
.
getString
();
...
...
@@ -1502,14 +1493,10 @@ public class Function extends Expression implements FunctionCall {
break
;
case
EXTRACT:
{
int
field
=
getDatePart
(
v0
.
getString
());
// Normal case when we don't retrieve the EPOCH time
if
(
field
!=
EPOCH
)
{
result
=
ValueInt
.
get
(
getDatePart
(
v1
,
field
));
result
=
ValueInt
.
get
(
getIntDatePart
(
v1
,
field
));
}
else
{
// Case where we retrieve the EPOCH time.
// First we retrieve the dateValue and his time in nanoseconds.
long
[]
a
=
DateTimeUtils
.
dateAndTimeFromValue
(
v1
);
...
...
@@ -1520,37 +1507,40 @@ public class Function extends Expression implements FunctionCall {
BigDecimal
numberOfDays
=
new
BigDecimal
(
DateTimeUtils
.
absoluteDayFromDateValue
(
dateValue
));
BigDecimal
nanosSeconds
=
new
BigDecimal
(
1_000_000_000
);
BigDecimal
secondsPerDay
=
new
BigDecimal
(
DateTimeUtils
.
SECONDS_PER_DAY
);
// Case where the value is of type time e.g. '10:00:00'
if
(
v1
instanceof
ValueTime
)
{
// In order to retrieve the EPOCH time we only have to convert the time
// In order to retrieve the EPOCH time we only have to convert the time
// in nanoseconds (previously retrieved) in seconds.
result
=
ValueDecimal
.
get
(
timeNanosBigDecimal
.
divide
(
nanosSeconds
));
}
else
if
(
v1
instanceof
ValueDate
)
{
// Case where the value is of type date '2000:01:01', we have to retrieve the
total
// number of days and multiply it by the number of seconds in a day.
// Case where the value is of type date '2000:01:01', we have to retrieve the
//
total
number of days and multiply it by the number of seconds in a day.
result
=
ValueDecimal
.
get
(
numberOfDays
.
multiply
(
secondsPerDay
));
}
else
if
(
v1
instanceof
ValueTimestampTimeZone
)
{
// Case where the value is a of type ValueTimestampTimeZone ('2000:01:01 10:00:00+05).
// We retrieve the time zone offset in minute
// Case where the value is a of type ValueTimestampTimeZone
// ('2000:01:01 10:00:00+05').
// We retrieve the time zone offset in minutes
ValueTimestampTimeZone
v
=
(
ValueTimestampTimeZone
)
v1
;
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.
result
=
ValueDecimal
.
get
(
timeNanosBigDecimal
.
divide
(
nanosSeconds
)
.
add
(
numberOfDays
.
multiply
(
secondsPerDay
))
.
subtract
(
timeZoneOffsetSeconds
));
.
add
(
numberOfDays
.
multiply
(
secondsPerDay
)).
subtract
(
timeZoneOffsetSeconds
));
}
else
{
// By default, we have the date and the time ('2000:01:01 10:00:00) if no type is given.
// 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
)));
// By default, we have the date and the time ('2000:01:01 10:00:00') if no type
// is given.
// 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
;
...
...
@@ -1866,8 +1856,7 @@ public class Function extends Expression implements FunctionCall {
private
static
Value
dateadd
(
String
part
,
long
count
,
Value
v
)
{
int
field
=
getDatePart
(
part
);
//v = v.convertTo(Value.TIMESTAMP);
if
(
field
!=
MILLISECOND
&&
if
(
field
!=
MILLISECOND
&&
field
!=
MICROSECOND
&&
field
!=
NANOSECOND
&&
(
count
>
Integer
.
MAX_VALUE
||
count
<
Integer
.
MIN_VALUE
))
{
throw
DbException
.
getInvalidValueException
(
"DATEADD count"
,
count
);
}
...
...
@@ -1917,11 +1906,17 @@ public class Function extends Expression implements FunctionCall {
count
*=
60_000_000_000L
;
break
;
case
SECOND:
case
EPOCH:
count
*=
1_000_000_000
;
break
;
case
MILLISECOND:
count
*=
1_000_000
;
break
;
case
MICROSECOND:
count
*=
1_000
;
break
;
case
NANOSECOND:
break
;
default
:
throw
DbException
.
getUnsupportedException
(
"DATEADD "
+
part
);
}
...
...
@@ -1966,17 +1961,27 @@ public class Function extends Expression implements FunctionCall {
long
dateValue2
=
a2
[
0
];
long
absolute2
=
DateTimeUtils
.
absoluteDayFromDateValue
(
dateValue2
);
switch
(
field
)
{
case
NANOSECOND:
case
MICROSECOND:
case
MILLISECOND:
case
SECOND:
case
EPOCH:
case
MINUTE:
case
HOUR:
long
timeNanos1
=
a1
[
1
];
long
timeNanos2
=
a2
[
1
];
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:
return
(
absolute2
-
absolute1
)
*
DateTimeUtils
.
MILLIS_PER_DAY
+
(
timeNanos2
/
1_000_000
-
timeNanos1
/
1_000_000
);
case
SECOND:
case
EPOCH:
return
(
absolute2
-
absolute1
)
*
86_400
+
(
timeNanos2
/
1_000_000_000
-
timeNanos1
/
1_000_000_000
);
case
MINUTE:
...
...
@@ -2023,6 +2028,18 @@ public class Function extends Expression implements FunctionCall {
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
)
{
int
len
=
s
.
length
();
start
--;
...
...
@@ -2310,6 +2327,7 @@ public class Function extends Expression implements FunctionCall {
case
XMLTEXT:
case
TRUNCATE:
case
TO_TIMESTAMP:
case
TO_TIMESTAMP_TZ:
min
=
1
;
max
=
2
;
break
;
...
...
@@ -2859,7 +2877,7 @@ public class Function extends Expression implements FunctionCall {
* @param field the field type, see {@link Function} for constants
* @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
dateValue
=
a
[
0
];
long
timeNanos
=
a
[
1
];
...
...
@@ -2878,6 +2896,10 @@ public class Function extends Expression implements FunctionCall {
return
(
int
)
(
timeNanos
/
1_000_000_000
%
60
);
case
Function
.
MILLISECOND
:
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
:
return
DateTimeUtils
.
getDayOfYear
(
dateValue
);
case
Function
.
DAY_OF_WEEK
:
...
...
h2/src/main/org/h2/index/IndexCursor.java
浏览文件 @
9e5d9644
...
...
@@ -148,6 +148,9 @@ public class IndexCursor implements Cursor {
}
}
}
if
(
inColumn
!=
null
)
{
start
=
table
.
getTemplateRow
();
}
}
/**
...
...
@@ -326,7 +329,6 @@ public class IndexCursor implements Cursor {
while
(
inResult
.
next
())
{
Value
v
=
inResult
.
currentRow
()[
0
];
if
(
v
!=
ValueNull
.
INSTANCE
)
{
v
=
inColumn
.
convert
(
v
);
if
(
inResultTested
==
null
)
{
inResultTested
=
new
HashSet
<>();
}
...
...
@@ -342,9 +344,6 @@ public class IndexCursor implements Cursor {
private
void
find
(
Value
v
)
{
v
=
inColumn
.
convert
(
v
);
int
id
=
inColumn
.
getColumnId
();
if
(
start
==
null
)
{
start
=
table
.
getTemplateRow
();
}
start
.
setValue
(
id
,
v
);
cursor
=
index
.
find
(
tableFilter
,
start
,
start
);
}
...
...
h2/src/main/org/h2/mvstore/MVStore.java
浏览文件 @
9e5d9644
...
...
@@ -2450,27 +2450,27 @@ public final class MVStore {
* needed.
*/
void
writeInBackground
()
{
if
(
closed
)
{
return
;
}
try
{
if
(
closed
)
{
return
;
}
// could also commit when there are many unsaved pages,
// but according to a test it doesn't really help
// could also commit when there are many unsaved pages,
// but according to a test it doesn't really help
long
time
=
getTimeSinceCreation
();
if
(
time
<=
lastCommitTime
+
autoCommitDelay
)
{
return
;
}
if
(
hasUnsavedChanges
())
{
try
{
commitAndSave
();
}
catch
(
Throwable
e
)
{
handleException
(
e
);
long
time
=
getTimeSinceCreation
();
if
(
time
<=
lastCommitTime
+
autoCommitDelay
)
{
return
;
}
}
if
(
autoCompactFillRate
>
0
)
{
try
{
if
(
hasUnsavedChanges
())
{
try
{
commitAndSave
();
}
catch
(
Throwable
e
)
{
handleException
(
e
);
return
;
}
}
if
(
autoCompactFillRate
>
0
)
{
// whether there were file read or write operations since
// the last time
boolean
fileOps
;
...
...
@@ -2486,9 +2486,9 @@ public final class MVStore {
// in the bookkeeping?
compact
(
fillRate
,
autoCommitMemory
);
autoCompactLastFileOpCount
=
fileStore
.
getWriteCount
()
+
fileStore
.
getReadCount
();
}
catch
(
Throwable
e
)
{
handleException
(
e
);
}
}
catch
(
Throwable
e
)
{
handleException
(
e
);
}
}
...
...
@@ -2497,7 +2497,9 @@ public final class MVStore {
try
{
backgroundExceptionHandler
.
uncaughtException
(
null
,
ex
);
}
catch
(
Throwable
ignore
)
{
ex
.
addSuppressed
(
ignore
);
if
(
ex
!=
ignore
)
{
// OOME may be the same
ex
.
addSuppressed
(
ignore
);
}
}
}
}
...
...
h2/src/main/org/h2/store/DataReader.java
浏览文件 @
9e5d9644
...
...
@@ -171,7 +171,7 @@ public class DataReader extends Reader {
int
i
=
0
;
try
{
for
(;
i
<
len
;
i
++)
{
buff
[
i
]
=
readChar
();
buff
[
off
+
i
]
=
readChar
();
}
return
len
;
}
catch
(
EOFException
e
)
{
...
...
h2/src/main/org/h2/table/MetaTable.java
浏览文件 @
9e5d9644
...
...
@@ -1615,7 +1615,7 @@ public class MetaTable extends Table {
if
(
constraintType
==
Constraint
.
Type
.
CHECK
)
{
checkExpression
=
((
ConstraintCheck
)
constraint
).
getExpression
().
getSQL
();
}
else
if
(
constraintType
==
Constraint
.
Type
.
UNIQUE
||
constraintType
==
Constraint
.
Type
.
PRIMARY_KEY
)
{
constraintType
==
Constraint
.
Type
.
PRIMARY_KEY
)
{
indexColumns
=
((
ConstraintUnique
)
constraint
).
getColumns
();
}
else
if
(
constraintType
==
Constraint
.
Type
.
REFERENTIAL
)
{
indexColumns
=
((
ConstraintReferential
)
constraint
).
getColumns
();
...
...
h2/src/main/org/h2/tools/ChangeFileEncryption.java
浏览文件 @
9e5d9644
...
...
@@ -224,7 +224,8 @@ public class ChangeFileEncryption extends Tool {
try
(
FileChannel
fileIn
=
getFileChannel
(
fileName
,
"r"
,
decryptKey
)){
try
(
InputStream
inStream
=
new
FileChannelInputStream
(
fileIn
,
true
))
{
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
];
long
remaining
=
fileIn
.
size
();
long
total
=
remaining
;
...
...
h2/src/main/org/h2/util/DateTimeUtils.java
浏览文件 @
9e5d9644
...
...
@@ -36,7 +36,7 @@ public class DateTimeUtils {
* The number of milliseconds per day.
*/
public
static
final
long
MILLIS_PER_DAY
=
24
*
60
*
60
*
1000L
;
/**
* The number of seconds per day.
*/
...
...
@@ -85,6 +85,11 @@ public class DateTimeUtils {
private
static
final
ThreadLocal
<
GregorianCalendar
>
CACHED_CALENDAR_NON_DEFAULT_TIMEZONE
=
new
ThreadLocal
<>();
/**
* Cached local time zone.
*/
private
static
volatile
TimeZone
timeZone
;
/**
* 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
...
...
@@ -100,12 +105,26 @@ public class DateTimeUtils {
// 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
* changing the default timezone.
*/
public
static
void
resetCalendar
()
{
CACHED_CALENDAR
.
remove
();
timeZone
=
null
;
zoneOffsetMillis
=
DateTimeUtils
.
createGregorianCalendar
().
get
(
Calendar
.
ZONE_OFFSET
);
}
...
...
@@ -628,20 +647,6 @@ public class DateTimeUtils {
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,
* but without daylight saving time into account.
...
...
@@ -921,19 +926,6 @@ public class DateTimeUtils {
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.
*
...
...
@@ -1070,9 +1062,13 @@ public class DateTimeUtils {
* @return the date value
*/
public
static
long
dateValueFromDate
(
long
ms
)
{
Calendar
cal
=
getCalendar
();
cal
.
setTimeInMillis
(
ms
);
return
dateValueFromCalendar
(
cal
);
ms
+=
getTimeZone
().
getOffset
(
ms
);
long
absoluteDay
=
ms
/
MILLIS_PER_DAY
;
// Round toward negative infinity
if
(
ms
<
0
&&
(
absoluteDay
*
MILLIS_PER_DAY
!=
ms
))
{
absoluteDay
--;
}
return
dateValueFromAbsoluteDay
(
absoluteDay
);
}
/**
...
...
@@ -1082,10 +1078,12 @@ public class DateTimeUtils {
* @return the date value
*/
private
static
long
dateValueFromCalendar
(
Calendar
cal
)
{
int
year
,
month
,
day
;
year
=
getYear
(
cal
);
month
=
cal
.
get
(
Calendar
.
MONTH
)
+
1
;
day
=
cal
.
get
(
Calendar
.
DAY_OF_MONTH
);
int
year
=
cal
.
get
(
Calendar
.
YEAR
);
if
(
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
BC
)
{
year
=
1
-
year
;
}
int
month
=
cal
.
get
(
Calendar
.
MONTH
)
+
1
;
int
day
=
cal
.
get
(
Calendar
.
DAY_OF_MONTH
);
return
((
long
)
year
<<
SHIFT_YEAR
)
|
(
month
<<
SHIFT_MONTH
)
|
day
;
}
...
...
@@ -1097,9 +1095,13 @@ public class DateTimeUtils {
* @return the nanoseconds
*/
public
static
long
nanosFromDate
(
long
ms
)
{
Calendar
cal
=
getCalendar
();
cal
.
setTimeInMillis
(
ms
);
return
nanosFromCalendar
(
cal
);
ms
+=
getTimeZone
().
getOffset
(
ms
);
long
absoluteDay
=
ms
/
MILLIS_PER_DAY
;
// 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 {
m
+=
12
;
}
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)
a
+=
13
;
}
else
if
(
y
<
1901
||
y
>
2099
)
{
...
...
h2/src/main/org/h2/util/ToChar.java
浏览文件 @
9e5d9644
...
...
@@ -6,20 +6,19 @@
package
org
.
h2
.
util
;
import
java.math.BigDecimal
;
import
java.sql.Date
;
import
java.sql.Timestamp
;
import
java.text.DateFormatSymbols
;
import
java.text.DecimalFormat
;
import
java.text.DecimalFormatSymbols
;
import
java.text.SimpleDateFormat
;
import
java.util.Arrays
;
import
java.util.Calendar
;
import
java.util.Currency
;
import
java.util.GregorianCalendar
;
import
java.util.Locale
;
import
java.util.TimeZone
;
import
org.h2.api.ErrorCode
;
import
org.h2.message.DbException
;
import
org.h2.value.Value
;
import
org.h2.value.ValueTimestampTimeZone
;
/**
* Emulates Oracle's TO_CHAR function.
...
...
@@ -29,7 +28,7 @@ public class ToChar {
/**
* 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
,
5
,
4
,
1
};
...
...
@@ -37,14 +36,9 @@ public class ToChar {
private
static
final
String
[]
ROMAN_NUMERALS
=
{
"M"
,
"CM"
,
"D"
,
"CD"
,
"C"
,
"XC"
,
"L"
,
"XL"
,
"X"
,
"IX"
,
"V"
,
"IV"
,
"I"
};
static
{
GregorianCalendar
epoch
=
new
GregorianCalendar
(
Locale
.
ENGLISH
);
epoch
.
setGregorianChange
(
new
Date
(
Long
.
MAX_VALUE
));
epoch
.
clear
();
epoch
.
set
(
4713
,
Calendar
.
JANUARY
,
1
,
0
,
0
,
0
);
epoch
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
BC
);
JULIAN_EPOCH
=
epoch
.
getTimeInMillis
();
}
static
final
int
MONTHS
=
0
,
SHORT_MONTHS
=
1
,
WEEKDAYS
=
2
,
SHORT_WEEKDAYS
=
3
,
AM_PM
=
4
;
private
static
volatile
String
[][]
NAMES
;
private
ToChar
()
{
// utility class
...
...
@@ -460,6 +454,66 @@ public class ToChar {
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.
*
...
...
@@ -592,19 +646,31 @@ public class ToChar {
* See also TO_CHAR(datetime) and datetime format models
* 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 nlsParam the NLS parameter (if any)
* @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
)
{
format
=
"DD-MON-YY HH.MI.SS.FF PM"
;
}
GregorianCalendar
cal
=
new
GregorianCalendar
(
Locale
.
ENGLISH
);
cal
.
setTimeInMillis
(
ts
.
getTime
());
StringBuilder
output
=
new
StringBuilder
();
boolean
fillMode
=
true
;
...
...
@@ -615,197 +681,213 @@ public class ToChar {
// AD / BC
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
));
i
+=
4
;
}
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
));
i
+=
2
;
// AM / PM
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"A.M."
,
"P.M."
))
!=
null
)
{
String
am
=
cal
.
get
(
Calendar
.
AM_PM
)
==
Calendar
.
AM
?
"A.M."
:
"P.M."
;
String
am
=
is
AM
?
"A.M."
:
"P.M."
;
output
.
append
(
cap
.
apply
(
am
));
i
+=
4
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"AM"
,
"PM"
))
!=
null
)
{
String
am
=
cal
.
get
(
Calendar
.
AM_PM
)
==
Calendar
.
AM
?
"AM"
:
"PM"
;
String
am
=
is
AM
?
"AM"
:
"PM"
;
output
.
append
(
cap
.
apply
(
am
));
i
+=
2
;
// Long/short date/time format
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DL"
))
!=
null
)
{
output
.
append
(
new
SimpleDateFormat
(
"EEEE, MMMM d, yyyy"
).
format
(
ts
));
}
else
if
(
containsAt
(
format
,
i
,
"DL"
)
!=
null
)
{
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
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DS"
))
!=
null
)
{
output
.
append
(
new
SimpleDateFormat
(
"MM/dd/yyyy"
).
format
(
ts
));
}
else
if
(
containsAt
(
format
,
i
,
"DS"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
monthOfYear
);
output
.
append
(
'/'
);
StringUtils
.
appendZeroPadded
(
output
,
2
,
dayOfMonth
);
output
.
append
(
'/'
);
StringUtils
.
appendZeroPadded
(
output
,
4
,
posYear
);
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"TS"
))
!=
null
)
{
output
.
append
(
new
SimpleDateFormat
(
"h:mm:ss aa"
).
format
(
ts
));
}
else
if
(
containsAt
(
format
,
i
,
"TS"
)
!=
null
)
{
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
;
// Day
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"DDD"
)
)
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
DAY_OF_YEAR
));
}
else
if
(
containsAt
(
format
,
i
,
"DDD"
)
!=
null
)
{
output
.
append
(
DateTimeUtils
.
getDayOfYear
(
dateValue
));
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DD"
))
!=
null
)
{
output
.
append
(
String
.
format
(
"%02d"
,
cal
.
get
(
Calendar
.
DAY_OF_MONTH
)));
}
else
if
(
containsAt
(
format
,
i
,
"DD"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
dayOfMonth
);
i
+=
2
;
}
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
));
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"DAY"
))
!=
null
)
{
String
day
=
new
SimpleDateFormat
(
"EEEE"
).
format
(
ts
)
;
String
day
=
getNames
(
WEEKDAYS
)[
DateTimeUtils
.
getSundayDayOfWeek
(
dateValue
)]
;
if
(
fillMode
)
{
day
=
StringUtils
.
pad
(
day
,
"Wednesday"
.
length
(),
" "
,
true
);
}
output
.
append
(
cap
.
apply
(
day
));
i
+=
3
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"D"
)
)
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
DAY_OF_WEEK
));
}
else
if
(
containsAt
(
format
,
i
,
"D"
)
!=
null
)
{
output
.
append
(
DateTimeUtils
.
getSundayDayOfWeek
(
dateValue
));
i
+=
1
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"J"
))
!=
null
)
{
long
millis
=
ts
.
getTime
()
-
JULIAN_EPOCH
;
long
days
=
(
long
)
Math
.
floor
(
millis
/
(
1000
*
60
*
60
*
24
));
output
.
append
(
days
);
}
else
if
(
containsAt
(
format
,
i
,
"J"
)
!=
null
)
{
output
.
append
(
DateTimeUtils
.
absoluteDayFromDateValue
(
dateValue
)
-
JULIAN_EPOCH
);
i
+=
1
;
// Hours
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"HH24"
)
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
HOUR_OF_DAY
))
);
}
else
if
(
containsAt
(
format
,
i
,
"HH24"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
hour
);
i
+=
4
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"HH12"
)
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
HOUR
))
);
}
else
if
(
containsAt
(
format
,
i
,
"HH12"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
h12
);
i
+=
4
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"HH"
)
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
HOUR
))
);
}
else
if
(
containsAt
(
format
,
i
,
"HH"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
h12
);
i
+=
2
;
// Minutes
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"MI"
)
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
MINUTE
))
);
}
else
if
(
containsAt
(
format
,
i
,
"MI"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
minute
);
i
+=
2
;
// Seconds
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"SSSSS"
))
!=
null
)
{
int
seconds
=
cal
.
get
(
Calendar
.
HOUR_OF_DAY
)
*
60
*
60
;
seconds
+=
cal
.
get
(
Calendar
.
MINUTE
)
*
60
;
seconds
+=
cal
.
get
(
Calendar
.
SECOND
);
}
else
if
(
containsAt
(
format
,
i
,
"SSSSS"
)
!=
null
)
{
int
seconds
=
(
int
)
(
timeNanos
/
1_000_000_000
);
output
.
append
(
seconds
);
i
+=
5
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"SS"
)
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
cal
.
get
(
Calendar
.
SECOND
))
);
}
else
if
(
containsAt
(
format
,
i
,
"SS"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
second
);
i
+=
2
;
// Fractional seconds
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"FF1"
,
"FF2"
,
"FF3"
,
"FF4"
,
"FF5"
,
"FF6"
,
"FF7"
,
"FF8"
,
"FF9"
)
)
!=
null
)
{
int
x
=
Integer
.
parseInt
(
format
.
substring
(
i
+
2
,
i
+
3
))
;
int
ff
=
(
int
)
(
cal
.
get
(
Calendar
.
MILLISECOND
)
*
Math
.
pow
(
10
,
x
-
3
));
output
.
append
(
ff
);
}
else
if
(
containsAt
(
format
,
i
,
"FF1"
,
"FF2"
,
"FF3"
,
"FF4"
,
"FF5"
,
"FF6"
,
"FF7"
,
"FF8"
,
"FF9"
)
!=
null
)
{
int
x
=
format
.
charAt
(
i
+
2
)
-
'0'
;
int
ff
=
(
int
)
(
nanos
*
Math
.
pow
(
10
,
x
-
9
));
StringUtils
.
appendZeroPadded
(
output
,
x
,
ff
);
i
+=
3
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"FF"
)
)
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
MILLISECOND
)
*
1000
);
}
else
if
(
containsAt
(
format
,
i
,
"FF"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
9
,
nanos
);
i
+=
2
;
// Time zone
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"TZR"
))
!=
null
)
{
TimeZone
tz
=
TimeZone
.
getDefault
();
output
.
append
(
tz
.
getID
());
}
else
if
(
containsAt
(
format
,
i
,
"TZR"
)
!=
null
)
{
output
.
append
(
getTimeZone
(
value
,
false
));
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"TZD"
))
!=
null
)
{
TimeZone
tz
=
TimeZone
.
getDefault
();
boolean
daylight
=
tz
.
inDaylightTime
(
new
java
.
util
.
Date
());
output
.
append
(
tz
.
getDisplayName
(
daylight
,
TimeZone
.
SHORT
));
}
else
if
(
containsAt
(
format
,
i
,
"TZD"
)
!=
null
)
{
output
.
append
(
getTimeZone
(
value
,
true
));
i
+=
3
;
// Week
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"IW"
,
"WW"
)
)
!=
null
)
{
output
.
append
(
cal
.
get
(
Calendar
.
WEEK_OF_YEAR
));
}
else
if
(
containsAt
(
format
,
i
,
"IW"
,
"WW"
)
!=
null
)
{
output
.
append
(
DateTimeUtils
.
getWeekOfYear
(
dateValue
,
0
,
1
));
i
+=
2
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"W"
)
)
!=
null
)
{
int
w
=
(
int
)
(
1
+
Math
.
floor
(
cal
.
get
(
Calendar
.
DAY_OF_MONTH
)
/
7
))
;
}
else
if
(
containsAt
(
format
,
i
,
"W"
)
!=
null
)
{
int
w
=
1
+
dayOfMonth
/
7
;
output
.
append
(
w
);
i
+=
1
;
// Year
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"Y,YYY"
)
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"#,###"
).
format
(
getYear
(
cal
)
));
}
else
if
(
containsAt
(
format
,
i
,
"Y,YYY"
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"#,###"
).
format
(
posYear
));
i
+=
5
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"SYYYY"
))
!=
null
)
{
if
(
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
BC
)
{
}
else
if
(
containsAt
(
format
,
i
,
"SYYYY"
)
!=
null
)
{
// Should be <= 0, but Oracle prints negative years with off-by-one difference
if
(
year
<
0
)
{
output
.
append
(
'-'
);
}
output
.
append
(
new
DecimalFormat
(
"0000"
).
format
(
getYear
(
cal
))
);
StringUtils
.
appendZeroPadded
(
output
,
4
,
posYear
);
i
+=
5
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"YYYY"
,
"IYYY"
,
"RRRR"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"0000"
).
format
(
getYear
(
cal
)));
}
else
if
(
containsAt
(
format
,
i
,
"YYYY"
,
"RRRR"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
4
,
posYear
);
i
+=
4
;
}
else
if
(
containsAt
(
format
,
i
,
"IYYY"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
4
,
Math
.
abs
(
DateTimeUtils
.
getIsoWeekYear
(
dateValue
)));
i
+=
4
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"YYY"
,
"IYY"
)
)
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"000"
).
format
(
getYear
(
cal
)
%
1000
)
);
}
else
if
(
containsAt
(
format
,
i
,
"YYY"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
3
,
posYear
%
1000
);
i
+=
3
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"YY"
,
"IY"
,
"RR"
))
!=
null
)
{
output
.
append
(
new
DecimalFormat
(
"00"
).
format
(
getYear
(
cal
)
%
100
));
}
else
if
(
containsAt
(
format
,
i
,
"IYY"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
3
,
Math
.
abs
(
DateTimeUtils
.
getIsoWeekYear
(
dateValue
))
%
1000
);
i
+=
3
;
}
else
if
(
containsAt
(
format
,
i
,
"YY"
,
"RR"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
posYear
%
100
);
i
+=
2
;
}
else
if
(
containsAt
(
format
,
i
,
"IY"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
Math
.
abs
(
DateTimeUtils
.
getIsoWeekYear
(
dateValue
))
%
100
);
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"I"
,
"Y"
))
!=
null
)
{
output
.
append
(
getYear
(
cal
)
%
10
);
}
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
;
// Month / quarter
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MONTH"
))
!=
null
)
{
String
month
=
new
SimpleDateFormat
(
"MMMM"
).
format
(
ts
)
;
String
month
=
getNames
(
MONTHS
)[
monthOfYear
-
1
]
;
if
(
fillMode
)
{
month
=
StringUtils
.
pad
(
month
,
"September"
.
length
(),
" "
,
true
);
}
output
.
append
(
cap
.
apply
(
month
));
i
+=
5
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"MON"
))
!=
null
)
{
String
month
=
new
SimpleDateFormat
(
"MMM"
).
format
(
ts
)
;
String
month
=
getNames
(
SHORT_MONTHS
)[
monthOfYear
-
1
]
;
output
.
append
(
cap
.
apply
(
month
));
i
+=
3
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"MM"
)
)
!=
null
)
{
output
.
append
(
String
.
format
(
"%02d"
,
cal
.
get
(
Calendar
.
MONTH
)
+
1
)
);
}
else
if
(
containsAt
(
format
,
i
,
"MM"
)
!=
null
)
{
StringUtils
.
appendZeroPadded
(
output
,
2
,
monthOfYear
);
i
+=
2
;
}
else
if
((
cap
=
containsAt
(
format
,
i
,
"RM"
))
!=
null
)
{
int
month
=
cal
.
get
(
Calendar
.
MONTH
)
+
1
;
output
.
append
(
cap
.
apply
(
toRomanNumeral
(
month
)));
output
.
append
(
cap
.
apply
(
toRomanNumeral
(
monthOfYear
)));
i
+=
2
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"Q"
)
)
!=
null
)
{
int
q
=
(
int
)
(
1
+
Math
.
floor
(
cal
.
get
(
Calendar
.
MONTH
)
/
3
)
);
}
else
if
(
containsAt
(
format
,
i
,
"Q"
)
!=
null
)
{
int
q
=
1
+
((
monthOfYear
-
1
)
/
3
);
output
.
append
(
q
);
i
+=
1
;
// Local radix character
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"X"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"X"
)
!=
null
)
{
char
c
=
DecimalFormatSymbols
.
getInstance
().
getDecimalSeparator
();
output
.
append
(
c
);
i
+=
1
;
// Format modifiers
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"FM"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"FM"
)
!=
null
)
{
fillMode
=
!
fillMode
;
i
+=
2
;
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"FX"
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"FX"
)
!=
null
)
{
i
+=
2
;
// Literal text
}
else
if
(
(
cap
=
containsAt
(
format
,
i
,
"\""
)
)
!=
null
)
{
}
else
if
(
containsAt
(
format
,
i
,
"\""
)
!=
null
)
{
for
(
i
=
i
+
1
;
i
<
format
.
length
();
i
++)
{
char
c
=
format
.
charAt
(
i
);
if
(
c
!=
'"'
)
{
...
...
@@ -835,14 +917,6 @@ public class ToChar {
return
output
.
toString
();
}
private
static
int
getYear
(
Calendar
cal
)
{
int
year
=
cal
.
get
(
Calendar
.
YEAR
);
if
(
cal
.
get
(
Calendar
.
ERA
)
==
GregorianCalendar
.
BC
)
{
year
--;
}
return
year
;
}
/**
* Returns a capitalization strategy if the specified string contains any of
* the specified substrings at the specified index. The capitalization
...
...
h2/src/main/org/h2/util/ToDateParser.java
浏览文件 @
9e5d9644
...
...
@@ -7,9 +7,13 @@ package org.h2.util;
import
static
java
.
lang
.
String
.
format
;
import
java.sql.Timestamp
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
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>
...
...
@@ -21,8 +25,29 @@ public class ToDateParser {
private
final
ConfigParam
functionName
;
private
String
inputStr
;
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
...
...
@@ -31,20 +56,6 @@ public class ToDateParser {
* code)
*/
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
;
inputStr
=
input
.
trim
();
// Keep a copy
...
...
@@ -59,30 +70,65 @@ public class ToDateParser {
unmodifiedFormatStr
=
formatStr
;
}
private
static
ToDateParser
get
DateParser
(
String
input
,
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_DATE
,
input
,
format
);
private
static
ToDateParser
get
TimestampParser
(
ConfigParam
param
,
String
input
,
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
param
,
input
,
format
);
parse
(
result
);
return
result
;
}
private
static
ToDateParser
getTimestampParser
(
String
input
,
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_TIMESTAMP
,
input
,
format
);
parse
(
result
);
return
result
;
}
private
Timestamp
getResultingTimestamp
()
{
Calendar
cal
=
(
Calendar
)
getResultCalendar
().
clone
();
int
nanosToSet
=
nanos
==
null
?
cal
.
get
(
Calendar
.
MILLISECOND
)
*
1000000
:
nanos
.
intValue
();
cal
.
set
(
Calendar
.
MILLISECOND
,
0
);
Timestamp
ts
=
new
Timestamp
(
cal
.
getTimeInMillis
());
ts
.
setNanos
(
nanosToSet
);
return
ts
;
private
ValueTimestamp
getResultingValue
()
{
long
dateValue
;
if
(
absoluteDayValid
)
{
dateValue
=
DateTimeUtils
.
dateValueFromAbsoluteDay
(
absoluteDay
);
}
else
{
int
year
=
this
.
year
;
if
(
year
==
0
)
{
year
=
getCurrentYear
();
}
if
(
bc
)
{
year
=
1
-
year
;
}
if
(
doyValid
)
{
dateValue
=
DateTimeUtils
.
dateValueFromAbsoluteDay
(
DateTimeUtils
.
absoluteDayFromDateValue
(
DateTimeUtils
.
dateValue
(
year
,
1
,
1
))
+
dayOfYear
-
1
);
}
else
{
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
()
{
return
resultCalendar
;
private
ValueTimestampTimeZone
getResultingValueWithTimeZone
()
{
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
()
{
...
...
@@ -97,10 +143,111 @@ public class ToDateParser {
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
)
{
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
()
{
return
formatStr
.
length
()
>
0
;
}
...
...
@@ -180,9 +327,21 @@ public class ToDateParser {
* @param format the format
* @return the timestamp
*/
public
static
Timestamp
toTimestamp
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getTimestampParser
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
public
static
ValueTimestamp
toTimestamp
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getTimestampParser
(
ConfigParam
.
TO_TIMESTAMP
,
input
,
format
);
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 {
* @param format the format
* @return the date as a timestamp
*/
public
static
Timestamp
toDate
(
String
input
,
String
format
)
{
ToDateParser
parser
=
get
DateParser
(
input
,
format
);
return
parser
.
getResulting
Timestamp
();
public
static
Value
Timestamp
toDate
(
String
input
,
String
format
)
{
ToDateParser
parser
=
get
TimestampParser
(
ConfigParam
.
TO_DATE
,
input
,
format
);
return
parser
.
getResulting
Value
();
}
/**
...
...
@@ -202,7 +361,8 @@ public class ToDateParser {
*/
private
enum
ConfigParam
{
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
;
ConfigParam
(
String
defaultFormatStr
)
{
...
...
h2/src/main/org/h2/util/ToDateTokenizer.java
浏览文件 @
9e5d9644
...
...
@@ -6,17 +6,12 @@
package
org
.
h2
.
util
;
import
static
java
.
lang
.
String
.
format
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Calendar
;
import
java.util.Collections
;
import
java.util.Date
;
import
java.util.GregorianCalendar
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Locale
;
import
java.util.Map
;
import
java.util.TimeZone
;
import
java.util.regex.Matcher
;
...
...
@@ -144,38 +139,36 @@ class ToDateTokenizer {
* Parslet responsible for parsing year parameter
*/
static
class
YearParslet
implements
ToDateParslet
{
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
case
SYYYY:
case
YYYY:
case
IYYY:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_FOUR_DIGITS
,
params
,
formatTokenEnum
);
// only necessary for Java1.6
if
(
inputFragmentStr
.
startsWith
(
"+"
))
{
inputFragmentStr
=
inputFragmentStr
.
substring
(
1
);
}
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
if
(
dateNr
==
0
)
{
throwException
(
params
,
"Year may not be zero"
);
}
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
params
.
setYear
(
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
case
YYY:
case
IYY:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_THREE_DIGITS
,
params
,
formatTokenEnum
);
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.
// 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
;
case
RRRR:
inputFragmentStr
=
matchStringOrThrow
(
...
...
@@ -191,15 +184,14 @@ class ToDateTokenizer {
if
(
dateNr
==
0
)
{
throwException
(
params
,
"Year may not be zero"
);
}
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
params
.
setYear
(
dateNr
);
break
;
case
RR:
Calendar
calendar
=
DateTimeUtils
.
createGregorianCalendar
();
int
cc
=
calendar
.
get
(
Calendar
.
YEAR
)
/
100
;
int
cc
=
params
.
getCurrentYear
()
/
100
;
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
)
+
cc
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
params
.
setYear
(
dateNr
);
break
;
case
EE
/* NOT supported yet */
:
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
...
...
@@ -210,38 +202,40 @@ class ToDateTokenizer {
formatTokenEnum
.
name
()));
break
;
case
YY:
case
IY:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
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.
// 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
;
case
SCC:
case
CC:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
)
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
params
.
setYear
(
dateNr
);
break
;
case
Y:
case
I:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
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.
// 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
;
case
BC_AD:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_BC_AD
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
))
{
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
BC
);
}
else
{
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
AD
);
}
params
.
setBC
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
));
break
;
default
:
throw
new
IllegalArgumentException
(
format
(
...
...
@@ -262,29 +256,26 @@ class ToDateTokenizer {
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
s
=
params
.
getInputStr
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
case
MONTH:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
LONG
);
inputFragmentStr
=
setByName
(
params
,
ToChar
.
MONTHS
);
break
;
case
Q
/* NOT supported yet */
:
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
break
;
case
MON:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
SHORT
);
inputFragmentStr
=
setByName
(
params
,
ToChar
.
SHORT_MONTHS
);
break
;
case
MM:
// Note: In Calendar Month go from 0 - 11
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MONTH
,
dateNr
-
1
);
params
.
setMonth
(
dateNr
);
break
;
case
RM:
dateNr
=
0
;
...
...
@@ -293,7 +284,7 @@ class ToDateTokenizer {
int
len
=
monthName
.
length
();
if
(
s
.
length
()
>=
len
&&
monthName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
result
.
set
(
Calendar
.
MONTH
,
dateNr
);
params
.
setMonth
(
dateNr
+
1
);
inputFragmentStr
=
monthName
;
break
;
}
...
...
@@ -322,7 +313,6 @@ class ToDateTokenizer {
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
...
...
@@ -330,40 +320,31 @@ class ToDateTokenizer {
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_YEAR
,
dateNr
);
params
.
setDayOfYear
(
dateNr
);
break
;
case
DD:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
params
.
setDay
(
dateNr
);
break
;
case
D:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
params
.
setDay
(
dateNr
);
break
;
case
DAY:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
DAY_OF_WEEK
,
Calendar
.
LONG
);
inputFragmentStr
=
setByName
(
params
,
ToChar
.
WEEKDAYS
);
break
;
case
DY:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
DAY_OF_WEEK
,
Calendar
.
SHORT
);
inputFragmentStr
=
setByName
(
params
,
ToChar
.
SHORT_WEEKDAYS
);
break
;
case
J:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
try
{
Date
date
=
new
SimpleDateFormat
(
"Myydd"
)
.
parse
(
inputFragmentStr
);
result
.
setTime
(
date
);
}
catch
(
ParseException
e
)
{
throwException
(
params
,
format
(
"Failed to parse Julian date: %s"
,
inputFragmentStr
));
}
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
params
.
setAbsoluteDay
(
dateNr
+
ToChar
.
JULIAN_EPOCH
);
break
;
default
:
throw
new
IllegalArgumentException
(
format
(
...
...
@@ -382,7 +363,6 @@ class ToDateTokenizer {
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
...
...
@@ -390,97 +370,76 @@ class ToDateTokenizer {
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
dateNr
);
params
.
setHour
(
dateNr
);
break
;
case
HH12:
case
HH:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR
,
dateNr
);
params
.
setHour12
(
dateNr
);
break
;
case
MI:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MINUTE
,
dateNr
);
params
.
setMinute
(
dateNr
);
break
;
case
SS:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
params
.
setSecord
(
dateNr
);
break
;
case
SSSSS:
case
SSSSS:
{
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
result
.
set
(
Calendar
.
MINUTE
,
0
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
int
second
=
dateNr
%
60
;
dateNr
/=
60
;
int
minute
=
dateNr
%
60
;
dateNr
/=
60
;
int
hour
=
dateNr
%
24
;
params
.
setHour
(
hour
);
params
.
setMinute
(
minute
);
params
.
setSecord
(
second
);
break
;
}
case
FF:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
String
paddedRightNrStr
=
format
(
"%-9s"
,
inputFragmentStr
)
.
replace
(
' '
,
'0'
);
paddedRightNrStr
=
paddedRightNrStr
.
substring
(
0
,
9
);
Double
nineDigits
=
Double
.
parseDouble
(
paddedRightNrStr
);
params
.
setNanos
(
nineDigits
.
intValue
());
dateNr
=
(
int
)
Math
.
round
(
nineDigits
/
1000000.0
);
result
.
set
(
Calendar
.
MILLISECOND
,
dateNr
);
double
nineDigits
=
Double
.
parseDouble
(
paddedRightNrStr
);
params
.
setNanos
((
int
)
nineDigits
);
break
;
case
AM_PM:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_AM_PM
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"A"
))
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
AM
);
params
.
setAmPm
(
true
);
}
else
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
PM
);
params
.
setAmPm
(
false
);
}
break
;
case
TZH:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
TimeZone
tz
=
result
.
getTimeZone
();
int
offsetMillis
=
tz
.
getRawOffset
();
// purge min and sec
offsetMillis
=
(
offsetMillis
/
MILLIS_IN_HOUR
)
*
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
offsetMillis
+
dateNr
);
result
.
setTimeZone
(
tz
);
params
.
setTimeZoneHour
(
dateNr
);
break
;
case
TZM:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
tz
=
result
.
getTimeZone
();
offsetMillis
=
tz
.
getRawOffset
();
// purge hour
offsetMillis
=
offsetMillis
%
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
dateNr
*
MILLIS_IN_HOUR
+
offsetMillis
);
result
.
setTimeZone
(
tz
);
params
.
setTimeZoneMinute
(
dateNr
);
break
;
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:
// Must correspond with TZR region. Example: PST (for US/Pacific
// standard time)
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
String
tzName
=
params
.
getInputStr
();
params
.
setTimeZone
(
TimeZone
.
getTimeZone
(
tzName
));
inputFragmentStr
=
tzName
;
break
;
default
:
throw
new
IllegalArgumentException
(
format
(
...
...
@@ -535,22 +494,33 @@ class ToDateTokenizer {
/**
* Set the given field in the calendar.
*
* @param c the calendar
* @param params the parameters with the input string
* @param field the field to set
* @param style the data type
* @return the matched value
*/
static
String
setByName
(
Calendar
c
,
ToDateParser
params
,
int
field
,
int
style
)
{
static
String
setByName
(
ToDateParser
params
,
int
field
)
{
String
inputFragmentStr
=
null
;
String
s
=
params
.
getInputStr
();
Map
<
String
,
Integer
>
timeStringMap
=
c
.
getDisplayNames
(
field
,
style
,
Locale
.
getDefault
());
for
(
String
dayName
:
timeStringMap
.
keySet
())
{
String
[]
values
=
ToChar
.
getNames
(
field
);
for
(
int
i
=
0
;
i
<
values
.
length
;
i
++)
{
String
dayName
=
values
[
i
];
if
(
dayName
==
null
)
{
continue
;
}
int
len
=
dayName
.
length
();
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
;
break
;
}
...
...
@@ -558,7 +528,7 @@ class ToDateTokenizer {
if
(
inputFragmentStr
==
null
||
inputFragmentStr
.
isEmpty
())
{
throwException
(
params
,
format
(
"Tried to parse one of '%s' but failed (may be an internal error?)"
,
timeStringMap
.
keySet
(
)));
Arrays
.
toString
(
values
)));
}
return
inputFragmentStr
;
}
...
...
@@ -583,9 +553,10 @@ class ToDateTokenizer {
YYYY
(
PARSLET_YEAR
),
// 4-digit year with sign (- = B.C.)
SYYYY
(
PARSLET_YEAR
),
// 4-digit year based on the ISO standard (?)
IYYY
(
PARSLET_YEAR
),
YYY
(
PARSLET_YEAR
),
IYY
(
PARSLET_YEAR
),
YY
(
PARSLET_YEAR
),
IY
(
PARSLET_YEAR
),
// 3-digit year
YYY
(
PARSLET_YEAR
),
// 2-digit year
YY
(
PARSLET_YEAR
),
// Two-digit century with with sign (- = B.C.)
SCC
(
PARSLET_YEAR
),
// Two-digit century.
...
...
@@ -638,7 +609,7 @@ class ToDateTokenizer {
// NOT supported yet -
// Abbreviated era name (Japanese Imperial,
// 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).
Q
(
PARSLET_MONTH
),
// Day of week (1-7).
...
...
h2/src/main/org/h2/value/Transfer.java
浏览文件 @
9e5d9644
...
...
@@ -14,7 +14,6 @@ import java.io.Reader;
import
java.math.BigDecimal
;
import
java.net.InetAddress
;
import
java.net.Socket
;
import
java.nio.charset.StandardCharsets
;
import
java.sql.ResultSet
;
import
java.sql.ResultSetMetaData
;
import
java.sql.SQLException
;
...
...
@@ -463,10 +462,6 @@ public class Transfer {
throw
DbException
.
get
(
ErrorCode
.
CONNECTION_BROKEN_1
,
"length="
+
length
);
}
if
(
length
>
Integer
.
MAX_VALUE
)
{
throw
DbException
.
get
(
ErrorCode
.
CONNECTION_BROKEN_1
,
"length="
+
length
);
}
writeLong
(
length
);
Reader
reader
=
v
.
getReader
();
Data
.
copyString
(
reader
,
out
);
...
...
@@ -652,21 +647,10 @@ public class Transfer {
return
ValueLobDb
.
create
(
Value
.
CLOB
,
session
.
getDataHandler
(),
tableId
,
id
,
hmac
,
precision
);
}
if
(
length
<
0
||
length
>
Integer
.
MAX_VALUE
)
{
if
(
length
<
0
)
{
throw
DbException
.
get
(
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
().
createClob
(
new
DataReader
(
in
),
length
);
...
...
h2/src/main/org/h2/value/ValueLobDb.java
浏览文件 @
9e5d9644
...
...
@@ -26,6 +26,7 @@ import org.h2.store.FileStoreInputStream;
import
org.h2.store.FileStoreOutputStream
;
import
org.h2.store.LobStorageFrontend
;
import
org.h2.store.LobStorageInterface
;
import
org.h2.store.RangeReader
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.MathUtils
;
...
...
@@ -544,6 +545,15 @@ public class ValueLobDb extends Value implements Value.ValueClob,
*/
public
static
ValueLobDb
createTempClob
(
Reader
in
,
long
length
,
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
;
if
(
in
instanceof
BufferedReader
)
{
reader
=
(
BufferedReader
)
in
;
...
...
h2/src/main/org/h2/value/ValueTimestampTimeZone.java
浏览文件 @
9e5d9644
...
...
@@ -9,8 +9,6 @@ import java.math.BigDecimal;
import
java.sql.PreparedStatement
;
import
java.sql.SQLException
;
import
java.sql.Timestamp
;
import
java.util.SimpleTimeZone
;
import
java.util.TimeZone
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.TimestampWithTimeZone
;
import
org.h2.message.DbException
;
...
...
@@ -148,19 +146,6 @@ public class ValueTimestampTimeZone extends Value {
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
public
Timestamp
getTimestamp
()
{
throw
new
UnsupportedOperationException
(
"unimplemented"
);
...
...
@@ -219,34 +204,31 @@ public class ValueTimestampTimeZone extends Value {
@Override
protected
int
compareSecure
(
Value
o
,
CompareMode
mode
)
{
ValueTimestampTimeZone
t
=
(
ValueTimestampTimeZone
)
o
;
//
We are pretending that the dateValue is in UTC because that gives us
// a
stable sort even if the DST database changes.
// convert to minutes and add timezone offset
long
a
=
DateTimeUtils
.
convertDateValueToMillis
(
DateTimeUtils
.
UTC
,
dateValue
)
/
(
1000L
*
60L
)
;
long
ma
=
timeNanos
/
(
1000L
*
1000L
*
1000L
*
60L
);
a
+=
ma
;
a
-=
timeZoneOffsetMins
;
// convert to minutes and add timezone offset
long
b
=
DateTimeUtils
.
convertDateValueToMillis
(
DateTimeUtils
.
UTC
,
t
.
dateValue
)
/
(
1000L
*
60L
)
;
long
mb
=
t
.
timeNanos
/
(
1000L
*
1000L
*
1000L
*
60L
)
;
b
+=
mb
;
b
-=
t
.
timeZoneOffsetMins
;
// compare date
int
c
=
Long
.
compare
(
a
,
b
);
if
(
c
!=
0
)
{
return
c
;
//
Maximum time zone offset is +/-18 hours so difference in days between local
// a
nd UTC cannot be more than one day
long
daysA
=
DateTimeUtils
.
absoluteDayFromDateValue
(
dateValue
);
long
timeA
=
timeNanos
-
timeZoneOffsetMins
*
60_000_000_000L
;
if
(
timeA
<
0
)
{
timeA
+=
DateTimeUtils
.
NANOS_PER_DAY
;
daysA
--
;
}
else
if
(
timeA
>=
DateTimeUtils
.
NANOS_PER_DAY
)
{
timeA
-=
DateTimeUtils
.
NANOS_PER_DAY
;
daysA
++
;
}
long
daysB
=
DateTimeUtils
.
absoluteDayFromDateValue
(
t
.
dateValue
);
long
timeB
=
t
.
timeNanos
-
t
.
timeZoneOffsetMins
*
60_000_000_000L
;
if
(
timeB
<
0
)
{
timeB
+=
DateTimeUtils
.
NANOS_PER_DAY
;
daysB
--
;
}
else
if
(
timeB
>=
DateTimeUtils
.
NANOS_PER_DAY
)
{
timeB
-=
DateTimeUtils
.
NANOS_PER_DAY
;
daysB
++;
}
int
c
mp
=
Long
.
compare
(
daysA
,
daysB
);
if
(
c
mp
!=
0
)
{
return
c
mp
;
}
// compare time
long
na
=
timeNanos
-
(
ma
*
1000L
*
1000L
*
1000L
*
60L
);
long
nb
=
t
.
timeNanos
-
(
mb
*
1000L
*
1000L
*
1000L
*
60L
);
return
Long
.
compare
(
na
,
nb
);
return
Long
.
compare
(
timeA
,
timeB
);
}
@Override
...
...
h2/src/test/org/h2/test/TestBase.java
浏览文件 @
9e5d9644
...
...
@@ -6,6 +6,7 @@
package
org
.
h2
.
test
;
import
java.io.ByteArrayInputStream
;
import
java.io.File
;
import
java.io.FileWriter
;
import
java.io.IOException
;
import
java.io.InputStream
;
...
...
@@ -30,7 +31,9 @@ import java.sql.Types;
import
java.text.DateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.SimpleTimeZone
;
import
java.util.concurrent.TimeUnit
;
...
...
@@ -40,6 +43,7 @@ import org.h2.store.fs.FilePath;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.utils.ProxyCodeGenerator
;
import
org.h2.test.utils.ResultVerifier
;
import
org.h2.test.utils.SelfDestructor
;
import
org.h2.tools.DeleteDbFiles
;
/**
...
...
@@ -466,16 +470,16 @@ public abstract class TestBase {
throw
new
AssertionError
(
string
);
}
/**
* Log an error message.
*
* @param s the message
*/
public
static
void
logErrorMessage
(
String
s
)
{
System
.
out
.
flush
();
System
.
err
.
println
(
"ERROR: "
+
s
+
"------------------------------"
);
logThrowable
(
s
,
null
);
}
/**
* Log an error message.
*
* @param s the message
*/
public
static
void
logErrorMessage
(
String
s
)
{
System
.
out
.
flush
();
System
.
err
.
println
(
"ERROR: "
+
s
+
"------------------------------"
);
logThrowable
(
s
,
null
);
}
/**
* Log an error message.
...
...
@@ -1444,6 +1448,16 @@ public abstract class TestBase {
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.
*
...
...
@@ -1687,4 +1701,46 @@ public abstract class TestBase {
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;
import
java.util.Calendar
;
import
java.util.Currency
;
import
java.util.Date
;
import
java.util.GregorianCalendar
;
import
java.util.HashMap
;
import
java.util.Locale
;
import
java.util.Properties
;
...
...
@@ -56,6 +57,8 @@ import org.h2.util.StringUtils;
import
org.h2.util.ToChar.Capitalization
;
import
org.h2.util.ToDateParser
;
import
org.h2.value.Value
;
import
org.h2.value.ValueTimestamp
;
import
org.h2.value.ValueTimestampTimeZone
;
/**
* Tests for user defined functions and aggregates.
...
...
@@ -1296,10 +1299,13 @@ public class TestFunctions extends TestBase implements AggregateFunction {
}
private
void
testToDate
()
throws
ParseException
{
final
int
month
=
DateTimeUtils
.
createGregorianCalendar
().
get
(
Calendar
.
MONTH
);
Date
date
=
null
;
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1979-11-12"
);
GregorianCalendar
calendar
=
DateTimeUtils
.
createGregorianCalendar
();
int
year
=
calendar
.
get
(
Calendar
.
YEAR
);
int
month
=
calendar
.
get
(
Calendar
.
MONTH
)
+
1
;
// 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*foo*1112"
,
"YYYY\"*foo*\"MM\"\"DD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979-11-12"
,
"YYYY-MM-DD"
));
...
...
@@ -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"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"1979"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
"1979-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979"
,
"YYYY"
));
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 BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979"
,
"IYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"+1979"
,
"SYYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"RRRR"
));
date
=
new
SimpleDateFormat
(
"yyyy-mm"
).
parse
(
"1970-12"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"00:12:00"
);
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
(
"XI"
,
"RM"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"9"
)
;
setMonth
(
date
,
month
);
int
y
=
(
year
/
10
)
*
10
+
9
;
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"9"
,
"Y"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"9"
,
"I"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"79"
);
setMonth
(
date
,
month
);
y
=
(
year
/
100
)
*
100
+
79
;
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"YY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"IY"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"979"
);
setMonth
(
date
,
month
);
y
=
(
year
/
1_000
)
*
1_000
+
979
;
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"979"
,
"YYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"979"
,
"IYY"
));
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date
=
new
SimpleDateFormat
(
"yyy"
).
parse
(
"-99"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
"-99-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"0100 BC"
,
"YYYY BC"
));
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"
,
"YYYY"
));
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date
=
new
SimpleDateFormat
(
"y"
).
parse
(
"0"
);
setMonth
(
date
,
month
);
y
=
-((
year
/
1_000
)
*
1_000
+
99
);
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"
));
y
=
-((
year
/
10
)
*
10
);
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1 BC"
,
"Y BC"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:00"
);
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"
,
"HH24:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:00"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH:MI"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH12:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:34"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:34"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34"
,
"HH:MI:SS"
));
date
=
new
SimpleDateFormat
(
"ss"
).
parse
(
"34"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"12:00:00"
);
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"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss"
).
parse
(
"1970 08:12:34"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:34"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"29554"
,
"SSSSS"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss SSS"
).
parse
(
"1970 08:12:34 550"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:34.550"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34 550"
,
"HH:MI:SS FF"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34 55"
,
"HH:MI:SS FF2"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"14:04:00"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"14:04:00"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"02:04 P.M."
,
"HH:MI p.M."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"02:04 PM"
,
"HH:MI PM"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-12-12"
);
// does not work in all timezones
// assertEquals(date, ToDateParser.toDate("12", "DD"));
date
=
ValueTimestamp
.
parse
(
"1970-"
+
month
+
"-12"
);
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"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
)
.
parse
(
"2013-01-29"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"
113029
"
,
"J"
));
date
=
ValueTimestamp
.
parse
(
"2013-01-29"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"
2456322
"
,
"J"
));
if
(
Locale
.
getDefault
()
==
Locale
.
ENGLISH
)
{
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd'T'HH:mm:ss"
).
parse
(
"9999-12-31T
23:59:59"
);
if
(
Locale
.
getDefault
()
.
getLanguage
().
equals
(
"en"
)
)
{
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-RRRR HH24:MI:SS"
));
SimpleDateFormat
ymd
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
);
assertEquals
(
ymd
.
parse
(
"0001-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-0001"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"9999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-9999"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-000"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-099"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"0100-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-100"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-00"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"2049-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-49"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"1950-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-50"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-99"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
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
(
ValueTimestamp
.
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
(
ValueTimestamp
.
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
(
ValueTimestamp
.
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
(
ValueTimestamp
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-99"
,
"DD-MON-RRRR"
));
}
}
private
static
void
setMonth
(
Date
date
,
int
month
)
{
Calendar
c
=
DateTimeUtils
.
createGregorianCalendar
();
c
.
setTime
(
date
);
c
.
set
(
Calendar
.
MONTH
,
month
);
date
.
setTime
(
c
.
getTimeInMillis
());
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"
));
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-05-10 10:11:12-08:15"
),
ToDateParser
.
toTimestampTz
(
"2000-05-10 10:11:12 GMT-08:15"
,
"YYYY-MM-DD HH24:MI:SS TZR"
));
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-02-10 10:11:12-08"
),
ToDateParser
.
toTimestampTz
(
"2000-02-10 10:11:12 US/Pacific"
,
"YYYY-MM-DD HH24:MI:SS TZR"
));
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
{
...
...
@@ -1453,7 +1457,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertResult
(
"-100-01-15 14:04:02.12"
,
stat
,
"SELECT X FROM U"
);
String
expected
=
String
.
format
(
"%tb"
,
timestamp1979
).
toUpperCase
();
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"
);
assertResult
(
"- / , . ; : text - /"
,
stat
,
"SELECT TO_CHAR(X, '- / , . ; : \"text\" - /') FROM T"
);
...
...
@@ -1486,12 +1490,25 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertResult
(
"0 BC"
,
stat
,
"SELECT TO_CHAR(X, 'Y BC') FROM U"
);
assertResult
(
"1979 A.D."
,
stat
,
"SELECT TO_CHAR(X, 'YYYY B.C.') FROM T"
);
assertResult
(
"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 A.M."
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI A.M.') FROM T"
);
assertResult
(
"02:04 P.M."
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI A.M.') FROM U"
);
assertResult
(
"08:12 AM"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI PM') FROM T"
);
assertResult
(
"02:04 PM"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI PM') FROM U"
);
assertResult
(
"08:12 A.M."
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI P.M.') FROM T"
);
assertResult
(
"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"
);
...
...
@@ -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
(
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"
);
assertResult
(
"08:12:34.5"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF1') FROM T"
);
...
...
@@ -1552,10 +1569,10 @@ public class TestFunctions extends TestBase implements AggregateFunction {
"SELECT TO_CHAR(X, 'HH:MI:SS.FF8') FROM T"
);
assertResult
(
"08:12:34.560000000"
,
stat
,
"SELECT TO_CHAR(X, 'HH:MI:SS.FF9') FROM T"
);
assertResult
(
"0
8:12:34.560000000
"
,
stat
,
"SELECT TO_CHAR(
X, 'HH:MI:SS.ff9
') FROM T"
);
assertResult
(
"0
8:12:34.56000000
0"
,
stat
,
"SELECT TO_CHAR(
X, 'HH:MI:SS.fF9
') FROM T"
);
assertResult
(
"0
12345678
"
,
stat
,
"SELECT TO_CHAR(
TIME '0:00:00.012345678', 'FF
') FROM T"
);
assertResult
(
"00"
,
stat
,
"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, 'HH12: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 {
assertResult
(
expected
,
stat
,
"SELECT TO_CHAR(X, 'TS') FROM T"
);
assertResult
(
tzLongName
,
stat
,
"SELECT TO_CHAR(X, 'TZR') FROM T"
);
assertResult
(
tzShortName
,
stat
,
"SELECT TO_CHAR(X, 'TZD') FROM T"
);
assertResult
(
"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
);
assertResult
(
expected
,
stat
,
"SELECT TO_CHAR(X, 'X') FROM T"
);
expected
=
String
.
format
(
"%,d"
,
1979
);
...
...
@@ -1903,7 +1924,8 @@ public class TestFunctions extends TestBase implements AggregateFunction {
final
String
twoDecimals
=
"0"
+
decimalSeparator
+
"00"
;
assertResult
(
oneDecimal
,
stat
,
"select to_char(0, 'FM0D099') 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
(
oneDecimal
,
stat
,
"select to_char(0.0, 'FM0D099') 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;
import
java.util.Random
;
import
java.util.concurrent.atomic.AtomicReference
;
import
org.h2.api.ErrorCode
;
import
org.h2.message.DbException
;
import
org.h2.mvstore.MVStore
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePathMem
;
...
...
@@ -28,6 +27,8 @@ import org.h2.test.TestBase;
*/
public
class
TestOutOfMemory
extends
TestBase
{
private
static
final
String
DB_NAME
=
"outOfMemory"
;
/**
* Run just this test.
*
...
...
@@ -38,16 +39,18 @@ public class TestOutOfMemory extends TestBase {
}
@Override
public
void
test
()
throws
SQLException
,
Interrupted
Exception
{
public
void
test
()
throws
Exception
{
if
(
config
.
vmlens
)
{
// running out of memory will cause the vmlens agent to stop working
return
;
}
try
{
System
.
gc
();
testMVStoreUsingInMemoryFileSystem
();
System
.
gc
();
testDatabaseUsingInMemoryFileSystem
();
if
(!
config
.
travis
)
{
System
.
gc
();
testMVStoreUsingInMemoryFileSystem
();
System
.
gc
();
testDatabaseUsingInMemoryFileSystem
();
}
System
.
gc
();
testUpdateWhenNearlyOutOfMemory
();
}
finally
{
...
...
@@ -147,67 +150,92 @@ public class TestOutOfMemory extends TestBase {
}
}
private
void
testUpdateWhenNearlyOutOfMemory
()
throws
SQLException
,
Interrupted
Exception
{
private
void
testUpdateWhenNearlyOutOfMemory
()
throws
Exception
{
if
(
config
.
memory
)
{
return
;
}
recoverAfterOOM
();
deleteDb
(
"outOfMemory"
);
Connection
conn
=
getConnection
(
"outOfMemory;MAX_OPERATION_MEMORY=1000000"
);
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"drop all objects"
);
stat
.
execute
(
"create table stuff (id int, text varchar as space(100) || id)"
);
stat
.
execute
(
"insert into stuff(id) select x from system_range(1, 3000)"
);
PreparedStatement
prep
=
conn
.
prepareStatement
(
"update stuff set text = text || space(1000) || id"
);
prep
.
execute
();
stat
.
execute
(
"checkpoint"
);
eatMemory
(
80
);
try
{
try
{
prep
.
execute
();
fail
();
}
catch
(
DbException
ex
)
{
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
());
deleteDb
(
DB_NAME
);
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;
}
freeMemory
();
conn
=
null
;
conn
=
getConnection
(
"outOfMemory"
);
stat
=
conn
.
createStatement
();
ResultSet
rs
=
stat
.
executeQuery
(
"select count(*) from stuff"
);
rs
.
next
();
iter.remove();
}
MyChild.main(args.toArray(new String[0]));
//*/
try
(
Connection
conn
=
getConnection
(
DB_NAME
))
{
Statement
stat
=
conn
.
createStatement
();
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT count(*) FROM stuff"
);
assertTrue
(
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
{
freeMemory
();
if
(
conn
!=
null
)
{
try
{
conn
.
close
();
}
catch
(
SQLException
e
)
{
// out of memory will / may close the database
assertKnownException
(
e
);
}
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
);
}
deleteDb
(
"outOfMemory"
);
}
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
(
"UPDATE stuff SET text = IFNULL(text,'') || space(1000) || id"
);
prep
.
execute
();
stat
.
execute
(
"CHECKPOINT"
);
ResultSet
rs
=
stat
.
executeQuery
(
"SELECT sum(length(text)) FROM stuff"
);
assertTrue
(
rs
.
next
());
assertEquals
(
3010893
,
rs
.
getInt
(
1
));
eatMemory
(
80
);
prep
.
execute
();
fail
();
}
catch
(
SQLException
ignore
)
{
}
finally
{
freeMemory
();
}
}
}
}
h2/src/test/org/h2/test/jdbc/TestLobApi.java
浏览文件 @
9e5d9644
...
...
@@ -119,7 +119,20 @@ public class TestLobApi extends TestBase {
prep
.
setString
(
1
,
""
);
prep
.
setBytes
(
2
,
new
byte
[
0
]);
prep
.
execute
();
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
];
for
(
int
i
=
0
;
i
<
chars
.
length
;
i
++)
{
chars
[
i
]
=
(
char
)
r
.
nextInt
(
10000
);
...
...
@@ -130,6 +143,7 @@ public class TestLobApi extends TestBase {
r
.
nextBytes
(
bytes
);
prep
.
setBinaryStream
(
2
,
new
ByteArrayInputStream
(
bytes
),
-
1
);
prep
.
execute
();
conn
.
setAutoCommit
(
false
);
ResultSet
rs
=
stat
.
executeQuery
(
"select * from test order by id"
);
rs
.
next
();
...
...
@@ -138,18 +152,27 @@ public class TestLobApi extends TestBase {
rs
.
next
();
Clob
c2
=
rs
.
getClob
(
2
);
Blob
b2
=
rs
.
getBlob
(
3
);
rs
.
next
();
Clob
c3
=
rs
.
getClob
(
2
);
Blob
b3
=
rs
.
getBlob
(
3
);
assertFalse
(
rs
.
next
());
// now close
rs
.
close
();
// but the LOBs must stay open
assertEquals
(
0
,
c1
.
length
());
assertEquals
(
0
,
b1
.
length
());
assertEquals
(
chars
.
length
,
c2
.
length
());
assertEquals
(
bytes
.
length
,
b2
.
length
());
assertEquals
(
""
,
c1
.
getSubString
(
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"
);
conn
.
close
();
}
...
...
h2/src/test/org/h2/test/scripts/TestScript.java
浏览文件 @
9e5d9644
...
...
@@ -92,7 +92,7 @@ public class TestScript extends TestBase {
}
else
{
decimal2
=
"decimal_numeric"
;
}
for
(
String
s
:
new
String
[]
{
"array"
,
"bigint"
,
"binary"
,
"blob"
,
"boolean"
,
"char"
,
"clob"
,
"date"
,
"decimal"
,
decimal2
,
"double"
,
"enum"
,
"geometry"
,
"identity"
,
"int"
,
"other"
,
"real"
,
"smallint"
,
...
...
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');
>
2001
-
02
-
03
04
:
05
:
06
.
790001
>
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'
);
>
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
>
3408134399000
>
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'
);
>
0
0
>
-
-
...
...
h2/src/test/org/h2/test/scripts/functions/timeanddate/extract.sql
浏览文件 @
9e5d9644
...
...
@@ -3,6 +3,20 @@
-- 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'
);
>
0
...
...
h2/src/test/org/h2/test/store/TestMVStoreBenchmark.java
浏览文件 @
9e5d9644
...
...
@@ -124,14 +124,6 @@ public class TestMVStoreBenchmark extends TestBase {
}
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
++)
{
System
.
gc
();
try
{
...
...
h2/src/test/org/h2/test/synth/TestFuzzOptimizations.java
浏览文件 @
9e5d9644
...
...
@@ -10,6 +10,7 @@ import java.sql.PreparedStatement;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Random
;
...
...
@@ -107,33 +108,37 @@ public class TestFuzzOptimizations extends TestBase {
ArrayList
<
String
>
params
=
New
.
arrayList
();
String
condition
=
getRandomCondition
(
random
,
params
,
columns
,
compares
,
values
);
// System.out.println(condition + " " + params);
PreparedStatement
prep0
=
conn
.
prepareStatement
(
"select * from test0 where "
+
condition
+
" order by 1, 2, 3"
);
PreparedStatement
prep1
=
conn
.
prepareStatement
(
"select * from test1 where "
+
condition
+
" order by 1, 2, 3"
);
for
(
int
j
=
0
;
j
<
params
.
size
();
j
++)
{
prep0
.
setString
(
j
+
1
,
params
.
get
(
j
));
prep1
.
setString
(
j
+
1
,
params
.
get
(
j
));
}
ResultSet
rs0
=
prep0
.
executeQuery
();
ResultSet
rs1
=
prep1
.
executeQuery
();
assertEquals
(
"seed: "
+
seed
+
" "
+
condition
,
rs0
,
rs1
);
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
);
prep0
.
setString
(
j
+
1
,
value
);
prep1
.
setString
(
j
+
1
,
value
);
}
assertEquals
(
"seed: "
+
seed
+
" "
+
condition
,
rs0
,
rs1
);
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
(
"select * from test0 where "
+
condition
+
" order by 1, 2, 3"
);
PreparedStatement
prep1
=
conn
.
prepareStatement
(
"select * from test1 where "
+
condition
+
" order by 1, 2, 3"
);
for
(
int
j
=
0
;
j
<
params
.
size
();
j
++)
{
prep0
.
setString
(
j
+
1
,
params
.
get
(
j
));
prep1
.
setString
(
j
+
1
,
params
.
get
(
j
));
}
ResultSet
rs0
=
prep0
.
executeQuery
();
ResultSet
rs1
=
prep1
.
executeQuery
();
assertEquals
(
message
,
rs0
,
rs1
);
}
private
String
getRandomCondition
(
Random
random
,
ArrayList
<
String
>
params
,
String
[]
columns
,
String
[]
compares
,
String
[]
values
)
{
int
comp
=
1
+
random
.
nextInt
(
4
);
...
...
h2/src/test/org/h2/test/unit/TestClearReferences.java
浏览文件 @
9e5d9644
...
...
@@ -26,6 +26,7 @@ public class TestClearReferences extends TestBase {
"org.h2.compress.CompressLZF.cachedHashTable"
,
"org.h2.engine.DbSettings.defaultSettings"
,
"org.h2.engine.SessionRemote.sessionFactory"
,
"org.h2.expression.Function.MONTHS_AND_WEEKS"
,
"org.h2.jdbcx.JdbcDataSourceFactory.cachedTraceSystem"
,
"org.h2.store.RecoverTester.instance"
,
"org.h2.store.fs.FilePath.defaultProvider"
,
...
...
@@ -36,6 +37,7 @@ public class TestClearReferences extends TestBase {
"org.h2.tools.CompressTool.cachedBuffer"
,
"org.h2.util.CloseWatcher.queue"
,
"org.h2.util.CloseWatcher.refs"
,
"org.h2.util.DateTimeUtils.timeZone"
,
"org.h2.util.MathUtils.cachedSecureRandom"
,
"org.h2.util.NetUtils.cachedLocalAddress"
,
"org.h2.util.StringUtils.softCache"
,
...
...
@@ -43,6 +45,7 @@ public class TestClearReferences extends TestBase {
"org.h2.util.JdbcUtils.allowedClassNamePrefixes"
,
"org.h2.util.JdbcUtils.userClassFactories"
,
"org.h2.util.Task.counter"
,
"org.h2.util.ToChar.NAMES"
,
"org.h2.value.CompareMode.lastUsed"
,
"org.h2.value.Value.softCache"
,
};
...
...
h2/src/test/org/h2/test/unit/TestDateTimeUtils.java
浏览文件 @
9e5d9644
...
...
@@ -5,13 +5,16 @@
*/
package
org
.
h2
.
test
.
unit
;
import
static
org
.
h2
.
util
.
DateTimeUtils
.
dateValue
;
import
java.sql.Timestamp
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
import
java.util.TimeZone
;
import
org.h2.test.TestBase
;
import
org.h2.util.DateTimeUtils
;
import
static
org
.
h2
.
util
.
DateTimeUtils
.
dateValue
;
import
org.h2.value.ValueTimestamp
;
/**
* Unit tests for the DateTimeUtils class
...
...
@@ -21,9 +24,18 @@ public class TestDateTimeUtils extends TestBase {
/**
* 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
{
if
(
a
.
length
==
1
)
{
if
(
"testUtc2Value"
.
equals
(
a
[
0
]))
{
new
TestDateTimeUtils
().
testUTC2Value
(
true
);
return
;
}
}
TestBase
.
createCaller
().
init
().
test
();
}
...
...
@@ -33,6 +45,7 @@ public class TestDateTimeUtils extends TestBase {
testDayOfWeek
();
testWeekOfYear
();
testDateValueFromDenormalizedDate
();
testUTC2Value
(
false
);
}
private
void
testParseTimeNanosDB2Format
()
{
...
...
@@ -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)}.
*/
private
void
testDayOfWeek
()
{
...
...
@@ -106,4 +119,45 @@ public class TestDateTimeUtils extends TestBase {
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 {
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"
);
int
c
=
a
.
compareTo
(
b
,
null
);
assertEquals
(
c
,
1
);
assertEquals
(
1
,
c
);
c
=
b
.
compareTo
(
a
,
null
);
assertEquals
(-
1
,
c
);
}
private
void
test3
()
{
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"
);
int
c
=
a
.
compareTo
(
b
,
null
);
assertEquals
(
c
,
1
);
assertEquals
(
1
,
c
);
c
=
b
.
compareTo
(
a
,
null
);
assertEquals
(-
1
,
c
);
}
private
void
test4
()
{
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"
);
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
{
...
...
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
9e5d9644
...
...
@@ -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
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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论