1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * @t Temporal analytic module
11 * @a Pedro Ferreira
12 * @v 1.0
13 *
14 * Ranges calculation for temporal types for SQL windowing functions.
15 */
16
17#include "monetdb_config.h"
18#include "mal_exception.h"
19#include "mtime.h"
20
21#define date_sub_month(D,M) date_add_month(D,-(M))
22#define timestamp_sub_month(T,M) timestamp_add_month(T,-(M))
23
24#define daytime_add_msec(D,M) daytime_add_usec(D, 1000*(M))
25#define daytime_sub_msec(D,M) daytime_add_usec(D, -1000*(M))
26#define date_add_msec(D,M) date_add_day(D,(int) ((M)/(24*60*60*1000)))
27#define date_sub_msec(D,M) date_add_day(D,(int) (-(M)/(24*60*60*1000)))
28#define timestamp_add_msec(T,M) timestamp_add_usec(T, (M)*1000)
29#define timestamp_sub_msec(T,M) timestamp_add_usec(T, -(M)*1000)
30
31#define ANALYTICAL_WINDOW_BOUNDS_FIXED_RANGE_MTIME_PRECEDING(TPE1, LIMIT, TPE2, SUB, ADD) \
32 do { \
33 lng m = k - 1; \
34 TPE1 v, vmin, vmax; \
35 TPE2 rlimit; \
36 if (b->tnonil) { \
37 for (; k<i; k++, rb++) { \
38 rlimit = (TPE2) LIMIT; \
39 v = bp[k]; \
40 vmin = SUB(v, rlimit); \
41 vmax = ADD(v, rlimit); \
42 for (j=k; ; j--) { \
43 if (j == m) \
44 break; \
45 if ((!is_##TPE1##_nil(vmin) && bp[j] < vmin) || \
46 (!is_##TPE1##_nil(vmax) && bp[j] > vmax)) \
47 break; \
48 } \
49 j++; \
50 *rb = j; \
51 } \
52 } else { \
53 for (; k<i; k++, rb++) { \
54 rlimit = (TPE2) LIMIT; \
55 v = bp[k]; \
56 if (is_##TPE1##_nil(v)) { \
57 for (j=k; ; j--) { \
58 if (!is_##TPE1##_nil(bp[j])) \
59 break; \
60 } \
61 } else { \
62 vmin = SUB(v, rlimit); \
63 vmax = ADD(v, rlimit); \
64 for (j=k; ; j--) { \
65 if (j == m) \
66 break; \
67 if (is_##TPE1##_nil(bp[j])) \
68 break; \
69 if ((!is_##TPE1##_nil(vmin) && bp[j] < vmin) || \
70 (!is_##TPE1##_nil(vmax) && bp[j] > vmax)) \
71 break; \
72 } \
73 } \
74 j++; \
75 *rb = j; \
76 } \
77 } \
78 } while(0)
79
80#define ANALYTICAL_WINDOW_BOUNDS_FIXED_RANGE_MTIME_FOLLOWING(TPE1, LIMIT, TPE2, SUB, ADD) \
81 do { \
82 TPE1 v, vmin, vmax; \
83 TPE2 rlimit; \
84 if (b->tnonil) { \
85 for (; k<i; k++, rb++) { \
86 rlimit = (TPE2) LIMIT; \
87 v = bp[k]; \
88 vmin = SUB(v, rlimit); \
89 vmax = ADD(v, rlimit); \
90 for (j=k+1; j<i; j++) { \
91 if ((!is_##TPE1##_nil(vmin) && bp[j] < vmin) || \
92 (!is_##TPE1##_nil(vmax) && bp[j] > vmax)) \
93 break; \
94 } \
95 *rb = j; \
96 } \
97 } else { \
98 for (; k<i; k++, rb++) { \
99 rlimit = (TPE2) LIMIT; \
100 v = bp[k]; \
101 if (is_##TPE1##_nil(v)) { \
102 for (j=k+1; j<i; j++) { \
103 if (!is_##TPE1##_nil(bp[j])) \
104 break; \
105 } \
106 } else { \
107 vmin = SUB(v, rlimit); \
108 vmax = ADD(v, rlimit); \
109 for (j=k+1; j<i; j++) { \
110 if (is_##TPE1##_nil(bp[j])) \
111 break; \
112 if ((!is_##TPE1##_nil(vmin) && bp[j] < vmin) || \
113 (!is_##TPE1##_nil(vmax) && bp[j] > vmax)) \
114 break; \
115 } \
116 } \
117 *rb = j; \
118 } \
119 } \
120 } while(0)
121
122#define ANALYTICAL_WINDOW_BOUNDS_CALC_FIXED_MTIME(TPE1, IMP, LIMIT, TPE2, SUB, ADD) \
123 do { \
124 TPE1 *restrict bp = (TPE1*)Tloc(b, 0); \
125 if(np) { \
126 nend += cnt; \
127 for(; np<nend; np++) { \
128 if (*np) { \
129 i += (np - pnp); \
130 IMP(TPE1, LIMIT, TPE2, SUB, ADD); \
131 pnp = np; \
132 } \
133 } \
134 i += (np - pnp); \
135 IMP(TPE1, LIMIT, TPE2, SUB, ADD); \
136 } else { \
137 i += (lng) cnt; \
138 IMP(TPE1, LIMIT, TPE2, SUB, ADD); \
139 } \
140 } while(0)
141
142#define ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_MONTH_INTERVAL(IMP, LIMIT) \
143 do { \
144 if(tp1 == TYPE_date) { \
145 ANALYTICAL_WINDOW_BOUNDS_CALC_FIXED_MTIME(date, ANALYTICAL_WINDOW_BOUNDS_FIXED_RANGE_MTIME##IMP, LIMIT, int, date_sub_month, date_add_month); \
146 } else if(tp1 == TYPE_timestamp) { \
147 ANALYTICAL_WINDOW_BOUNDS_CALC_FIXED_MTIME(timestamp, ANALYTICAL_WINDOW_BOUNDS_FIXED_RANGE_MTIME##IMP, LIMIT, int, timestamp_sub_month, timestamp_add_month); \
148 } else { \
149 goto type_not_supported; \
150 } \
151 } while(0)
152
153#define ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_SEC_INTERVAL(IMP, LIMIT) \
154 do { \
155 if(tp1 == TYPE_daytime) { \
156 ANALYTICAL_WINDOW_BOUNDS_CALC_FIXED_MTIME(daytime, ANALYTICAL_WINDOW_BOUNDS_FIXED_RANGE_MTIME##IMP, LIMIT, lng, daytime_sub_msec, daytime_add_msec); \
157 } else if(tp1 == TYPE_date) { \
158 ANALYTICAL_WINDOW_BOUNDS_CALC_FIXED_MTIME(date, ANALYTICAL_WINDOW_BOUNDS_FIXED_RANGE_MTIME##IMP, LIMIT, lng, date_sub_msec, date_add_msec); \
159 } else if(tp1 == TYPE_timestamp) { \
160 ANALYTICAL_WINDOW_BOUNDS_CALC_FIXED_MTIME(timestamp, ANALYTICAL_WINDOW_BOUNDS_FIXED_RANGE_MTIME##IMP, LIMIT, lng, timestamp_sub_msec, timestamp_add_msec); \
161 } else { \
162 goto type_not_supported; \
163 } \
164 } while(0)
165
166str //VERY IMPORTANT -> the FRAME_ALL case shall never fall here, as well as FRAME_GROUPS and FRAME_ROWS
167MTIMEanalyticalrangebounds(BAT *r, BAT *b, BAT *p, BAT *l, const void* restrict bound, int tp1, int tp2,
168 bool preceding, lng first_half)
169{
170 BUN cnt = BATcount(b), nils = 0;
171 lng *restrict rb = (lng*) Tloc(r, 0), i = 0, k = 0, j = 0;
172 bit *np = p ? (bit*) Tloc(p, 0) : NULL, *pnp = np, *nend = np;
173 str msg = MAL_SUCCEED;
174
175 (void) first_half;
176 assert((l && !bound) || (!l && bound));
177
178 if (l) { /* dynamic bounds */
179 switch(tp2) {
180 case TYPE_int: { //month_interval (not available for daytime type)
181 int *restrict limit = (int*) Tloc(l, 0);
182 if(preceding) {
183 ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_MONTH_INTERVAL(_PRECEDING, limit[k]);
184 } else {
185 ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_MONTH_INTERVAL(_FOLLOWING, limit[k]);
186 }
187 } break;
188 case TYPE_lng: { //sec_interval, which are milliseconds
189 lng *restrict limit = (lng*) Tloc(l, 0);
190 if(preceding) {
191 ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_SEC_INTERVAL(_PRECEDING, limit[k]);
192 } else {
193 ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_SEC_INTERVAL(_FOLLOWING, limit[k]);
194 }
195 } break;
196 default:
197 goto bound_not_supported;
198 }
199 } else { /* static bounds */
200 switch(tp2) {
201 case TYPE_int: {
202 int limit = (*(int*)bound);
203 if(preceding) {
204 ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_MONTH_INTERVAL(_PRECEDING, limit);
205 } else {
206 ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_MONTH_INTERVAL(_FOLLOWING, limit);
207 }
208 } break;
209 case TYPE_lng: {
210 lng limit = (*(lng*)bound);
211 if(preceding) {
212 ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_SEC_INTERVAL(_PRECEDING, limit);
213 } else {
214 ANALYTICAL_WINDOW_BOUNDS_BRANCHES_RANGE_MTIME_SEC_INTERVAL(_FOLLOWING, limit);
215 }
216 } break;
217 default:
218 goto bound_not_supported;
219 }
220 }
221 BATsetcount(r, cnt);
222 r->tnonil = (nils == 0);
223 r->tnil = (nils > 0);
224 return msg;
225bound_not_supported:
226 throw(MAL, "mtime.analyticalrangebounds", SQLSTATE(42000) "range frame bound type %s not supported.\n", ATOMname(tp2));
227type_not_supported:
228 throw(MAL, "mtime.analyticalrangebounds", SQLSTATE(42000) "type %s not supported for %s frame bound type.\n", ATOMname(tp1), ATOMname(tp2));
229}
230