Skip to content

Commit 3c7ed45

Browse files
Implement DayTimeInterval and YearMonthTimeInterval types (#512)
* Add support for DayTimeInterval and YearMonthTimeInterval * add tests for invalid inputs * require heavydb 6.2 * implement dunder hash for Type * Add DayTime and YearMonthTime to api.rst Co-authored-by: Pearu Peterson <[email protected]>
1 parent e55ca1d commit 3c7ed45

9 files changed

+652
-8
lines changed

doc/api.rst

+8-6
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,11 @@ one cannot create and use them inside the REPL, for instance.
7373
.. autosummary::
7474
:toctree: generated/
7575

76-
rbc.heavydb.Array
77-
rbc.heavydb.Column
78-
rbc.heavydb.ColumnList
79-
rbc.heavydb.TextEncodingDict
80-
rbc.heavydb.TextEncodingNone
81-
rbc.heavydb.Timestamp
76+
heavydb.Array
77+
heavydb.Column
78+
heavydb.ColumnList
79+
heavydb.TextEncodingDict
80+
heavydb.TextEncodingNone
81+
heavydb.Timestamp
82+
heavydb.DayTimeInterval
83+
heavydb.YearMonthTimeInterval

rbc/extension_functions.thrift

+4-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ enum TExtArgumentType {
7575
ColumnListArrayTextEncodingNone,
7676
ArrayTextEncodingDict,
7777
ColumnArrayTextEncodingDict,
78-
ColumnListArrayTextEncodingDict
78+
ColumnListArrayTextEncodingDict,
79+
GeoMultiPoint,
80+
DayTimeInterval,
81+
YearMonthTimeInterval,
7982
}
8083

8184
/* See QueryEngine/TableFunctions/TableFunctionsFactory.h for required

rbc/heavydb/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
from .string_dict_proxy import * # noqa: F401, F403
1111
from .text_encoding_none import * # noqa: F401, F403
1212
from .timestamp import * # noqa: F401, F403
13+
from .day_time_interval import * # noqa: F401, F403
14+
from .year_month_time_interval import * # noqa: F401, F403
1315
from .remoteheavydb import * # noqa: F401, F403
1416

1517
from . import mathimpl as math # noqa: F401

rbc/heavydb/day_time_interval.py

+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
"""RBC DayTimeInterval type."""
2+
import operator
3+
from rbc import typesystem
4+
from rbc.heavydb import HeavyDBMetaType
5+
from rbc.external import external
6+
from rbc.targetinfo import TargetInfo
7+
from numba.core import extending, cgutils, datamodel
8+
from numba.core import types as nb_types
9+
from .timestamp import TimestampNumbaType, Timestamp, kMicroSecsPerSec
10+
11+
__all__ = [
12+
"HeavyDBDayTimeIntervalType",
13+
"DayTimeInterval",
14+
"DayTimeIntervalNumbaType",
15+
]
16+
17+
18+
daYEAR = 0
19+
daQUARTER = 1
20+
daMONTH = 2
21+
daDAY = 3
22+
daHOUR = 4
23+
daMINUTE = 5
24+
daSECOND = 6
25+
daMILLENNIUM = 7
26+
daCENTURY = 8
27+
daDECADE = 9
28+
daMILLISECOND = 10
29+
daMICROSECOND = 11
30+
daNANOSECOND = 12
31+
daWEEK = 13
32+
daQUARTERDAY = 14
33+
daWEEKDAY = 15
34+
daDAYOFYEAR = 16
35+
daINVALID = 17
36+
37+
38+
class DayTimeInterval(metaclass=HeavyDBMetaType):
39+
"""
40+
RBC ``DayTimeInterval`` type.
41+
42+
.. code-block:: c
43+
44+
struct DayTimeInterval {
45+
int64_t timeval;
46+
};
47+
48+
"""
49+
50+
def __init__(self, timeval: int) -> 'DayTimeInterval':
51+
pass
52+
53+
def numStepsBetween(self, start: Timestamp, stop: Timestamp) -> int:
54+
"""
55+
Return a new ``Timestamp`` with ``time`` truncated to microseconds
56+
"""
57+
pass
58+
59+
def __eq__(self, other: "DayTimeInterval") -> bool:
60+
""" """
61+
pass
62+
63+
def __ne__(self, other: "DayTimeInterval") -> bool:
64+
""" """
65+
pass
66+
67+
def __mul__(self, other: int) -> bool:
68+
""" """
69+
pass
70+
71+
def __add__(self, other: Timestamp) -> bool:
72+
""" """
73+
pass
74+
75+
76+
class DayTimeIntervalNumbaType(nb_types.Type):
77+
def __init__(self):
78+
super().__init__(name="DayTimeInterval")
79+
80+
81+
@extending.register_model(DayTimeIntervalNumbaType)
82+
class DayTimeIntervalModel(datamodel.models.StructModel):
83+
def __init__(self, dmm, fe_type):
84+
members = [
85+
("timeval", nb_types.int64),
86+
]
87+
datamodel.models.StructModel.__init__(self, dmm, fe_type, members)
88+
89+
90+
extending.make_attribute_wrapper(DayTimeIntervalNumbaType, "timeval", "timeval")
91+
92+
93+
class HeavyDBDayTimeIntervalType(typesystem.Type):
94+
"""Typesystem type class for HeavyDB DayTimeInterval structures."""
95+
96+
@property
97+
def __typesystem_type__(self):
98+
return typesystem.Type.fromstring("{int64 timeval}").params(
99+
name="DayTimeInterval", NumbaType=DayTimeIntervalNumbaType
100+
)
101+
102+
def tonumba(self, bool_is_int8=None):
103+
return DayTimeIntervalNumbaType()
104+
105+
def tostring(
106+
self,
107+
use_typename=False,
108+
use_annotation=True,
109+
use_name=True,
110+
use_annotation_name=False,
111+
_skip_annotation=False,
112+
):
113+
return "DayTimeInterval"
114+
115+
116+
@extending.type_callable(DayTimeInterval)
117+
def type_heavydb_daytimeinterval(context):
118+
def typer(arg):
119+
if isinstance(arg, nb_types.Integer):
120+
return typesystem.Type.fromobject("DayTimeInterval").tonumba()
121+
122+
return typer
123+
124+
125+
@extending.lower_builtin(DayTimeInterval, nb_types.Integer)
126+
def heavydb_daytimeinterval_int_ctor(context, builder, sig, args):
127+
timeval = args[0]
128+
typ = sig.return_type
129+
dti = cgutils.create_struct_proxy(typ)(context, builder)
130+
dti.timeval = timeval
131+
return dti._getvalue()
132+
133+
134+
@extending.overload(operator.mul)
135+
def ol_day_time_interval_operator_mul(a, t):
136+
if isinstance(a, DayTimeIntervalNumbaType) and isinstance(t, nb_types.Integer):
137+
138+
def impl(a, t):
139+
return DayTimeInterval(a.timeval * t)
140+
141+
return impl
142+
143+
144+
@extending.overload(operator.eq)
145+
def ol_day_time_interval_operator_eq(a, b):
146+
if isinstance(a, DayTimeIntervalNumbaType) and isinstance(
147+
b, DayTimeIntervalNumbaType
148+
):
149+
150+
def impl(a, b):
151+
return a.timeval == b.timeval
152+
153+
return impl
154+
155+
156+
@extending.overload(operator.ne)
157+
def ol_day_time_interval_operator_ne(a, b):
158+
if isinstance(a, DayTimeIntervalNumbaType) and isinstance(
159+
b, DayTimeIntervalNumbaType
160+
):
161+
162+
def impl(a, b):
163+
return not (a == b)
164+
165+
return impl
166+
167+
168+
@extending.overload(operator.add)
169+
def ol_day_time_interval_operator_add(a, b):
170+
from .timestamp import Timestamp, TimestampNumbaType
171+
172+
target_info = TargetInfo()
173+
i64_null_val = target_info.null_values["int64"]
174+
if target_info.is_cpu:
175+
DateAddHighPrecisionNullable = external(
176+
"int64 DateAddHighPrecisionNullable(int64, int64, int64, int32, int64)|cpu"
177+
)
178+
179+
if isinstance(a, DayTimeIntervalNumbaType) and isinstance(b, TimestampNumbaType):
180+
181+
def impl(a, b):
182+
t = DateAddHighPrecisionNullable(
183+
daMILLISECOND, a.timeval, b.time, 9, i64_null_val
184+
)
185+
return Timestamp(t)
186+
187+
return impl
188+
elif isinstance(a, TimestampNumbaType) and isinstance(b, DayTimeIntervalNumbaType):
189+
190+
def impl(a, b):
191+
t = DateAddHighPrecisionNullable(
192+
daMILLISECOND, b.timeval, a.time, 9, i64_null_val
193+
)
194+
return Timestamp(t)
195+
196+
return impl
197+
198+
199+
@extending.overload_method(DayTimeIntervalNumbaType, "numStepsBetween")
200+
def ol_day_time_interval_numStepBetween_method(dti, begin, end):
201+
# importing here to avoid circular dependency error
202+
203+
if isinstance(begin, TimestampNumbaType) and isinstance(end, TimestampNumbaType):
204+
205+
def impl(dti, begin, end):
206+
timeval = dti.timeval
207+
if (timeval > 0 and end.time < begin.time) or (
208+
timeval < 0 and end.time > begin.time
209+
):
210+
return -1
211+
212+
diff = nb_types.int64(end.time - begin.time)
213+
asNanoSecs = timeval * kMicroSecsPerSec
214+
return diff // asNanoSecs
215+
return impl

rbc/heavydb/remoteheavydb.py

+4
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@ def add(a, b):
409409
TableFunctionManager='HeavyDBTableFunctionManagerType',
410410
RowFunctionManager='HeavyDBRowFunctionManagerType',
411411
Timestamp='HeavyDBTimestampType',
412+
DayTimeInterval='HeavyDBDayTimeIntervalType',
413+
YearMonthTimeInterval='HeavyDBYearMonthTimeIntervalType',
412414
UDTF='int32|kind=UDTF'
413415
)
414416

@@ -900,6 +902,8 @@ def _get_ext_arguments_map(self):
900902
'TextEncodingNone': typemap['TExtArgumentType'].get('TextEncodingNone'),
901903
'TextEncodingDict': typemap['TExtArgumentType'].get('TextEncodingDict'),
902904
'Timestamp': typemap['TExtArgumentType'].get('Timestamp'),
905+
'DayTimeInterval': typemap['TExtArgumentType'].get('DayTimeInterval'),
906+
'YearMonthTimeInterval': typemap['TExtArgumentType'].get('YearMonthTimeInterval'),
903907
}
904908

905909
if self.version[:2] < (5, 4):

0 commit comments

Comments
 (0)