forked from heavyai/heavydb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDateTimeUtils.h
189 lines (168 loc) · 5.91 KB
/
DateTimeUtils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
* Copyright 2022 HEAVY.AI, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "DateAdd.h"
#include "DateTruncate.h"
#include <cstdint>
#include <ctime>
#include <map>
#include <string>
#include "../Shared/sqldefs.h"
namespace {
static const std::map<std::pair<int32_t, ExtractField>, std::pair<SQLOps, int64_t>>
extract_precision_lookup = {{{3, kMICROSECOND}, {kMULTIPLY, kMilliSecsPerSec}},
{{3, kNANOSECOND}, {kMULTIPLY, kMicroSecsPerSec}},
{{6, kMILLISECOND}, {kDIVIDE, kMilliSecsPerSec}},
{{6, kNANOSECOND}, {kMULTIPLY, kMilliSecsPerSec}},
{{9, kMILLISECOND}, {kDIVIDE, kMicroSecsPerSec}},
{{9, kMICROSECOND}, {kDIVIDE, kMilliSecsPerSec}}};
static const std::map<std::pair<int32_t, DatetruncField>, int64_t>
datetrunc_precision_lookup = {{{6, dtMILLISECOND}, kMilliSecsPerSec},
{{9, dtMICROSECOND}, kMilliSecsPerSec},
{{9, dtMILLISECOND}, kMicroSecsPerSec}};
} // namespace
namespace DateTimeUtils {
// Enum helpers for precision scaling up/down.
enum ScalingType { ScaleUp, ScaleDown };
constexpr inline int64_t get_timestamp_precision_scale(const int32_t dimen) {
switch (dimen) {
case 0:
return 1;
case 3:
return kMilliSecsPerSec;
case 6:
return kMicroSecsPerSec;
case 9:
return kNanoSecsPerSec;
default:
throw std::runtime_error("Unknown dimen = " + std::to_string(dimen));
}
return -1;
}
constexpr inline int64_t get_dateadd_timestamp_precision_scale(const DateaddField field) {
switch (field) {
case daMILLISECOND:
return kMilliSecsPerSec;
case daMICROSECOND:
return kMicroSecsPerSec;
case daNANOSECOND:
return kNanoSecsPerSec;
default:
throw std::runtime_error("Unknown field = " + std::to_string(field));
}
return -1;
}
constexpr inline int64_t get_extract_timestamp_precision_scale(const ExtractField field) {
switch (field) {
case kMILLISECOND:
return kMilliSecsPerSec;
case kMICROSECOND:
return kMicroSecsPerSec;
case kNANOSECOND:
return kNanoSecsPerSec;
default:
throw std::runtime_error("Unknown field = " + std::to_string(field));
}
return -1;
}
constexpr inline bool is_subsecond_extract_field(const ExtractField& field) {
return field == kMILLISECOND || field == kMICROSECOND || field == kNANOSECOND;
}
constexpr inline bool is_subsecond_dateadd_field(const DateaddField field) {
return field == daMILLISECOND || field == daMICROSECOND || field == daNANOSECOND;
}
constexpr inline bool is_subsecond_datetrunc_field(const DatetruncField field) {
return field == dtMILLISECOND || field == dtMICROSECOND || field == dtNANOSECOND;
}
const inline std::pair<SQLOps, int64_t> get_dateadd_high_precision_adjusted_scale(
const DateaddField field,
int32_t dimen) {
switch (field) {
case daNANOSECOND:
switch (dimen) {
case 9:
return {};
case 6:
return {kDIVIDE, kMilliSecsPerSec};
case 3:
return {kDIVIDE, kMicroSecsPerSec};
default:
throw std::runtime_error("Unknown dimen = " + std::to_string(dimen));
}
case daMICROSECOND:
switch (dimen) {
case 9:
return {kMULTIPLY, kMilliSecsPerSec};
case 6:
return {};
case 3:
return {kDIVIDE, kMilliSecsPerSec};
default:
throw std::runtime_error("Unknown dimen = " + std::to_string(dimen));
}
case daMILLISECOND:
switch (dimen) {
case 9:
return {kMULTIPLY, kMicroSecsPerSec};
case 6:
return {kMULTIPLY, kMilliSecsPerSec};
case 3:
return {};
default:
throw std::runtime_error("Unknown dimen = " + std::to_string(dimen));
}
default:
throw std::runtime_error("Unknown field = " + std::to_string(field));
}
return {};
}
const inline std::pair<SQLOps, int64_t> get_extract_high_precision_adjusted_scale(
const ExtractField& field,
const int32_t dimen) {
const auto result = extract_precision_lookup.find(std::make_pair(dimen, field));
if (result != extract_precision_lookup.end()) {
return result->second;
}
return {};
}
const inline int64_t get_datetrunc_high_precision_scale(const DatetruncField& field,
const int32_t dimen) {
const auto result = datetrunc_precision_lookup.find(std::make_pair(dimen, field));
if (result != datetrunc_precision_lookup.end()) {
return result->second;
}
return -1;
}
constexpr inline int64_t get_datetime_scaled_epoch(const ScalingType direction,
const int64_t epoch,
const int32_t dimen) {
switch (direction) {
case ScaleUp: {
const auto scaled_epoch = epoch * get_timestamp_precision_scale(dimen);
if (epoch && epoch != scaled_epoch / get_timestamp_precision_scale(dimen)) {
throw std::runtime_error(
"Value Overflow/underflow detected while scaling DateTime precision.");
}
return scaled_epoch;
}
case ScaleDown:
return epoch / get_timestamp_precision_scale(dimen);
default:
abort();
}
return std::numeric_limits<int64_t>::min();
}
} // namespace DateTimeUtils