Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
41c30c1c
提交
41c30c1c
authored
6 年前
作者:
Evgenij Ryazanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Implement date-time subtraction properly
上级
02ef458f
显示空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
85 行增加
和
26 行删除
+85
-26
IntervalOperation.java
h2/src/main/org/h2/expression/IntervalOperation.java
+54
-10
Operation.java
h2/src/main/org/h2/expression/Operation.java
+3
-11
interval.sql
h2/src/test/org/h2/test/scripts/datatypes/interval.sql
+23
-0
testScript.sql
h2/src/test/org/h2/test/scripts/testScript.sql
+5
-5
没有找到文件。
h2/src/main/org/h2/expression/IntervalOperation.java
浏览文件 @
41c30c1c
...
@@ -22,6 +22,7 @@ import org.h2.value.ValueDate;
...
@@ -22,6 +22,7 @@ import org.h2.value.ValueDate;
import
org.h2.value.ValueInterval
;
import
org.h2.value.ValueInterval
;
import
org.h2.value.ValueNull
;
import
org.h2.value.ValueNull
;
import
org.h2.value.ValueTime
;
import
org.h2.value.ValueTime
;
import
org.h2.value.ValueTimestampTimeZone
;
/**
/**
* A mathematical operation with intervals.
* A mathematical operation with intervals.
...
@@ -57,7 +58,12 @@ public class IntervalOperation extends Expression {
...
@@ -57,7 +58,12 @@ public class IntervalOperation extends Expression {
/**
/**
* Interval divided by numeric.
* Interval divided by numeric.
*/
*/
INTERVAL_DIVIDE_NUMERIC
INTERVAL_DIVIDE_NUMERIC
,
/**
* Date-time minus date-time.
*/
DATETIME_MINUS_DATETIME
}
}
private
final
IntervalOpType
opType
;
private
final
IntervalOpType
opType
;
...
@@ -68,16 +74,26 @@ public class IntervalOperation extends Expression {
...
@@ -68,16 +74,26 @@ public class IntervalOperation extends Expression {
this
.
opType
=
opType
;
this
.
opType
=
opType
;
this
.
left
=
left
;
this
.
left
=
left
;
this
.
right
=
right
;
this
.
right
=
right
;
int
l
=
left
.
getType
(),
r
=
right
.
getType
();
switch
(
opType
)
{
switch
(
opType
)
{
case
INTERVAL_PLUS_INTERVAL:
case
INTERVAL_PLUS_INTERVAL:
case
INTERVAL_MINUS_INTERVAL:
case
INTERVAL_MINUS_INTERVAL:
dataType
=
Value
.
getHigherOrder
(
l
eft
.
getType
(),
right
.
getType
()
);
dataType
=
Value
.
getHigherOrder
(
l
,
r
);
break
;
break
;
case
DATETIME_PLUS_INTERVAL:
case
DATETIME_PLUS_INTERVAL:
case
DATETIME_MINUS_INTERVAL:
case
DATETIME_MINUS_INTERVAL:
case
INTERVAL_MULTIPLY_NUMERIC:
case
INTERVAL_MULTIPLY_NUMERIC:
case
INTERVAL_DIVIDE_NUMERIC:
case
INTERVAL_DIVIDE_NUMERIC:
dataType
=
left
.
getType
();
dataType
=
l
;
break
;
case
DATETIME_MINUS_DATETIME:
if
(
l
==
Value
.
TIME
&&
r
==
Value
.
TIME
)
{
dataType
=
Value
.
INTERVAL_HOUR_TO_SECOND
;
}
else
if
(
l
==
Value
.
DATE
&&
r
==
Value
.
DATE
)
{
dataType
=
Value
.
INTERVAL_DAY
;
}
else
{
dataType
=
Value
.
INTERVAL_DAY_TO_SECOND
;
}
}
}
}
}
...
@@ -93,6 +109,7 @@ public class IntervalOperation extends Expression {
...
@@ -93,6 +109,7 @@ public class IntervalOperation extends Expression {
return
'+'
;
return
'+'
;
case
INTERVAL_MINUS_INTERVAL:
case
INTERVAL_MINUS_INTERVAL:
case
DATETIME_MINUS_INTERVAL:
case
DATETIME_MINUS_INTERVAL:
case
DATETIME_MINUS_DATETIME:
return
'-'
;
return
'-'
;
case
INTERVAL_MULTIPLY_NUMERIC:
case
INTERVAL_MULTIPLY_NUMERIC:
return
'*'
;
return
'*'
;
...
@@ -110,21 +127,22 @@ public class IntervalOperation extends Expression {
...
@@ -110,21 +127,22 @@ public class IntervalOperation extends Expression {
if
(
l
==
ValueNull
.
INSTANCE
||
r
==
ValueNull
.
INSTANCE
)
{
if
(
l
==
ValueNull
.
INSTANCE
||
r
==
ValueNull
.
INSTANCE
)
{
return
ValueNull
.
INSTANCE
;
return
ValueNull
.
INSTANCE
;
}
}
int
lType
=
l
.
getType
(),
rType
=
r
.
getType
();
switch
(
opType
)
{
switch
(
opType
)
{
case
INTERVAL_PLUS_INTERVAL:
case
INTERVAL_PLUS_INTERVAL:
case
INTERVAL_MINUS_INTERVAL:
{
case
INTERVAL_MINUS_INTERVAL:
{
BigInteger
a1
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
l
);
BigInteger
a1
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
l
);
BigInteger
a2
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
r
);
BigInteger
a2
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
r
);
return
DateTimeUtils
.
intervalFromAbsolute
(
return
DateTimeUtils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
Value
.
getHigherOrder
(
l
.
getType
(),
r
.
getType
()
)
-
Value
.
INTERVAL_YEAR
),
IntervalQualifier
.
valueOf
(
Value
.
getHigherOrder
(
l
Type
,
rType
)
-
Value
.
INTERVAL_YEAR
),
opType
==
IntervalOpType
.
INTERVAL_PLUS_INTERVAL
?
a1
.
add
(
a2
)
:
a1
.
subtract
(
a2
));
opType
==
IntervalOpType
.
INTERVAL_PLUS_INTERVAL
?
a1
.
add
(
a2
)
:
a1
.
subtract
(
a2
));
}
}
case
DATETIME_PLUS_INTERVAL:
case
DATETIME_PLUS_INTERVAL:
case
DATETIME_MINUS_INTERVAL:
case
DATETIME_MINUS_INTERVAL:
switch
(
l
.
getType
()
)
{
switch
(
l
Type
)
{
case
Value
.
TIME
:
{
case
Value
.
TIME
:
{
if
(
DataType
.
isYearMonthIntervalType
(
r
.
getType
()
))
{
if
(
DataType
.
isYearMonthIntervalType
(
r
Type
))
{
throw
DbException
.
throwInternalError
(
"type="
+
r
.
getType
()
);
throw
DbException
.
throwInternalError
(
"type="
+
r
Type
);
}
}
BigInteger
a1
=
BigInteger
.
valueOf
(((
ValueTime
)
l
).
getNanos
());
BigInteger
a1
=
BigInteger
.
valueOf
(((
ValueTime
)
l
).
getNanos
());
BigInteger
a2
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
r
);
BigInteger
a2
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
r
);
...
@@ -137,7 +155,7 @@ public class IntervalOperation extends Expression {
...
@@ -137,7 +155,7 @@ public class IntervalOperation extends Expression {
case
Value
.
DATE
:
case
Value
.
DATE
:
case
Value
.
TIMESTAMP
:
case
Value
.
TIMESTAMP
:
case
Value
.
TIMESTAMP_TZ
:
case
Value
.
TIMESTAMP_TZ
:
if
(
DataType
.
isYearMonthIntervalType
(
r
.
getType
()
))
{
if
(
DataType
.
isYearMonthIntervalType
(
r
Type
))
{
long
m
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
r
).
longValue
();
long
m
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
r
).
longValue
();
if
(
opType
==
IntervalOpType
.
DATETIME_MINUS_INTERVAL
)
{
if
(
opType
==
IntervalOpType
.
DATETIME_MINUS_INTERVAL
)
{
m
=
-
m
;
m
=
-
m
;
...
@@ -145,7 +163,7 @@ public class IntervalOperation extends Expression {
...
@@ -145,7 +163,7 @@ public class IntervalOperation extends Expression {
return
DateTimeFunctions
.
dateadd
(
"MONTH"
,
m
,
l
);
return
DateTimeFunctions
.
dateadd
(
"MONTH"
,
m
,
l
);
}
else
{
}
else
{
BigInteger
a2
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
r
);
BigInteger
a2
=
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
r
);
if
(
l
.
getType
()
==
Value
.
DATE
)
{
if
(
l
Type
==
Value
.
DATE
)
{
BigInteger
a1
=
BigInteger
BigInteger
a1
=
BigInteger
.
valueOf
(
DateTimeUtils
.
absoluteDayFromDateValue
(((
ValueDate
)
l
).
getDateValue
()));
.
valueOf
(
DateTimeUtils
.
absoluteDayFromDateValue
(((
ValueDate
)
l
).
getDateValue
()));
a2
=
a2
.
divide
(
BigInteger
.
valueOf
(
DateTimeUtils
.
NANOS_PER_DAY
));
a2
=
a2
.
divide
(
BigInteger
.
valueOf
(
DateTimeUtils
.
NANOS_PER_DAY
));
...
@@ -180,10 +198,36 @@ public class IntervalOperation extends Expression {
...
@@ -180,10 +198,36 @@ public class IntervalOperation extends Expression {
case
INTERVAL_DIVIDE_NUMERIC:
{
case
INTERVAL_DIVIDE_NUMERIC:
{
BigDecimal
a1
=
new
BigDecimal
(
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
l
));
BigDecimal
a1
=
new
BigDecimal
(
DateTimeUtils
.
intervalToAbsolute
((
ValueInterval
)
l
));
BigDecimal
a2
=
r
.
getBigDecimal
();
BigDecimal
a2
=
r
.
getBigDecimal
();
return
DateTimeUtils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
l
.
getType
()
-
Value
.
INTERVAL_YEAR
),
return
DateTimeUtils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
l
Type
-
Value
.
INTERVAL_YEAR
),
(
opType
==
IntervalOpType
.
INTERVAL_MULTIPLY_NUMERIC
?
a1
.
multiply
(
a2
)
:
a1
.
divide
(
a2
))
(
opType
==
IntervalOpType
.
INTERVAL_MULTIPLY_NUMERIC
?
a1
.
multiply
(
a2
)
:
a1
.
divide
(
a2
))
.
toBigInteger
());
.
toBigInteger
());
}
}
case
DATETIME_MINUS_DATETIME:
if
(
lType
==
Value
.
TIME
&&
rType
==
Value
.
TIME
)
{
long
diff
=
((
ValueTime
)
l
).
getNanos
()
-
((
ValueTime
)
r
).
getNanos
();
return
ValueInterval
.
from
(
IntervalQualifier
.
HOUR_TO_SECOND
,
diff
/
3_600_000_000_000L
,
Math
.
abs
(
diff
%
3_600_000_000_000L
));
}
else
if
(
lType
==
Value
.
DATE
&&
rType
==
Value
.
DATE
)
{
return
ValueInterval
.
from
(
IntervalQualifier
.
DAY
,
DateTimeUtils
.
absoluteDayFromDateValue
(((
ValueDate
)
l
).
getDateValue
())
-
DateTimeUtils
.
absoluteDayFromDateValue
(((
ValueDate
)
r
).
getDateValue
()),
0L
);
}
else
{
long
[]
a
=
DateTimeUtils
.
dateAndTimeFromValue
(
l
);
long
[]
b
=
DateTimeUtils
.
dateAndTimeFromValue
(
r
);
BigInteger
bi1
=
BigInteger
.
valueOf
(
a
[
0
]).
multiply
(
BigInteger
.
valueOf
(
DateTimeUtils
.
NANOS_PER_DAY
))
.
add
(
BigInteger
.
valueOf
(
a
[
1
]));
BigInteger
bi2
=
BigInteger
.
valueOf
(
b
[
0
]).
multiply
(
BigInteger
.
valueOf
(
DateTimeUtils
.
NANOS_PER_DAY
))
.
add
(
BigInteger
.
valueOf
(
b
[
1
]));
BigInteger
diff
=
bi1
.
subtract
(
bi2
);
if
(
lType
==
Value
.
TIMESTAMP_TZ
||
rType
==
Value
.
TIMESTAMP_TZ
)
{
l
=
l
.
convertTo
(
Value
.
TIMESTAMP_TZ
);
r
=
r
.
convertTo
(
Value
.
TIMESTAMP_TZ
);
diff
=
diff
.
add
(
BigInteger
.
valueOf
((((
ValueTimestampTimeZone
)
r
).
getTimeZoneOffsetMins
()
-
((
ValueTimestampTimeZone
)
l
).
getTimeZoneOffsetMins
())
*
60_000_000_000L
));
}
return
DateTimeUtils
.
intervalFromAbsolute
(
IntervalQualifier
.
DAY_TO_SECOND
,
diff
);
}
}
}
throw
DbException
.
throwInternalError
(
"type="
+
opType
);
throw
DbException
.
throwInternalError
(
"type="
+
opType
);
}
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/expression/Operation.java
浏览文件 @
41c30c1c
...
@@ -388,21 +388,13 @@ public class Operation extends Expression {
...
@@ -388,21 +388,13 @@ public class Operation extends Expression {
return
this
;
return
this
;
case
Value
.
DATE
:
case
Value
.
DATE
:
case
Value
.
TIMESTAMP
:
case
Value
.
TIMESTAMP
:
case
Value
.
TIMESTAMP_TZ
:
{
case
Value
.
TIMESTAMP_TZ
:
// Oracle date subtract
return
new
IntervalOperation
(
IntervalOpType
.
DATETIME_MINUS_DATETIME
,
left
,
right
);
Function
f
=
Function
.
getFunction
(
session
.
getDatabase
(),
"DATEDIFF"
);
f
.
setParameter
(
0
,
ValueExpression
.
get
(
ValueString
.
get
(
"DAY"
)));
f
.
setParameter
(
1
,
right
);
f
.
setParameter
(
2
,
left
);
f
.
doneWithParameters
();
return
f
.
optimize
(
session
);
}
}
}
break
;
break
;
case
Value
.
TIME
:
case
Value
.
TIME
:
if
(
r
==
Value
.
TIME
)
{
if
(
r
==
Value
.
TIME
)
{
dataType
=
Value
.
TIME
;
return
new
IntervalOperation
(
IntervalOpType
.
DATETIME_MINUS_DATETIME
,
left
,
right
);
return
this
;
}
}
break
;
break
;
}
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/scripts/datatypes/interval.sql
浏览文件 @
41c30c1c
...
@@ -669,3 +669,26 @@ SELECT INTERVAL '1-2' YEAR TO MONTH + TIMESTAMP WITH TIME ZONE '2000-01-01 12:00
...
@@ -669,3 +669,26 @@ SELECT INTERVAL '1-2' YEAR TO MONTH + TIMESTAMP WITH TIME ZONE '2000-01-01 12:00
SELECT
TIMESTAMP
WITH
TIME
ZONE
'2000-01-01 12:00:00+01'
-
INTERVAL
'1-2'
YEAR
TO
MONTH
;
SELECT
TIMESTAMP
WITH
TIME
ZONE
'2000-01-01 12:00:00+01'
-
INTERVAL
'1-2'
YEAR
TO
MONTH
;
>>
1998
-
11
-
01
12
:
00
:
00
+
01
>>
1998
-
11
-
01
12
:
00
:
00
+
01
-- Date-time subtraction
SELECT
TIME
'10:30:15.123456789'
-
TIME
'11:00:00'
;
>>
INTERVAL
'0:29:44.876543211'
HOUR
TO
SECOND
SELECT
DATE
'2010-01-15'
-
DATE
'2009-12-31'
;
>>
INTERVAL
'15'
DAY
SELECT
TIMESTAMP
'2010-01-15 12:00:00.5'
-
TIMESTAMP
'2010-01-13 01:30:00'
;
>>
INTERVAL
'2 10:30:00.5'
DAY
TO
SECOND
SELECT
TIMESTAMP
WITH
TIME
ZONE
'2010-01-15 12:00:00.5+01'
-
TIMESTAMP
WITH
TIME
ZONE
'2010-01-13 01:30:00+01'
;
>>
INTERVAL
'2 10:30:00.5'
DAY
TO
SECOND
SELECT
TIMESTAMP
WITH
TIME
ZONE
'2010-01-15 12:00:00.5+01'
-
TIMESTAMP
WITH
TIME
ZONE
'2010-01-13 01:30:00+02'
;
>>
INTERVAL
'2 11:30:00.5'
DAY
TO
SECOND
SELECT
TIMESTAMP
'2010-01-15 12:00:00.5+01'
-
TIMESTAMP
WITH
TIME
ZONE
'2010-01-13 01:30:00+02'
;
>>
INTERVAL
'2 11:30:00.5'
DAY
TO
SECOND
SELECT
TIMESTAMP
WITH
TIME
ZONE
'2010-01-15 12:00:00.5+01'
-
TIMESTAMP
'2010-01-13 01:30:00+02'
;
>>
INTERVAL
'2 11:30:00.5'
DAY
TO
SECOND
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/scripts/testScript.sql
浏览文件 @
41c30c1c
...
@@ -6132,11 +6132,11 @@ SELECT * FROM TEST;
...
@@ -6132,11 +6132,11 @@ SELECT * FROM TEST;
>
rows
:
4
>
rows
:
4
SELECT
XD
+
1
,
XD
-
1
,
XD
-
XD
FROM
TEST
;
SELECT
XD
+
1
,
XD
-
1
,
XD
-
XD
FROM
TEST
;
>
DATEADD
(
'DAY'
,
1
,
XD
)
DATEADD
(
'DAY'
,
-
1
,
XD
)
DATEDIFF
(
'DAY'
,
XD
,
XD
)
>
DATEADD
(
'DAY'
,
1
,
XD
)
DATEADD
(
'DAY'
,
-
1
,
XD
)
XD
-
XD
>
--------------------- ---------------------- ----------------
-------
>
--------------------- ---------------------- ----------------
>
0001
-
02
-
04
0001
-
02
-
02
0
>
0001
-
02
-
04
0001
-
02
-
02
INTERVAL
'0'
DAY
>
0004
-
05
-
07
0004
-
05
-
05
0
>
0004
-
05
-
07
0004
-
05
-
05
INTERVAL
'0'
DAY
>
2000
-
01
-
01
1999
-
12
-
30
0
>
2000
-
01
-
01
1999
-
12
-
30
INTERVAL
'0'
DAY
>
null
null
null
>
null
null
null
>
rows
:
4
>
rows
:
4
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论