Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
7e8fa541
提交
7e8fa541
authored
1月 11, 2016
作者:
Thomas Mueller Graf
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Formatting / spellcheck
上级
3d253279
隐藏空白字符变更
内嵌
并排
正在显示
15 个修改的文件
包含
465 行增加
和
404 行删除
+465
-404
Function.java
h2/src/main/org/h2/expression/Function.java
+13
-3
JoinBatch.java
h2/src/main/org/h2/table/JoinBatch.java
+3
-3
DateTimeUtils.java
h2/src/main/org/h2/util/DateTimeUtils.java
+4
-1
ToDate.java
h2/src/main/org/h2/util/ToDate.java
+0
-19
ToDateParser.java
h2/src/main/org/h2/util/ToDateParser.java
+70
-56
ToDateTokenizer.java
h2/src/main/org/h2/util/ToDateTokenizer.java
+250
-204
Value.java
h2/src/main/org/h2/value/Value.java
+1
-1
ValueTimestampUtc.java
h2/src/main/org/h2/value/ValueTimestampUtc.java
+3
-3
TestFunctions.java
h2/src/test/org/h2/test/db/TestFunctions.java
+77
-69
TestOptimizations.java
h2/src/test/org/h2/test/db/TestOptimizations.java
+15
-15
TestTableEngines.java
h2/src/test/org/h2/test/db/TestTableEngines.java
+18
-18
TestDate.java
h2/src/test/org/h2/test/unit/TestDate.java
+2
-1
TestTimeStampUtc.java
h2/src/test/org/h2/test/unit/TestTimeStampUtc.java
+3
-3
BuildBase.java
h2/src/tools/org/h2/build/BuildBase.java
+1
-1
dictionary.txt
h2/src/tools/org/h2/build/doc/dictionary.txt
+5
-7
没有找到文件。
h2/src/main/org/h2/expression/Function.java
浏览文件 @
7e8fa541
...
...
@@ -44,7 +44,17 @@ import org.h2.table.Table;
import
org.h2.table.TableFilter
;
import
org.h2.tools.CompressTool
;
import
org.h2.tools.Csv
;
import
org.h2.util.*
;
import
org.h2.util.AutoCloseInputStream
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.JdbcUtils
;
import
org.h2.util.MathUtils
;
import
org.h2.util.New
;
import
org.h2.util.StatementBuilder
;
import
org.h2.util.StringUtils
;
import
org.h2.util.ToChar
;
import
org.h2.util.ToDateParser
;
import
org.h2.util.Utils
;
import
org.h2.value.DataType
;
import
org.h2.value.Value
;
import
org.h2.value.ValueArray
;
...
...
@@ -1424,11 +1434,11 @@ public class Function extends Expression implements FunctionCall {
}
break
;
case
TO_DATE:
result
=
ValueTimestamp
.
get
(
ToDate
.
TO_DATE
(
v0
.
getString
(),
result
=
ValueTimestamp
.
get
(
ToDate
Parser
.
toDate
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
()));
break
;
case
TO_TIMESTAMP:
result
=
ValueTimestamp
.
get
(
ToDate
.
TO_TIMESTAMP
(
v0
.
getString
(),
result
=
ValueTimestamp
.
get
(
ToDate
Parser
.
toTimestamp
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
()));
break
;
case
TRANSLATE:
{
...
...
h2/src/main/org/h2/table/JoinBatch.java
浏览文件 @
7e8fa541
...
...
@@ -410,9 +410,9 @@ public final class JoinBatch {
@Override
public
String
toString
()
{
return
"JoinBatch->\nprev->"
+
(
current
==
null
?
null
:
current
.
prev
)
+
"\ncurr->"
+
current
+
"\nnext->"
+
(
current
==
null
?
null
:
current
.
next
);
return
"JoinBatch->\n
"
+
"
prev->"
+
(
current
==
null
?
null
:
current
.
prev
)
+
"\n
"
+
"
curr->"
+
current
+
"\n
"
+
"
next->"
+
(
current
==
null
?
null
:
current
.
next
);
}
/**
...
...
h2/src/main/org/h2/util/DateTimeUtils.java
浏览文件 @
7e8fa541
...
...
@@ -11,7 +11,10 @@ import java.sql.Date;
import
java.sql.Time
;
import
java.sql.Timestamp
;
import
java.text.SimpleDateFormat
;
import
java.util.*
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
import
java.util.Locale
;
import
java.util.TimeZone
;
import
org.h2.api.ErrorCode
;
import
org.h2.message.DbException
;
...
...
h2/src/main/org/h2/util/ToDate.java
deleted
100644 → 0
浏览文件 @
3d253279
package
org
.
h2
.
util
;
import
java.sql.Timestamp
;
import
java.util.Date
;
/**
* Emulates Oracle's TO_DATE function.<br>
* Main class
*/
public
class
ToDate
{
public
static
Timestamp
TO_DATE
(
final
String
input
,
final
String
format
)
{
ToDateParser
parser
=
ToDateParser
.
toDate
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
}
public
static
Timestamp
TO_TIMESTAMP
(
final
String
input
,
final
String
format
)
{
ToDateParser
parser
=
ToDateParser
.
toTimestamp
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
}
}
\ No newline at end of file
h2/src/main/org/h2/util/ToDateParser.java
浏览文件 @
7e8fa541
/*
* Copyright 2004-2016 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: Daniel Gredler
*/
package
org
.
h2
.
util
;
import
static
java
.
lang
.
String
.
format
;
import
java.sql.Timestamp
;
import
java.util.Calendar
;
import
java.util.Date
;
import
java.util.List
;
/**
* Emulates Oracle's TO_DATE function.<br>
* This class holds and handles the input data form the TO_DATE-method
*/
class
ToDateParser
{
public
class
ToDateParser
{
private
final
String
unmodifiedInputStr
;
private
final
String
unmodifiedFormatStr
;
private
final
ConfigParam
functionName
;
private
String
inputStr
;
private
String
formatStr
;
private
final
Calendar
resultCalendar
=
(
Calendar
)
Calendar
.
getInstance
().
clone
();
private
Integer
nanos
=
null
;
private
enum
ConfigParam
{
TO_DATE
(
"DD MON YYYY"
),
TO_TIMESTAMP
(
"DD MON YYYY HH:MI:SS"
);
private
final
String
defaultFormatStr
;
ConfigParam
(
final
String
defaultFormatStr
)
{
this
.
defaultFormatStr
=
defaultFormatStr
;
}
String
getDefaultFormatStr
()
{
return
defaultFormatStr
;
}
}
static
ToDateParser
toDate
(
final
String
input
,
final
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_DATE
,
input
,
format
);
parse
(
result
);
return
result
;
}
static
ToDateParser
toTimestamp
(
final
String
input
,
final
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_TIMESTAMP
,
input
,
format
);
parse
(
result
);
return
result
;
}
private
Integer
nanos
;
/**
* @param input the input date with the date-time info
* @param format the format of date-time info
* @param functionName one of [TO_DATE, TO_TIMESTAMP] (both share the same code)
*/
ToDateParser
(
final
ConfigParam
functionName
,
final
String
input
,
final
String
format
)
{
private
ToDateParser
(
ConfigParam
functionName
,
String
input
,
String
format
)
{
// reset calendar - default oracle behaviour
resultCalendar
.
set
(
Calendar
.
YEAR
,
1970
);
resultCalendar
.
set
(
Calendar
.
MONTH
,
Calendar
.
getInstance
().
get
(
Calendar
.
MONTH
));
...
...
@@ -65,16 +46,31 @@ class ToDateParser {
this
.
functionName
=
functionName
;
inputStr
=
input
.
trim
();
unmodifiedInputStr
=
inputStr
;
// Keep a copy
// Keep a copy
unmodifiedInputStr
=
inputStr
;
if
(
format
==
null
||
format
.
isEmpty
())
{
formatStr
=
functionName
.
getDefaultFormatStr
();
// default Oracle format.
// default Oracle format.
formatStr
=
functionName
.
getDefaultFormatStr
();
}
else
{
formatStr
=
format
.
trim
();
}
unmodifiedFormatStr
=
formatStr
;
// Keep a copy
// Keep a copy
unmodifiedFormatStr
=
formatStr
;
}
private
static
ToDateParser
getDateParser
(
String
input
,
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_DATE
,
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
;
}
Timestamp
getResultingTimestamp
()
{
private
Timestamp
getResultingTimestamp
()
{
Calendar
cal
=
(
Calendar
)
getResultCalendar
().
clone
();
int
nanosToSet
=
nanos
==
null
?
cal
.
get
(
Calendar
.
MILLISECOND
)
*
1000000
:
nanos
.
intValue
();
cal
.
set
(
Calendar
.
MILLISECOND
,
0
);
...
...
@@ -99,15 +95,15 @@ class ToDateParser {
return
functionName
.
name
();
}
void
setNanos
(
final
int
nanos
)
{
void
setNanos
(
int
nanos
)
{
this
.
nanos
=
nanos
;
}
boolean
hasToParseData
()
{
private
boolean
hasToParseData
()
{
return
formatStr
.
length
()
>
0
;
}
void
removeFirstChar
()
{
private
void
removeFirstChar
()
{
if
(!
formatStr
.
isEmpty
())
{
formatStr
=
formatStr
.
substring
(
1
);
}
...
...
@@ -116,7 +112,7 @@ class ToDateParser {
}
}
private
static
ToDateParser
parse
(
final
ToDateParser
p
)
{
private
static
ToDateParser
parse
(
ToDateParser
p
)
{
while
(
p
.
hasToParseData
())
{
List
<
ToDateTokenizer
.
FormatTokenEnum
>
tokenList
=
ToDateTokenizer
.
FormatTokenEnum
.
getTokensInQuestion
(
p
.
getFormatStr
());
if
(
tokenList
.
isEmpty
())
{
...
...
@@ -138,19 +134,9 @@ class ToDateParser {
return
p
;
}
void
remove
(
final
String
toIgnore
)
{
if
(
toIgnore
!=
null
)
{
int
trimLeng
=
toIgnore
.
length
();
formatStr
=
formatStr
.
substring
(
trimLeng
);
if
(
inputStr
.
length
()
>=
trimLeng
)
{
inputStr
=
inputStr
.
substring
(
trimLeng
);
}
}
}
void
remove
(
final
String
intputFragmentStr
,
final
String
formatFragment
)
{
if
(
intputFragmentStr
!=
null
&&
inputStr
.
length
()
>=
intputFragmentStr
.
length
())
{
inputStr
=
inputStr
.
substring
(
intputFragmentStr
.
length
());
void
remove
(
String
inputFragmentStr
,
String
formatFragment
)
{
if
(
inputFragmentStr
!=
null
&&
inputStr
.
length
()
>=
inputFragmentStr
.
length
())
{
inputStr
=
inputStr
.
substring
(
inputFragmentStr
.
length
());
}
if
(
formatFragment
!=
null
&&
formatStr
.
length
()
>=
formatFragment
.
length
())
{
formatStr
=
formatStr
.
substring
(
formatFragment
.
length
());
...
...
@@ -159,21 +145,49 @@ class ToDateParser {
@Override
public
String
toString
()
{
int
inputStrLen
g
=
inputStr
.
length
();
int
orgInputLen
g
=
unmodifiedInputStr
.
length
();
int
currentInputPos
=
orgInputLen
g
-
inputStrLeng
;
int
restInputLen
g
=
inputStrLeng
<=
0
?
inputStrLeng
:
inputStrLeng
-
1
;
int
inputStrLen
=
inputStr
.
length
();
int
orgInputLen
=
unmodifiedInputStr
.
length
();
int
currentInputPos
=
orgInputLen
-
inputStrLen
;
int
restInputLen
=
inputStrLen
<=
0
?
inputStrLen
:
inputStrLen
-
1
;
int
orgFormatLen
g
=
unmodifiedFormatStr
.
length
();
int
currentFormatPos
=
orgFormatLen
g
-
formatStr
.
length
();
int
orgFormatLen
=
unmodifiedFormatStr
.
length
();
int
currentFormatPos
=
orgFormatLen
-
formatStr
.
length
();
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
format
(
"\n %s('%s', '%s')"
,
functionName
,
unmodifiedInputStr
,
unmodifiedFormatStr
));
sb
.
append
(
format
(
"\n %s^%s , %s^ <-- Parsing failed at this point"
,
//
sb
.
append
(
format
(
"\n %s^%s , %s^ <-- Parsing failed at this point"
,
format
(
"%"
+
(
functionName
.
name
().
length
()
+
currentInputPos
)
+
"s"
,
""
),
restInputLen
g
<=
0
?
""
:
format
(
"%"
+
restInputLeng
+
"s"
,
""
),
restInputLen
<=
0
?
""
:
format
(
"%"
+
restInputLen
+
"s"
,
""
),
currentFormatPos
<=
0
?
""
:
format
(
"%"
+
currentFormatPos
+
"s"
,
""
)));
return
sb
.
toString
();
}
public
static
Timestamp
toTimestamp
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getTimestampParser
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
}
public
static
Timestamp
toDate
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getDateParser
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
}
/**
* The configuration of the date parser.
*/
private
enum
ConfigParam
{
TO_DATE
(
"DD MON YYYY"
),
TO_TIMESTAMP
(
"DD MON YYYY HH:MI:SS"
);
private
final
String
defaultFormatStr
;
ConfigParam
(
String
defaultFormatStr
)
{
this
.
defaultFormatStr
=
defaultFormatStr
;
}
String
getDefaultFormatStr
()
{
return
defaultFormatStr
;
}
}
}
\ No newline at end of file
h2/src/main/org/h2/util/ToDateTokenizer.java
浏览文件 @
7e8fa541
/*
* Copyright 2004-2016 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: Daniel Gredler
*/
package
org
.
h2
.
util
;
import
static
java
.
lang
.
String
.
format
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.*
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Calendar
;
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
;
import
java.util.regex.Pattern
;
...
...
@@ -16,139 +30,20 @@ import org.h2.message.DbException;
* This class knows all about the TO_DATE-format conventions and how to parse the corresponding data
*/
class
ToDateTokenizer
{
private
static
final
Pattern
PATTERN_NUMBER
=
Pattern
.
compile
(
"^([+-]?[0-9]+)"
);
private
static
final
Pattern
PATTERN_FOUR_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{4})"
);
private
static
final
Pattern
PATTERN_THREE_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{3})"
);
private
static
final
Pattern
PATTERN_TWO_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{2})"
);
private
static
final
Pattern
PATTERN_TWO_DIGITS_OR_LESS
=
Pattern
.
compile
(
"^([+-]?[0-9][0-9]?)"
);
private
static
final
Pattern
PATTERN_ONE_DIGIT
=
Pattern
.
compile
(
"^([+-]?[0-9])"
);
private
static
final
Pattern
PATTERN_FF
=
Pattern
.
compile
(
"^(FF[0-9]?)"
,
Pattern
.
CASE_INSENSITIVE
);
private
static
final
Pattern
PATTERN_AM_PM
=
Pattern
.
compile
(
"^(AM|A\\.M\\.|PM|P\\.M\\.)"
,
Pattern
.
CASE_INSENSITIVE
);
private
static
final
Pattern
PATTERN_BC_AD
=
Pattern
.
compile
(
"^(BC|B\\.C\\.|AD|A\\.D\\.)"
,
Pattern
.
CASE_INSENSITIVE
);
private
static
final
YearParslet
PARSLET_YEAR
=
new
YearParslet
();
private
static
final
MonthParslet
PARSLET_MONTH
=
new
MonthParslet
();
private
static
final
DayParslet
PARSLET_DAY
=
new
DayParslet
();
private
static
final
TimeParslet
PARSLET_TIME
=
new
TimeParslet
();
static
enum
FormatTokenEnum
{
YYYY
(
PARSLET_YEAR
)
// 4-digit year
,
SYYYY
(
PARSLET_YEAR
)
// 4-digit year with sign (- = B.C.)
,
IYYY
(
PARSLET_YEAR
)
// 4-digit year based on the ISO standard (?)
,
YYY
(
PARSLET_YEAR
)
//
,
IYY
(
PARSLET_YEAR
)
//
,
YY
(
PARSLET_YEAR
)
//
,
IY
(
PARSLET_YEAR
)
//
,
SCC
(
PARSLET_YEAR
)
// Two-digit century with with sign (- = B.C.)
,
CC
(
PARSLET_YEAR
)
// Two-digit century.
,
RRRR
(
PARSLET_YEAR
)
// 2-digit -> 4-digit year 0-49 -> 20xx , 50-99 -> 19xx
,
RR
(
PARSLET_YEAR
)
// last 2-digit of the year using "current" century value.
,
BC_AD
(
PARSLET_YEAR
,
PATTERN_BC_AD
)
// Meridian indicator
,
MONTH
(
PARSLET_MONTH
)
// Full Name of month
,
MON
(
PARSLET_MONTH
)
// Abbreviated name of month.
,
MM
(
PARSLET_MONTH
)
// Month (01-12; JAN = 01).
,
RM
(
PARSLET_MONTH
)
// Roman numeral month (I-XII; JAN = I).
,
DDD
(
PARSLET_DAY
)
// Day of year (1-366).
,
DAY
(
PARSLET_DAY
)
// Name of day.
,
DD
(
PARSLET_DAY
)
// Day of month (1-31).
,
DY
(
PARSLET_DAY
)
// Abbreviated name of day.
,
HH24
(
PARSLET_TIME
)
//
,
HH12
(
PARSLET_TIME
)
//
,
HH
(
PARSLET_TIME
)
// Hour of day (1-12).
,
MI
(
PARSLET_TIME
)
// Min
,
SSSSS
(
PARSLET_TIME
)
// Seconds past midnight (0-86399)
,
SS
(
PARSLET_TIME
)
//
,
FF
(
PARSLET_TIME
,
PATTERN_FF
)
// Fractional seconds
,
TZH
(
PARSLET_TIME
)
// Time zone hour.
,
TZM
(
PARSLET_TIME
)
// Time zone minute.
,
TZR
(
PARSLET_TIME
)
// Time zone region ID
,
TZD
(
PARSLET_TIME
)
// Daylight savings information. Example: PST (for US/Pacific standard time);
,
AM_PM
(
PARSLET_TIME
,
PATTERN_AM_PM
)
// Meridian indicator
,
EE
(
PARSLET_YEAR
)
// NOT supported yet - Full era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
,
E
(
PARSLET_YEAR
)
// NOT supported yet - Abbreviated era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
,
Y
(
PARSLET_YEAR
)
//
,
I
(
PARSLET_YEAR
)
//
,
Q
(
PARSLET_MONTH
)
// Quarter of year (1, 2, 3, 4; JAN-MAR = 1).
,
D
(
PARSLET_DAY
)
// Day of week (1-7).
,
J
(
PARSLET_DAY
);
// NOT supported yet - Julian day; the number of days since Jan 1, 4712 BC.
private
final
static
Map
<
Character
,
List
<
FormatTokenEnum
>>
cache
=
new
HashMap
<
Character
,
List
<
FormatTokenEnum
>>(
FormatTokenEnum
.
values
().
length
);
private
final
ToDateParslet
toDateParslet
;
private
final
Pattern
patternToUse
;
FormatTokenEnum
(
final
ToDateParslet
toDateParslet
,
final
Pattern
patternToUse
)
{
this
.
toDateParslet
=
toDateParslet
;
this
.
patternToUse
=
patternToUse
;
}
FormatTokenEnum
(
final
ToDateParslet
toDateParslet
)
{
this
.
toDateParslet
=
toDateParslet
;
patternToUse
=
Pattern
.
compile
(
format
(
"^(%s)"
,
name
()),
Pattern
.
CASE_INSENSITIVE
);
}
private
static
List
<
FormatTokenEnum
>
EMPTY_LIST
=
new
ArrayList
<
FormatTokenEnum
>(
0
);
/**
* OPTIMISATION: Only return a list of {@link FormatTokenEnum} that share the same 1st char
* using the 1st char of the 'to parse' formatStr. Or return empty list if no match.
*/
static
List
<
FormatTokenEnum
>
getTokensInQuestion
(
String
formatStr
)
{
List
<
FormatTokenEnum
>
result
=
EMPTY_LIST
;
if
(
cache
.
size
()
<=
0
)
{
initCache
();
}
if
(
formatStr
!=
null
&&
formatStr
.
length
()
>
0
)
{
Character
key
=
Character
.
toUpperCase
(
formatStr
.
charAt
(
0
));
result
=
cache
.
get
(
key
);
}
if
(
result
==
null
)
{
result
=
EMPTY_LIST
;
}
return
result
;
}
private
static
synchronized
void
initCache
()
{
if
(
cache
.
size
()
<=
0
)
{
for
(
FormatTokenEnum
token
:
FormatTokenEnum
.
values
())
{
List
<
Character
>
tokenKeys
=
new
ArrayList
<
Character
>();
if
(
token
.
name
().
contains
(
"_"
))
{
String
[]
tokens
=
token
.
name
().
split
(
"_"
);
for
(
String
tokenLets
:
tokens
)
{
tokenKeys
.
add
(
tokenLets
.
toUpperCase
().
charAt
(
0
));
}
}
else
{
tokenKeys
.
add
(
token
.
name
().
toUpperCase
().
charAt
(
0
));
}
for
(
Character
tokenKey
:
tokenKeys
)
{
List
<
FormatTokenEnum
>
l
=
cache
.
get
(
tokenKey
);
if
(
l
==
null
)
{
l
=
new
ArrayList
<
FormatTokenEnum
>(
1
);
cache
.
put
(
tokenKey
,
l
);
}
l
.
add
(
token
);
}
}
}
}
/**
* Parse the format-string with passed token of {@link FormatTokenEnum}}.<br>
* If token matches return true, otherwise false.
*/
boolean
parseFormatStrWithToken
(
final
ToDateParser
params
)
{
Matcher
matcher
=
patternToUse
.
matcher
(
params
.
getFormatStr
());
boolean
foundToken
=
matcher
.
find
();
if
(
foundToken
)
{
String
formatTokenStr
=
matcher
.
group
(
1
);
toDateParslet
.
parse
(
params
,
this
,
formatTokenStr
);
}
return
foundToken
;
}
}
static
final
Pattern
PATTERN_NUMBER
=
Pattern
.
compile
(
"^([+-]?[0-9]+)"
);
static
final
Pattern
PATTERN_FOUR_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{4})"
);
static
final
Pattern
PATTERN_THREE_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{3})"
);
static
final
Pattern
PATTERN_TWO_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{2})"
);
static
final
Pattern
PATTERN_TWO_DIGITS_OR_LESS
=
Pattern
.
compile
(
"^([+-]?[0-9][0-9]?)"
);
static
final
Pattern
PATTERN_ONE_DIGIT
=
Pattern
.
compile
(
"^([+-]?[0-9])"
);
static
final
Pattern
PATTERN_FF
=
Pattern
.
compile
(
"^(FF[0-9]?)"
,
Pattern
.
CASE_INSENSITIVE
);
static
final
Pattern
PATTERN_AM_PM
=
Pattern
.
compile
(
"^(AM|A\\.M\\.|PM|P\\.M\\.)"
,
Pattern
.
CASE_INSENSITIVE
);
static
final
Pattern
PATTERN_BC_AD
=
Pattern
.
compile
(
"^(BC|B\\.C\\.|AD|A\\.D\\.)"
,
Pattern
.
CASE_INSENSITIVE
);
static
final
YearParslet
PARSLET_YEAR
=
new
YearParslet
();
static
final
MonthParslet
PARSLET_MONTH
=
new
MonthParslet
();
static
final
DayParslet
PARSLET_DAY
=
new
DayParslet
();
static
final
TimeParslet
PARSLET_TIME
=
new
TimeParslet
();
static
final
int
MILLIS_IN_HOUR
=
60
*
60
*
1000
;
/**
* Interface of the classes that can parse a specialized small bit of the TO_DATE format-string
...
...
@@ -160,39 +55,39 @@ class ToDateTokenizer {
/**
* Parslet responsible for parsing year parameter
*/
private
static
final
class
YearParslet
implements
ToDateParslet
{
static
class
YearParslet
implements
ToDateParslet
{
@Override
public
void
parse
(
final
ToDateParser
params
,
final
FormatTokenEnum
formatTokenEnum
,
final
String
formatTokenStr
)
{
final
Calendar
result
=
params
.
getResultCalendar
();
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
=
matchStringOr
Die
(
PATTERN_FOUR_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_FOUR_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
// 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
);
break
;
case
YYY:
case
IYY:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_THREE_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_THREE_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
// 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
);
break
;
case
RRRR:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
+=
dateNr
<
50
?
2000
:
1900
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
break
;
case
RR:
Calendar
calendar
=
Calendar
.
getInstance
();
int
cc
=
(
calendar
.
get
(
Calendar
.
YEAR
)
/
100
)
;
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
int
cc
=
calendar
.
get
(
Calendar
.
YEAR
)
/
100
;
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
)
+
cc
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
break
;
...
...
@@ -204,30 +99,29 @@ class ToDateTokenizer {
break
;
case
YY:
case
IY:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
// 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
);
break
;
case
SCC:
case
CC:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
)
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
break
;
case
Y:
case
I:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
// 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
);
break
;
case
BC_AD:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_BC_AD
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
))
{
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_BC_AD
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
))
{
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
BC
);
}
else
{
}
else
{
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
AD
);
}
break
;
...
...
@@ -242,15 +136,15 @@ class ToDateTokenizer {
/**
* Parslet responsible for parsing month parameter
*/
private
static
final
class
MonthParslet
implements
ToDateParslet
{
private
static
final
String
[]
ROMAN_M
onth
=
{
"I"
,
"II"
,
"III"
,
"IV"
,
"V"
,
"VI"
,
"VII"
,
"VIII"
,
"IX"
,
"X"
,
static
class
MonthParslet
implements
ToDateParslet
{
private
static
final
String
[]
ROMAN_M
ONTH
=
{
"I"
,
"II"
,
"III"
,
"IV"
,
"V"
,
"VI"
,
"VII"
,
"VIII"
,
"IX"
,
"X"
,
"XI"
,
"XII"
};
@Override
public
void
parse
(
final
ToDateParser
params
,
final
FormatTokenEnum
formatTokenEnum
,
final
String
formatTokenStr
)
{
final
Calendar
result
=
params
.
getResultCalendar
();
final
String
s
=
params
.
getInputStr
();
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
)
{
...
...
@@ -258,23 +152,23 @@ class ToDateTokenizer {
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
LONG
);
break
;
case
Q
/*NOT supported yet*/
:
throwException
(
params
,
format
(
"token '%s' not supported
j
et."
,
formatTokenEnum
.
name
()));
throwException
(
params
,
format
(
"token '%s' not supported
y
et."
,
formatTokenEnum
.
name
()));
break
;
case
MON:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
SHORT
);
break
;
case
MM:
// Note: In Calendar Month go from 0 - 11
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MONTH
,
dateNr
-
1
);
break
;
case
RM:
dateNr
=
0
;
for
(
String
monthName
:
ROMAN_M
onth
)
{
for
(
String
monthName
:
ROMAN_M
ONTH
)
{
dateNr
++;
int
len
g
=
monthName
.
length
();
if
(
s
.
length
()
>=
len
g
&&
monthName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
leng
)))
{
int
len
=
monthName
.
length
();
if
(
s
.
length
()
>=
len
&&
monthName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
result
.
set
(
Calendar
.
MONTH
,
dateNr
);
inputFragmentStr
=
monthName
;
break
;
...
...
@@ -283,7 +177,7 @@ class ToDateTokenizer {
if
(
inputFragmentStr
==
null
||
inputFragmentStr
.
isEmpty
())
{
throwException
(
params
,
format
(
"Issue happened when parsing token '%s'. Expected one of: %s"
,
formatTokenEnum
.
name
(),
Arrays
.
toString
(
ROMAN_M
onth
)));
formatTokenEnum
.
name
(),
Arrays
.
toString
(
ROMAN_M
ONTH
)));
}
break
;
default
:
...
...
@@ -297,26 +191,26 @@ class ToDateTokenizer {
/**
* Parslet responsible for parsing day parameter
*/
private
static
final
class
DayParslet
implements
ToDateParslet
{
static
class
DayParslet
implements
ToDateParslet
{
@Override
public
void
parse
(
final
ToDateParser
params
,
final
FormatTokenEnum
formatTokenEnum
,
final
String
formatTokenStr
)
{
final
Calendar
result
=
params
.
getResultCalendar
();
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
case
DDD:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_YEAR
,
dateNr
);
break
;
case
DD:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
break
;
case
D:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
break
;
...
...
@@ -327,7 +221,7 @@ class ToDateTokenizer {
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
DAY_OF_WEEK
,
Calendar
.
SHORT
);
break
;
case
J:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
try
{
Date
date
=
new
SimpleDateFormat
(
"Myydd"
).
parse
(
inputFragmentStr
);
result
.
setTime
(
date
);
...
...
@@ -343,50 +237,48 @@ class ToDateTokenizer {
}
}
private
static
int
MILLIS_in_hour
=
60
*
60
*
1000
;
/**
* Parslet responsible for parsing time parameter
*/
private
static
final
class
TimeParslet
implements
ToDateParslet
{
static
class
TimeParslet
implements
ToDateParslet
{
@Override
public
void
parse
(
final
ToDateParser
params
,
final
FormatTokenEnum
formatTokenEnum
,
final
String
formatTokenStr
)
{
final
Calendar
result
=
params
.
getResultCalendar
();
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
case
HH24:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
dateNr
);
break
;
case
HH12:
case
HH:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR
,
dateNr
);
break
;
case
MI:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MINUTE
,
dateNr
);
break
;
case
SS:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
break
;
case
SSSSS:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
result
.
set
(
Calendar
.
MINUTE
,
0
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
break
;
case
FF:
//
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
case
FF:
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
String
paddedRightNrStr
=
format
(
"%-9s"
,
inputFragmentStr
).
replace
(
' '
,
'0'
);
paddedRightNrStr
=
paddedRightNrStr
.
substring
(
0
,
9
);
Double
nineDigits
=
Double
.
parseDouble
(
paddedRightNrStr
);
...
...
@@ -395,35 +287,36 @@ class ToDateTokenizer {
result
.
set
(
Calendar
.
MILLISECOND
,
dateNr
);
break
;
case
AM_PM:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_AM_PM
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"A"
))
{
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_AM_PM
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"A"
))
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
AM
);
}
else
{
}
else
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
PM
);
}
break
;
case
TZH:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
TimeZone
tz
=
result
.
getTimeZone
();
int
offsetMillis
=
tz
.
getRawOffset
();
offsetMillis
=
(
offsetMillis
/
MILLIS_in_hour
)
*
MILLIS_in_hour
;
// purge min and sec
// purge min and sec
offsetMillis
=
(
offsetMillis
/
MILLIS_IN_HOUR
)
*
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
offsetMillis
+
dateNr
);
result
.
setTimeZone
(
tz
);
break
;
case
TZM:
inputFragmentStr
=
matchStringOr
Die
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOr
Throw
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
tz
=
result
.
getTimeZone
();
offsetMillis
=
tz
.
getRawOffset
();
offsetMillis
=
offsetMillis
%
MILLIS_in_hour
;
// purge hour
tz
.
setRawOffset
(
dateNr
*
MILLIS_in_hour
+
offsetMillis
);
// purge hour
offsetMillis
=
offsetMillis
%
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
dateNr
*
MILLIS_IN_HOUR
+
offsetMillis
);
result
.
setTimeZone
(
tz
);
break
;
case
TZR:
// Example: US/Pacific
final
String
s
=
params
.
getInputStr
();
case
TZR:
// Example: US/Pacific
String
s
=
params
.
getInputStr
();
tz
=
result
.
getTimeZone
();
for
(
String
tzName
:
TimeZone
.
getAvailableIDs
())
{
int
length
=
tzName
.
length
();
...
...
@@ -435,7 +328,8 @@ class ToDateTokenizer {
}
}
break
;
case
TZD:
// Must correspond with TZR region. Example: PST (for US/Pacific standard time)
case
TZD:
// Must correspond with TZR region. Example: PST (for US/Pacific standard time)
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
break
;
default
:
...
...
@@ -446,7 +340,7 @@ class ToDateTokenizer {
}
}
private
static
int
parseInt
(
final
String
s
)
{
static
int
parseInt
(
String
s
)
{
int
result
=
0
;
if
(
s
.
length
()
>
0
&&
s
.
charAt
(
0
)
==
'+'
)
{
result
=
Integer
.
parseInt
(
s
.
substring
(
1
));
...
...
@@ -456,22 +350,22 @@ class ToDateTokenizer {
return
result
;
}
private
static
String
matchStringOrDie
(
final
Pattern
p
,
final
ToDateParser
params
,
final
Enum
<?>
aEnum
)
{
final
String
s
=
params
.
getInputStr
();
static
String
matchStringOrThrow
(
Pattern
p
,
ToDateParser
params
,
Enum
<?>
aEnum
)
{
String
s
=
params
.
getInputStr
();
Matcher
matcher
=
p
.
matcher
(
s
);
if
(!
matcher
.
find
())
{
throwException
(
params
,
format
(
"Issue happend when parsing token '%s'"
,
aEnum
.
name
()));
throwException
(
params
,
format
(
"Issue happen
e
d when parsing token '%s'"
,
aEnum
.
name
()));
}
return
matcher
.
group
(
1
);
}
private
static
String
setByName
(
final
Calendar
c
,
final
ToDateParser
params
,
final
int
field
,
final
int
style
)
{
static
String
setByName
(
Calendar
c
,
ToDateParser
params
,
int
field
,
int
style
)
{
String
inputFragmentStr
=
null
;
String
s
=
params
.
getInputStr
();
Map
<
String
,
Integer
>
timeStringMap
=
c
.
getDisplayNames
(
field
,
style
,
Locale
.
getDefault
());
for
(
String
dayName
:
timeStringMap
.
keySet
())
{
int
len
g
=
dayName
.
length
();
if
(
dayName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
g
)))
{
int
len
=
dayName
.
length
();
if
(
dayName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
c
.
set
(
field
,
timeStringMap
.
get
(
dayName
));
inputFragmentStr
=
dayName
;
break
;
...
...
@@ -484,11 +378,163 @@ class ToDateTokenizer {
return
inputFragmentStr
;
}
private
static
void
throwException
(
final
ToDateParser
params
,
final
String
errorStr
)
{
static
void
throwException
(
ToDateParser
params
,
String
errorStr
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_TO_DATE_FORMAT
,
params
.
getFunctionName
(),
format
(
" %s. Details: %s"
,
errorStr
,
params
));
}
/**
* The format tokens.
*/
static
enum
FormatTokenEnum
{
// 4-digit year
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
),
// Two-digit century with with sign (- = B.C.)
SCC
(
PARSLET_YEAR
),
// Two-digit century.
CC
(
PARSLET_YEAR
),
// 2-digit -> 4-digit year 0-49 -> 20xx , 50-99 -> 19xx
RRRR
(
PARSLET_YEAR
),
// last 2-digit of the year using "current" century value.
RR
(
PARSLET_YEAR
),
// Meridian indicator
BC_AD
(
PARSLET_YEAR
,
PATTERN_BC_AD
),
// Full Name of month
MONTH
(
PARSLET_MONTH
),
// Abbreviated name of month.
MON
(
PARSLET_MONTH
),
// Month (01-12; JAN = 01).
MM
(
PARSLET_MONTH
),
// Roman numeral month (I-XII; JAN = I).
RM
(
PARSLET_MONTH
),
// Day of year (1-366).
DDD
(
PARSLET_DAY
),
// Name of day.
DAY
(
PARSLET_DAY
),
// Day of month (1-31).
DD
(
PARSLET_DAY
),
// Abbreviated name of day.
DY
(
PARSLET_DAY
),
HH24
(
PARSLET_TIME
),
HH12
(
PARSLET_TIME
),
// Hour of day (1-12).
HH
(
PARSLET_TIME
),
// Min
MI
(
PARSLET_TIME
),
// Seconds past midnight (0-86399)
SSSSS
(
PARSLET_TIME
),
SS
(
PARSLET_TIME
),
// Fractional seconds
FF
(
PARSLET_TIME
,
PATTERN_FF
),
// Time zone hour.
TZH
(
PARSLET_TIME
),
// Time zone minute.
TZM
(
PARSLET_TIME
),
// Time zone region ID
TZR
(
PARSLET_TIME
),
// Daylight savings information. Example: PST (for US/Pacific standard time);
TZD
(
PARSLET_TIME
),
// Meridian indicator
AM_PM
(
PARSLET_TIME
,
PATTERN_AM_PM
),
// NOT supported yet - Full era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
EE
(
PARSLET_YEAR
),
// NOT supported yet - Abbreviated era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
E
(
PARSLET_YEAR
),
Y
(
PARSLET_YEAR
),
I
(
PARSLET_YEAR
),
// Quarter of year (1, 2, 3, 4; JAN-MAR = 1).
Q
(
PARSLET_MONTH
),
// Day of week (1-7).
D
(
PARSLET_DAY
),
// NOT supported yet - Julian day; the number of days since Jan 1, 4712 BC.
J
(
PARSLET_DAY
);
private
static
final
List
<
FormatTokenEnum
>
EMPTY_LIST
=
new
ArrayList
<
FormatTokenEnum
>(
0
);
private
static
final
Map
<
Character
,
List
<
FormatTokenEnum
>>
CACHE
=
new
HashMap
<
Character
,
List
<
FormatTokenEnum
>>(
FormatTokenEnum
.
values
().
length
);
private
final
ToDateParslet
toDateParslet
;
private
final
Pattern
patternToUse
;
FormatTokenEnum
(
ToDateParslet
toDateParslet
,
Pattern
patternToUse
)
{
this
.
toDateParslet
=
toDateParslet
;
this
.
patternToUse
=
patternToUse
;
}
FormatTokenEnum
(
ToDateParslet
toDateParslet
)
{
this
.
toDateParslet
=
toDateParslet
;
patternToUse
=
Pattern
.
compile
(
format
(
"^(%s)"
,
name
()),
Pattern
.
CASE_INSENSITIVE
);
}
/**
* OPTIMISATION: Only return a list of {@link FormatTokenEnum} that share the same 1st char
* using the 1st char of the 'to parse' formatStr. Or return empty list if no match.
*/
static
List
<
FormatTokenEnum
>
getTokensInQuestion
(
String
formatStr
)
{
List
<
FormatTokenEnum
>
result
=
EMPTY_LIST
;
if
(
CACHE
.
size
()
<=
0
)
{
initCache
();
}
if
(
formatStr
!=
null
&&
formatStr
.
length
()
>
0
)
{
Character
key
=
Character
.
toUpperCase
(
formatStr
.
charAt
(
0
));
result
=
CACHE
.
get
(
key
);
}
if
(
result
==
null
)
{
result
=
EMPTY_LIST
;
}
return
result
;
}
private
static
synchronized
void
initCache
()
{
if
(
CACHE
.
size
()
<=
0
)
{
for
(
FormatTokenEnum
token
:
FormatTokenEnum
.
values
())
{
List
<
Character
>
tokenKeys
=
new
ArrayList
<
Character
>();
if
(
token
.
name
().
contains
(
"_"
))
{
String
[]
tokens
=
token
.
name
().
split
(
"_"
);
for
(
String
tokenLets
:
tokens
)
{
tokenKeys
.
add
(
tokenLets
.
toUpperCase
().
charAt
(
0
));
}
}
else
{
tokenKeys
.
add
(
token
.
name
().
toUpperCase
().
charAt
(
0
));
}
for
(
Character
tokenKey
:
tokenKeys
)
{
List
<
FormatTokenEnum
>
l
=
CACHE
.
get
(
tokenKey
);
if
(
l
==
null
)
{
l
=
new
ArrayList
<
FormatTokenEnum
>(
1
);
CACHE
.
put
(
tokenKey
,
l
);
}
l
.
add
(
token
);
}
}
}
}
/**
* Parse the format-string with passed token of {@link FormatTokenEnum}}.<br>
* If token matches return true, otherwise false.
*/
boolean
parseFormatStrWithToken
(
ToDateParser
params
)
{
Matcher
matcher
=
patternToUse
.
matcher
(
params
.
getFormatStr
());
boolean
foundToken
=
matcher
.
find
();
if
(
foundToken
)
{
String
formatTokenStr
=
matcher
.
group
(
1
);
toDateParslet
.
parse
(
params
,
this
,
formatTokenStr
);
}
return
foundToken
;
}
}
}
\ No newline at end of file
h2/src/main/org/h2/value/Value.java
浏览文件 @
7e8fa541
...
...
@@ -767,7 +767,7 @@ public abstract class Value {
case
TIMESTAMP_UTC:
return
ValueTimestamp
.
fromMillisNanos
(
((
ValueTimestampUtc
)
this
).
getUtcDateTimeMillis
(),
((
ValueTimestampUtc
)
this
).
getNanosSinceLastMilli
());
((
ValueTimestampUtc
)
this
).
getNanosSinceLastMilli
s
());
}
break
;
}
...
...
h2/src/main/org/h2/value/ValueTimestampUtc.java
浏览文件 @
7e8fa541
...
...
@@ -110,14 +110,14 @@ public final class ValueTimestampUtc extends Value {
return
utcDateTimeNanos
/
1000
/
1000
;
}
public
int
getNanosSinceLastMilli
()
{
int
getNanosSinceLastMillis
()
{
return
(
int
)
(
utcDateTimeNanos
%
(
1000
*
1000
));
}
@Override
public
java
.
sql
.
Timestamp
getTimestamp
()
{
java
.
sql
.
Timestamp
ts
=
new
java
.
sql
.
Timestamp
(
getUtcDateTimeMillis
());
ts
.
setNanos
(
getNanosSinceLastMilli
());
ts
.
setNanos
(
getNanosSinceLastMilli
s
());
return
ts
;
}
...
...
@@ -157,7 +157,7 @@ public final class ValueTimestampUtc extends Value {
timeNanos
*=
60
;
timeNanos
+=
cal
.
get
(
Calendar
.
MILLISECOND
);
timeNanos
*=
1000
*
1000
;
timeNanos
+=
getNanosSinceLastMilli
();
timeNanos
+=
getNanosSinceLastMilli
s
();
ValueTime
.
appendTime
(
buff
,
timeNanos
,
true
);
buff
.
append
(
" UTC"
);
return
buff
.
toString
();
...
...
h2/src/test/org/h2/test/db/TestFunctions.java
浏览文件 @
7e8fa541
...
...
@@ -52,7 +52,7 @@ import org.h2.tools.SimpleResultSet;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
import
org.h2.util.StringUtils
;
import
org.h2.util.ToDate
;
import
org.h2.util.ToDate
Parser
;
import
org.h2.value.Value
;
/**
...
...
@@ -1283,119 +1283,127 @@ public class TestFunctions extends TestBase implements AggregateFunction {
private
void
testToDateException
()
{
try
{
ToDate
.
TO_DATE
(
"1979-ThisWillFail-12"
,
"YYYY-MM-DD"
);
ToDate
Parser
.
toDate
(
"1979-ThisWillFail-12"
,
"YYYY-MM-DD"
);
}
catch
(
Exception
e
)
{
assertEquals
(
DbException
.
class
.
getSimpleName
(),
e
.
getClass
().
getSimpleName
());
}
}
private
void
testToDate
()
throws
SQLException
,
ParseException
{
private
void
testToDate
()
throws
ParseException
{
final
int
curM
onth
=
Calendar
.
getInstance
().
get
(
Calendar
.
MONTH
);
final
int
m
onth
=
Calendar
.
getInstance
().
get
(
Calendar
.
MONTH
);
Date
date
=
null
;
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1979-11-12"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979-11-12"
,
"YYYY-MM-DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979/11/12"
,
"YYYY/MM/DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979,11,12"
,
"YYYY,MM,DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979.11.12"
,
"YYYY.MM.DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979;11;12"
,
"YYYY;MM;DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979:11:12"
,
"YYYY:MM:DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979-11-12"
,
"YYYY-MM-DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979/11/12"
,
"YYYY/MM/DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979,11,12"
,
"YYYY,MM,DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979.11.12"
,
"YYYY.MM.DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979;11;12"
,
"YYYY;MM;DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979:11:12"
,
"YYYY:MM:DD"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"1979"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979"
,
"YYYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979 AD"
,
"YYYY AD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979 A.D."
,
"YYYY A.D."
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979 A.D."
,
"YYYY BC"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979"
,
"IYYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"+1979"
,
"SYYYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"79"
,
"RRRR"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979"
,
"YYYY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979 AD"
,
"YYYY AD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979 A.D."
,
"YYYY A.D."
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979 A.D."
,
"YYYY BC"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979"
,
"IYYY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"+1979"
,
"SYYYY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"79"
,
"RRRR"
));
date
=
new
SimpleDateFormat
(
"yyyy-mm"
).
parse
(
"1970-12"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"12"
,
"MI"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"12"
,
"MI"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM"
).
parse
(
"1970-11"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"11"
,
"MM"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"11"
,
"Mm"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"11"
,
"mM"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"11"
,
"mm"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"XI"
,
"RM"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"11"
,
"MM"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"11"
,
"Mm"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"11"
,
"mM"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"11"
,
"mm"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"XI"
,
"RM"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"9"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"9"
,
"Y"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"9"
,
"I"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"9"
,
"Y"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"9"
,
"I"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"79"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"79"
,
"YY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"79"
,
"IY"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"79"
,
"YY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"79"
,
"IY"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"979"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"979"
,
"YYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"979"
,
"IYY"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"979"
,
"YYY"
));
assertEquals
(
date
,
ToDate
Parser
.
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"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"0100 BC"
,
"YYYY BC"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"0100 B.C."
,
"YYYY B.C."
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"100 BC"
,
"YYY BC"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"-0100"
,
"SYYYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"-0100"
,
"YYYY"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"0100 BC"
,
"YYYY BC"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"0100 B.C."
,
"YYYY B.C."
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"100 BC"
,
"YYY BC"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"-0100"
,
"SYYYY"
));
assertEquals
(
date
,
ToDate
Parser
.
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"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"01 BC"
,
"YY BC"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1 BC"
,
"Y BC"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"01 BC"
,
"YY BC"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1 BC"
,
"Y BC"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12 AM"
,
"HH:MI AM"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12 A.M."
,
"HH:MI A.M."
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12"
,
"HH24:MI"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12 AM"
,
"HH:MI AM"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12 A.M."
,
"HH:MI A.M."
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12"
,
"HH24:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12"
,
"HH:MI"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12"
,
"HH12:MI"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12"
,
"HH:MI"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12"
,
"HH12:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:34"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12:34"
,
"HH:MI:SS"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12:34"
,
"HH:MI:SS"
));
date
=
new
SimpleDateFormat
(
"ss"
).
parse
(
"34"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"34"
,
"SS"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"34"
,
"SS"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss"
).
parse
(
"1970 08:12:34"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"29554"
,
"SSSSS"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"29554"
,
"SSSSS"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss SSS"
).
parse
(
"1970 08:12:34 550"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12:34 550"
,
"HH:MI:SS FF"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12:34 55"
,
"HH:MI:SS FF2"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12:34 550"
,
"HH:MI:SS FF"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12:34 55"
,
"HH:MI:SS FF2"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"14:04:00"
);
date
.
setMonth
(
curM
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"02:04 P.M."
,
"HH:MI p.M."
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"02:04 PM"
,
"HH:MI PM"
));
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"02:04 P.M."
,
"HH:MI p.M."
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"02:04 PM"
,
"HH:MI PM"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-12-12"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"12"
,
"DD"
));
// does not work in all timezones
// assertEquals(date, ToDateParser.toDate("12", "DD"));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-11-12"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"316"
,
"DDD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"316"
,
"DdD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"316"
,
"dDD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"316"
,
"ddd"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"316"
,
"DDD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"316"
,
"DdD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"316"
,
"dDD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"316"
,
"ddd"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"2013-01-29"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"113029"
,
"J"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"113029"
,
"J"
));
}
private
static
void
setMonth
(
Date
date
,
int
month
)
{
Calendar
c
=
Calendar
.
getInstance
();
c
.
setTime
(
date
);
c
.
set
(
Calendar
.
MONTH
,
month
);
date
.
setTime
(
c
.
getTimeInMillis
());
}
private
void
testToCharFromDateTime
()
throws
SQLException
{
...
...
@@ -1907,7 +1915,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
private
void
testAnnotationProcessorsOutput
()
throws
SQLException
{
try
{
System
.
setProperty
(
TestAnnotationProcessor
.
MESSAGES_KEY
,
"WARNING,foo1|ERROR,foo2"
);
callCompiledFunction
(
"test_a
tp
_warn_and_error"
);
callCompiledFunction
(
"test_a
nnotation_processor
_warn_and_error"
);
fail
();
}
catch
(
JdbcSQLException
e
)
{
assertEquals
(
ErrorCode
.
SYNTAX_ERROR_1
,
e
.
getErrorCode
());
...
...
h2/src/test/org/h2/test/db/TestOptimizations.java
浏览文件 @
7e8fa541
...
...
@@ -1033,32 +1033,32 @@ public class TestOptimizations extends TestBase {
deleteDb
(
"optimizations"
);
Connection
conn
=
getConnection
(
"optimizations"
);
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"CREATE TABLE T
BL
_A(id IDENTITY PRIMARY KEY NOT NULL, "
+
stat
.
execute
(
"CREATE TABLE T
ABLE
_A(id IDENTITY PRIMARY KEY NOT NULL, "
+
"name VARCHAR NOT NULL, active BOOLEAN DEFAULT TRUE, "
+
"UNIQUE KEY T
BL
_A_UK (name) )"
);
stat
.
execute
(
"CREATE TABLE T
BL
_B(id IDENTITY PRIMARY KEY NOT NULL, "
+
"
tbl
_a_id BIGINT NOT NULL, createDate TIMESTAMP DEFAULT NOW(), "
+
"UNIQUE KEY T
BL_B_UK (tbl
_a_id, createDate), "
+
"FOREIGN KEY (t
bl_a_id) REFERENCES TBL
_A(id) )"
);
stat
.
execute
(
"INSERT INTO T
BL
_A (name) SELECT 'package_' || CAST(X as VARCHAR) "
+
"UNIQUE KEY T
ABLE
_A_UK (name) )"
);
stat
.
execute
(
"CREATE TABLE T
ABLE
_B(id IDENTITY PRIMARY KEY NOT NULL, "
+
"
TABLE
_a_id BIGINT NOT NULL, createDate TIMESTAMP DEFAULT NOW(), "
+
"UNIQUE KEY T
ABLE_B_UK (table
_a_id, createDate), "
+
"FOREIGN KEY (t
able_a_id) REFERENCES TABLE
_A(id) )"
);
stat
.
execute
(
"INSERT INTO T
ABLE
_A (name) SELECT 'package_' || CAST(X as VARCHAR) "
+
"FROM SYSTEM_RANGE(1, 100) WHERE X <= 100"
);
stat
.
execute
(
"INSERT INTO T
BL_B (tbl
_a_id, createDate) SELECT "
+
"CASE WHEN t
bl_a_id = 0 THEN 1 ELSE tbl
_a_id END, createDate "
+
"FROM ( SELECT ROUND((RAND() * 100)) AS t
bl
_a_id, "
+
stat
.
execute
(
"INSERT INTO T
ABLE_B (table
_a_id, createDate) SELECT "
+
"CASE WHEN t
able_a_id = 0 THEN 1 ELSE table
_a_id END, createDate "
+
"FROM ( SELECT ROUND((RAND() * 100)) AS t
able
_a_id, "
+
"DATEADD('SECOND', X, NOW()) as createDate FROM SYSTEM_RANGE(1, 50000) "
+
"WHERE X < 50000 )"
);
stat
.
execute
(
"CREATE INDEX t
bl_b_idx ON tbl_b(tbl
_a_id, id)"
);
stat
.
execute
(
"CREATE INDEX t
able_b_idx ON table_b(table
_a_id, id)"
);
stat
.
execute
(
"ANALYZE"
);
ResultSet
rs
=
stat
.
executeQuery
(
"EXPLAIN ANALYZE SELECT MAX(b.id) as id "
+
"FROM t
bl_b b JOIN tbl_a a ON b.tbl_a_id = a.id GROUP BY b.tbl
_a_id "
+
"FROM t
able_b b JOIN table_a a ON b.table_a_id = a.id GROUP BY b.table
_a_id "
+
"HAVING A.ACTIVE = TRUE"
);
rs
.
next
();
assertContains
(
rs
.
getString
(
1
),
"/* PUBLIC.T
BL_B_IDX: TBL
_A_ID = A.ID */"
);
assertContains
(
rs
.
getString
(
1
),
"/* PUBLIC.T
ABLE_B_IDX: TABLE
_A_ID = A.ID */"
);
rs
=
stat
.
executeQuery
(
"EXPLAIN ANALYZE SELECT MAX(id) FROM t
bl_b GROUP BY tbl
_a_id"
);
rs
=
stat
.
executeQuery
(
"EXPLAIN ANALYZE SELECT MAX(id) FROM t
able_b GROUP BY table
_a_id"
);
rs
.
next
();
assertContains
(
rs
.
getString
(
1
),
"/* PUBLIC.T
BL
_B_IDX"
);
assertContains
(
rs
.
getString
(
1
),
"/* PUBLIC.T
ABLE
_B_IDX"
);
conn
.
close
();
}
}
h2/src/test/org/h2/test/db/TestTableEngines.java
浏览文件 @
7e8fa541
...
...
@@ -351,15 +351,15 @@ public class TestTableEngines extends TestBase {
deleteDb
(
"testQueryExpressionFlag"
);
Connection
conn
=
getConnection
(
"testQueryExpressionFlag"
);
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table QRY_EXPR_TEST(id int) ENGINE \""
+
stat
.
execute
(
"create table Q
UE
RY_EXPR_TEST(id int) ENGINE \""
+
TreeSetIndexTableEngine
.
class
.
getName
()
+
"\""
);
stat
.
execute
(
"create table QRY_EXPR_TEST_NO(id int) ENGINE \""
+
stat
.
execute
(
"create table Q
UE
RY_EXPR_TEST_NO(id int) ENGINE \""
+
TreeSetIndexTableEngine
.
class
.
getName
()
+
"\""
);
stat
.
executeQuery
(
"select 1 + (select 1 from QRY_EXPR_TEST)"
).
next
();
stat
.
executeQuery
(
"select 1 from QRY_EXPR_TEST_NO where id in "
+
"(select id from QRY_EXPR_TEST)"
);
stat
.
executeQuery
(
"select 1 from QRY_EXPR_TEST_NO n "
+
"where exists(select 1 from QRY_EXPR_TEST y where y.id = n.id)"
);
stat
.
executeQuery
(
"select 1 + (select 1 from Q
UE
RY_EXPR_TEST)"
).
next
();
stat
.
executeQuery
(
"select 1 from Q
UE
RY_EXPR_TEST_NO where id in "
+
"(select id from Q
UE
RY_EXPR_TEST)"
);
stat
.
executeQuery
(
"select 1 from Q
UE
RY_EXPR_TEST_NO n "
+
"where exists(select 1 from Q
UE
RY_EXPR_TEST y where y.id = n.id)"
);
deleteDb
(
"testQueryExpressionFlag"
);
}
...
...
@@ -621,7 +621,7 @@ public class TestTableEngines extends TestBase {
setBatchingEnabled
(
stat
,
true
);
List
<
List
<
Object
>>
actual
=
query
(
stat
,
sql
);
if
(!
expected
.
equals
(
actual
))
{
fail
(
"\n
expected: "
+
expected
+
"\n
actual: "
+
actual
);
fail
(
"\n
"
+
"expected: "
+
expected
+
"\n"
+
"
actual: "
+
actual
);
}
}
...
...
@@ -699,10 +699,10 @@ public class TestTableEngines extends TestBase {
private
static
void
setBatchSize
(
TreeSetTable
t
,
int
batchSize
)
{
if
(
t
.
getIndexes
()
==
null
)
{
t
.
scan
.
preferedBatchSize
=
batchSize
;
t
.
scan
.
prefer
r
edBatchSize
=
batchSize
;
}
else
{
for
(
Index
idx
:
t
.
getIndexes
())
{
((
TreeSetIndex
)
idx
).
preferedBatchSize
=
batchSize
;
((
TreeSetIndex
)
idx
).
prefer
r
edBatchSize
=
batchSize
;
}
}
}
...
...
@@ -746,7 +746,7 @@ public class TestTableEngines extends TestBase {
t
>>>=
4
;
}
if
(
where
.
length
()
!=
0
)
{
b
.
append
(
"\nwhere "
).
append
(
where
);
b
.
append
(
"\n
"
+
"
where "
).
append
(
where
);
}
return
b
.
toString
();
...
...
@@ -1313,7 +1313,7 @@ public class TestTableEngines extends TestBase {
static
AtomicInteger
lookupBatches
=
new
AtomicInteger
();
int
preferedBatchSize
;
int
prefer
r
edBatchSize
;
final
TreeSet
<
SearchRow
>
set
=
new
TreeSet
<
SearchRow
>(
this
);
...
...
@@ -1337,8 +1337,8 @@ public class TestTableEngines extends TestBase {
@Override
public
IndexLookupBatch
createLookupBatch
(
final
TableFilter
filter
)
{
assert0
(
filter
.
getMasks
()
!=
null
||
"scan"
.
equals
(
getName
()),
"masks"
);
final
int
prefer
edSize
=
prefe
redBatchSize
;
if
(
preferedSize
==
0
)
{
final
int
prefer
redSize
=
prefer
redBatchSize
;
if
(
prefer
r
edSize
==
0
)
{
return
null
;
}
lookupBatches
.
incrementAndGet
();
...
...
@@ -1351,7 +1351,7 @@ public class TestTableEngines extends TestBase {
}
@Override
public
boolean
isBatchFull
()
{
return
searchRows
.
size
()
>=
preferedSize
*
2
;
return
searchRows
.
size
()
>=
prefer
r
edSize
*
2
;
}
@Override
...
...
@@ -1490,9 +1490,9 @@ public class TestTableEngines extends TestBase {
String
alias
=
alias
(
session
.
getSubQueryInfo
());
assert0
(
alias
.
equals
(
"ZZ"
),
"select expression sub-query: "
+
alias
);
assert0
(
session
.
getSubQueryInfo
().
getUpper
()
==
null
,
"upper"
);
}
else
if
(
getTable
().
getName
().
equals
(
"QRY_EXPR_TEST"
))
{
}
else
if
(
getTable
().
getName
().
equals
(
"Q
UE
RY_EXPR_TEST"
))
{
assert0
(
session
.
isPreparingQueryExpression
(),
"preparing query expression"
);
}
else
if
(
getTable
().
getName
().
equals
(
"QRY_EXPR_TEST_NO"
))
{
}
else
if
(
getTable
().
getName
().
equals
(
"Q
UE
RY_EXPR_TEST_NO"
))
{
assert0
(!
session
.
isPreparingQueryExpression
(),
"not preparing query expression"
);
}
}
...
...
@@ -1588,7 +1588,7 @@ public class TestTableEngines extends TestBase {
@Override
public
String
toString
()
{
return
"IterCursor->"
+
current
;
return
"Iter
ator
Cursor->"
+
current
;
}
}
...
...
h2/src/test/org/h2/test/unit/TestDate.java
浏览文件 @
7e8fa541
...
...
@@ -474,7 +474,8 @@ public class TestDate extends TestBase {
assertEquals
(
"-999-08-07 13:14:15.16"
,
ts1a
.
getString
());
assertEquals
(
"19999-08-07 13:14:15.16"
,
ts2a
.
getString
());
// test for bug on Java 1.8.0_60 in "Europe/Moscow" timezone. Doesn't affect most other timezones
// test for bug on Java 1.8.0_60 in "Europe/Moscow" timezone.
// Doesn't affect most other timezones
long
millis
=
1407437460000L
;
long
result1
=
DateTimeUtils
.
nanosFromDate
(
DateTimeUtils
.
getTimeUTCWithoutDst
(
millis
));
long
result2
=
DateTimeUtils
.
nanosFromDate
(
DateTimeUtils
.
getTimeUTCWithoutDst
(
millis
));
...
...
h2/src/test/org/h2/test/unit/TestTimeStampUtc.java
浏览文件 @
7e8fa541
...
...
@@ -26,13 +26,13 @@ public class TestTimeStampUtc extends TestBase {
@Override
public
void
test
()
throws
SQLException
{
deleteDb
(
"timestamputc"
);
deleteDb
(
"timestamp
_
utc"
);
test1
();
deleteDb
(
"timestamputc"
);
deleteDb
(
"timestamp
_
utc"
);
}
private
void
test1
()
throws
SQLException
{
Connection
conn
=
getConnection
(
"timestamputc"
);
Connection
conn
=
getConnection
(
"timestamp
_
utc"
);
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table test(id identity, t1 timestamp_utc)"
);
stat
.
execute
(
"insert into test(t1) values(0)"
);
...
...
h2/src/tools/org/h2/build/BuildBase.java
浏览文件 @
7e8fa541
...
...
@@ -308,7 +308,7 @@ public class BuildBase {
protected
int
execScript
(
String
script
,
StringList
args
)
{
if
(
isWindows
())
{
// Under windows, we use the "cmd" command interpreter since it will
// search the path for us without us having to hardcode an extension
// search the path for us without us having to hard
-
code an extension
// for the script we want. (Sometimes we don't know if the extension
// will be .bat or .cmd)
StringList
newArgs
=
new
StringList
();
...
...
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
7e8fa541
...
...
@@ -778,10 +778,8 @@ dance schedule hitting reverted youngest footers inliner deadlocked reorder nger
nullid syspublic sysibmts sysibminternal syscat sysfun sysstat systools sysibmadm
sysproc jcc expecting gpg showed unreferenced activating cvf stephane lacoin
centrale umr ecole nantes sticc lab reordering preferable simultaneously
--- todo
timestamputc lazily satisfy nexpected messager participating eviction milli globally
futures atp lookups batches slot nnext forced tbl diagnostic filer stamp turn going
nwhere hardcode cancellation qry nprev fetched produced nactual incurring interpreter
batching ncurr prefered fewer runners iter
lazily satisfy participating eviction globally futures batches slot forced
diagnostic filer stamp turn going cancellation fetched produced incurring
interpreter batching fewer runners imperial correspond nine purge meridian
calendars moscow messager lookups unhandled buddha parslet
tzh roc xii tzm viii myydd mar vii
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论