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 | |
166 | str //VERY IMPORTANT -> the FRAME_ALL case shall never fall here, as well as FRAME_GROUPS and FRAME_ROWS |
167 | MTIMEanalyticalrangebounds(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; |
225 | bound_not_supported: |
226 | throw(MAL, "mtime.analyticalrangebounds" , SQLSTATE(42000) "range frame bound type %s not supported.\n" , ATOMname(tp2)); |
227 | type_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 | |