Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /* (c) M.L. Kersten
14 : Most optimizers need easy access to key information
15 : for proper plan generation. Amongst others, this
16 : information consists of the tuple count, size,
17 : min- and max-value, and the null-density.
18 :
19 : We made need an directly accessible structure to speedup
20 : analysis by optimizers.
21 : */
22 : #include "monetdb_config.h"
23 : #include "sql_statistics.h"
24 :
25 : static str
26 0 : sql_set_stats(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, int type)
27 : {
28 0 : mvc *m = NULL;
29 0 : str sch = NULL, tbl = NULL, col = NULL, msg = MAL_SUCCEED;
30 :
31 0 : if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
32 : return msg;
33 0 : if ((msg = checkSQLContext(cntxt)) != NULL)
34 : return msg;
35 :
36 0 : sch = *getArgReference_str(stk, pci, 1);
37 0 : tbl = *getArgReference_str(stk, pci, 2);
38 0 : col = *getArgReference_str(stk, pci, 3);
39 :
40 0 : sql_schema *s = mvc_bind_schema(m, sch);
41 0 : sql_table *t = s?mvc_bind_table(m, s, tbl):NULL;
42 0 : sql_column *c = t?mvc_bind_column(m, t, col):NULL;
43 0 : if (!c || !t || !s)
44 0 : throw(SQL, "sql.set_stats", SQLSTATE(42000) "Cannot not find Column '%s.%s.%s'", sch, tbl, col);
45 0 : sql_trans *tr = m->session->tr;
46 0 : sqlstore *store = tr->store;
47 0 : if (type > 0) {
48 0 : if (getArgType(mb, pci, 4) != c->type.type->localtype)
49 0 : throw(SQL, "sql.set_stats", SQLSTATE(42000) "Wrong value type '%s'", BATatoms[getArgType(mb, pci, 4)].name);
50 0 : ptr val = getArgReference(stk, pci, 4);
51 0 : store->storage_api.set_stats_col(tr, c, NULL, type==1?val:NULL, type==2?val:NULL);
52 : } else { /* count lng type */
53 0 : if (getArgType(mb, pci, 4) != TYPE_lng)
54 0 : throw(SQL, "sql.set_stats", SQLSTATE(42000) "Wrong value type '%s'", BATatoms[getArgType(mb, pci, 4)].name);
55 0 : lng cnt = *getArgReference_lng(stk, pci, 4);
56 0 : double est = (double) cnt;
57 0 : store->storage_api.set_stats_col(tr, c, &est, NULL, NULL);
58 : }
59 : return msg;
60 : }
61 :
62 : str
63 0 : sql_set_count_distinct(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
64 : {
65 0 : return sql_set_stats(cntxt, mb, stk, pci, 0);
66 : }
67 :
68 : str
69 0 : sql_set_min(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
70 : {
71 0 : return sql_set_stats(cntxt, mb, stk, pci, 1);
72 : }
73 :
74 : str
75 0 : sql_set_max(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
76 : {
77 0 : return sql_set_stats(cntxt, mb, stk, pci, 2);
78 : }
79 :
80 : str
81 49 : sql_analyze(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
82 : {
83 49 : mvc *m = NULL;
84 49 : sql_trans *tr = NULL;
85 49 : str sch = NULL, tbl = NULL, col = NULL, msg = MAL_SUCCEED;
86 49 : int argc = pci->argc, sfnd = 0, tfnd = 0, cfnd = 0;
87 :
88 49 : if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
89 : return msg;
90 49 : if ((msg = checkSQLContext(cntxt)) != NULL)
91 : return msg;
92 :
93 49 : tr = m->session->tr;
94 49 : switch (argc) {
95 12 : case 4:
96 12 : col = *getArgReference_str(stk, pci, 3);
97 12 : if (strNil(col))
98 0 : throw(SQL, "sql.analyze", SQLSTATE(42000) "Column name cannot be NULL");
99 : /* fall through */
100 : case 3:
101 44 : tbl = *getArgReference_str(stk, pci, 2);
102 44 : if (strNil(tbl))
103 0 : throw(SQL, "sql.analyze", SQLSTATE(42000) "Table name cannot be NULL");
104 : /* fall through */
105 : case 2:
106 49 : sch = *getArgReference_str(stk, pci, 1);
107 49 : if (strNil(sch))
108 0 : throw(SQL, "sql.analyze", SQLSTATE(42000) "Schema name cannot be NULL");
109 : }
110 :
111 49 : TRC_DEBUG(SQL_PARSER, "analyze %s.%s.%s\n", (sch ? sch : ""), (tbl ? tbl : " "), (col ? col : " "));
112 :
113 : /* Do all the validations before doing any analyze */
114 49 : struct os_iter si;
115 49 : os_iterator(&si, tr->cat->schemas, tr, NULL);
116 400 : for(sql_base *b = oi_next(&si); b; b = oi_next(&si)) {
117 352 : sql_schema *s = (sql_schema *)b;
118 352 : if (s->base.name[0] == '%')
119 304 : continue;
120 :
121 303 : if (sch && strcmp(s->base.name, sch))
122 255 : continue;
123 48 : sfnd = 1;
124 48 : struct os_iter oi;
125 48 : os_iterator(&oi, s->tables, tr, NULL);
126 5215 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
127 5168 : sql_table *t = (sql_table *)b;
128 :
129 5168 : if (tbl && strcmp(t->base.name, tbl))
130 4870 : continue;
131 44 : if (tbl && !isTable(t))
132 1 : throw(SQL, "sql.analyze", SQLSTATE(42S02) "%s '%s' is not persistent", TABLE_TYPE_DESCRIPTION(t->type, t->properties), t->base.name);
133 297 : if (isTable(t) && ol_first_node(t->columns)) {
134 124 : bool allowed = table_privs(m, t, PRIV_SELECT);
135 124 : tfnd |= allowed;
136 622 : for (node *ncol = ol_first_node((t)->columns); ncol; ncol = ncol->next) {
137 498 : sql_column *c = (sql_column *) ncol->data;
138 :
139 498 : if (col && strcmp(c->base.name, col))
140 18 : continue;
141 480 : if (!allowed && !column_privs(m, c, PRIV_SELECT))
142 0 : continue;
143 : cfnd = 1;
144 : tfnd |= cfnd;
145 : }
146 : }
147 : }
148 : }
149 48 : if (sch && !sfnd)
150 1 : throw(SQL, "sql.analyze", SQLSTATE(3F000) "Schema '%s' does not exist", sch);
151 47 : if (tbl && !tfnd)
152 0 : throw(SQL, "sql.analyze", SQLSTATE(42S02) "Table '%s' does not exist", tbl);
153 47 : if (col && !cfnd)
154 0 : throw(SQL, "sql.analyze", SQLSTATE(38000) "Column '%s' does not exist", col);
155 :
156 47 : sqlstore *store = tr->store;
157 47 : os_iterator(&si, tr->cat->schemas, tr, NULL);
158 384 : for(sql_base *b = oi_next(&si); b; b = oi_next(&si)) {
159 337 : sql_schema *s = (sql_schema *)b;
160 337 : if (b->name[0] == '%')
161 290 : continue;
162 :
163 290 : if (sch && strcmp(sch, b->name))
164 243 : continue;
165 47 : struct os_iter oi;
166 47 : os_iterator(&oi, s->tables, tr, NULL);
167 5214 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
168 5167 : sql_table *t = (sql_table *) b;
169 :
170 5167 : if (tbl && strcmp(b->name, tbl))
171 4870 : continue;
172 297 : if (isTable(t) && ol_first_node(t->columns)) {
173 124 : bool allowed = table_privs(m, t, PRIV_SELECT);
174 622 : for (node *ncol = ol_first_node((t)->columns); ncol; ncol = ncol->next) {
175 498 : sql_column *c = (sql_column *) ncol->data;
176 498 : if (!allowed && !column_privs(m, c, PRIV_SELECT))
177 0 : continue;
178 498 : BAT *b, *unq;
179 498 : ptr mn, mx;
180 :
181 498 : if (col && strcmp(c->base.name, col))
182 18 : continue;
183 :
184 480 : int access = c->storage_type && c->storage_type[0] == 'D' ? RD_EXT : RDONLY;
185 480 : if (!(b = store->storage_api.bind_col(tr, c, access)))
186 0 : continue; /* At the moment we ignore the error, but maybe we can change this */
187 480 : if (VIEWtparent(b)) { /* If it is a view get the parent BAT */
188 479 : BAT *nb = BATdescriptor(VIEWtparent(b));
189 479 : BBPunfix(b->batCacheid);
190 479 : b = nb;
191 479 : if (b == NULL)
192 0 : continue;
193 : }
194 :
195 : /* Collect new sorted and revsorted properties */
196 480 : (void) BATordered(b);
197 480 : (void) BATordered_rev(b);
198 :
199 : /* Check for nils existence */
200 480 : (void) BATcount_no_nil(b, NULL);
201 :
202 : /* Test if column is unique */
203 480 : if ((unq = BATunique(b, NULL)))
204 480 : BBPunfix(unq->batCacheid);
205 :
206 : /* Guess number of uniques if not entirely unique */
207 480 : (void) BATguess_uniques(b, NULL);
208 :
209 : /* Collect min and max values */
210 480 : mn = BATmin(b, NULL);
211 480 : GDKfree(mn);
212 480 : mx = BATmax(b, NULL);
213 480 : GDKfree(mx);
214 480 : BBPunfix(b->batCacheid);
215 : }
216 : }
217 : }
218 : }
219 : return MAL_SUCCEED;
220 : }
221 :
222 : str
223 217 : sql_statistics(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
224 : {
225 217 : BAT *cid, *sch, *tab, *col, *type, *width, *count, *unique, *nils, *minval, *maxval, *sorted, *revsorted;
226 217 : mvc *m = NULL;
227 217 : sql_trans *tr = NULL;
228 217 : sqlstore *store = NULL;
229 217 : bat *rcid = getArgReference_bat(stk, pci, 0);
230 217 : bat *rsch = getArgReference_bat(stk, pci, 1);
231 217 : bat *rtab = getArgReference_bat(stk, pci, 2);
232 217 : bat *rcol = getArgReference_bat(stk, pci, 3);
233 217 : bat *rtype = getArgReference_bat(stk, pci, 4);
234 217 : bat *rwidth = getArgReference_bat(stk, pci, 5);
235 217 : bat *rcount = getArgReference_bat(stk, pci, 6);
236 217 : bat *runique = getArgReference_bat(stk, pci, 7);
237 217 : bat *rnils = getArgReference_bat(stk, pci, 8);
238 217 : bat *rminval = getArgReference_bat(stk, pci, 9);
239 217 : bat *rmaxval = getArgReference_bat(stk, pci, 10);
240 217 : bat *rsorted = getArgReference_bat(stk, pci, 11);
241 217 : bat *rrevsorted = getArgReference_bat(stk, pci, 12);
242 217 : str sname = NULL, tname = NULL, cname = NULL, msg = MAL_SUCCEED;
243 217 : struct os_iter si = {0};
244 217 : BUN nrows = 0;
245 217 : int sfnd = 0, tfnd = 0, cfnd = 0;
246 217 : size_t buflen = 0;
247 217 : char *buf = NULL, *nval = NULL;
248 :
249 217 : if ((msg = getSQLContext(cntxt, mb, &m, NULL)) != NULL)
250 : return msg;
251 217 : if ((msg = checkSQLContext(cntxt)) != NULL)
252 : return msg;
253 :
254 217 : if (pci->argc - pci->retc >= 1) {
255 6 : sname = *getArgReference_str(stk, pci, pci->retc);
256 6 : if (strNil(sname))
257 0 : throw(SQL, "sql.statistics", SQLSTATE(42000) "Schema name cannot be NULL");
258 : }
259 217 : if (pci->argc - pci->retc >= 2) {
260 6 : tname = *getArgReference_str(stk, pci, pci->retc + 1);
261 6 : if (strNil(tname))
262 0 : throw(SQL, "sql.statistics", SQLSTATE(42000) "Table name cannot be NULL");
263 : }
264 217 : if (pci->argc - pci->retc >= 3) {
265 0 : cname = *getArgReference_str(stk, pci, pci->retc + 2);
266 0 : if (strNil(cname))
267 0 : throw(SQL, "sql.statistics", SQLSTATE(42000) "Column name cannot be NULL");
268 : }
269 :
270 217 : tr = m->session->tr;
271 217 : store = tr->store;
272 : /* Do all the validations before retrieving any statistics */
273 217 : os_iterator(&si, tr->cat->schemas, tr, NULL);
274 1742 : for(sql_base *b = oi_next(&si); b; b = oi_next(&si)) {
275 1525 : sql_schema *s = (sql_schema *)b;
276 1525 : if (s->base.name[0] == '%')
277 247 : continue;
278 :
279 1308 : if (sname && strcmp(s->base.name, sname))
280 30 : continue;
281 1278 : sfnd = 1;
282 1278 : struct os_iter oi;
283 1278 : os_iterator(&oi, s->tables, tr, NULL);
284 32230 : for(sql_base *b = oi_next(&oi); b; b = oi_next(&oi)) {
285 30952 : sql_table *t = (sql_table *)b;
286 :
287 30952 : if (tname && strcmp(t->base.name, tname))
288 750 : continue;
289 6 : if (tname && !isTable(t))
290 0 : throw(SQL, "sql.statistics", SQLSTATE(42S02) "%s '%s' is not persistent", TABLE_TYPE_DESCRIPTION(t->type, t->properties), t->base.name);
291 30202 : if (isTable(t) && ol_first_node(t->columns)) {
292 9520 : bool allowed = table_privs(m, t, PRIV_SELECT);
293 9520 : tfnd |= allowed;
294 58132 : for (node *ncol = ol_first_node((t)->columns); ncol; ncol = ncol->next) {
295 48612 : sql_column *c = (sql_column *) ncol->data;
296 :
297 48612 : if (cname && strcmp(c->base.name, cname))
298 0 : continue;
299 48612 : nrows++;
300 48612 : if (!allowed && !column_privs(m, c, PRIV_SELECT))
301 130 : continue;
302 : cfnd = 1;
303 : tfnd |= cfnd;
304 : }
305 : }
306 : }
307 : }
308 217 : if (sname && !sfnd)
309 0 : throw(SQL, "sql.statistics", SQLSTATE(3F000) "Schema '%s' does not exist", sname);
310 217 : if (tname && !tfnd)
311 0 : throw(SQL, "sql.statistics", SQLSTATE(42S02) "Table '%s' does not exist", tname);
312 217 : if (cname && !cfnd)
313 0 : throw(SQL, "sql.statistics", SQLSTATE(38000) "Column '%s' does not exist", cname);
314 :
315 217 : cid = COLnew(0, TYPE_int, nrows, TRANSIENT);
316 217 : sch = COLnew(0, TYPE_str, nrows, TRANSIENT);
317 217 : tab = COLnew(0, TYPE_str, nrows, TRANSIENT);
318 217 : col = COLnew(0, TYPE_str, nrows, TRANSIENT);
319 217 : type = COLnew(0, TYPE_str, nrows, TRANSIENT);
320 217 : width = COLnew(0, TYPE_int, nrows, TRANSIENT);
321 217 : count = COLnew(0, TYPE_lng, nrows, TRANSIENT);
322 217 : unique = COLnew(0, TYPE_bit, nrows, TRANSIENT);
323 217 : nils = COLnew(0, TYPE_bit, nrows, TRANSIENT);
324 217 : minval = COLnew(0, TYPE_str, nrows, TRANSIENT);
325 217 : maxval = COLnew(0, TYPE_str, nrows, TRANSIENT);
326 217 : sorted = COLnew(0, TYPE_bit, nrows, TRANSIENT);
327 217 : revsorted = COLnew(0, TYPE_bit, nrows, TRANSIENT);
328 :
329 217 : if (!cid || !sch || !tab || !col || !type || !width || !count || !unique || !nils || !minval || !maxval || !sorted || !revsorted) {
330 0 : msg = createException(SQL, "sql.statistics", SQLSTATE(HY013) MAL_MALLOC_FAIL);
331 0 : goto bailout;
332 : }
333 :
334 217 : si = (struct os_iter) {0};
335 217 : os_iterator(&si, tr->cat->schemas, tr, NULL);
336 1742 : for (sql_base *b = oi_next(&si); b; b = oi_next(&si)) {
337 1525 : sql_schema *s = (sql_schema *) b;
338 1525 : if ((sname && strcmp(b->name, sname)) || b->name[0] == '%')
339 247 : continue;
340 1278 : if (s->tables) {
341 1278 : struct os_iter oi;
342 :
343 1278 : os_iterator(&oi, s->tables, tr, NULL);
344 32230 : for (sql_base *bt = oi_next(&oi); bt; bt = oi_next(&oi)) {
345 30952 : sql_table *t = (sql_table *) bt;
346 30952 : if (tname && strcmp(bt->name, tname))
347 750 : continue;
348 30202 : if (isTable(t) && ol_first_node(t->columns)) {
349 9520 : bool allowed = table_privs(m, t, PRIV_SELECT);
350 58132 : for (node *ncol = ol_first_node((t)->columns); ncol; ncol = ncol->next) {
351 48612 : sql_column *c = (sql_column *) ncol->data;
352 48612 : if (!allowed && !column_privs(m, c, PRIV_SELECT))
353 130 : continue;
354 48482 : int w;
355 48482 : lng cnt;
356 48482 : bit un, hnils, issorted, isrevsorted, dict;
357 48482 : BAT *qd = NULL, *fb = NULL, *re = NULL;
358 :
359 48482 : if (cname && strcmp(c->base.name, cname))
360 0 : continue;
361 :
362 48482 : if (!(qd = store->storage_api.bind_col(tr, c, QUICK))) {
363 0 : msg = createException(SQL, "sql.statistics", SQLSTATE(HY005) "Cannot access column descriptor");
364 0 : goto bailout;
365 : }
366 48482 : BATiter qdi = bat_iterator(qd);
367 48482 : BATiter posi;
368 48482 : if ((dict = (c->storage_type && c->storage_type[0] == 'D'))) {
369 0 : if (!(re = store->storage_api.bind_col(tr, c, RD_EXT))) {
370 0 : bat_iterator_end(&qdi);
371 0 : msg = createException(SQL, "sql.statistics", SQLSTATE(HY005) "Cannot access column descriptor");
372 0 : goto bailout;
373 : }
374 0 : BATiter rei = bat_iterator(re);
375 0 : if (VIEWtparent(re)) { /* If it is a view get the parent BAT */
376 0 : BAT *nb = BATdescriptor(VIEWtparent(re));
377 0 : BBPunfix(re->batCacheid);
378 0 : re = nb;
379 0 : if (re == NULL) {
380 0 : bat_iterator_end(&qdi);
381 0 : bat_iterator_end(&rei);
382 0 : msg = createException(SQL, "sql.statistics", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
383 0 : goto bailout;
384 : }
385 : }
386 0 : issorted = qdi.sorted && rei.sorted;
387 0 : isrevsorted = qdi.revsorted && rei.revsorted;
388 0 : hnils = !rei.nonil || rei.nil;
389 0 : posi = bat_iterator_copy(&rei);
390 0 : bat_iterator_end(&rei);
391 : } else {
392 48482 : issorted = qdi.sorted;
393 48482 : isrevsorted = qdi.revsorted;
394 48482 : hnils = !qdi.nonil || qdi.nil;
395 48482 : posi = bat_iterator_copy(&qdi);
396 : }
397 :
398 48482 : w = qdi.width;
399 48482 : cnt = qdi.count;
400 48482 : un = qdi.key;
401 48482 : bat_iterator_end(&qdi);
402 :
403 96964 : if (BUNappend(cid, &c->base.id, false) != GDK_SUCCEED ||
404 96964 : BUNappend(sch, b->name, false) != GDK_SUCCEED ||
405 96964 : BUNappend(tab, bt->name, false) != GDK_SUCCEED ||
406 96964 : BUNappend(col, c->base.name, false) != GDK_SUCCEED ||
407 96964 : BUNappend(type, c->type.type->base.name, false) != GDK_SUCCEED ||
408 96964 : BUNappend(width, &w, false) != GDK_SUCCEED ||
409 96964 : BUNappend(count, &cnt, false) != GDK_SUCCEED ||
410 96964 : BUNappend(unique, &un, false) != GDK_SUCCEED ||
411 96964 : BUNappend(nils, &hnils, false) != GDK_SUCCEED ||
412 96964 : BUNappend(sorted, &issorted, false) != GDK_SUCCEED ||
413 48482 : BUNappend(revsorted, &isrevsorted, false) != GDK_SUCCEED) {
414 0 : bat_iterator_end(&posi);
415 0 : BBPreclaim(re);
416 0 : goto bailout;
417 : }
418 :
419 65372 : if (posi.minpos != BUN_NONE || posi.maxpos != BUN_NONE) {
420 16890 : bat_iterator_end(&posi);
421 16890 : if (dict) {
422 : fb = re;
423 : } else {
424 16890 : if (!(fb = store->storage_api.bind_col(tr, c, RDONLY))) {
425 0 : msg = createException(SQL, "sql.statistics", SQLSTATE(HY005) "Cannot access column descriptor");
426 0 : goto bailout;
427 : }
428 16890 : if (VIEWtparent(fb)) { /* If it is a view get the parent BAT */
429 16890 : BAT *nb = BATdescriptor(VIEWtparent(fb));
430 16890 : BBPunfix(fb->batCacheid);
431 16890 : fb = nb;
432 16890 : if (fb == NULL) {
433 0 : msg = createException(SQL, "sql.statistics", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
434 0 : goto bailout;
435 : }
436 : }
437 : }
438 :
439 16890 : BATiter fbi = bat_iterator(fb);
440 16890 : ssize_t (*tostr)(str*,size_t*,const void*,bool) = BATatoms[fbi.type].atomToStr;
441 16890 : if (fbi.minpos != BUN_NONE) {
442 16516 : if (tostr(&buf, &buflen, BUNtail(fbi, fbi.minpos), false) < 0) {
443 0 : bat_iterator_end(&fbi);
444 0 : BBPunfix(fb->batCacheid);
445 0 : msg = createException(SQL, "sql.statistics", SQLSTATE(HY013) MAL_MALLOC_FAIL);
446 0 : goto bailout;
447 : }
448 16516 : nval = buf;
449 : } else {
450 : nval = (char *) str_nil;
451 : }
452 16890 : if (BUNappend(minval, nval, false) != GDK_SUCCEED) {
453 0 : bat_iterator_end(&fbi);
454 0 : BBPunfix(fb->batCacheid);
455 0 : goto bailout;
456 : }
457 :
458 16890 : if (fbi.maxpos != BUN_NONE) {
459 16734 : if (tostr(&buf, &buflen, BUNtail(fbi, fbi.maxpos), false) < 0) {
460 0 : bat_iterator_end(&fbi);
461 0 : BBPunfix(fb->batCacheid);
462 0 : msg = createException(SQL, "sql.statistics", SQLSTATE(HY013) MAL_MALLOC_FAIL);
463 0 : goto bailout;
464 : }
465 16734 : nval = buf;
466 : } else {
467 : nval = (char *) str_nil;
468 : }
469 16890 : bat_iterator_end(&fbi);
470 16890 : if (BUNappend(maxval, nval, false) != GDK_SUCCEED) {
471 0 : BBPunfix(fb->batCacheid);
472 0 : goto bailout;
473 : }
474 16890 : BBPunfix(fb->batCacheid);
475 31592 : } else if (BUNappend(minval, str_nil, false) != GDK_SUCCEED || BUNappend(maxval, str_nil, false) != GDK_SUCCEED) {
476 0 : bat_iterator_end(&posi);
477 0 : BBPreclaim(re);
478 0 : goto bailout;
479 31592 : } else if (re) {
480 0 : bat_iterator_end(&posi);
481 0 : BBPunfix(re->batCacheid);
482 : } else {
483 31592 : bat_iterator_end(&posi);
484 : }
485 : }
486 : }
487 : }
488 : }
489 : }
490 :
491 217 : GDKfree(buf);
492 217 : *rcid = cid->batCacheid;
493 217 : BBPkeepref(cid);
494 217 : *rsch = sch->batCacheid;
495 217 : BBPkeepref(sch);
496 217 : *rtab = tab->batCacheid;
497 217 : BBPkeepref(tab);
498 217 : *rcol = col->batCacheid;
499 217 : BBPkeepref(col);
500 217 : *rtype = type->batCacheid;
501 217 : BBPkeepref(type);
502 217 : *rwidth = width->batCacheid;
503 217 : BBPkeepref(width);
504 217 : *rcount = count->batCacheid;
505 217 : BBPkeepref(count);
506 217 : *runique = unique->batCacheid;
507 217 : BBPkeepref(unique);
508 217 : *rnils = nils->batCacheid;
509 217 : BBPkeepref(nils);
510 217 : *rminval = minval->batCacheid;
511 217 : BBPkeepref(minval);
512 217 : *rmaxval = maxval->batCacheid;
513 217 : BBPkeepref(maxval);
514 217 : *rsorted = sorted->batCacheid;
515 217 : BBPkeepref(sorted);
516 217 : *rrevsorted = revsorted->batCacheid;
517 217 : BBPkeepref(revsorted);
518 217 : return MAL_SUCCEED;
519 0 : bailout:
520 0 : GDKfree(buf);
521 0 : BBPreclaim(cid);
522 0 : BBPreclaim(sch);
523 0 : BBPreclaim(tab);
524 0 : BBPreclaim(col);
525 0 : BBPreclaim(type);
526 0 : BBPreclaim(width);
527 0 : BBPreclaim(count);
528 0 : BBPreclaim(unique);
529 0 : BBPreclaim(nils);
530 0 : BBPreclaim(minval);
531 0 : BBPreclaim(maxval);
532 0 : BBPreclaim(sorted);
533 0 : BBPreclaim(revsorted);
534 0 : if (!msg)
535 0 : msg = createException(SQL, "sql.statistics", GDK_EXCEPTION);
536 : return msg;
537 : }
|