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 : #include "monetdb_config.h"
14 : #include "opt_mergetable.h"
15 :
16 : typedef enum mat_type_t {
17 : mat_none = 0, /* Simple mat aligned operations (ie batcalc etc) */
18 : mat_grp = 1, /* result of phase one of a mat - group.new/derive */
19 : mat_ext = 2, /* mat_grp extend */
20 : mat_cnt = 3, /* mat_grp count */
21 : mat_tpn = 4, /* Phase one of topn on a mat */
22 : mat_slc = 5, /* Last phase of topn (or just slice) on a mat */
23 : mat_rdr = 6 /* Phase one of sorting, ie sorted the parts so far */
24 : } mat_type_t;
25 :
26 : typedef struct mat {
27 : InstrPtr mi; /* mat instruction */
28 : InstrPtr org; /* orignal instruction */
29 : int mv; /* mat variable */
30 : int im; /* input mat, for attribute of sub relations */
31 : int pm; /* parent mat, for sub relations */
32 : mat_type_t type; /* type of operation */
33 : int packed;
34 : int pushed; /* set if instruction pushed and shouldn't be freed */
35 : } mat_t;
36 :
37 : typedef struct matlist {
38 : mat_t *v;
39 : int *vars; /* result variable is a mat */
40 : int top;
41 : int size;
42 :
43 : int *horigin;
44 : int *torigin;
45 : int vsize;
46 : } matlist_t;
47 :
48 : static inline mat_type_t
49 : mat_type(mat_t *mat, int n)
50 : {
51 235149 : mat_type_t type = mat_none;
52 : (void) mat;
53 : (void) n;
54 : return type;
55 : }
56 :
57 : static inline int
58 31546079 : is_a_mat(int idx, const matlist_t *ml)
59 : {
60 31546079 : if (ml->vars[idx] >= 0 && !ml->v[ml->vars[idx]].packed)
61 7869826 : return ml->vars[idx];
62 : return -1;
63 : }
64 :
65 : static int
66 6172556 : nr_of_mats(InstrPtr p, const matlist_t *ml)
67 : {
68 6172556 : int j, cnt = 0;
69 30832665 : for (j = p->retc; j < p->argc; j++)
70 24660109 : if (is_a_mat(getArg(p, j), ml) >= 0)
71 2224767 : cnt++;
72 6172556 : return cnt;
73 : }
74 :
75 : static int
76 1163027 : nr_of_bats(MalBlkPtr mb, InstrPtr p)
77 : {
78 1163027 : int j, cnt = 0;
79 4245825 : for (j = p->retc; j < p->argc; j++)
80 3082798 : if (isaBatType(getArgType(mb, p, j))
81 2666418 : && !isVarConstant(mb, getArg(p, j)))
82 2499761 : cnt++;
83 1163027 : return cnt;
84 : }
85 :
86 : static int
87 1163027 : nr_of_nilbats(MalBlkPtr mb, InstrPtr p)
88 : {
89 1163027 : int j, cnt = 0;
90 4245825 : for (j = p->retc; j < p->argc; j++)
91 3082798 : if (isaBatType(getArgType(mb, p, j))
92 3082798 : && isVarConstant(mb, getArg(p, j))
93 166657 : && getVarConstant(mb, getArg(p, j)).val.bval == bat_nil)
94 166657 : cnt++;
95 1163027 : return cnt;
96 : }
97 :
98 : /* some mat's have intermediates (with intermediate result variables),
99 : * therefore we pass the old output mat variable */
100 : inline static int
101 1361867 : mat_add_var(matlist_t *ml, InstrPtr q, InstrPtr p, int var, mat_type_t type,
102 : int inputmat, int parentmat, int pushed)
103 : {
104 1361867 : if (ml->top == ml->size) {
105 0 : int s = ml->size * 2;
106 0 : mat_t *v = (mat_t *) GDKzalloc(s * sizeof(mat_t));
107 0 : if (!v)
108 : return -1;
109 0 : memcpy(v, ml->v, ml->top * sizeof(mat_t));
110 0 : GDKfree(ml->v);
111 0 : ml->size = s;
112 0 : ml->v = v;
113 : }
114 1361867 : mat_t *dst = &ml->v[ml->top];
115 1361867 : dst->mi = q;
116 1361867 : dst->org = p;
117 1361867 : dst->mv = var;
118 1361867 : dst->type = type;
119 1361867 : dst->im = inputmat;
120 1361867 : dst->pm = parentmat;
121 1361867 : dst->packed = 0;
122 1361867 : dst->pushed = pushed;
123 1361867 : if (ml->vars[var] < 0 || dst->type != mat_ext) {
124 1351293 : if (ml->vars[var] >= 0) {
125 0 : ml->v[ml->vars[var]].packed = 1;
126 : }
127 1351293 : ml->vars[var] = ml->top;
128 : }
129 1361867 : ++ml->top;
130 1361867 : return 0;
131 : }
132 :
133 : inline static int
134 866961 : mat_add(matlist_t *ml, InstrPtr q, mat_type_t type, const char *func)
135 : {
136 866961 : (void) func;
137 : //printf (" ml.top %d %s\n", ml.top, func);
138 866961 : return mat_add_var(ml, q, NULL, getArg(q, 0), type, -1, -1, 0);
139 : }
140 :
141 : static void
142 150147 : matlist_pack(matlist_t *ml, int m)
143 : {
144 150147 : int i, idx = ml->v[m].mv;
145 :
146 150147 : assert(ml->v[m].packed == 0);
147 150147 : ml->v[m].packed = 1;
148 150147 : ml->vars[idx] = -1;
149 :
150 34102537 : for (i = 0; i < ml->top; i++)
151 33952390 : if (!ml->v[i].packed && ml->v[i].mv == idx) {
152 0 : ml->vars[idx] = i;
153 0 : break;
154 : }
155 150147 : }
156 :
157 : static str
158 150147 : mat_pack(MalBlkPtr mb, matlist_t *ml, int m)
159 : {
160 150147 : InstrPtr r;
161 :
162 150147 : if (ml->v[m].packed)
163 : return MAL_SUCCEED;
164 :
165 150147 : if ((ml->v[m].mi->argc - ml->v[m].mi->retc) == 1) {
166 : /* simple assignment is sufficient */
167 0 : r = newInstruction(mb, NULL, NULL);
168 0 : if (r == NULL) {
169 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
170 : }
171 0 : getArg(r, 0) = getArg(ml->v[m].mi, 0);
172 0 : getArg(r, 1) = getArg(ml->v[m].mi, 1);
173 0 : r->retc = 1;
174 0 : r->argc = 2;
175 : } else {
176 150147 : int l;
177 :
178 150147 : r = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
179 150147 : if (r == NULL) {
180 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
181 : }
182 150147 : getArg(r, 0) = getArg(ml->v[m].mi, 0);
183 1287616 : for (l = ml->v[m].mi->retc; l < ml->v[m].mi->argc; l++)
184 1137469 : r = pushArgument(mb, r, getArg(ml->v[m].mi, l));
185 150147 : if (mb->errors) {
186 0 : freeInstruction(r);
187 0 : char *msg = mb->errors;
188 0 : mb->errors = NULL;
189 0 : return msg;
190 : }
191 : }
192 150147 : matlist_pack(ml, m);
193 150147 : pushInstruction(mb, r);
194 150147 : return MAL_SUCCEED;
195 : }
196 :
197 : static int
198 72411498 : checksize(matlist_t *ml, int v)
199 : {
200 72411498 : if (v >= ml->vsize) {
201 11734 : int sz = ml->vsize, i, *nhorigin, *ntorigin, *nvars;
202 :
203 11734 : int nvsize = ml->vsize * 2;
204 11734 : assert(v < nvsize);
205 11734 : if (v >= nvsize)
206 : nvsize = v + 10;
207 11734 : nhorigin = (int *) GDKrealloc(ml->horigin, sizeof(int) * nvsize);
208 11734 : if (nhorigin == NULL)
209 : return -1;
210 11734 : ml->horigin = nhorigin;
211 11734 : ntorigin = (int *) GDKrealloc(ml->torigin, sizeof(int) * nvsize);
212 11734 : if (ntorigin == NULL)
213 : return -1;
214 11734 : ml->torigin = ntorigin;
215 11734 : nvars = (int *) GDKrealloc(ml->vars, sizeof(int) * nvsize);
216 11734 : if (nvars == NULL)
217 : return -1;
218 11734 : ml->vars = nvars;
219 11734 : ml->vsize = nvsize;
220 :
221 13778134 : for (i = sz; i < ml->vsize; i++) {
222 13766400 : ml->horigin[i] = ml->torigin[i] = -1;
223 13766400 : ml->vars[i] = -1;
224 : }
225 : }
226 : return 0;
227 : }
228 :
229 : static int
230 9755561 : setPartnr(matlist_t *ml, int ivar, int ovar, int pnr)
231 : {
232 9755561 : int tpnr = -1;
233 :
234 9755561 : if (checksize(ml, ivar) || checksize(ml, ovar))
235 0 : return -1;
236 9755561 : if (ivar >= 0)
237 6446259 : tpnr = ml->torigin[ivar];
238 6446259 : if (tpnr >= 0)
239 169914 : ml->torigin[ovar] = tpnr;
240 9755561 : assert(ovar < ml->vsize);
241 9755561 : ml->horigin[ovar] = pnr;
242 : //printf("%d %d ", pnr, tpnr);
243 9755561 : return 0;
244 : }
245 :
246 : static int
247 810176 : propagatePartnr(matlist_t *ml, int ivar, int ovar, int pnr)
248 : {
249 : /* prop head ids to tail */
250 810176 : int tpnr = -1;
251 :
252 810176 : if (checksize(ml, ivar) || checksize(ml, ovar))
253 0 : return -1;
254 810176 : if (ivar >= 0)
255 810176 : tpnr = ml->horigin[ivar];
256 810176 : if (tpnr >= 0)
257 441126 : ml->torigin[ovar] = tpnr;
258 810176 : assert(ovar < ml->vsize);
259 810176 : ml->horigin[ovar] = pnr;
260 : //printf("%d %d ", pnr, tpnr);
261 810176 : return 0;
262 : }
263 :
264 : static int
265 648146 : propagateMirror(matlist_t *ml, int ivar, int ovar)
266 : {
267 : /* prop head ids to head and tail */
268 648146 : int tpnr;
269 :
270 648146 : if (checksize(ml, ivar) || checksize(ml, ovar))
271 0 : return -1;
272 648146 : tpnr = ml->horigin[ivar];
273 648146 : if (tpnr >= 0) {
274 648146 : assert(ovar < ml->vsize);
275 648146 : ml->horigin[ovar] = tpnr;
276 648146 : ml->torigin[ovar] = tpnr;
277 : }
278 : return 0;
279 : }
280 :
281 : static int
282 24991866 : overlap(matlist_t *ml, int lv, int rv, int lnr, int rnr, int ontails)
283 : {
284 24991866 : int lpnr, rpnr;
285 :
286 24991866 : if (checksize(ml, lv) || checksize(ml, rv))
287 0 : return -1;
288 24991866 : lpnr = ml->torigin[lv];
289 24991866 : rpnr = (ontails) ? ml->torigin[rv] : ml->horigin[rv];
290 :
291 24991866 : if (lpnr < 0 && rpnr < 0)
292 0 : return lnr == rnr;
293 24991866 : if (rpnr < 0)
294 130109 : return lpnr == rnr;
295 24861757 : if (lpnr < 0)
296 1724091 : return rpnr == lnr;
297 23137666 : return lpnr == rpnr;
298 : }
299 :
300 : static int
301 233783 : mat_set_prop(matlist_t *ml, MalBlkPtr mb, InstrPtr p)
302 : {
303 233783 : int k, tpe = getArgType(mb, p, 0);
304 :
305 233783 : tpe = getBatType(tpe);
306 1962838 : for (k = 1; k < p->argc; k++) {
307 1729055 : if (setPartnr(ml, -1, getArg(p, k), k))
308 : return -1;
309 1729055 : if (tpe == TYPE_oid && propagateMirror(ml, getArg(p, k), getArg(p, k)))
310 : return -1;
311 : }
312 : return 0;
313 : }
314 :
315 : static InstrPtr
316 88588 : mat_delta(matlist_t *ml, MalBlkPtr mb, InstrPtr p, mat_t *mat, int m, int n,
317 : int o, int e, int mvar, int nvar, int ovar, int evar)
318 : {
319 88588 : int tpe, k, j, is_subdelta = (getFunctionId(p) == subdeltaRef),
320 88588 : is_projectdelta = (getFunctionId(p) == projectdeltaRef);
321 88588 : InstrPtr r = NULL;
322 88588 : int pushed = 0;
323 :
324 : //printf("# %s.%s(%d,%d,%d,%d)", getModuleId(p), getFunctionId(p), m, n, o, e);
325 :
326 88588 : if ((r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
327 : return NULL;
328 88588 : getArg(r, 0) = getArg(p, 0);
329 88588 : tpe = getArgType(mb, p, 0);
330 :
331 : /* Handle like mat_projection, ie overlapping partitions */
332 88588 : if (evar == 1 && mat[e].mi->argc != mat[m].mi->argc) {
333 : int nr = 1;
334 0 : for (k = 1; k < mat[e].mi->argc; k++) {
335 0 : for (j = 1; j < mat[m].mi->argc; j++) {
336 0 : InstrPtr q;
337 0 : switch (overlap(ml, getArg(mat[e].mi, k), getArg(mat[m].mi, j), k, j, 0)) {
338 0 : case 0:
339 0 : continue;
340 : case -1:
341 : return NULL;
342 0 : case 1:
343 0 : q = copyInstruction(p);
344 0 : if (!q) {
345 0 : freeInstruction(r);
346 0 : return NULL;
347 : }
348 0 : getArg(q, 0) = newTmpVariable(mb, tpe);
349 0 : getArg(q, mvar) = getArg(mat[m].mi, j);
350 0 : getArg(q, nvar) = getArg(mat[n].mi, j);
351 0 : getArg(q, ovar) = getArg(mat[o].mi, j);
352 0 : getArg(q, evar) = getArg(mat[e].mi, k);
353 0 : pushInstruction(mb, q);
354 0 : if (mb->errors) {
355 0 : freeInstruction(r);
356 0 : return NULL;
357 : }
358 0 : if (setPartnr(ml, getArg(mat[m].mi, j), getArg(q, 0), nr)) {
359 0 : freeInstruction(r);
360 0 : return NULL;
361 : }
362 0 : r = pushArgument(mb, r, getArg(q, 0));
363 :
364 0 : nr++;
365 0 : break;
366 : }
367 : }
368 : }
369 : } else {
370 697469 : for (k = 1; k < mat[m].mi->argc; k++) {
371 608881 : InstrPtr q = copyInstruction(p);
372 608881 : if (!q) {
373 0 : freeInstruction(r);
374 0 : return NULL;
375 : }
376 608881 : getArg(q, 0) = newTmpVariable(mb, tpe);
377 608881 : getArg(q, mvar) = getArg(mat[m].mi, k);
378 608881 : getArg(q, nvar) = getArg(mat[n].mi, k);
379 608881 : getArg(q, ovar) = getArg(mat[o].mi, k);
380 608881 : if (e >= 0)
381 192705 : getArg(q, evar) = getArg(mat[e].mi, k);
382 608881 : pushInstruction(mb, q);
383 608881 : if (mb->errors) {
384 0 : freeInstruction(r);
385 0 : return NULL;
386 : }
387 608881 : if (setPartnr(ml, is_subdelta ? getArg(mat[m].mi, k) : -1, getArg(q, 0), k)) {
388 0 : freeInstruction(r);
389 0 : return NULL;
390 : }
391 608881 : r = pushArgument(mb, r, getArg(q, 0));
392 : }
393 88588 : if (evar == 1 && e >= 0 && mat[e].type == mat_slc && is_projectdelta) {
394 0 : InstrPtr q = newInstruction(mb, algebraRef, projectionRef);
395 0 : if (q == NULL) {
396 0 : freeInstruction(r);
397 0 : return NULL;
398 : }
399 0 : getArg(q, 0) = getArg(r, 0);
400 0 : q = pushArgument(mb, q, getArg(mat[e].mi, 0));
401 0 : getArg(r, 0) = newTmpVariable(mb, tpe);
402 0 : q = pushArgument(mb, q, getArg(r, 0));
403 0 : pushInstruction(mb, r);
404 0 : pushInstruction(mb, q);
405 0 : if (mb->errors)
406 : return NULL;
407 : pushed = 1;
408 : r = q;
409 : }
410 : }
411 88588 : if (mat_add_var(ml, r, NULL, getArg(r, 0), mat_type(mat, m), -1, -1, pushed)) {
412 0 : freeInstruction(r);
413 0 : return NULL;
414 : }
415 88588 : if (pushed)
416 0 : matlist_pack(ml, ml->top - 1);
417 : return r;
418 : }
419 :
420 : static InstrPtr
421 3 : mat_assign(MalBlkPtr mb, InstrPtr p, matlist_t *ml)
422 : {
423 3 : InstrPtr r = NULL;
424 3 : mat_t *mat = ml->v;
425 :
426 9 : for (int i = 0; i < p->retc; i++) {
427 6 : int m = is_a_mat(getArg(p, p->retc + i), ml);
428 6 : assert(is_a_mat(getArg(p, i), ml) < 0 && m >= 0);
429 :
430 6 : if ((r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
431 : return NULL;
432 6 : getArg(r, 0) = getArg(p, i);
433 54 : for (int k = 1; k < mat[m].mi->argc; k++) {
434 : /* reuse inputs of old mat */
435 48 : r = pushArgument(mb, r, getArg(mat[m].mi, k));
436 48 : if (setPartnr(ml, -1, getArg(mat[m].mi, k), k)) {
437 0 : freeInstruction(r);
438 0 : return NULL;
439 : }
440 : }
441 6 : if (mat_add(ml, r, mat_none, getFunctionId(p))) {
442 0 : freeInstruction(r);
443 0 : return NULL;
444 : }
445 : }
446 : return r;
447 : }
448 :
449 : static int
450 6206 : mat_apply1(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int var)
451 : {
452 6206 : int tpe, k, is_select = isSelect(p),
453 6206 : is_mirror = (getFunctionId(p) == mirrorRef);
454 12412 : int is_identity = (getFunctionId(p) == identityRef
455 6206 : && getModuleId(p) == batcalcRef);
456 6206 : int ident_var = 0, is_assign = (getFunctionId(p) == NULL), n = 0;
457 6206 : InstrPtr r = NULL, q;
458 6206 : mat_t *mat = ml->v;
459 :
460 6206 : assert(!is_assign);
461 :
462 6206 : assert(p->retc == 1);
463 :
464 : /* Find the mat we overwrite */
465 6206 : if (is_assign) {
466 : n = is_a_mat(getArg(p, 0), ml);
467 : is_assign = (n >= 0);
468 : }
469 :
470 6206 : if (m < 0
471 6206 : || (r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
472 0 : return -1;
473 6206 : getArg(r, 0) = getArg(p, 0);
474 6206 : tpe = getArgType(mb, p, 0);
475 :
476 6206 : if (is_identity) {
477 1 : if ((q = newInstruction(mb, NULL, NULL)) == NULL) {
478 0 : freeInstruction(r);
479 0 : return -1;
480 : }
481 1 : getArg(q, 0) = newTmpVariable(mb, TYPE_oid);
482 1 : q->retc = 1;
483 1 : q->argc = 1;
484 1 : q = pushOid(mb, q, 0);
485 1 : ident_var = getArg(q, 0);
486 1 : pushInstruction(mb, q);
487 1 : if (mb->errors) {
488 0 : freeInstruction(r);
489 0 : return -1;
490 : }
491 : }
492 54080 : for (k = 1; k < mat[m].mi->argc; k++) {
493 47874 : int res = 0;
494 47874 : if ((q = copyInstruction(p)) == NULL) {
495 0 : freeInstruction(r);
496 0 : return -1;
497 : }
498 :
499 47874 : if (is_assign)
500 : getArg(q, 0) = getArg(mat[n].mi, k);
501 : else
502 47874 : getArg(q, 0) = newTmpVariable(mb, tpe);
503 47874 : if (is_identity)
504 4 : getArg(q, 1) = newTmpVariable(mb, TYPE_oid);
505 47874 : getArg(q, var +is_identity) = getArg(mat[m].mi, k);
506 47874 : if (is_identity) {
507 4 : getArg(q, 3) = ident_var;
508 4 : q->retc = 2;
509 4 : q->argc = 4;
510 : /* make sure to resolve again */
511 4 : q->token = ASSIGNsymbol;
512 4 : q->typeresolved = false;
513 4 : q->fcn = NULL;
514 4 : q->blk = NULL;
515 : }
516 47874 : ident_var = getArg(q, 1);
517 47874 : pushInstruction(mb, q);
518 47874 : if (mb->errors) {
519 0 : freeInstruction(r);
520 0 : return -1;
521 : }
522 47874 : if (is_mirror || is_identity) {
523 47842 : res = propagateMirror(ml, getArg(mat[m].mi, k), getArg(q, 0));
524 32 : } else if (is_select)
525 32 : res = propagatePartnr(ml, getArg(mat[m].mi, k), getArg(q, 0), k);
526 : else
527 0 : res = setPartnr(ml, -1, getArg(q, 0), k);
528 47874 : if (res) {
529 0 : freeInstruction(r);
530 0 : return -1;
531 : }
532 47874 : r = pushArgument(mb, r, getArg(q, 0));
533 : }
534 6206 : if (mb->errors) {
535 0 : freeInstruction(r);
536 0 : return -1;
537 : }
538 6206 : if (!r || mat_add(ml, r, mat_type(ml->v, m), getFunctionId(p))) {
539 0 : freeInstruction(r);
540 0 : return -1;
541 : }
542 : return 0;
543 : }
544 :
545 : static int
546 146557 : mat_apply(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int nrmats)
547 : {
548 146557 : int matvar[8], fargument[8], k, l, parts = 0;
549 :
550 146557 : if (nrmats == 1
551 67463 : && ((getModuleId(p) == batcalcRef && getFunctionId(p) == identityRef)
552 67462 : || (getModuleId(p) == batRef && getFunctionId(p) == mirrorRef)))
553 6202 : return mat_apply1(mb, p, ml, is_a_mat(getArg(p, 1), ml), 1);
554 140355 : assert(nrmats <= 8);
555 :
556 140355 : assert(p->retc < p->argc); /* i.e. matvar[0] gets initialized */
557 653425 : for (k = p->retc, l = 0; k < p->argc; k++) {
558 513070 : int mv = is_a_mat(getArg(p, k), ml);
559 513070 : if (mv >= 0) {
560 234224 : matvar[l] = mv;
561 234224 : fargument[l] = k;
562 234224 : l++;
563 234224 : if (parts == 0)
564 140355 : parts = ml->v[mv].mi->argc;
565 234224 : if (parts != ml->v[mv].mi->argc)
566 : return -1;
567 : }
568 : }
569 :
570 140355 : InstrPtr *r = (InstrPtr *) GDKmalloc(sizeof(InstrPtr) * p->retc);
571 140355 : if (!r)
572 : return -1;
573 280710 : for (k = 0; k < p->retc; k++) {
574 140355 : if ((r[k] = newInstructionArgs(mb, matRef, packRef, parts)) == NULL) {
575 0 : while (k > 0)
576 0 : freeInstruction(r[--k]);
577 0 : GDKfree(r);
578 0 : return -1;
579 : }
580 140355 : getArg(r[k], 0) = getArg(p, k);
581 : }
582 :
583 1161888 : for (k = 1; k < ml->v[matvar[0]].mi->argc; k++) {
584 1021533 : int tpe;
585 1021533 : InstrPtr q = copyInstruction(p);
586 1021533 : if (q == NULL) {
587 0 : for (k = 0; k < p->retc; k++)
588 0 : freeInstruction(r[k]);
589 0 : GDKfree(r);
590 0 : return -1;
591 : }
592 :
593 2043066 : for (l = 0; l < p->retc; l++) {
594 1021533 : tpe = getArgType(mb, p, l);
595 1021533 : getArg(q, l) = newTmpVariable(mb, tpe);
596 : }
597 2746019 : for (l = 0; l < nrmats; l++)
598 1724486 : getArg(q, fargument[l]) = getArg(ml->v[matvar[l]].mi, k);
599 1021533 : pushInstruction(mb, q);
600 3064599 : for (l = 0; l < p->retc; l++) {
601 1021533 : if (setPartnr(ml, -1, getArg(q, l), k)) {
602 0 : for (k = 0; k < p->retc; k++)
603 0 : freeInstruction(r[k]);
604 0 : GDKfree(r);
605 0 : return -1;
606 : }
607 1021533 : r[l] = pushArgument(mb, r[l], getArg(q, l));
608 : }
609 1021533 : if (mb->errors) {
610 0 : for (k = 0; k < p->retc; k++)
611 0 : freeInstruction(r[k]);
612 0 : GDKfree(r);
613 0 : return -1;
614 : }
615 : }
616 280710 : for (k = 0; k < p->retc; k++) {
617 140355 : if (mat_add_var(ml, r[k], NULL, getArg(r[k], 0),
618 : mat_type(ml->v, matvar[0]), -1, -1, 0)) {
619 0 : for (l = k; l < p->retc; l++)
620 0 : freeInstruction(r[l]);
621 0 : GDKfree(r);
622 0 : return -1;
623 : }
624 : }
625 140355 : GDKfree(r);
626 140355 : return 0;
627 : }
628 :
629 :
630 : static int
631 8662 : mat_setop(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int o)
632 : {
633 8662 : int tpe = getArgType(mb, p, 0), k, j;
634 8662 : mat_t *mat = ml->v;
635 8662 : InstrPtr r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
636 :
637 8662 : if (!r)
638 : return -1;
639 :
640 8662 : getArg(r, 0) = getArg(p, 0);
641 :
642 : //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
643 8662 : assert(m >= 0 || n >= 0);
644 8662 : if (m >= 0 && n >= 0) {
645 8434 : int nr = 1;
646 :
647 8434 : assert(o < 0 || mat[m].mi->argc == mat[o].mi->argc);
648 :
649 73918 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
650 65484 : InstrPtr q = copyInstruction(p);
651 130968 : InstrPtr s = newInstructionArgs(mb, matRef, packRef,
652 65484 : mat[n].mi->argc);
653 65484 : int ttpe = 0;
654 :
655 65484 : if (q == NULL
656 65484 : || s == NULL
657 65484 : || (getArg(s, 0) = newTmpVariable(mb, getArgType(mb, mat[n].mi, k))) < 0) {
658 0 : freeInstruction(q);
659 0 : freeInstruction(s);
660 0 : freeInstruction(r);
661 0 : return -1;
662 : }
663 :
664 65484 : ttpe = getArgType(mb, mat[n].mi, 0);
665 789892 : for (j = 1; j < mat[n].mi->argc; j++) {
666 724408 : int ov = 0;
667 724408 : if (getBatType(ttpe) != TYPE_oid
668 723310 : || (ov = overlap(ml, getArg(mat[m].mi, k),
669 : getArg(mat[n].mi, j), k, j, 1)) == 1) {
670 92668 : s = pushArgument(mb, s, getArg(mat[n].mi, j));
671 : }
672 724408 : if (ov == -1) {
673 0 : freeInstruction(q);
674 0 : freeInstruction(s);
675 0 : freeInstruction(r);
676 0 : return -1;
677 : }
678 : }
679 65484 : if (s->retc == 1 && s->argc == 2) { /* only one input, change into an assignment */
680 61468 : getFunctionId(s) = NULL;
681 61468 : getModuleId(s) = NULL;
682 61468 : s->token = ASSIGNsymbol;
683 61468 : s->typeresolved = false;
684 61468 : s->fcn = NULL;
685 61468 : s->blk = NULL;
686 : }
687 65484 : pushInstruction(mb, s);
688 :
689 65484 : getArg(q, 0) = newTmpVariable(mb, tpe);
690 65484 : getArg(q, 1) = getArg(mat[m].mi, k);
691 65484 : getArg(q, 2) = getArg(s, 0);
692 65484 : if (o >= 0)
693 1295 : getArg(q, 3) = getArg(mat[o].mi, k);
694 65484 : if (setPartnr(ml, getArg(mat[m].mi, k), getArg(q, 0), nr)) {
695 0 : freeInstruction(q);
696 0 : freeInstruction(r);
697 0 : return -1;
698 : }
699 65484 : pushInstruction(mb, q);
700 :
701 65484 : r = pushArgument(mb, r, getArg(q, 0));
702 65484 : nr++;
703 : }
704 : } else {
705 228 : assert(m >= 0);
706 228 : assert(o < 0 || mat[m].mi->argc == mat[o].mi->argc);
707 :
708 1896 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
709 1668 : InstrPtr q = copyInstruction(p);
710 1668 : if (!q) {
711 0 : freeInstruction(r);
712 0 : return -1;
713 : }
714 :
715 1668 : getArg(q, 0) = newTmpVariable(mb, tpe);
716 1668 : getArg(q, 1) = getArg(mat[m].mi, k);
717 1668 : if (o >= 0)
718 64 : getArg(q, 3) = getArg(mat[o].mi, k);
719 1668 : pushInstruction(mb, q);
720 :
721 1668 : if (setPartnr(ml, getArg(q, 2), getArg(q, 0), k)) {
722 0 : freeInstruction(r);
723 0 : return -1;
724 : }
725 1668 : r = pushArgument(mb, r, getArg(q, 0));
726 : }
727 : }
728 :
729 8662 : if (mb->errors || mat_add(ml, r, mat_none, getFunctionId(p))) {
730 0 : freeInstruction(r);
731 0 : return -1;
732 : }
733 : return 0;
734 : }
735 :
736 : static int
737 757027 : mat_projection(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n)
738 : {
739 757027 : int tpe = getArgType(mb, p, 0), k, j;
740 757027 : mat_t *mat = ml->v;
741 757027 : InstrPtr r;
742 :
743 : //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
744 757027 : assert(m >= 0 || n >= 0);
745 757027 : if (m >= 0 && n >= 0) {
746 677012 : int nr = 1;
747 1354024 : r = newInstructionArgs(mb, matRef, packRef,
748 677012 : mat[m].mi->argc * mat[n].mi->argc);
749 :
750 677012 : if (!r)
751 : return -1;
752 :
753 677012 : getArg(r, 0) = getArg(p, 0);
754 :
755 6076164 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
756 24268556 : for (j = 1; j < mat[n].mi->argc; j++) {
757 24268556 : InstrPtr q;
758 24268556 : switch (overlap(ml, getArg(mat[m].mi, k),
759 : getArg(mat[n].mi, j), k, j, 0)) {
760 18869404 : case 0:
761 18869404 : continue;
762 0 : case -1:
763 0 : freeInstruction(r);
764 0 : return -1;
765 5399152 : case 1:
766 5399152 : q = copyInstruction(p);
767 :
768 5399152 : if (!q) {
769 0 : freeInstruction(r);
770 0 : return -1;
771 : }
772 :
773 5399152 : getArg(q, 0) = newTmpVariable(mb, tpe);
774 5399152 : getArg(q, 1) = getArg(mat[m].mi, k);
775 5399152 : getArg(q, 2) = getArg(mat[n].mi, j);
776 5399152 : pushInstruction(mb, q);
777 :
778 5399152 : if (mb->errors || setPartnr(ml, getArg(mat[n].mi, j), getArg(q, 0), nr)) {
779 0 : freeInstruction(r);
780 0 : return -1;
781 : }
782 5399152 : r = pushArgument(mb, r, getArg(q, 0));
783 :
784 5399152 : nr++;
785 5399152 : break;
786 : }
787 : break; /* only in case of overlap */
788 : }
789 : }
790 : } else {
791 80015 : assert(m >= 0);
792 80015 : r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
793 :
794 80015 : if (!r)
795 : return -1;
796 :
797 80015 : getArg(r, 0) = getArg(p, 0);
798 :
799 712669 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
800 632654 : InstrPtr q = copyInstruction(p);
801 :
802 632654 : if (!q) {
803 0 : freeInstruction(r);
804 0 : return -1;
805 : }
806 :
807 632654 : getArg(q, 0) = newTmpVariable(mb, tpe);
808 632654 : getArg(q, 1) = getArg(mat[m].mi, k);
809 632654 : pushInstruction(mb, q);
810 :
811 632654 : if (mb->errors || setPartnr(ml, getArg(q, 2), getArg(q, 0), k)) {
812 0 : freeInstruction(r);
813 0 : return -1;
814 : }
815 632654 : r = pushArgument(mb, r, getArg(q, 0));
816 : }
817 : }
818 :
819 757027 : if (mb->errors || mat_add(ml, r, mat_none, getFunctionId(p))) {
820 0 : freeInstruction(r);
821 0 : return -1;
822 : }
823 : return 0;
824 : }
825 :
826 : static int
827 47480 : mat_join2(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int lc, int rc)
828 : {
829 47480 : int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), j, k, nr = 1;
830 47480 : mat_t *mat = ml->v;
831 47480 : InstrPtr l;
832 47480 : InstrPtr r;
833 :
834 : //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
835 :
836 47480 : assert(m >= 0 || n >= 0);
837 47480 : if (m >= 0 && n >= 0) {
838 1180 : l = newInstructionArgs(mb, matRef, packRef,
839 590 : mat[m].mi->argc * mat[n].mi->argc);
840 1180 : r = newInstructionArgs(mb, matRef, packRef,
841 590 : mat[m].mi->argc * mat[n].mi->argc);
842 590 : if (!l || !r) {
843 0 : freeInstruction(l);
844 0 : freeInstruction(r);
845 0 : return -1;
846 : }
847 :
848 590 : getArg(l, 0) = getArg(p, 0);
849 590 : getArg(r, 0) = getArg(p, 1);
850 :
851 5156 : for (k = 1; k < mat[m].mi->argc; k++) {
852 40552 : for (j = 1; j < mat[n].mi->argc; j++) {
853 35986 : InstrPtr q = copyInstruction(p);
854 :
855 35986 : if (!q) {
856 0 : freeInstruction(l);
857 0 : freeInstruction(r);
858 0 : return -1;
859 : }
860 :
861 35986 : getArg(q, 0) = newTmpVariable(mb, tpe1);
862 35986 : getArg(q, 1) = newTmpVariable(mb, tpe2);
863 35986 : getArg(q, 2) = getArg(mat[m].mi, k);
864 35986 : getArg(q, 3) = getArg(mat[n].mi, j);
865 35986 : if (lc >= 0)
866 241 : getArg(q, 4) = getArg(mat[lc].mi, k);
867 35986 : if (rc >= 0)
868 0 : getArg(q, 5) = getArg(mat[rc].mi, j);
869 35986 : pushInstruction(mb, q);
870 :
871 35986 : if (mb->errors
872 35986 : || propagatePartnr(ml, getArg(mat[m].mi, k), getArg(q, 0),
873 : nr)
874 35986 : || propagatePartnr(ml, getArg(mat[n].mi, j), getArg(q, 1),
875 : nr)) {
876 0 : freeInstruction(r);
877 0 : freeInstruction(l);
878 0 : return -1;
879 : }
880 :
881 : /* add result to mat */
882 35986 : l = pushArgument(mb, l, getArg(q, 0));
883 35986 : r = pushArgument(mb, r, getArg(q, 1));
884 35986 : nr++;
885 : }
886 : }
887 : } else {
888 46890 : int mv = (m >= 0) ? m : n;
889 46890 : int av = (m < 0);
890 46890 : int bv = (m >= 0);
891 46890 : int mc = (lc >= 0) ? lc : rc;
892 :
893 46890 : l = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
894 46890 : r = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
895 46890 : if (!l || !r) {
896 0 : freeInstruction(l);
897 0 : freeInstruction(r);
898 0 : return -1;
899 : }
900 :
901 46890 : getArg(l, 0) = getArg(p, 0);
902 46890 : getArg(r, 0) = getArg(p, 1);
903 :
904 415693 : for (k = 1; k < mat[mv].mi->argc; k++) {
905 368803 : InstrPtr q = copyInstruction(p);
906 :
907 368803 : if (!q) {
908 0 : freeInstruction(l);
909 0 : freeInstruction(r);
910 0 : return -1;
911 : }
912 :
913 368803 : getArg(q, 0) = newTmpVariable(mb, tpe1);
914 368803 : getArg(q, 1) = newTmpVariable(mb, tpe2);
915 368803 : getArg(q, p->retc + av) = getArg(mat[mv].mi, k);
916 368803 : if (mc >= 0)
917 1151 : getArg(q, p->retc + 2 + av) = getArg(mat[mc].mi, k);
918 368803 : pushInstruction(mb, q);
919 :
920 368803 : if (mb->errors
921 368803 : || propagatePartnr(ml, getArg(mat[mv].mi, k), getArg(q, av), k)
922 368803 : || propagatePartnr(ml, getArg(p, p->retc + bv), getArg(q, bv),
923 : k)) {
924 0 : freeInstruction(l);
925 0 : freeInstruction(r);
926 0 : return -1;
927 : }
928 :
929 : /* add result to mat */
930 368803 : l = pushArgument(mb, l, getArg(q, 0));
931 368803 : r = pushArgument(mb, r, getArg(q, 1));
932 : }
933 : }
934 47480 : if (mb->errors || mat_add(ml, l, mat_none, getFunctionId(p))) {
935 0 : freeInstruction(l);
936 0 : freeInstruction(r);
937 0 : return -1;
938 : }
939 47480 : if (mat_add(ml, r, mat_none, getFunctionId(p))) {
940 0 : freeInstruction(r);
941 0 : return -1;
942 : }
943 : return 0;
944 : }
945 :
946 : static int
947 4 : join_split(Client cntxt, InstrPtr p, int args)
948 : {
949 4 : char *name = NULL;
950 4 : size_t len;
951 4 : int i, res = 0;
952 4 : Symbol sym;
953 4 : MalBlkPtr mb;
954 4 : InstrPtr q;
955 :
956 4 : if (args <= 3) /* we asume there are no 2x1 joins! */
957 : return 1;
958 :
959 0 : len = strlen(getFunctionId(p));
960 0 : name = GDKmalloc(len + 3);
961 0 : if (!name)
962 : return -2;
963 0 : strncpy(name, getFunctionId(p), len - 7);
964 0 : strcpy(name + len - 7, "join");
965 :
966 0 : sym = findSymbol(cntxt->usermodule, getModuleId(p), name);
967 0 : assert(sym);
968 0 : mb = sym->def;
969 :
970 0 : assert(0);
971 : q = mb->stmt[0];
972 : for (i = q->retc; i < q->argc; i++) {
973 : if (isaBatType(getArgType(mb, q, i)))
974 : res++;
975 : else
976 : break;
977 : }
978 : GDKfree(name);
979 : return res - 1;
980 : }
981 :
982 : /* 1 or 2 mat lists:
983 : * in case of one take the second half of the code
984 : * in case of two we need to detect the list lengths.
985 : *
986 : * input is one list of arguments (just total length of mats)
987 : */
988 : static int
989 50 : mat_joinNxM(Client cntxt, MalBlkPtr mb, InstrPtr p, matlist_t *ml, int args)
990 : {
991 50 : int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), j, k, nr = 1;
992 50 : InstrPtr l;
993 50 : InstrPtr r;
994 50 : mat_t *mat = ml->v;
995 50 : int *mats = (int *) GDKzalloc(sizeof(int) * args);
996 50 : int nr_mats = 0, first = -1, res = 0;
997 :
998 50 : if (!mats) {
999 : return -1;
1000 : }
1001 :
1002 211 : for (j = 0; j < args; j++) {
1003 161 : mats[j] = is_a_mat(getArg(p, p->retc + j), ml);
1004 161 : if (mats[j] != -1) {
1005 60 : nr_mats++;
1006 60 : if (first < 0)
1007 50 : first = j;
1008 : }
1009 : }
1010 :
1011 : //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
1012 :
1013 50 : if (args == nr_mats) {
1014 4 : int mv1 = mats[0], i;
1015 4 : int mv2 = mats[args - 1];
1016 4 : int split = join_split(cntxt, p, args);
1017 4 : int nr_mv1 = split;
1018 :
1019 4 : if (split == -2) {
1020 0 : GDKfree(mats);
1021 0 : return -1;
1022 : }
1023 4 : if (split < 0) {
1024 0 : GDKfree(mats);
1025 0 : mb->errors = createException(MAL, "mergetable.join",
1026 : SQLSTATE(42000) " incorrect split level");
1027 0 : return 0;
1028 : }
1029 :
1030 8 : l = newInstructionArgs(mb, matRef, packRef,
1031 4 : mat[mv1].mi->argc * mat[mv2].mi->argc);
1032 8 : r = newInstructionArgs(mb, matRef, packRef,
1033 4 : mat[mv1].mi->argc * mat[mv2].mi->argc);
1034 4 : if (l == NULL || r == NULL) {
1035 0 : freeInstruction(l);
1036 0 : freeInstruction(r);
1037 0 : GDKfree(mats);
1038 0 : return -1;
1039 : }
1040 4 : getArg(l, 0) = getArg(p, 0);
1041 4 : getArg(r, 0) = getArg(p, 1);
1042 :
1043 : /* now detect split point */
1044 16 : for (k = 1; k < mat[mv1].mi->argc; k++) {
1045 48 : for (j = 1; j < mat[mv2].mi->argc; j++) {
1046 36 : InstrPtr q = copyInstruction(p);
1047 36 : if (!q) {
1048 0 : freeInstruction(r);
1049 0 : freeInstruction(l);
1050 0 : GDKfree(mats);
1051 0 : return -1;
1052 : }
1053 :
1054 36 : getArg(q, 0) = newTmpVariable(mb, tpe1);
1055 36 : getArg(q, 1) = newTmpVariable(mb, tpe2);
1056 72 : for (i = 0; i < nr_mv1; i++)
1057 36 : getArg(q, q->retc + i) = getArg(mat[mats[i]].mi, k);
1058 108 : for (; i < nr_mats; i++)
1059 72 : getArg(q, q->retc + i) = getArg(mat[mats[i]].mi, j);
1060 36 : pushInstruction(mb, q);
1061 :
1062 36 : if (mb->errors
1063 36 : || propagatePartnr(ml, getArg(mat[mv1].mi, k), getArg(q, 0),
1064 : nr)
1065 36 : || propagatePartnr(ml, getArg(mat[mv2].mi, j), getArg(q, 1),
1066 : nr)) {
1067 0 : freeInstruction(r);
1068 0 : freeInstruction(l);
1069 0 : GDKfree(mats);
1070 0 : return -1;
1071 : }
1072 :
1073 : /* add result to mat */
1074 36 : l = pushArgument(mb, l, getArg(q, 0));
1075 36 : r = pushArgument(mb, r, getArg(q, 1));
1076 36 : nr++;
1077 : }
1078 : }
1079 : } else {
1080 : /* only one side
1081 : * mats from first..first+nr_mats
1082 : */
1083 46 : int mv = mats[first];
1084 :
1085 46 : l = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
1086 46 : r = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
1087 46 : if (l == NULL || r == NULL) {
1088 0 : freeInstruction(l);
1089 0 : freeInstruction(r);
1090 0 : GDKfree(mats);
1091 0 : return -1;
1092 : }
1093 46 : getArg(l, 0) = getArg(p, 0);
1094 46 : getArg(r, 0) = getArg(p, 1);
1095 :
1096 293 : for (k = 1; k < mat[mv].mi->argc; k++) {
1097 247 : InstrPtr q = copyInstruction(p);
1098 247 : if (!q) {
1099 0 : freeInstruction(r);
1100 0 : freeInstruction(l);
1101 0 : GDKfree(mats);
1102 0 : return -1;
1103 : }
1104 :
1105 247 : getArg(q, 0) = newTmpVariable(mb, tpe1);
1106 247 : getArg(q, 1) = newTmpVariable(mb, tpe2);
1107 500 : for (j = 0; j < nr_mats; j++) {
1108 253 : assert(mat[mats[first]].mi->argc == mat[mats[first + j]].mi->argc);
1109 253 : getArg(q, p->retc + first + j) = getArg(mat[mats[first + j]].mi, k);
1110 : }
1111 247 : if (mb->errors
1112 247 : || propagatePartnr(ml, getArg(mat[mv].mi, k),
1113 247 : getArg(q, (first != 0)), k)
1114 247 : || propagatePartnr(ml,
1115 247 : getArg(p, p->retc + (first) ? nr_mats : 0),
1116 247 : getArg(q, (first == 0)), k)) {
1117 0 : freeInstruction(q);
1118 0 : freeInstruction(r);
1119 0 : freeInstruction(l);
1120 0 : GDKfree(mats);
1121 0 : return -1;
1122 : }
1123 247 : pushInstruction(mb, q);
1124 :
1125 : /* add result to mat */
1126 247 : l = pushArgument(mb, l, getArg(q, 0));
1127 247 : r = pushArgument(mb, r, getArg(q, 1));
1128 : }
1129 : }
1130 50 : if (mb->errors || mat_add(ml, l, mat_none, getFunctionId(p))) {
1131 0 : freeInstruction(l);
1132 0 : freeInstruction(r);
1133 0 : res = -1;
1134 50 : } else if (mat_add(ml, r, mat_none, getFunctionId(p))) {
1135 0 : freeInstruction(r);
1136 0 : res = -1;
1137 : }
1138 50 : GDKfree(mats);
1139 50 : return res;
1140 : }
1141 :
1142 :
1143 : static const char *
1144 4749 : aggr_phase2(const char *aggr, int type_dbl)
1145 : {
1146 4749 : if (aggr == countRef || aggr == count_no_nilRef
1147 4468 : || (aggr == avgRef && type_dbl))
1148 1269 : return sumRef;
1149 3480 : if (aggr == subcountRef || (aggr == subavgRef && type_dbl))
1150 2704 : return subsumRef;
1151 : /* min/max/sum/prod and unique are fine */
1152 : return aggr;
1153 : }
1154 :
1155 : static str
1156 1601 : mat_aggr(MalBlkPtr mb, InstrPtr p, mat_t *mat, int m)
1157 : {
1158 1601 : int tp = getArgType(mb, p, 0), k, tp2 = TYPE_lng, i;
1159 1601 : int battp = (getModuleId(p) == aggrRef) ? newBatType(tp) : tp, battp2 = 0;
1160 1601 : int isAvg = (getFunctionId(p) == avgRef);
1161 1601 : InstrPtr r = NULL, s = NULL, q = NULL, u = NULL, v = NULL;
1162 :
1163 : /* we pack the partitial result */
1164 1601 : r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
1165 1601 : if (r == NULL)
1166 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1167 1601 : getArg(r, 0) = newTmpVariable(mb, battp);
1168 :
1169 1601 : if (isAvg) { /* remainders or counts */
1170 1011 : battp2 = newBatType(tp2);
1171 1011 : u = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
1172 1011 : if (u == NULL) {
1173 0 : freeInstruction(r);
1174 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1175 : }
1176 1011 : getArg(u, 0) = newTmpVariable(mb, battp2);
1177 : }
1178 1601 : if (isAvg && tp != TYPE_dbl) { /* counts */
1179 23 : battp2 = newBatType(tp2);
1180 23 : v = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
1181 23 : if (v == NULL) {
1182 0 : freeInstruction(r);
1183 0 : freeInstruction(u);
1184 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1185 : }
1186 23 : getArg(v, 0) = newTmpVariable(mb, battp2);
1187 : }
1188 13078 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
1189 11477 : q = newInstruction(mb, NULL, NULL);
1190 11477 : if (q == NULL) {
1191 0 : freeInstruction(r);
1192 0 : freeInstruction(u);
1193 0 : freeInstruction(v);
1194 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1195 : }
1196 11477 : if (isAvg && tp == TYPE_dbl)
1197 7811 : setModuleId(q, batcalcRef);
1198 : else
1199 3666 : setModuleId(q, getModuleId(p));
1200 11477 : setFunctionId(q, getFunctionId(p));
1201 11477 : getArg(q, 0) = newTmpVariable(mb, tp);
1202 11477 : if (isAvg)
1203 7982 : q = pushReturn(mb, q, newTmpVariable(mb, tp2));
1204 11477 : if (isAvg && tp != TYPE_dbl)
1205 171 : q = pushReturn(mb, q, newTmpVariable(mb, tp2));
1206 11477 : q = pushArgument(mb, q, getArg(mat[m].mi, k));
1207 12099 : for (i = q->argc; i < p->argc; i++)
1208 622 : q = pushArgument(mb, q, getArg(p, i));
1209 11477 : pushInstruction(mb, q);
1210 :
1211 11477 : r = pushArgument(mb, r, getArg(q, 0));
1212 11477 : if (isAvg)
1213 7982 : u = pushArgument(mb, u, getArg(q, 1));
1214 11477 : if (isAvg && tp != TYPE_dbl)
1215 171 : v = pushArgument(mb, v, getArg(q, 2));
1216 : }
1217 1601 : pushInstruction(mb, r);
1218 1601 : if (isAvg)
1219 1011 : pushInstruction(mb, u);
1220 1601 : if (isAvg && tp != TYPE_dbl)
1221 23 : pushInstruction(mb, v);
1222 :
1223 : /* Filter empty partitions */
1224 1601 : if (mb->errors == NULL && getModuleId(p) == aggrRef && !isAvg) {
1225 590 : s = newInstruction(mb, algebraRef, selectNotNilRef);
1226 590 : if (s == NULL) {
1227 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1228 : }
1229 590 : getArg(s, 0) = newTmpVariable(mb, battp);
1230 590 : s = pushArgument(mb, s, getArg(r, 0));
1231 590 : pushInstruction(mb, s);
1232 590 : r = s;
1233 : }
1234 :
1235 : /* for avg we do sum (avg*(count/sumcount) ) */
1236 1601 : if (mb->errors == NULL && isAvg && tp == TYPE_dbl) {
1237 988 : InstrPtr v, w, x, y, cond;
1238 :
1239 : /* lng w = sum counts */
1240 988 : w = newInstruction(mb, aggrRef, sumRef);
1241 988 : if (w == NULL) {
1242 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1243 : }
1244 988 : getArg(w, 0) = newTmpVariable(mb, tp2);
1245 988 : w = pushArgument(mb, w, getArg(u, 0));
1246 988 : pushInstruction(mb, w);
1247 :
1248 : /* y=count = ifthenelse(w=count==0,NULL,w=count) */
1249 988 : cond = newInstruction(mb, calcRef, eqRef);
1250 988 : if (cond == NULL) {
1251 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1252 : }
1253 988 : getArg(cond, 0) = newTmpVariable(mb, TYPE_bit);
1254 988 : cond = pushArgument(mb, cond, getArg(w, 0));
1255 988 : cond = pushLng(mb, cond, 0);
1256 988 : pushInstruction(mb, cond);
1257 :
1258 988 : y = newInstruction(mb, calcRef, ifthenelseRef);
1259 988 : if (y == NULL) {
1260 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1261 : }
1262 988 : getArg(y, 0) = newTmpVariable(mb, tp2);
1263 988 : y = pushArgument(mb, y, getArg(cond, 0));
1264 988 : y = pushNil(mb, y, tp2);
1265 988 : y = pushArgument(mb, y, getArg(w, 0));
1266 988 : pushInstruction(mb, y);
1267 :
1268 : /* dbl v = double(count) */
1269 988 : v = newInstruction(mb, batcalcRef, dblRef);
1270 988 : if (v == NULL) {
1271 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1272 : }
1273 988 : getArg(v, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
1274 988 : v = pushArgument(mb, v, getArg(u, 0));
1275 988 : pushInstruction(mb, v);
1276 :
1277 : /* dbl x = v / y */
1278 988 : x = newInstruction(mb, batcalcRef, divRef);
1279 988 : if (x == NULL) {
1280 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1281 : }
1282 988 : getArg(x, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
1283 988 : x = pushArgument(mb, x, getArg(v, 0));
1284 988 : x = pushArgument(mb, x, getArg(y, 0));
1285 988 : if (isaBatType(getArgType(mb, x, 0)))
1286 988 : x = pushNilBat(mb, x);
1287 988 : if (isaBatType(getArgType(mb, y, 0)))
1288 0 : x = pushNilBat(mb, x);
1289 988 : pushInstruction(mb, x);
1290 :
1291 : /* dbl w = avg * x */
1292 988 : w = newInstruction(mb, batcalcRef, mulRef);
1293 988 : if (w == NULL) {
1294 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1295 : }
1296 988 : getArg(w, 0) = newTmpVariable(mb, battp);
1297 988 : w = pushArgument(mb, w, getArg(r, 0));
1298 988 : w = pushArgument(mb, w, getArg(x, 0));
1299 988 : if (isaBatType(getArgType(mb, r, 0)))
1300 988 : w = pushNilBat(mb, w);
1301 988 : if (isaBatType(getArgType(mb, x, 0)))
1302 988 : w = pushNilBat(mb, w);
1303 988 : pushInstruction(mb, w);
1304 :
1305 988 : r = w;
1306 :
1307 : /* filter nils */
1308 988 : s = newInstruction(mb, algebraRef, selectNotNilRef);
1309 988 : if (s == NULL) {
1310 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1311 : }
1312 988 : getArg(s, 0) = newTmpVariable(mb, battp);
1313 988 : s = pushArgument(mb, s, getArg(r, 0));
1314 988 : pushInstruction(mb, s);
1315 988 : r = s;
1316 : }
1317 :
1318 1601 : if (mb->errors == NULL) {
1319 1601 : s = newInstruction(mb, getModuleId(p),
1320 : aggr_phase2(getFunctionId(p), tp == TYPE_dbl));
1321 1601 : if (s == NULL) {
1322 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1323 : }
1324 1601 : getArg(s, 0) = getArg(p, 0);
1325 1601 : s = pushArgument(mb, s, getArg(r, 0));
1326 1601 : if (isAvg && tp != TYPE_dbl) {
1327 23 : s = pushArgument(mb, s, getArg(u, 0));
1328 23 : s = pushArgument(mb, s, getArg(v, 0));
1329 : }
1330 1601 : pushInstruction(mb, s);
1331 : }
1332 1601 : if (mb->errors) {
1333 0 : str msg = mb->errors;
1334 0 : mb->errors = NULL;
1335 0 : return msg;
1336 : }
1337 : return MAL_SUCCEED;
1338 : }
1339 :
1340 : static int
1341 7238 : chain_by_length(mat_t *mat, int g)
1342 : {
1343 7238 : int cnt = 0;
1344 17937 : while (g >= 0) {
1345 10699 : g = mat[g].pm;
1346 10699 : cnt++;
1347 : }
1348 4756 : return cnt;
1349 : }
1350 :
1351 : static int
1352 3439 : walk_n_back(mat_t *mat, int g, int cnt)
1353 : {
1354 16565 : while (cnt > 0) {
1355 5866 : g = mat[g].pm;
1356 5866 : cnt--;
1357 : }
1358 3564 : return g;
1359 : }
1360 :
1361 : static int
1362 3439 : group_by_ext(matlist_t *ml, int g)
1363 : {
1364 3439 : int i;
1365 :
1366 14013 : for (i = g; i < ml->top; i++) {
1367 21148 : if (ml->v[i].pm == g)
1368 : return i;
1369 : }
1370 : return 0;
1371 : }
1372 :
1373 : /* In some cases we have non groupby attribute columns, these require
1374 : * gext.projection(mat.pack(per partition ext.projections(x)))
1375 : */
1376 :
1377 : static int
1378 7025 : mat_group_project(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int e, int a)
1379 : {
1380 7025 : int tp = getArgType(mb, p, 0), k;
1381 7025 : mat_t *mat = ml->v;
1382 7025 : InstrPtr ai1 = newInstructionArgs(mb, matRef, packRef, mat[a].mi->argc), r;
1383 :
1384 7025 : if (!ai1)
1385 : return -1;
1386 :
1387 7025 : getArg(ai1, 0) = newTmpVariable(mb, tp);
1388 7025 : if (mb->errors) {
1389 0 : freeInstruction(ai1);
1390 0 : return -1;
1391 : }
1392 :
1393 7025 : assert(mat[e].mi->argc == mat[a].mi->argc);
1394 66067 : for (k = 1; k < mat[a].mi->argc; k++) {
1395 59042 : InstrPtr q = copyInstruction(p);
1396 59042 : if (!q) {
1397 0 : freeInstruction(ai1);
1398 0 : return -1;
1399 : }
1400 :
1401 59042 : getArg(q, 0) = newTmpVariable(mb, tp);
1402 59042 : getArg(q, 1) = getArg(mat[e].mi, k);
1403 59042 : getArg(q, 2) = getArg(mat[a].mi, k);
1404 59042 : pushInstruction(mb, q);
1405 59042 : if (mb->errors) {
1406 0 : freeInstruction(ai1);
1407 0 : return -1;
1408 : }
1409 59042 : if (setPartnr(ml, getArg(mat[a].mi, k), getArg(q, 0), k)) {
1410 0 : freeInstruction(ai1);
1411 0 : return -1;
1412 : }
1413 :
1414 : /* pack the result into a mat */
1415 59042 : ai1 = pushArgument(mb, ai1, getArg(q, 0));
1416 : }
1417 7025 : pushInstruction(mb, ai1);
1418 7025 : if (mb->errors) {
1419 : return -1;
1420 : }
1421 :
1422 7025 : if ((r = copyInstruction(p)) == NULL)
1423 : return -1;
1424 7025 : getArg(r, 1) = mat[e].mv;
1425 7025 : getArg(r, 2) = getArg(ai1, 0);
1426 7025 : pushInstruction(mb, r);
1427 7025 : return mb->errors ? -1 : 0;
1428 : }
1429 :
1430 : /* Per partition aggregates are merged and aggregated together. For
1431 : * most (handled) aggregates thats relatively simple. AVG is somewhat
1432 : * more complex. */
1433 : static int
1434 3148 : mat_group_aggr(MalBlkPtr mb, InstrPtr p, mat_t *mat, int b, int g, int e)
1435 : {
1436 3148 : int tp = getArgType(mb, p, 0), k, tp2 = 0, tpe = getBatType(tp);
1437 3148 : const char *aggr2 = aggr_phase2(getFunctionId(p), tpe == TYPE_dbl);
1438 3148 : int isAvg = (getFunctionId(p) == subavgRef);
1439 3148 : InstrPtr ai1 = newInstructionArgs(mb, matRef, packRef, mat[b].mi->argc),
1440 3148 : ai10 = NULL, ai11 = NULL, ai2;
1441 :
1442 3148 : if (!ai1)
1443 : return -1;
1444 :
1445 3148 : getArg(ai1, 0) = newTmpVariable(mb, tp);
1446 :
1447 3148 : if (mb->errors == NULL && isAvg) { /* remainders or counts */
1448 51 : tp2 = newBatType(TYPE_lng);
1449 51 : ai10 = newInstructionArgs(mb, matRef, packRef, mat[b].mi->argc);
1450 51 : if (!ai10) {
1451 0 : freeInstruction(ai1);
1452 0 : return -1;
1453 : }
1454 51 : getArg(ai10, 0) = newTmpVariable(mb, tp2);
1455 : }
1456 3148 : if (mb->errors == NULL && isAvg && tpe != TYPE_dbl) { /* counts */
1457 19 : tp2 = newBatType(TYPE_lng);
1458 19 : ai11 = newInstructionArgs(mb, matRef, packRef, mat[b].mi->argc);
1459 19 : if (!ai11) {
1460 0 : freeInstruction(ai1);
1461 0 : freeInstruction(ai10);
1462 0 : return -1;
1463 : }
1464 19 : getArg(ai11, 0) = newTmpVariable(mb, tp2);
1465 : }
1466 :
1467 31996 : for (k = 1; mb->errors == NULL && k < mat[b].mi->argc; k++) {
1468 28848 : int off = 0;
1469 28848 : InstrPtr q = copyInstructionArgs(p, p->argc + (isAvg && tpe == TYPE_dbl));
1470 28848 : if (!q) {
1471 0 : freeInstruction(ai1);
1472 0 : freeInstruction(ai10);
1473 0 : return -1;
1474 : }
1475 :
1476 28848 : getArg(q, 0) = newTmpVariable(mb, tp);
1477 28848 : if (isAvg && tpe == TYPE_dbl) {
1478 197 : off = 1;
1479 197 : getArg(q, 1) = newTmpVariable(mb, tp2);
1480 197 : q = pushArgument(mb, q, getArg(q, 1)); /* push at end, create space */
1481 197 : q->retc = 2;
1482 197 : getArg(q, q->argc - 1) = getArg(q, q->argc - 2);
1483 197 : getArg(q, q->argc - 2) = getArg(q, q->argc - 3);
1484 28651 : } else if (isAvg) {
1485 152 : getArg(q, 1) = newTmpVariable(mb, tp2);
1486 152 : getArg(q, 2) = newTmpVariable(mb, tp2);
1487 152 : off = 2;
1488 : }
1489 28848 : getArg(q, 1 + off) = getArg(mat[b].mi, k);
1490 28848 : getArg(q, 2 + off) = getArg(mat[g].mi, k);
1491 28848 : getArg(q, 3 + off) = getArg(mat[e].mi, k);
1492 28848 : pushInstruction(mb, q);
1493 :
1494 : /* pack the result into a mat */
1495 28848 : ai1 = pushArgument(mb, ai1, getArg(q, 0));
1496 28848 : if (isAvg)
1497 349 : ai10 = pushArgument(mb, ai10, getArg(q, 1));
1498 28848 : if (isAvg && tpe != TYPE_dbl)
1499 152 : ai11 = pushArgument(mb, ai11, getArg(q, 2));
1500 : }
1501 3148 : pushInstruction(mb, ai1);
1502 3148 : if (isAvg)
1503 51 : pushInstruction(mb, ai10);
1504 3148 : if (isAvg && tpe != TYPE_dbl)
1505 19 : pushInstruction(mb, ai11);
1506 :
1507 : /* for avg we do sum (avg*(count/sumcount) ) */
1508 3148 : if (mb->errors == NULL && isAvg && tpe == TYPE_dbl) {
1509 32 : InstrPtr r, s, v, w, cond;
1510 :
1511 : /* lng s = sum counts */
1512 32 : s = newInstruction(mb, aggrRef, subsumRef);
1513 32 : if (s == NULL)
1514 : return -1;
1515 32 : getArg(s, 0) = newTmpVariable(mb, tp2);
1516 32 : s = pushArgument(mb, s, getArg(ai10, 0));
1517 32 : s = pushArgument(mb, s, mat[g].mv);
1518 32 : s = pushArgument(mb, s, mat[e].mv);
1519 32 : s = pushBit(mb, s, 1); /* skip nils */
1520 32 : pushInstruction(mb, s);
1521 :
1522 : /* w=count = ifthenelse(s=count==0,NULL,s=count) */
1523 32 : cond = newInstruction(mb, batcalcRef, eqRef);
1524 32 : if (cond == NULL)
1525 : return -1;
1526 32 : getArg(cond, 0) = newTmpVariable(mb, newBatType(TYPE_bit));
1527 32 : cond = pushArgument(mb, cond, getArg(s, 0));
1528 32 : cond = pushLng(mb, cond, 0);
1529 32 : pushInstruction(mb, cond);
1530 :
1531 32 : w = newInstruction(mb, batcalcRef, ifthenelseRef);
1532 32 : if (w == NULL)
1533 : return -1;
1534 32 : getArg(w, 0) = newTmpVariable(mb, tp2);
1535 32 : w = pushArgument(mb, w, getArg(cond, 0));
1536 32 : w = pushNil(mb, w, TYPE_lng);
1537 32 : w = pushArgument(mb, w, getArg(s, 0));
1538 32 : pushInstruction(mb, w);
1539 :
1540 : /* fetchjoin with groups */
1541 32 : r = newInstruction(mb, algebraRef, projectionRef);
1542 32 : if (r == NULL)
1543 : return -1;
1544 32 : getArg(r, 0) = newTmpVariable(mb, tp2);
1545 32 : r = pushArgument(mb, r, mat[g].mv);
1546 32 : r = pushArgument(mb, r, getArg(w, 0));
1547 32 : pushInstruction(mb, r);
1548 32 : s = r;
1549 :
1550 : /* dbl v = double(count) */
1551 32 : v = newInstruction(mb, batcalcRef, dblRef);
1552 32 : if (v == NULL)
1553 : return -1;
1554 32 : getArg(v, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
1555 32 : v = pushArgument(mb, v, getArg(ai10, 0));
1556 32 : pushInstruction(mb, v);
1557 :
1558 : /* dbl r = v / s */
1559 32 : r = newInstruction(mb, batcalcRef, divRef);
1560 32 : if (r == NULL)
1561 : return -1;
1562 32 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
1563 32 : r = pushArgument(mb, r, getArg(v, 0));
1564 32 : r = pushArgument(mb, r, getArg(s, 0));
1565 32 : if (isaBatType(getArgType(mb, v, 0)))
1566 32 : r = pushNilBat(mb, r);
1567 32 : if (isaBatType(getArgType(mb, s, 0)))
1568 32 : r = pushNilBat(mb, r);
1569 32 : pushInstruction(mb, r);
1570 :
1571 : /* dbl s = avg * r */
1572 32 : s = newInstruction(mb, batcalcRef, mulRef);
1573 32 : if (s == NULL)
1574 : return -1;
1575 32 : getArg(s, 0) = newTmpVariable(mb, tp);
1576 32 : s = pushArgument(mb, s, getArg(ai1, 0));
1577 32 : s = pushArgument(mb, s, getArg(r, 0));
1578 32 : if (isaBatType(getArgType(mb, ai1, 0)))
1579 32 : s = pushNilBat(mb, s);
1580 32 : if (isaBatType(getArgType(mb, r, 0)))
1581 32 : s = pushNilBat(mb, s);
1582 32 : pushInstruction(mb, s);
1583 :
1584 32 : ai1 = s;
1585 : }
1586 3148 : ai2 = newInstruction(mb, aggrRef, aggr2);
1587 3148 : if (ai2 == NULL)
1588 : return -1;
1589 3148 : getArg(ai2, 0) = getArg(p, 0);
1590 3148 : if (isAvg && tpe != TYPE_dbl) {
1591 19 : getArg(ai2, 1) = getArg(p, 1);
1592 19 : getArg(ai2, 2) = getArg(p, 2);
1593 : }
1594 3148 : ai2 = pushArgument(mb, ai2, getArg(ai1, 0));
1595 3148 : if (isAvg && tpe != TYPE_dbl) {
1596 19 : ai2 = pushArgument(mb, ai2, getArg(ai10, 0));
1597 19 : ai2 = pushArgument(mb, ai2, getArg(ai11, 0));
1598 : }
1599 3148 : ai2 = pushArgument(mb, ai2, mat[g].mv);
1600 3148 : ai2 = pushArgument(mb, ai2, mat[e].mv);
1601 3148 : ai2 = pushBit(mb, ai2, 1); /* skip nils */
1602 3148 : pushInstruction(mb, ai2);
1603 3148 : if (mb->errors)
1604 : return -1;
1605 : return 0;
1606 : }
1607 :
1608 : /* The mat_group_{new,derive} keep an ext,attr1..attrn table.
1609 : * This is the input for the final second phase group by.
1610 : */
1611 : static int
1612 4653 : mat_pack_group(MalBlkPtr mb, matlist_t *ml, int g)
1613 : {
1614 4653 : mat_t *mat = ml->v;
1615 4653 : int cnt = chain_by_length(mat, g), i;
1616 4653 : InstrPtr cur = NULL;
1617 :
1618 11788 : for (i = cnt - 1; i >= 0; i--) {
1619 : /* if cur is non-NULL, it's a subgroup; if i is zero, it's "done" */
1620 14270 : InstrPtr grp = newInstruction(mb, groupRef,
1621 2482 : cur ? i ? subgroupRef : subgroupdoneRef : i ?
1622 4653 : groupRef : groupdoneRef);
1623 7135 : if (grp == NULL)
1624 : return -1;
1625 14270 : int ogrp = walk_n_back(mat, g, i);
1626 7135 : int oext = group_by_ext(ml, ogrp);
1627 7135 : int attr = mat[oext].im;
1628 :
1629 7135 : getArg(grp, 0) = mat[ogrp].mv;
1630 7135 : grp = pushReturn(mb, grp, mat[oext].mv);
1631 7135 : grp = pushReturn(mb, grp, newTmpVariable(mb, newBatType(TYPE_lng)));
1632 7135 : grp = pushArgument(mb, grp, getArg(mat[attr].mi, 0));
1633 7135 : if (cur)
1634 2482 : grp = pushArgument(mb, grp, getArg(cur, 0));
1635 7135 : pushInstruction(mb, grp);
1636 7135 : cur = grp;
1637 7135 : if (mb->errors)
1638 : return -1;
1639 : }
1640 4653 : mat[g].im = -1; /* only pack once */
1641 4653 : return 0;
1642 : }
1643 :
1644 : /*
1645 : * foreach parent subgroup, do the
1646 : * e2.projection(grp.projection((ext.projection(b)))
1647 : * and one for the current group
1648 : */
1649 : static int
1650 2482 : mat_group_attr(MalBlkPtr mb, matlist_t *ml, int g, InstrPtr cext, int push)
1651 : {
1652 2482 : int cnt = chain_by_length(ml->v, g), i; /* number of attributes */
1653 : int ogrp = g; /* previous group */
1654 :
1655 5921 : for (i = 0; i < cnt; i++) {
1656 3439 : int agrp = walk_n_back(ml->v, ogrp, i);
1657 3439 : int b = ml->v[agrp].im;
1658 3439 : int aext = group_by_ext(ml, agrp);
1659 3439 : int a = ml->v[aext].im;
1660 3439 : int atp = getArgType(mb, ml->v[a].mi, 0), k;
1661 3439 : InstrPtr attr = newInstructionArgs(mb, matRef, packRef, ml->v[a].mi->argc);
1662 3439 : if (attr == NULL) {
1663 : return -1;
1664 : }
1665 :
1666 : //getArg(attr,0) = newTmpVariable(mb, atp);
1667 3439 : getArg(attr, 0) = getArg(ml->v[b].mi, 0);
1668 :
1669 30251 : for (k = 1; mb->errors == NULL && k < ml->v[a].mi->argc; k++) {
1670 26812 : InstrPtr r = newInstruction(mb, algebraRef, projectionRef);
1671 26812 : InstrPtr q = newInstruction(mb, algebraRef, projectionRef);
1672 26812 : if (r == NULL || q == NULL) {
1673 0 : freeInstruction(attr);
1674 0 : freeInstruction(r);
1675 0 : freeInstruction(q);
1676 0 : return -1;
1677 : }
1678 :
1679 26812 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
1680 26812 : r = pushArgument(mb, r, getArg(cext, k));
1681 26812 : r = pushArgument(mb, r, getArg(ml->v[ogrp].mi, k));
1682 26812 : pushInstruction(mb, r);
1683 :
1684 26812 : getArg(q, 0) = newTmpVariable(mb, atp);
1685 26812 : q = pushArgument(mb, q, getArg(r, 0));
1686 26812 : q = pushArgument(mb, q, getArg(ml->v[a].mi, k));
1687 26812 : pushInstruction(mb, q);
1688 :
1689 26812 : attr = pushArgument(mb, attr, getArg(q, 0));
1690 : }
1691 3439 : if (push)
1692 2482 : pushInstruction(mb, attr);
1693 3439 : if (mb->errors || mat_add_var(ml, attr, NULL, getArg(attr, 0), mat_ext,
1694 : -1, -1, push)) {
1695 0 : if (!push)
1696 0 : freeInstruction(attr);
1697 0 : return -1;
1698 : }
1699 : /* keep new attribute with the group extend */
1700 3439 : ml->v[aext].im = ml->top - 1;
1701 : }
1702 : return 0;
1703 : }
1704 :
1705 : static int
1706 4653 : mat_group_new(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int b)
1707 : {
1708 4653 : int tp0 = getArgType(mb, p, 0);
1709 4653 : int tp1 = getArgType(mb, p, 1);
1710 4653 : int tp2 = getArgType(mb, p, 2);
1711 4653 : int atp = getArgType(mb, p, 3), i, a, g, push = 0;
1712 4653 : InstrPtr r0, r1, r2, attr;
1713 :
1714 4653 : if (getFunctionId(p) == subgroupdoneRef || getFunctionId(p) == groupdoneRef)
1715 2551 : push = 1;
1716 :
1717 4653 : r0 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1718 4653 : if (r0 == NULL)
1719 : return -1;
1720 4653 : getArg(r0, 0) = newTmpVariable(mb, tp0);
1721 :
1722 4653 : r1 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1723 4653 : if (r1 == NULL) {
1724 0 : freeInstruction(r0);
1725 0 : return -1;
1726 : }
1727 4653 : getArg(r1, 0) = newTmpVariable(mb, tp1);
1728 :
1729 4653 : r2 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1730 4653 : if (r2 == NULL) {
1731 0 : freeInstruction(r0);
1732 0 : freeInstruction(r1);
1733 0 : return -1;
1734 : }
1735 4653 : getArg(r2, 0) = newTmpVariable(mb, tp2);
1736 :
1737 : /* we keep an extend, attr table result, which will later be used
1738 : * when we pack the group result */
1739 4653 : attr = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1740 4653 : if (attr == NULL) {
1741 0 : freeInstruction(r0);
1742 0 : freeInstruction(r1);
1743 0 : freeInstruction(r2);
1744 0 : return -1;
1745 : }
1746 4653 : getArg(attr, 0) = getArg(ml->v[b].mi, 0);
1747 :
1748 44866 : for (i = 1; mb->errors == NULL && i < ml->v[b].mi->argc; i++) {
1749 40213 : InstrPtr q = copyInstruction(p), r;
1750 40213 : if (!q) {
1751 0 : freeInstruction(r0);
1752 0 : freeInstruction(r1);
1753 0 : freeInstruction(r2);
1754 0 : freeInstruction(attr);
1755 0 : return -1;
1756 : }
1757 :
1758 40213 : getArg(q, 0) = newTmpVariable(mb, tp0);
1759 40213 : getArg(q, 1) = newTmpVariable(mb, tp1);
1760 40213 : getArg(q, 2) = newTmpVariable(mb, tp2);
1761 40213 : getArg(q, 3) = getArg(ml->v[b].mi, i);
1762 40213 : pushInstruction(mb, q);
1763 40213 : if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 0), i)
1764 40213 : || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 1), i)
1765 40213 : || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 2), i)) {
1766 0 : freeInstruction(r0);
1767 0 : freeInstruction(r1);
1768 0 : freeInstruction(r2);
1769 0 : freeInstruction(attr);
1770 0 : return -1;
1771 : }
1772 :
1773 : /* add result to mats */
1774 40213 : r0 = pushArgument(mb, r0, getArg(q, 0));
1775 40213 : r1 = pushArgument(mb, r1, getArg(q, 1));
1776 40213 : r2 = pushArgument(mb, r2, getArg(q, 2));
1777 :
1778 40213 : r = newInstruction(mb, algebraRef, projectionRef);
1779 40213 : if (r == NULL) {
1780 0 : freeInstruction(r0);
1781 0 : freeInstruction(r1);
1782 0 : freeInstruction(r2);
1783 0 : freeInstruction(attr);
1784 0 : return -1;
1785 : }
1786 40213 : getArg(r, 0) = newTmpVariable(mb, atp);
1787 40213 : r = pushArgument(mb, r, getArg(q, 1));
1788 40213 : r = pushArgument(mb, r, getArg(ml->v[b].mi, i));
1789 40213 : if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(r, 0), i)) {
1790 0 : freeInstruction(r0);
1791 0 : freeInstruction(r1);
1792 0 : freeInstruction(r2);
1793 0 : freeInstruction(attr);
1794 0 : freeInstruction(r);
1795 0 : return -1;
1796 : }
1797 40213 : pushInstruction(mb, r);
1798 :
1799 40213 : attr = pushArgument(mb, attr, getArg(r, 0));
1800 : }
1801 4653 : pushInstruction(mb, r0);
1802 4653 : pushInstruction(mb, r1);
1803 4653 : pushInstruction(mb, r2);
1804 4653 : if (push)
1805 2551 : pushInstruction(mb, attr);
1806 :
1807 : /* create mat's for the intermediates */
1808 4653 : a = ml->top;
1809 4653 : if (mb->errors || mat_add_var(ml, attr, NULL, getArg(attr, 0), mat_ext,
1810 : -1, -1, push)) {
1811 0 : if (!push)
1812 0 : freeInstruction(attr);
1813 0 : return -1;
1814 : }
1815 4653 : g = ml->top;
1816 4653 : if (mat_add_var(ml, r0, p, getArg(p, 0), mat_grp, b, -1, 1)
1817 4653 : || mat_add_var(ml, r1, p, getArg(p, 1), mat_ext, a, ml->top - 1, 1) /* point back at group */
1818 4653 : || mat_add_var(ml, r2, p, getArg(p, 2), mat_cnt, -1, ml->top - 1, 1)) /* point back at ext */
1819 0 : return -1;
1820 4653 : if (push)
1821 2551 : return mat_pack_group(mb, ml, g);
1822 : return 0;
1823 : }
1824 :
1825 : static int
1826 2482 : mat_group_derive(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int b, int g)
1827 : {
1828 2482 : int tp0 = getArgType(mb, p, 0);
1829 2482 : int tp1 = getArgType(mb, p, 1);
1830 2482 : int tp2 = getArgType(mb, p, 2);
1831 2482 : int atp = getArgType(mb, p, 3), i, a, push = 0;
1832 2482 : InstrPtr r0, r1, r2, attr;
1833 :
1834 2482 : if (getFunctionId(p) == subgroupdoneRef || getFunctionId(p) == groupdoneRef)
1835 2102 : push = 1;
1836 :
1837 2482 : if (ml->v[g].im == -1) { /* already packed */
1838 0 : InstrPtr q = copyInstruction(p);
1839 0 : if (!q)
1840 : return -1;
1841 0 : pushInstruction(mb, q);
1842 0 : return 0;
1843 : }
1844 :
1845 2482 : r0 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1846 2482 : if (r0 == NULL)
1847 : return -1;
1848 2482 : getArg(r0, 0) = newTmpVariable(mb, tp0);
1849 :
1850 2482 : r1 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1851 2482 : if (r1 == NULL) {
1852 0 : freeInstruction(r0);
1853 0 : return -1;
1854 : }
1855 2482 : getArg(r1, 0) = newTmpVariable(mb, tp1);
1856 :
1857 2482 : r2 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1858 2482 : if (r2 == NULL) {
1859 0 : freeInstruction(r0);
1860 0 : freeInstruction(r1);
1861 0 : return -1;
1862 : }
1863 2482 : getArg(r2, 0) = newTmpVariable(mb, tp2);
1864 :
1865 : /* we keep an extend, attr table result, which will later be used
1866 : * when we pack the group result */
1867 2482 : attr = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1868 2482 : if (attr == NULL) {
1869 0 : freeInstruction(r0);
1870 0 : freeInstruction(r1);
1871 0 : freeInstruction(r2);
1872 0 : return -1;
1873 : }
1874 2482 : getArg(attr, 0) = getArg(ml->v[b].mi, 0);
1875 :
1876 : /* we need overlapping ranges */
1877 21780 : for (i = 1; mb->errors == NULL && i < ml->v[b].mi->argc; i++) {
1878 19298 : InstrPtr q = copyInstruction(p), r;
1879 19298 : if (!q) {
1880 0 : freeInstruction(r0);
1881 0 : freeInstruction(r1);
1882 0 : freeInstruction(r2);
1883 0 : freeInstruction(attr);
1884 0 : return -1;
1885 : }
1886 :
1887 19298 : getArg(q, 0) = newTmpVariable(mb, tp0);
1888 19298 : getArg(q, 1) = newTmpVariable(mb, tp1);
1889 19298 : getArg(q, 2) = newTmpVariable(mb, tp2);
1890 19298 : getArg(q, 3) = getArg(ml->v[b].mi, i);
1891 19298 : getArg(q, 4) = getArg(ml->v[g].mi, i);
1892 19298 : pushInstruction(mb, q);
1893 19298 : if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 0), i)
1894 19298 : || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 1), i)
1895 19298 : || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 2), i)) {
1896 0 : freeInstruction(r0);
1897 0 : freeInstruction(r1);
1898 0 : freeInstruction(r2);
1899 0 : freeInstruction(attr);
1900 0 : return -1;
1901 : }
1902 :
1903 : /* add result to mats */
1904 19298 : r0 = pushArgument(mb, r0, getArg(q, 0));
1905 19298 : r1 = pushArgument(mb, r1, getArg(q, 1));
1906 19298 : r2 = pushArgument(mb, r2, getArg(q, 2));
1907 :
1908 19298 : r = newInstruction(mb, algebraRef, projectionRef);
1909 19298 : if (r == NULL) {
1910 0 : freeInstruction(r0);
1911 0 : freeInstruction(r1);
1912 0 : freeInstruction(r2);
1913 0 : freeInstruction(attr);
1914 0 : return -1;
1915 : }
1916 19298 : getArg(r, 0) = newTmpVariable(mb, atp);
1917 19298 : r = pushArgument(mb, r, getArg(q, 1));
1918 19298 : r = pushArgument(mb, r, getArg(ml->v[b].mi, i));
1919 19298 : if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(r, 0), i)) {
1920 0 : freeInstruction(r0);
1921 0 : freeInstruction(r1);
1922 0 : freeInstruction(r2);
1923 0 : freeInstruction(attr);
1924 0 : freeInstruction(r);
1925 0 : return -1;
1926 : }
1927 19298 : pushInstruction(mb, r);
1928 :
1929 19298 : attr = pushArgument(mb, attr, getArg(r, 0));
1930 : }
1931 2482 : pushInstruction(mb, r0);
1932 2482 : pushInstruction(mb, r1);
1933 2482 : pushInstruction(mb, r2);
1934 2482 : if (push)
1935 2102 : pushInstruction(mb, attr);
1936 :
1937 2482 : if (mb->errors || mat_group_attr(mb, ml, g, r1, push))
1938 0 : return -1;
1939 :
1940 : /* create mat's for the intermediates */
1941 2482 : a = ml->top;
1942 2482 : if (mat_add_var(ml, attr, NULL, getArg(attr, 0), mat_ext, -1, -1, push)) {
1943 0 : if (!push)
1944 0 : freeInstruction(attr);
1945 0 : return -1;
1946 : }
1947 2482 : if (mat_add_var(ml, r0, p, getArg(p, 0), mat_grp, b, g, 1))
1948 : return -1;
1949 2482 : g = ml->top - 1;
1950 4964 : if (mat_add_var(ml, r1, p, getArg(p, 1), mat_ext, a, ml->top - 1, 1) || /* point back at group */
1951 2482 : mat_add_var(ml, r2, p, getArg(p, 2), mat_cnt, -1, ml->top - 1, 1)) /* point back at ext */
1952 0 : return -1;
1953 2482 : if (push)
1954 2102 : return mat_pack_group(mb, ml, g);
1955 : return 0;
1956 : }
1957 :
1958 : static int
1959 591 : mat_topn_project(MalBlkPtr mb, InstrPtr p, mat_t *mat, int m, int n)
1960 : {
1961 591 : int tpe = getArgType(mb, p, 0), k;
1962 591 : InstrPtr pck, q;
1963 :
1964 591 : pck = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
1965 591 : if (pck == NULL)
1966 : return -1;
1967 591 : getArg(pck, 0) = newTmpVariable(mb, tpe);
1968 :
1969 5628 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
1970 5037 : InstrPtr q = copyInstruction(p);
1971 5037 : if (!q) {
1972 0 : freeInstruction(pck);
1973 0 : return -1;
1974 : }
1975 :
1976 5037 : getArg(q, 0) = newTmpVariable(mb, tpe);
1977 5037 : getArg(q, 1) = getArg(mat[m].mi, k);
1978 5037 : getArg(q, 2) = getArg(mat[n].mi, k);
1979 5037 : pushInstruction(mb, q);
1980 :
1981 5037 : pck = pushArgument(mb, pck, getArg(q, 0));
1982 : }
1983 591 : pushInstruction(mb, pck);
1984 :
1985 591 : if (mb->errors || (q = copyInstruction(p)) == NULL)
1986 0 : return -1;
1987 591 : getArg(q, 2) = getArg(pck, 0);
1988 591 : pushInstruction(mb, q);
1989 591 : if (mb->errors)
1990 : return -1;
1991 : return 0;
1992 : }
1993 :
1994 : static int
1995 103 : mat_pack_topn(MalBlkPtr mb, InstrPtr slc, mat_t *mat, int m)
1996 : {
1997 : /* find chain of topn's */
1998 103 : int cnt = chain_by_length(mat, m), i;
1999 103 : InstrPtr cur = NULL;
2000 :
2001 228 : for (i = cnt - 1; mb->errors == NULL && i >= 0; i--) {
2002 125 : int otpn = walk_n_back(mat, m, i), var = 1, k;
2003 125 : int attr = mat[otpn].im;
2004 125 : int tpe = getVarType(mb, getArg(mat[attr].mi, 0));
2005 125 : InstrPtr pck, tpn, otopn = mat[otpn].org, a;
2006 :
2007 125 : pck = newInstructionArgs(mb, matRef, packRef, mat[attr].mi->argc);
2008 125 : if (pck == NULL)
2009 : return -1;
2010 125 : getArg(pck, 0) = newTmpVariable(mb, tpe);
2011 :
2012 : /* m.projection(attr); */
2013 1071 : for (k = 1; mb->errors == NULL && k < mat[attr].mi->argc; k++) {
2014 946 : InstrPtr q = newInstruction(mb, algebraRef, projectionRef);
2015 946 : if (q == NULL) {
2016 0 : freeInstruction(pck);
2017 0 : return -1;
2018 : }
2019 946 : getArg(q, 0) = newTmpVariable(mb, tpe);
2020 :
2021 946 : q = pushArgument(mb, q, getArg(slc, k));
2022 946 : q = pushArgument(mb, q, getArg(mat[attr].mi, k));
2023 946 : pushInstruction(mb, q);
2024 :
2025 946 : pck = pushArgument(mb, pck, getArg(q, 0));
2026 : }
2027 125 : pushInstruction(mb, pck);
2028 :
2029 125 : a = pck;
2030 :
2031 125 : if (mb->errors || (tpn = copyInstruction(otopn)) == NULL)
2032 0 : return -1;
2033 125 : var = 1;
2034 125 : if (cur) {
2035 22 : getArg(tpn, tpn->retc + var) = getArg(cur, 0);
2036 22 : var ++;
2037 22 : if (cur->retc == 2) {
2038 22 : getArg(tpn, tpn->retc + var) = getArg(cur, 1);
2039 22 : var ++;
2040 : }
2041 : }
2042 125 : getArg(tpn, tpn->retc) = getArg(a, 0);
2043 125 : pushInstruction(mb, tpn);
2044 125 : cur = tpn;
2045 : }
2046 103 : if (mb->errors)
2047 : return -1;
2048 : return 0;
2049 : }
2050 :
2051 : static int
2052 179 : mat_topn(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int o)
2053 : {
2054 179 : int tpe = getArgType(mb, p, 0), k, is_slice = isSlice(p), zero = -1;
2055 179 : InstrPtr pck, gpck = NULL, q, r;
2056 179 : int with_groups = (p->retc == 2), piv = 0, topn2 = (n >= 0);
2057 :
2058 179 : assert(topn2 || o < 0);
2059 : /* dummy mat instruction (needed to share result of p) */
2060 179 : pck = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
2061 179 : if (pck == NULL)
2062 : return -1;
2063 179 : getArg(pck, 0) = getArg(p, 0);
2064 :
2065 179 : if (with_groups) {
2066 22 : gpck = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
2067 22 : if (gpck == NULL) {
2068 0 : freeInstruction(pck);
2069 0 : return -1;
2070 : }
2071 22 : getArg(gpck, 0) = getArg(p, 1);
2072 : }
2073 :
2074 179 : if (is_slice) {
2075 54 : ValRecord cst;
2076 54 : cst.vtype = getArgType(mb, p, 2);
2077 54 : cst.val.lval = 0;
2078 54 : cst.len = 0;
2079 54 : zero = defConstant(mb, cst.vtype, &cst);
2080 54 : if (zero < 0) {
2081 0 : freeInstruction(pck);
2082 0 : return -1;
2083 : }
2084 : }
2085 179 : assert((n < 0 && o < 0)
2086 : || (ml->v[m].mi->argc == ml->v[n].mi->argc
2087 : && ml->v[m].mi->argc == ml->v[o].mi->argc));
2088 :
2089 1511 : for (k = 1; mb->errors == NULL && k < ml->v[m].mi->argc; k++) {
2090 1332 : if ((q = copyInstruction(p)) == NULL) {
2091 0 : freeInstruction(gpck);
2092 0 : freeInstruction(pck);
2093 0 : return -1;
2094 : }
2095 1332 : getArg(q, 0) = newTmpVariable(mb, tpe);
2096 1332 : if (with_groups)
2097 178 : getArg(q, 1) = newTmpVariable(mb, tpe);
2098 1332 : getArg(q, q->retc) = getArg(ml->v[m].mi, k);
2099 1332 : if (is_slice) /* lower bound should always be 0 on partial slices */
2100 386 : getArg(q, q->retc + 1) = zero;
2101 946 : else if (topn2) {
2102 178 : getArg(q, q->retc + 1) = getArg(ml->v[n].mi, k);
2103 178 : getArg(q, q->retc + 2) = getArg(ml->v[o].mi, k);
2104 : }
2105 1332 : pushInstruction(mb, q);
2106 :
2107 1332 : pck = pushArgument(mb, pck, getArg(q, 0));
2108 1332 : if (with_groups)
2109 178 : gpck = pushArgument(mb, gpck, getArg(q, 1));
2110 : }
2111 :
2112 179 : piv = ml->top;
2113 304 : if (mb->errors || mat_add_var(ml, pck, p, getArg(p, 0), is_slice ? mat_slc : mat_tpn, m, n, 0)) {
2114 0 : freeInstruction(pck);
2115 0 : freeInstruction(gpck);
2116 0 : return -1;
2117 : }
2118 179 : if (with_groups
2119 22 : && mat_add_var(ml, gpck, p, getArg(p, 1), is_slice ? mat_slc : mat_tpn,
2120 : m, piv, 0)) {
2121 0 : freeInstruction(gpck);
2122 0 : return -1;
2123 : }
2124 :
2125 179 : if (is_slice || p->retc == 1 /* single result, ie last of the topn's */ ) {
2126 157 : if (ml->v[m].type == mat_tpn || !is_slice) {
2127 103 : if (mat_pack_topn(mb, pck, ml->v, (!is_slice) ? piv : m))
2128 : return -1;
2129 : }
2130 :
2131 : /* topn/slice over merged parts */
2132 103 : if (is_slice) {
2133 : /* real instruction */
2134 54 : r = newInstructionArgs(mb, matRef, packRef, pck->argc);
2135 54 : if (r == NULL)
2136 : return -1;
2137 54 : getArg(r, 0) = newTmpVariable(mb, tpe);
2138 :
2139 440 : for (k = 1; k < pck->argc; k++)
2140 386 : r = pushArgument(mb, r, getArg(pck, k));
2141 54 : pushInstruction(mb, r);
2142 :
2143 54 : if ((q = copyInstruction(p)) == NULL)
2144 : return -1;
2145 54 : setFunctionId(q, subsliceRef);
2146 54 : if (ml->v[m].type != mat_tpn || is_slice)
2147 54 : getArg(q, 1) = getArg(r, 0);
2148 54 : pushInstruction(mb, q);
2149 : }
2150 :
2151 157 : ml->v[piv].type = mat_slc;
2152 : }
2153 179 : if (mb->errors)
2154 : return -1;
2155 : return 0;
2156 : }
2157 :
2158 : static int
2159 0 : mat_sample(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m)
2160 : {
2161 : /* transform
2162 : * a := sample.subuniform(b,n);
2163 : * into
2164 : * t1 := sample.subuniform(b1,n);
2165 : * t2 := sample.subuniform(b2,n);
2166 : * ...
2167 : * t0 := mat.pack(t1,t2,...);
2168 : * tn := sample.subuniform(t0,n);
2169 : * a := algebra.projection(tn,t0);
2170 : *
2171 : * Note that this does *not* give a uniform sample of the original
2172 : * bat b!
2173 : */
2174 :
2175 0 : int tpe = getArgType(mb, p, 0), k, piv;
2176 0 : InstrPtr pck, q, r;
2177 :
2178 0 : pck = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
2179 0 : if (pck == NULL)
2180 : return -1;
2181 0 : getArg(pck, 0) = newTmpVariable(mb, tpe);
2182 :
2183 0 : for (k = 1; mb->errors == NULL && k < ml->v[m].mi->argc; k++) {
2184 0 : if ((q = copyInstruction(p)) == NULL) {
2185 0 : freeInstruction(pck);
2186 0 : return -1;
2187 : }
2188 0 : getArg(q, 0) = newTmpVariable(mb, tpe);
2189 0 : getArg(q, q->retc) = getArg(ml->v[m].mi, k);
2190 0 : pushInstruction(mb, q);
2191 0 : pck = pushArgument(mb, pck, getArg(q, 0));
2192 : }
2193 :
2194 0 : piv = ml->top;
2195 0 : if (mb->errors || mat_add_var(ml, pck, p, getArg(p, 0), mat_slc, m, -1, 1)) {
2196 0 : freeInstruction(pck);
2197 0 : return -1;
2198 : }
2199 0 : pushInstruction(mb, pck);
2200 :
2201 0 : if ((q = copyInstruction(p)) == NULL)
2202 : return -1;
2203 0 : getArg(q, 0) = newTmpVariable(mb, tpe);
2204 0 : getArg(q, q->retc) = getArg(pck, 0);
2205 0 : pushInstruction(mb, q);
2206 :
2207 0 : r = newInstruction(mb, algebraRef, projectionRef);
2208 0 : if (r == NULL)
2209 : return -1;
2210 0 : getArg(r, 0) = getArg(p, 0);
2211 0 : r = pushArgument(mb, r, getArg(q, 0));
2212 0 : r = pushArgument(mb, r, getArg(pck, 0));
2213 0 : pushInstruction(mb, r);
2214 :
2215 0 : matlist_pack(ml, piv);
2216 0 : ml->v[piv].type = mat_slc;
2217 0 : if (mb->errors)
2218 : return -1;
2219 : return 0;
2220 : }
2221 :
2222 : str
2223 477351 : OPTmergetableImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
2224 : InstrPtr pci)
2225 : {
2226 477351 : InstrPtr p, *old;
2227 477351 : matlist_t ml;
2228 477351 : int oldtop, fm, fn, fo, fe, i, k, m, n, o, e, slimit, bailout = 0;
2229 477351 : int size = 0, match, actions = 0, distinct_topn = 0, /*topn_res = 0, */ groupdone = 0, *vars; //, maxvars;
2230 477351 : char *group_input;
2231 477351 : str msg = MAL_SUCCEED;
2232 :
2233 477351 : if (isOptimizerUsed(mb, pci, mitosisRef) <= 0)
2234 33719 : goto cleanup2;
2235 443693 : old = mb->stmt;
2236 443693 : oldtop = mb->stop;
2237 :
2238 443693 : vars = (int *) GDKmalloc(sizeof(int) * mb->vtop);
2239 : //maxvars = mb->vtop;
2240 443690 : group_input = (char *) GDKzalloc(sizeof(char) * mb->vtop);
2241 443692 : if (vars == NULL || group_input == NULL) {
2242 0 : if (vars)
2243 0 : GDKfree(vars);
2244 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2245 : }
2246 : /* check for bailout conditions */
2247 20178146 : for (i = 1; i < oldtop && !bailout; i++) {
2248 19734467 : int j;
2249 :
2250 19734467 : p = old[i];
2251 :
2252 39796341 : for (j = 0; j < p->retc; j++) {
2253 20061874 : int res = getArg(p, j);
2254 20061874 : vars[res] = i;
2255 : }
2256 :
2257 : /* pack if there is a group statement following a groupdone (ie aggr(distinct)) */
2258 19734467 : if (getModuleId(p) == groupRef && p->argc == 5
2259 4917 : && (getFunctionId(p) == subgroupRef
2260 3437 : || getFunctionId(p) == subgroupdoneRef
2261 0 : || getFunctionId(p) == groupRef
2262 0 : || getFunctionId(p) == groupdoneRef)) {
2263 4917 : InstrPtr q = old[vars[getArg(p, p->argc - 1)]]; /* group result from a previous group(done) */
2264 :
2265 4917 : if (getFunctionId(q) == subgroupdoneRef
2266 4912 : || getFunctionId(q) == groupdoneRef)
2267 19734467 : groupdone = 1;
2268 : }
2269 : /* bail out if there is a input for a group, which has been used for a group already (solves problems with cube like groupings) */
2270 19734467 : if (getModuleId(p) == groupRef
2271 25120 : && (getFunctionId(p) == subgroupRef
2272 23640 : || getFunctionId(p) == subgroupdoneRef
2273 20203 : || getFunctionId(p) == groupRef
2274 16738 : || getFunctionId(p) == groupdoneRef)) {
2275 25120 : int input = getArg(p, p->retc); /* argument one is first input */
2276 :
2277 25120 : if (group_input[input]) {
2278 108 : TRC_INFO(MAL_OPTIMIZER,
2279 : "Mergetable bailout on group input reuse in group statement\n");
2280 : bailout = 1;
2281 : }
2282 :
2283 25120 : group_input[input] = 1;
2284 : }
2285 19734467 : if (getModuleId(p) == algebraRef && getFunctionId(p) == selectNotNilRef) {
2286 0 : TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout not nil ref\n");
2287 : bailout = 1;
2288 : }
2289 19734467 : if (getModuleId(p) == algebraRef && getFunctionId(p) == semijoinRef) {
2290 161 : TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout semijoin ref\n");
2291 : bailout = 1;
2292 : }
2293 19734467 : if (getModuleId(p) == algebraRef && getFunctionId(p) == thetajoinRef) {
2294 2595 : assert(p->argc == 9);
2295 2595 : if (p->argc == 9
2296 2595 : && getVarConstant(mb,
2297 : getArg(p,
2298 2595 : 6)).val.ival == 6 /* op == '<>' */ ) {
2299 0 : TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout thetajoin ref\n");
2300 : bailout = 1;
2301 : }
2302 : }
2303 19734467 : if (isSample(p)) {
2304 21 : bailout = 1;
2305 : }
2306 : /*
2307 : if (isTopn(p))
2308 : topn_res = getArg(p, 0);
2309 : */
2310 : /* not idea how to detect this yet */
2311 : //distinct_topn = 1;
2312 : }
2313 443679 : GDKfree(group_input);
2314 :
2315 443680 : ml.horigin = 0;
2316 443680 : ml.torigin = 0;
2317 443680 : ml.v = 0;
2318 443680 : ml.vars = 0;
2319 443680 : if (bailout)
2320 290 : goto cleanup;
2321 :
2322 : /* the number of MATs is limited to the variable stack */
2323 443390 : ml.size = mb->vtop;
2324 443390 : ml.top = 0;
2325 443390 : ml.v = (mat_t *) GDKzalloc(ml.size * sizeof(mat_t));
2326 443403 : ml.vsize = mb->vsize;
2327 443403 : ml.horigin = (int *) GDKmalloc(sizeof(int) * ml.vsize);
2328 443387 : ml.torigin = (int *) GDKmalloc(sizeof(int) * ml.vsize);
2329 443377 : ml.vars = (int *) GDKmalloc(sizeof(int) * ml.vsize);
2330 443385 : if (ml.v == NULL || ml.horigin == NULL || ml.torigin == NULL
2331 443385 : || ml.vars == NULL) {
2332 0 : goto cleanup;
2333 : }
2334 123522809 : for (i = 0; i < ml.vsize; i++) {
2335 123079424 : ml.horigin[i] = ml.torigin[i] = -1;
2336 123079424 : ml.vars[i] = -1;
2337 : }
2338 :
2339 443385 : slimit = mb->ssize;
2340 443385 : size = (mb->stop * 1.2 < mb->ssize) ? mb->ssize : (int) (mb->stop * 1.2);
2341 443385 : mb->stmt = (InstrPtr *) GDKzalloc(size * sizeof(InstrPtr));
2342 443402 : if (mb->stmt == NULL) {
2343 0 : mb->stmt = old;
2344 0 : msg = createException(MAL, "optimizer.mergetable",
2345 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2346 0 : goto cleanup;
2347 : }
2348 443402 : mb->ssize = size;
2349 443402 : mb->stop = 0;
2350 :
2351 6849731 : for (i = 0; i < oldtop; i++) {
2352 6849731 : int bats = 0, nilbats = 0;
2353 6849731 : InstrPtr r, cp;
2354 :
2355 6849731 : p = old[i];
2356 :
2357 6849731 : if (p->token == ENDsymbol) /* don't copy the optimizer pipeline added after final instruction */
2358 : break;
2359 6406333 : if (getModuleId(p) == matRef
2360 233783 : && (getFunctionId(p) == newRef || getFunctionId(p) == packRef)) {
2361 233783 : if (mat_set_prop(&ml, mb, p)
2362 233783 : || mat_add_var(&ml, p, NULL, getArg(p, 0), mat_none, -1, -1,
2363 : 1)) {
2364 0 : msg = createException(MAL, "optimizer.mergetable",
2365 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2366 0 : goto cleanup;
2367 : }
2368 233783 : continue;
2369 : }
2370 :
2371 : /*
2372 : * If the instruction does not contain MAT references it can simply be added.
2373 : * Otherwise we have to decide on either packing them or replacement.
2374 : */
2375 6172550 : if ((match = nr_of_mats(p, &ml)) == 0) {
2376 5009523 : cp = copyInstruction(p);
2377 5009527 : if (!cp) {
2378 0 : msg = createException(MAL, "optimizer.mergetable",
2379 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2380 0 : goto cleanup;
2381 : }
2382 5009527 : pushInstruction(mb, cp);
2383 5009531 : continue;
2384 : }
2385 1163027 : bats = nr_of_bats(mb, p);
2386 1163027 : nilbats = nr_of_nilbats(mb, p);
2387 :
2388 : /* left joins can match at isMatJoinOp, so run this check beforehand */
2389 1163027 : if (match > 0 && isMatLeftJoinOp(p) && p->argc >= 5 && p->retc == 2
2390 291 : && (match == 1 || match == 2) && bats + nilbats == 4) {
2391 291 : m = is_a_mat(getArg(p, p->retc), &ml);
2392 291 : o = is_a_mat(getArg(p, p->retc + 2), &ml);
2393 :
2394 291 : if ((match == 1 && m >= 0) || (match == 2 && m >= 0 && o >= 0)) {
2395 284 : if (mat_join2(mb, p, &ml, m, -1, o, -1)) {
2396 0 : msg = createException(MAL, "optimizer.mergetable",
2397 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2398 0 : goto cleanup;
2399 : }
2400 284 : actions++;
2401 284 : continue;
2402 : }
2403 : }
2404 :
2405 : /* (l,r) Join (L, R, ..)
2406 : * 2 -> (l,r) equi/theta joins (l,r)
2407 : * 3 -> (l,r) range-joins (l,r1,r2)
2408 : * NxM -> (l,r) filter-joins (l1,..,ln,r1,..,rm)
2409 : */
2410 1162743 : if (match > 0 && isMatJoinOp(p) && !isMatLeftJoinOp(p) && p->argc >= 5
2411 48868 : && p->retc == 2 && bats + nilbats >= 4) {
2412 42132 : if (bats + nilbats == 4) {
2413 42082 : m = is_a_mat(getArg(p, p->retc), &ml);
2414 42082 : n = is_a_mat(getArg(p, p->retc + 1), &ml);
2415 42082 : o = is_a_mat(getArg(p, p->retc + 2), &ml);
2416 42082 : e = is_a_mat(getArg(p, p->retc + 3), &ml);
2417 42082 : if (mat_join2(mb, p, &ml, m, n, o, e)) {
2418 0 : msg = createException(MAL, "optimizer.mergetable",
2419 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2420 0 : goto cleanup;
2421 : }
2422 : } else {
2423 50 : if (mat_joinNxM(cntxt, mb, p, &ml, bats)) {
2424 0 : msg = createException(MAL, "optimizer.mergetable",
2425 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2426 0 : goto cleanup;
2427 : }
2428 : }
2429 42132 : actions++;
2430 42132 : continue;
2431 : }
2432 1120611 : if (match > 0 && getModuleId(p) == algebraRef
2433 882950 : && getFunctionId(p) == crossRef && p->argc == 5 && p->retc == 2
2434 6736 : && bats == 2) {
2435 1127347 : int max_one = (isVarConstant(mb, getArg(p, 4))
2436 6736 : && getVarConstant(mb, getArg(p, 4)).val.btval);
2437 10228 : if (!max_one) {
2438 5114 : m = is_a_mat(getArg(p, p->retc), &ml);
2439 5114 : n = is_a_mat(getArg(p, p->retc + 1), &ml);
2440 5114 : if (mat_join2(mb, p, &ml, m, n, -1, -1)) {
2441 0 : msg = createException(MAL, "optimizer.mergetable",
2442 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2443 0 : goto cleanup;
2444 : }
2445 5114 : actions++;
2446 5114 : continue;
2447 : }
2448 : }
2449 : /*
2450 : * Aggregate handling is a prime target for optimization.
2451 : * The simple cases are dealt with first.
2452 : * Handle the rewrite v:=aggr.count(b) and sum()
2453 : * And the min/max is as easy
2454 : */
2455 1115497 : if (match == 1 && p->argc >= 2 &&
2456 233001 : ((getModuleId(p) == aggrRef &&
2457 1716 : (getFunctionId(p) == countRef
2458 1435 : || getFunctionId(p) == count_no_nilRef
2459 1435 : || getFunctionId(p) == minRef || getFunctionId(p) == maxRef
2460 1341 : || getFunctionId(p) == avgRef || getFunctionId(p) == sumRef
2461 120 : || getFunctionId(p) == prodRef)))
2462 1601 : && (m = is_a_mat(getArg(p, p->retc + 0), &ml)) >= 0) {
2463 1601 : if ((msg = mat_aggr(mb, p, ml.v, m)) != MAL_SUCCEED)
2464 0 : goto cleanup;
2465 1601 : actions++;
2466 1601 : continue;
2467 : }
2468 :
2469 1113896 : if (match == 1 && bats == 1 && p->argc == 4 && isSlice(p)
2470 54 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
2471 54 : if (mat_topn(mb, p, &ml, m, -1, -1)) {
2472 0 : msg = createException(MAL, "optimizer.mergetable",
2473 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2474 0 : goto cleanup;
2475 : }
2476 54 : actions++;
2477 54 : continue;
2478 : }
2479 :
2480 1113842 : if (match == 1 && bats == 1 && p->argc == 3 && isSample(p)
2481 0 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
2482 0 : if (mat_sample(mb, p, &ml, m)) {
2483 0 : msg = createException(MAL, "optimizer.mergetable",
2484 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2485 0 : goto cleanup;
2486 : }
2487 0 : actions++;
2488 0 : continue;
2489 : }
2490 :
2491 1113842 : if (!distinct_topn && match == 1 && bats == 1 && isTopn(p)
2492 103 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
2493 103 : if (mat_topn(mb, p, &ml, m, -1, -1)) {
2494 0 : msg = createException(MAL, "optimizer.mergetable",
2495 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2496 0 : goto cleanup;
2497 : }
2498 103 : actions++;
2499 103 : continue;
2500 : }
2501 1113739 : if (!distinct_topn && match == 3 && bats == 3 && isTopn(p)
2502 22 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)
2503 22 : && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
2504 22 : && ((o = is_a_mat(getArg(p, p->retc + 2), &ml)) >= 0)) {
2505 22 : if (mat_topn(mb, p, &ml, m, n, o)) {
2506 0 : msg = createException(MAL, "optimizer.mergetable",
2507 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2508 0 : goto cleanup;
2509 : }
2510 22 : actions++;
2511 22 : continue;
2512 : }
2513 :
2514 : /* Now we handle subgroup and aggregation statements. */
2515 1113717 : if (!groupdone && match == 1 && bats == 1 && p->argc == 4
2516 15090 : && getModuleId(p) == groupRef &&
2517 4653 : (getFunctionId(p) == subgroupRef
2518 4653 : || getFunctionId(p) == subgroupdoneRef
2519 4653 : || getFunctionId(p) == groupRef
2520 2551 : || getFunctionId(p) == groupdoneRef)
2521 4653 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
2522 4653 : if (mat_group_new(mb, p, &ml, m)) {
2523 0 : msg = createException(MAL, "optimizer.mergetable",
2524 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2525 0 : goto cleanup;
2526 : }
2527 4653 : actions++;
2528 4653 : continue;
2529 : }
2530 1109064 : if (!groupdone && match == 2 && bats == 2 && p->argc == 5
2531 33673 : && getModuleId(p) == groupRef &&
2532 2482 : (getFunctionId(p) == subgroupRef
2533 2102 : || getFunctionId(p) == subgroupdoneRef
2534 0 : || getFunctionId(p) == groupRef
2535 0 : || getFunctionId(p) == groupdoneRef)
2536 2482 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)
2537 2482 : && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
2538 2482 : && ml.v[n].im >= 0 /* not packed */ ) {
2539 2482 : if (mat_group_derive(mb, p, &ml, m, n)) {
2540 0 : msg = createException(MAL, "optimizer.mergetable",
2541 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2542 0 : goto cleanup;
2543 : }
2544 2482 : actions++;
2545 2482 : continue;
2546 : }
2547 : /* TODO sub'aggr' with cand list */
2548 1106582 : if (match == 3 && bats == 3 && getModuleId(p) == aggrRef && p->argc >= 4
2549 3148 : && (getFunctionId(p) == subcountRef
2550 476 : || getFunctionId(p) == subminRef
2551 423 : || getFunctionId(p) == submaxRef
2552 368 : || getFunctionId(p) == subavgRef
2553 317 : || getFunctionId(p) == subsumRef
2554 3 : || getFunctionId(p) == subprodRef)
2555 3148 : && ((m = is_a_mat(getArg(p, p->retc + 0), &ml)) >= 0)
2556 3148 : && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
2557 3148 : && ((o = is_a_mat(getArg(p, p->retc + 2), &ml)) >= 0)) {
2558 3148 : if (mat_group_aggr(mb, p, ml.v, m, n, o)) {
2559 0 : msg = createException(MAL, "optimizer.mergetable",
2560 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2561 0 : goto cleanup;
2562 : }
2563 3148 : actions++;
2564 3148 : continue;
2565 : }
2566 : /* Handle cases of ext.projection and .projection(grp) */
2567 1103434 : if (match == 2 && getModuleId(p) == algebraRef
2568 721014 : && getFunctionId(p) == projectionRef
2569 684628 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
2570 684628 : && (n = is_a_mat(getArg(p, 2), &ml)) >= 0
2571 684628 : && (ml.v[m].type == mat_ext || ml.v[n].type == mat_grp)) {
2572 7025 : assert(ml.v[m].pushed);
2573 7025 : if (!ml.v[n].pushed) {
2574 7025 : if (mat_group_project(mb, p, &ml, m, n)) {
2575 0 : msg = createException(MAL, "optimizer.mergetable",
2576 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2577 0 : goto cleanup;
2578 : }
2579 : } else {
2580 0 : cp = copyInstruction(p);
2581 0 : if (!cp) {
2582 0 : msg = createException(MAL, "optimizer.mergetable",
2583 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2584 0 : goto cleanup;
2585 : }
2586 0 : pushInstruction(mb, cp);
2587 : }
2588 7025 : continue;
2589 : }
2590 1096409 : if (match == 1 && getModuleId(p) == algebraRef
2591 156432 : && getFunctionId(p) == projectRef
2592 11947 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
2593 11947 : && (ml.v[m].type == mat_ext)) {
2594 0 : assert(ml.v[m].pushed);
2595 0 : cp = copyInstruction(p);
2596 0 : if (!cp) {
2597 0 : msg = createException(MAL, "optimizer.mergetable",
2598 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2599 0 : goto cleanup;
2600 : }
2601 0 : pushInstruction(mb, cp);
2602 0 : continue;
2603 : }
2604 :
2605 : /* Handle cases of slice.projection */
2606 1096409 : if (match == 2 && getModuleId(p) == algebraRef
2607 713989 : && getFunctionId(p) == projectionRef
2608 677603 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
2609 677603 : && (n = is_a_mat(getArg(p, 2), &ml)) >= 0
2610 677603 : && (ml.v[m].type == mat_slc)) {
2611 591 : if (mat_topn_project(mb, p, ml.v, m, n)) {
2612 0 : msg = createException(MAL, "optimizer.mergetable",
2613 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2614 0 : goto cleanup;
2615 : }
2616 591 : actions++;
2617 591 : continue;
2618 : }
2619 :
2620 : /* Handle projection */
2621 1095818 : if (match > 0
2622 1095818 : &&
2623 1095818 : ((getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef)
2624 320311 : || ((getModuleId(p) == dictRef || getModuleId(p) == forRef)
2625 125 : && getFunctionId(p) == decompressRef))
2626 775575 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0) {
2627 757027 : n = is_a_mat(getArg(p, 2), &ml);
2628 757027 : if (mat_projection(mb, p, &ml, m, n)) {
2629 0 : msg = createException(MAL, "optimizer.mergetable",
2630 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2631 0 : goto cleanup;
2632 : }
2633 757027 : actions++;
2634 757027 : continue;
2635 : }
2636 : /* Handle setops */
2637 338791 : if (match > 0 && getModuleId(p) == algebraRef
2638 113082 : && (getFunctionId(p) == differenceRef
2639 104589 : || getFunctionId(p) == intersectRef)
2640 9517 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0) {
2641 8662 : n = is_a_mat(getArg(p, 2), &ml);
2642 8662 : o = is_a_mat(getArg(p, 3), &ml);
2643 8662 : if (mat_setop(mb, p, &ml, m, n, o)) {
2644 0 : msg = createException(MAL, "optimizer.mergetable",
2645 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2646 0 : goto cleanup;
2647 : }
2648 8662 : actions++;
2649 8662 : continue;
2650 : }
2651 :
2652 330129 : if (match == p->retc && p->argc == (p->retc * 2)
2653 9446 : && getFunctionId(p) == NULL) {
2654 3 : if ((r = mat_assign(mb, p, &ml)) == NULL) {
2655 0 : msg = createException(MAL, "optimizer.mergetable",
2656 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2657 0 : goto cleanup;
2658 : }
2659 3 : actions++;
2660 3 : continue;
2661 : }
2662 :
2663 330126 : m = n = o = e = -1;
2664 698547 : for (fm = p->argc - 1; fm >= p->retc; fm--)
2665 698547 : if ((m = is_a_mat(getArg(p, fm), &ml)) >= 0)
2666 : break;
2667 :
2668 422481 : for (fn = fm - 1; fn >= p->retc; fn--)
2669 276126 : if ((n = is_a_mat(getArg(p, fn), &ml)) >= 0)
2670 : break;
2671 :
2672 345139 : for (fo = fn - 1; fo >= p->retc; fo--)
2673 128279 : if ((o = is_a_mat(getArg(p, fo), &ml)) >= 0)
2674 : break;
2675 :
2676 348635 : for (fe = fo - 1; fe >= p->retc; fe--)
2677 55048 : if ((e = is_a_mat(getArg(p, fe), &ml)) >= 0)
2678 : break;
2679 :
2680 : /* delta* operator */
2681 330126 : if (match == 3 && bats == 3 && isDelta(p)
2682 56133 : && (m = is_a_mat(getArg(p, fm), &ml)) >= 0
2683 56133 : && (n = is_a_mat(getArg(p, fn), &ml)) >= 0
2684 56133 : && (o = is_a_mat(getArg(p, fo), &ml)) >= 0) {
2685 56133 : if ((r = mat_delta(&ml, mb, p, ml.v, m, n, o, -1, fm, fn, fo, 0)) != NULL) {
2686 56133 : actions++;
2687 : } else {
2688 0 : msg = createException(MAL, "optimizer.mergetable",
2689 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2690 0 : goto cleanup;
2691 : }
2692 :
2693 56133 : continue;
2694 : }
2695 273993 : if (match == 4 && bats == 4 && isDelta(p)
2696 32455 : && (m = is_a_mat(getArg(p, fm), &ml)) >= 0
2697 32455 : && (n = is_a_mat(getArg(p, fn), &ml)) >= 0
2698 32455 : && (o = is_a_mat(getArg(p, fo), &ml)) >= 0
2699 32455 : && (e = is_a_mat(getArg(p, fe), &ml)) >= 0) {
2700 32455 : if ((r = mat_delta(&ml, mb, p, ml.v, m, n, o, e, fm, fn, fo, fe)) != NULL) {
2701 32455 : actions++;
2702 : } else {
2703 0 : msg = createException(MAL, "optimizer.mergetable",
2704 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2705 0 : goto cleanup;
2706 : }
2707 32455 : continue;
2708 : }
2709 :
2710 : /* select on insert, should use last tid only */
2711 : #if 0
2712 : if (match == 1 && fm == 2 && isSelect(p) && p->retc == 1 && (m = is_a_mat(getArg(p, fm), &ml)) >= 0 && !ml.v[m].packed && /* not packed yet */
2713 : (getArg(p, fm - 1) > maxvars
2714 : || getModuleId(old[vars[getArg(p, fm - 1)]]) == sqlRef)) {
2715 : if ((r = copyInstruction(p)) == NULL) {
2716 : msg = createException(MAL, "optimizer.mergetable",
2717 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2718 : goto cleanup;
2719 : }
2720 : getArg(r, fm) = getArg(ml.v[m].mi, ml.v[m].mi->argc - 1);
2721 : pushInstruction(mb, r);
2722 : actions++;
2723 : continue;
2724 : }
2725 : #endif
2726 :
2727 : /* select on update, with nil bat */
2728 241538 : if (match == 1 && fm == 1 && isSelect(p) && p->retc == 1
2729 35605 : && (m = is_a_mat(getArg(p, fm), &ml)) >= 0 && bats == 2
2730 7020 : && isaBatType(getArgType(mb, p, 2))
2731 7020 : && isVarConstant(mb, getArg(p, 2))
2732 4 : && is_bat_nil(getVarConstant(mb, getArg(p, 2)).val.bval)) {
2733 4 : if (mat_apply1(mb, p, &ml, m, fm)) {
2734 0 : msg = createException(MAL, "optimizer.mergetable",
2735 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2736 0 : goto cleanup;
2737 : }
2738 4 : actions++;
2739 4 : continue;
2740 : }
2741 :
2742 : /* handle dict select */
2743 241534 : if ((match == 1 || match == bats - 1) && p->retc == 1 && isSelect(p)
2744 35654 : && getModuleId(p) == dictRef) {
2745 49 : if (mat_apply(mb, p, &ml, match)) {
2746 0 : msg = createException(MAL, "optimizer.mergetable",
2747 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2748 0 : goto cleanup;
2749 : }
2750 49 : actions++;
2751 49 : continue;
2752 : }
2753 : /* handle dict renumber */
2754 241485 : if (match == 1 && match == bats - 1 && p->retc == 1
2755 62686 : && getFunctionId(p) == renumberRef && getModuleId(p) == dictRef) {
2756 4 : if (mat_apply(mb, p, &ml, match)) {
2757 0 : msg = createException(MAL, "optimizer.mergetable",
2758 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2759 0 : goto cleanup;
2760 : }
2761 4 : actions++;
2762 4 : continue;
2763 : }
2764 :
2765 241481 : if (match == bats && p->retc == 1
2766 146676 : && (isMap2Op(p) || isMapOp(p) || isFragmentGroup(p)
2767 16163 : || isFragmentGroup2(p))) {
2768 146504 : if (mat_apply(mb, p, &ml, match)) {
2769 0 : msg = createException(MAL, "optimizer.mergetable",
2770 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2771 0 : goto cleanup;
2772 : }
2773 146504 : actions++;
2774 146504 : continue;
2775 : }
2776 :
2777 : /*
2778 : * All other instructions should be checked for remaining MAT dependencies.
2779 : * It requires MAT materialization.
2780 : */
2781 :
2782 473081 : for (k = p->retc; msg == MAL_SUCCEED && k < p->argc; k++) {
2783 378104 : if ((m = is_a_mat(getArg(p, k), &ml)) >= 0) {
2784 150147 : msg = mat_pack(mb, &ml, m);
2785 150147 : if (msg)
2786 : break;
2787 : }
2788 : }
2789 94977 : if (msg)
2790 : break;
2791 :
2792 94977 : cp = copyInstruction(p);
2793 94977 : if (!cp) {
2794 0 : msg = createException(MAL, "optimizer.mergetable",
2795 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2796 0 : goto cleanup;
2797 : }
2798 94977 : pushInstruction(mb, cp);
2799 : }
2800 : (void) stk;
2801 :
2802 14186060 : for (; i < oldtop; i++) { /* add optimizer pipeline back again */
2803 13742666 : pushInstruction(mb, old[i]);
2804 : }
2805 :
2806 443394 : if (mb->errors == MAL_SUCCEED) {
2807 6849701 : for (i = 0; i < slimit; i++) {
2808 6849701 : if (old[i] && old[i]->token == ENDsymbol) /* don't free optimizer calls */
2809 : break;
2810 6406318 : freeInstruction(old[i]);
2811 : }
2812 443383 : GDKfree(old);
2813 : }
2814 1805265 : for (i = 0; i < ml.top; i++) {
2815 1361867 : if (ml.v[i].mi && !ml.v[i].pushed)
2816 1099544 : freeInstruction(ml.v[i].mi);
2817 : }
2818 443398 : cleanup:
2819 443688 : if (vars)
2820 443688 : GDKfree(vars);
2821 443690 : if (ml.v)
2822 443400 : GDKfree(ml.v);
2823 443690 : if (ml.horigin)
2824 443400 : GDKfree(ml.horigin);
2825 443691 : if (ml.torigin)
2826 443401 : GDKfree(ml.torigin);
2827 443689 : if (ml.vars)
2828 443399 : GDKfree(ml.vars);
2829 443688 : if (mb->errors) {
2830 0 : freeException(msg);
2831 0 : msg = mb->errors;
2832 0 : mb->errors = NULL;
2833 : }
2834 : /* Defense line against incorrect plans */
2835 443688 : if (actions > 0 && msg == MAL_SUCCEED) {
2836 28927 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
2837 28927 : if (!msg)
2838 28927 : msg = chkFlow(mb);
2839 28927 : if (!msg)
2840 28927 : msg = chkDeclarations(mb);
2841 : }
2842 414761 : cleanup2:
2843 : /* keep actions taken as a fake argument */
2844 477407 : if (msg == MAL_SUCCEED) {
2845 477378 : (void) pushInt(mb, pci, actions);
2846 477444 : msg = mb->errors; /* may well be NULL */
2847 477444 : mb->errors = NULL;
2848 : }
2849 :
2850 : #ifndef NDEBUG
2851 477473 : if (bailout)
2852 290 : TRC_INFO(MAL_OPTIMIZER, "Merge table bailout\n");
2853 : #endif
2854 : return msg;
2855 : }
|