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, 2025 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; /* original 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 339215 : mat_type_t type = mat_none;
52 : (void) mat;
53 : (void) n;
54 : return type;
55 : }
56 :
57 : static inline int
58 36222917 : is_a_mat(int idx, const matlist_t *ml)
59 : {
60 36222917 : if (ml->vars[idx] >= 0 && !ml->v[ml->vars[idx]].packed)
61 9201512 : return ml->vars[idx];
62 : return -1;
63 : }
64 :
65 : static int
66 7009996 : nr_of_mats(InstrPtr p, const matlist_t *ml)
67 : {
68 7009996 : int j, cnt = 0;
69 35127470 : for (j = p->retc; j < p->argc; j++)
70 28117474 : if (is_a_mat(getArg(p, j), ml) >= 0)
71 2627678 : cnt++;
72 7009996 : return cnt;
73 : }
74 :
75 : static int
76 1369093 : nr_of_bats(MalBlkPtr mb, InstrPtr p)
77 : {
78 1369093 : int j, cnt = 0;
79 5099524 : for (j = p->retc; j < p->argc; j++)
80 3730431 : if (isaBatType(getArgType(mb, p, j))
81 3179785 : && !isVarConstant(mb, getArg(p, j)))
82 2955161 : cnt++;
83 1369093 : return cnt;
84 : }
85 :
86 : static int
87 1369093 : nr_of_nilbats(MalBlkPtr mb, InstrPtr p)
88 : {
89 1369093 : int j, cnt = 0;
90 5099524 : for (j = p->retc; j < p->argc; j++)
91 3730431 : if (isaBatType(getArgType(mb, p, j))
92 3730431 : && isVarConstant(mb, getArg(p, j))
93 224624 : && getVarConstant(mb, getArg(p, j)).val.bval == bat_nil)
94 224624 : cnt++;
95 1369093 : 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 1624747 : 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 1624747 : 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 1624747 : mat_t *dst = &ml->v[ml->top];
115 1624747 : dst->mi = q;
116 1624747 : dst->org = p;
117 1624747 : dst->mv = var;
118 1624747 : dst->type = type;
119 1624747 : dst->im = inputmat;
120 1624747 : dst->pm = parentmat;
121 1624747 : dst->packed = 0;
122 1624747 : dst->pushed = pushed;
123 1624747 : if (ml->vars[var] < 0 || dst->type != mat_ext) {
124 1613358 : if (ml->vars[var] >= 0) {
125 0 : ml->v[ml->vars[var]].packed = 1;
126 : }
127 1613358 : ml->vars[var] = ml->top;
128 : }
129 1624747 : ++ml->top;
130 1624747 : return 0;
131 : }
132 :
133 : inline static int
134 997786 : mat_add(matlist_t *ml, InstrPtr q, mat_type_t type, const char *func)
135 : {
136 997786 : (void) func;
137 : //printf (" ml.top %d %s\n", ml.top, func);
138 997786 : return mat_add_var(ml, q, NULL, getArg(q, 0), type, -1, -1, 0);
139 : }
140 :
141 : static void
142 135028 : matlist_pack(matlist_t *ml, int m)
143 : {
144 135028 : int i, idx = ml->v[m].mv;
145 :
146 135028 : assert(ml->v[m].packed == 0);
147 135028 : ml->v[m].packed = 1;
148 135028 : ml->vars[idx] = -1;
149 :
150 35166217 : for (i = 0; i < ml->top; i++)
151 35031189 : if (!ml->v[i].packed && ml->v[i].mv == idx) {
152 0 : ml->vars[idx] = i;
153 0 : break;
154 : }
155 135028 : }
156 :
157 : static str
158 135028 : mat_pack(MalBlkPtr mb, matlist_t *ml, int m)
159 : {
160 135028 : InstrPtr r;
161 :
162 135028 : if (ml->v[m].packed)
163 : return MAL_SUCCEED;
164 :
165 135028 : 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 135028 : int l;
177 :
178 135028 : r = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
179 135028 : if (r == NULL) {
180 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
181 : }
182 135028 : getArg(r, 0) = getArg(ml->v[m].mi, 0);
183 1159016 : for (l = ml->v[m].mi->retc; l < ml->v[m].mi->argc; l++)
184 1023988 : r = pushArgument(mb, r, getArg(ml->v[m].mi, l));
185 135028 : 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 135028 : matlist_pack(ml, m);
193 135028 : pushInstruction(mb, r);
194 135028 : return MAL_SUCCEED;
195 : }
196 :
197 : static int
198 84675646 : checksize(matlist_t *ml, int v)
199 : {
200 84675646 : if (v >= ml->vsize) {
201 15530 : int sz = ml->vsize, i, *nhorigin, *ntorigin, *nvars;
202 :
203 15530 : int nvsize = ml->vsize * 2;
204 15530 : assert(v < nvsize);
205 15530 : if (v >= nvsize)
206 : nvsize = v + 10;
207 15530 : nhorigin = (int *) GDKrealloc(ml->horigin, sizeof(int) * nvsize);
208 15530 : if (nhorigin == NULL)
209 : return -1;
210 15530 : ml->horigin = nhorigin;
211 15530 : ntorigin = (int *) GDKrealloc(ml->torigin, sizeof(int) * nvsize);
212 15530 : if (ntorigin == NULL)
213 : return -1;
214 15530 : ml->torigin = ntorigin;
215 15530 : nvars = (int *) GDKrealloc(ml->vars, sizeof(int) * nvsize);
216 15530 : if (nvars == NULL)
217 : return -1;
218 15530 : ml->vars = nvars;
219 15530 : ml->vsize = nvsize;
220 :
221 17039274 : for (i = sz; i < ml->vsize; i++) {
222 17023744 : ml->horigin[i] = ml->torigin[i] = -1;
223 17023744 : ml->vars[i] = -1;
224 : }
225 : }
226 : return 0;
227 : }
228 :
229 : static int
230 11534653 : setPartnr(matlist_t *ml, int ivar, int ovar, int pnr)
231 : {
232 11534653 : int tpnr = -1;
233 :
234 11534653 : if (checksize(ml, ivar) || checksize(ml, ovar))
235 0 : return -1;
236 11534653 : if (ivar >= 0)
237 7295928 : tpnr = ml->torigin[ivar];
238 7295928 : if (tpnr >= 0)
239 401123 : ml->torigin[ovar] = tpnr;
240 11534653 : assert(ovar < ml->vsize);
241 11534653 : ml->horigin[ovar] = pnr;
242 : //printf("%d %d ", pnr, tpnr);
243 11534653 : return 0;
244 : }
245 :
246 : static int
247 1016004 : propagatePartnr(matlist_t *ml, int ivar, int ovar, int pnr)
248 : {
249 : /* prop head ids to tail */
250 1016004 : int tpnr = -1;
251 :
252 1016004 : if (checksize(ml, ivar) || checksize(ml, ovar))
253 0 : return -1;
254 1016004 : if (ivar >= 0)
255 1016004 : tpnr = ml->horigin[ivar];
256 1016004 : if (tpnr >= 0)
257 550120 : ml->torigin[ovar] = tpnr;
258 1016004 : assert(ovar < ml->vsize);
259 1016004 : ml->horigin[ovar] = pnr;
260 : //printf("%d %d ", pnr, tpnr);
261 1016004 : return 0;
262 : }
263 :
264 : static int
265 827300 : propagateMirror(matlist_t *ml, int ivar, int ovar)
266 : {
267 : /* prop head ids to head and tail */
268 827300 : int tpnr;
269 :
270 827300 : if (checksize(ml, ivar) || checksize(ml, ovar))
271 0 : return -1;
272 827300 : tpnr = ml->horigin[ivar];
273 827300 : if (tpnr >= 0) {
274 827300 : assert(ovar < ml->vsize);
275 827300 : ml->horigin[ovar] = tpnr;
276 827300 : ml->torigin[ovar] = tpnr;
277 : }
278 : return 0;
279 : }
280 :
281 : static int
282 28959866 : overlap(matlist_t *ml, int lv, int rv, int lnr, int rnr, int ontails)
283 : {
284 28959866 : int lpnr, rpnr;
285 :
286 28959866 : if (checksize(ml, lv) || checksize(ml, rv))
287 0 : return -1;
288 28959866 : lpnr = ml->torigin[lv];
289 28959866 : rpnr = (ontails) ? ml->torigin[rv] : ml->horigin[rv];
290 :
291 28959866 : if (lpnr < 0 && rpnr < 0)
292 0 : return lnr == rnr;
293 28959866 : if (rpnr < 0)
294 603257 : return lpnr == rnr;
295 28356609 : if (lpnr < 0)
296 3072431 : return rpnr == lnr;
297 25284178 : return lpnr == rpnr;
298 : }
299 :
300 : static int
301 267513 : mat_set_prop(matlist_t *ml, MalBlkPtr mb, InstrPtr p)
302 : {
303 267513 : int k, tpe = getArgType(mb, p, 0);
304 :
305 267513 : tpe = getBatType(tpe);
306 2227973 : for (k = 1; k < p->argc; k++) {
307 1960460 : if (setPartnr(ml, -1, getArg(p, k), k))
308 : return -1;
309 1960460 : 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 111695 : 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 111695 : int tpe, k, j, is_subdelta = (getFunctionId(p) == subdeltaRef),
320 111695 : is_projectdelta = (getFunctionId(p) == projectdeltaRef);
321 111695 : InstrPtr r = NULL;
322 111695 : int pushed = 0;
323 :
324 : //printf("# %s.%s(%d,%d,%d,%d)", getModuleId(p), getFunctionId(p), m, n, o, e);
325 :
326 111695 : if ((r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
327 : return NULL;
328 111695 : getArg(r, 0) = getArg(p, 0);
329 111695 : tpe = getArgType(mb, p, 0);
330 :
331 : /* Handle like mat_projection, ie overlapping partitions */
332 111695 : 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 866408 : for (k = 1; k < mat[m].mi->argc; k++) {
371 754713 : InstrPtr q = copyInstruction(p);
372 754713 : if (!q) {
373 0 : freeInstruction(r);
374 0 : return NULL;
375 : }
376 754713 : getArg(q, 0) = newTmpVariable(mb, tpe);
377 754713 : getArg(q, mvar) = getArg(mat[m].mi, k);
378 754713 : getArg(q, nvar) = getArg(mat[n].mi, k);
379 754713 : getArg(q, ovar) = getArg(mat[o].mi, k);
380 754713 : if (e >= 0)
381 281856 : getArg(q, evar) = getArg(mat[e].mi, k);
382 754713 : pushInstruction(mb, q);
383 754713 : if (mb->errors) {
384 0 : freeInstruction(r);
385 0 : return NULL;
386 : }
387 754713 : 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 754713 : r = pushArgument(mb, r, getArg(q, 0));
392 : }
393 111695 : 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 111695 : 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 111695 : if (pushed)
416 0 : matlist_pack(ml, ml->top - 1);
417 : return r;
418 : }
419 :
420 : static InstrPtr
421 2 : mat_assign(MalBlkPtr mb, InstrPtr p, matlist_t *ml)
422 : {
423 2 : InstrPtr r = NULL;
424 2 : mat_t *mat = ml->v;
425 :
426 6 : for (int i = 0; i < p->retc; i++) {
427 4 : int m = is_a_mat(getArg(p, p->retc + i), ml);
428 4 : assert(is_a_mat(getArg(p, i), ml) < 0 && m >= 0);
429 :
430 4 : if ((r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
431 : return NULL;
432 4 : getArg(r, 0) = getArg(p, i);
433 26 : for (int k = 1; k < mat[m].mi->argc; k++) {
434 : /* reuse inputs of old mat */
435 22 : r = pushArgument(mb, r, getArg(mat[m].mi, k));
436 22 : if (setPartnr(ml, -1, getArg(mat[m].mi, k), k)) {
437 0 : freeInstruction(r);
438 0 : return NULL;
439 : }
440 : }
441 4 : 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 14129 : mat_apply1(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int var)
451 : {
452 14129 : int tpe, k, is_select = isSelect(p),
453 14129 : is_mirror = (getFunctionId(p) == mirrorRef);
454 28258 : int is_identity = (getFunctionId(p) == identityRef
455 14129 : && getModuleId(p) == batcalcRef);
456 14129 : int ident_var = 0, is_assign = (getFunctionId(p) == NULL), n = 0;
457 14129 : InstrPtr r = NULL, q;
458 14129 : mat_t *mat = ml->v;
459 :
460 14129 : assert(!is_assign);
461 :
462 14129 : assert(p->retc == 1);
463 :
464 : /* Find the mat we overwrite */
465 14129 : if (is_assign) {
466 : n = is_a_mat(getArg(p, 0), ml);
467 : is_assign = (n >= 0);
468 : }
469 :
470 14129 : if (m < 0
471 14129 : || (r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
472 0 : return -1;
473 14129 : getArg(r, 0) = getArg(p, 0);
474 14129 : tpe = getArgType(mb, p, 0);
475 :
476 14129 : if (is_identity) {
477 2 : if ((q = newInstruction(mb, NULL, NULL)) == NULL) {
478 0 : freeInstruction(r);
479 0 : return -1;
480 : }
481 2 : getArg(q, 0) = newTmpVariable(mb, TYPE_oid);
482 2 : q->retc = 1;
483 2 : q->argc = 1;
484 2 : q = pushOid(mb, q, 0);
485 2 : ident_var = getArg(q, 0);
486 2 : pushInstruction(mb, q);
487 2 : if (mb->errors) {
488 0 : freeInstruction(r);
489 0 : return -1;
490 : }
491 : }
492 125164 : for (k = 1; k < mat[m].mi->argc; k++) {
493 111035 : int res = 0;
494 111035 : if ((q = copyInstruction(p)) == NULL) {
495 0 : freeInstruction(r);
496 0 : return -1;
497 : }
498 :
499 111035 : if (is_assign)
500 : getArg(q, 0) = getArg(mat[n].mi, k);
501 : else
502 111035 : getArg(q, 0) = newTmpVariable(mb, tpe);
503 111035 : if (is_identity)
504 8 : getArg(q, 1) = newTmpVariable(mb, TYPE_oid);
505 111035 : getArg(q, var +is_identity) = getArg(mat[m].mi, k);
506 111035 : if (is_identity) {
507 8 : getArg(q, 3) = ident_var;
508 8 : q->retc = 2;
509 8 : q->argc = 4;
510 : /* make sure to resolve again */
511 8 : q->token = ASSIGNsymbol;
512 8 : q->typeresolved = false;
513 8 : q->fcn = NULL;
514 8 : q->blk = NULL;
515 : }
516 111035 : ident_var = getArg(q, 1);
517 111035 : pushInstruction(mb, q);
518 111035 : if (mb->errors) {
519 0 : freeInstruction(r);
520 0 : return -1;
521 : }
522 111035 : if (is_mirror || is_identity) {
523 111003 : 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 111035 : if (res) {
529 0 : freeInstruction(r);
530 0 : return -1;
531 : }
532 111035 : r = pushArgument(mb, r, getArg(q, 0));
533 : }
534 14129 : if (mb->errors) {
535 0 : freeInstruction(r);
536 0 : return -1;
537 : }
538 14129 : 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 227516 : mat_apply(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int nrmats)
547 : {
548 227516 : int matvar[8], fargument[8], k, l, parts = 0;
549 :
550 227516 : if (nrmats == 1
551 109589 : && ((getModuleId(p) == batcalcRef && getFunctionId(p) == identityRef)
552 109587 : || (getModuleId(p) == batRef && getFunctionId(p) == mirrorRef)))
553 14125 : return mat_apply1(mb, p, ml, is_a_mat(getArg(p, 1), ml), 1);
554 213391 : assert(nrmats <= 8);
555 :
556 213391 : assert(p->retc < p->argc); /* i.e. matvar[0] gets initialized */
557 956308 : for (k = p->retc, l = 0; k < p->argc; k++) {
558 742917 : int mv = is_a_mat(getArg(p, k), ml);
559 742917 : if (mv >= 0) {
560 362964 : matvar[l] = mv;
561 362964 : fargument[l] = k;
562 362964 : l++;
563 362964 : if (parts == 0)
564 213391 : parts = ml->v[mv].mi->argc;
565 362964 : if (parts != ml->v[mv].mi->argc)
566 : return -1;
567 : }
568 : }
569 :
570 213391 : InstrPtr *r = (InstrPtr *) GDKmalloc(sizeof(InstrPtr) * p->retc);
571 213391 : if (!r)
572 : return -1;
573 426782 : for (k = 0; k < p->retc; k++) {
574 213391 : 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 213391 : getArg(r[k], 0) = getArg(p, k);
581 : }
582 :
583 1810390 : for (k = 1; k < ml->v[matvar[0]].mi->argc; k++) {
584 1596999 : int tpe;
585 1596999 : InstrPtr q = copyInstruction(p);
586 1596999 : 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 3193998 : for (l = 0; l < p->retc; l++) {
594 1596999 : tpe = getArgType(mb, p, l);
595 1596999 : getArg(q, l) = newTmpVariable(mb, tpe);
596 : }
597 4334715 : for (l = 0; l < nrmats; l++)
598 2737716 : getArg(q, fargument[l]) = getArg(ml->v[matvar[l]].mi, k);
599 1596999 : pushInstruction(mb, q);
600 4790997 : for (l = 0; l < p->retc; l++) {
601 1596999 : 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 1596999 : r[l] = pushArgument(mb, r[l], getArg(q, l));
608 : }
609 1596999 : 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 426782 : for (k = 0; k < p->retc; k++) {
617 213391 : 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 213391 : GDKfree(r);
626 213391 : return 0;
627 : }
628 :
629 :
630 : static int
631 18546 : mat_setop(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int o)
632 : {
633 18546 : int tpe = getArgType(mb, p, 0), k, j;
634 18546 : mat_t *mat = ml->v;
635 18546 : InstrPtr r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
636 :
637 18546 : if (!r)
638 : return -1;
639 :
640 18546 : getArg(r, 0) = getArg(p, 0);
641 :
642 : //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
643 18546 : assert(m >= 0 || n >= 0);
644 18546 : if (m >= 0 && n >= 0) {
645 18170 : int nr = 1;
646 :
647 18170 : assert(o < 0 || mat[m].mi->argc == mat[o].mi->argc);
648 :
649 161325 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
650 143155 : InstrPtr q = copyInstruction(p);
651 286310 : InstrPtr s = newInstructionArgs(mb, matRef, packRef,
652 143155 : mat[n].mi->argc);
653 143155 : int ttpe = 0;
654 :
655 143155 : if (q == NULL
656 143155 : || s == NULL
657 143155 : || (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 143155 : ttpe = getArgType(mb, mat[n].mi, 0);
665 1530088 : for (j = 1; j < mat[n].mi->argc; j++) {
666 1386933 : int ov = 0;
667 1386933 : if (getBatType(ttpe) != TYPE_oid
668 1385621 : || (ov = overlap(ml, getArg(mat[m].mi, k),
669 : getArg(mat[n].mi, j), k, j, 1)) == 1) {
670 175775 : s = pushArgument(mb, s, getArg(mat[n].mi, j));
671 : }
672 1386933 : if (ov == -1) {
673 0 : freeInstruction(q);
674 0 : freeInstruction(s);
675 0 : freeInstruction(r);
676 0 : return -1;
677 : }
678 : }
679 143155 : if (s->retc == 1 && s->argc == 2) { /* only one input, change into an assignment */
680 138377 : getFunctionId(s) = NULL;
681 138377 : getModuleId(s) = NULL;
682 138377 : s->token = ASSIGNsymbol;
683 138377 : s->typeresolved = false;
684 138377 : s->fcn = NULL;
685 138377 : s->blk = NULL;
686 : }
687 143155 : pushInstruction(mb, s);
688 :
689 143155 : getArg(q, 0) = newTmpVariable(mb, tpe);
690 143155 : getArg(q, 1) = getArg(mat[m].mi, k);
691 143155 : getArg(q, 2) = getArg(s, 0);
692 143155 : if (o >= 0)
693 1422 : getArg(q, 3) = getArg(mat[o].mi, k);
694 143155 : 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 143155 : pushInstruction(mb, q);
700 :
701 143155 : r = pushArgument(mb, r, getArg(q, 0));
702 143155 : nr++;
703 : }
704 : } else {
705 376 : assert(m >= 0);
706 376 : assert(o < 0 || mat[m].mi->argc == mat[o].mi->argc);
707 :
708 3184 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
709 2808 : InstrPtr q = copyInstruction(p);
710 2808 : if (!q) {
711 0 : freeInstruction(r);
712 0 : return -1;
713 : }
714 :
715 2808 : getArg(q, 0) = newTmpVariable(mb, tpe);
716 2808 : getArg(q, 1) = getArg(mat[m].mi, k);
717 2808 : if (o >= 0)
718 40 : getArg(q, 3) = getArg(mat[o].mi, k);
719 2808 : pushInstruction(mb, q);
720 :
721 2808 : if (setPartnr(ml, getArg(q, 2), getArg(q, 0), k)) {
722 0 : freeInstruction(r);
723 0 : return -1;
724 : }
725 2808 : r = pushArgument(mb, r, getArg(q, 0));
726 : }
727 : }
728 :
729 18546 : 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 844887 : mat_projection(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n)
738 : {
739 844887 : int tpe = getArgType(mb, p, 0), k, j;
740 844887 : mat_t *mat = ml->v;
741 844887 : InstrPtr r;
742 :
743 : //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
744 844887 : assert(m >= 0 || n >= 0);
745 844887 : if (m >= 0 && n >= 0) {
746 751446 : int nr = 1;
747 1502892 : r = newInstructionArgs(mb, matRef, packRef,
748 751446 : mat[m].mi->argc * mat[n].mi->argc);
749 :
750 751446 : if (!r)
751 : return -1;
752 :
753 751446 : getArg(r, 0) = getArg(p, 0);
754 :
755 6777449 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
756 27574245 : for (j = 1; j < mat[n].mi->argc; j++) {
757 27574245 : InstrPtr q;
758 27574245 : switch (overlap(ml, getArg(mat[m].mi, k),
759 : getArg(mat[n].mi, j), k, j, 0)) {
760 21548242 : case 0:
761 21548242 : continue;
762 0 : case -1:
763 0 : freeInstruction(r);
764 0 : return -1;
765 6026003 : case 1:
766 6026003 : q = copyInstruction(p);
767 :
768 6026003 : if (!q) {
769 0 : freeInstruction(r);
770 0 : return -1;
771 : }
772 :
773 6026003 : getArg(q, 0) = newTmpVariable(mb, tpe);
774 6026003 : getArg(q, 1) = getArg(mat[m].mi, k);
775 6026003 : getArg(q, 2) = getArg(mat[n].mi, j);
776 6026003 : pushInstruction(mb, q);
777 :
778 6026003 : if (mb->errors || setPartnr(ml, getArg(mat[n].mi, j), getArg(q, 0), nr)) {
779 0 : freeInstruction(r);
780 0 : return -1;
781 : }
782 6026003 : r = pushArgument(mb, r, getArg(q, 0));
783 :
784 6026003 : nr++;
785 6026003 : break;
786 : }
787 : break; /* only in case of overlap */
788 : }
789 : }
790 : } else {
791 93441 : assert(m >= 0);
792 93441 : r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
793 :
794 93441 : if (!r)
795 : return -1;
796 :
797 93441 : getArg(r, 0) = getArg(p, 0);
798 :
799 829993 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
800 736552 : InstrPtr q = copyInstruction(p);
801 :
802 736552 : if (!q) {
803 0 : freeInstruction(r);
804 0 : return -1;
805 : }
806 :
807 736552 : getArg(q, 0) = newTmpVariable(mb, tpe);
808 736552 : getArg(q, 1) = getArg(mat[m].mi, k);
809 736552 : pushInstruction(mb, q);
810 :
811 736552 : if (mb->errors || setPartnr(ml, getArg(q, 2), getArg(q, 0), k)) {
812 0 : freeInstruction(r);
813 0 : return -1;
814 : }
815 736552 : r = pushArgument(mb, r, getArg(q, 0));
816 : }
817 : }
818 :
819 844887 : 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 60053 : mat_join2(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int lc, int rc)
828 : {
829 60053 : int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), j, k, nr = 1;
830 60053 : mat_t *mat = ml->v;
831 60053 : InstrPtr l;
832 60053 : InstrPtr r;
833 :
834 : //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
835 :
836 60053 : assert(m >= 0 || n >= 0);
837 60053 : if (m >= 0 && n >= 0) {
838 1370 : l = newInstructionArgs(mb, matRef, packRef,
839 685 : mat[m].mi->argc * mat[n].mi->argc);
840 1370 : r = newInstructionArgs(mb, matRef, packRef,
841 685 : mat[m].mi->argc * mat[n].mi->argc);
842 685 : if (!l || !r) {
843 0 : freeInstruction(l);
844 0 : freeInstruction(r);
845 0 : return -1;
846 : }
847 :
848 685 : getArg(l, 0) = getArg(p, 0);
849 685 : getArg(r, 0) = getArg(p, 1);
850 :
851 6011 : for (k = 1; k < mat[m].mi->argc; k++) {
852 47392 : for (j = 1; j < mat[n].mi->argc; j++) {
853 42066 : InstrPtr q = copyInstruction(p);
854 :
855 42066 : if (!q) {
856 0 : freeInstruction(l);
857 0 : freeInstruction(r);
858 0 : return -1;
859 : }
860 :
861 42066 : getArg(q, 0) = newTmpVariable(mb, tpe1);
862 42066 : getArg(q, 1) = newTmpVariable(mb, tpe2);
863 42066 : getArg(q, 2) = getArg(mat[m].mi, k);
864 42066 : getArg(q, 3) = getArg(mat[n].mi, j);
865 42066 : if (lc >= 0)
866 241 : getArg(q, 4) = getArg(mat[lc].mi, k);
867 42066 : if (rc >= 0)
868 0 : getArg(q, 5) = getArg(mat[rc].mi, j);
869 42066 : pushInstruction(mb, q);
870 :
871 42066 : if (mb->errors
872 42066 : || propagatePartnr(ml, getArg(mat[m].mi, k), getArg(q, 0),
873 : nr)
874 42066 : || 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 42066 : l = pushArgument(mb, l, getArg(q, 0));
883 42066 : r = pushArgument(mb, r, getArg(q, 1));
884 42066 : nr++;
885 : }
886 : }
887 : } else {
888 59368 : int mv = (m >= 0) ? m : n;
889 59368 : int av = (m < 0);
890 59368 : int bv = (m >= 0);
891 59368 : int mc = (lc >= 0) ? lc : rc;
892 :
893 59368 : l = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
894 59368 : r = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
895 59368 : if (!l || !r) {
896 0 : freeInstruction(l);
897 0 : freeInstruction(r);
898 0 : return -1;
899 : }
900 :
901 59368 : getArg(l, 0) = getArg(p, 0);
902 59368 : getArg(r, 0) = getArg(p, 1);
903 :
904 524995 : for (k = 1; k < mat[mv].mi->argc; k++) {
905 465627 : InstrPtr q = copyInstruction(p);
906 :
907 465627 : if (!q) {
908 0 : freeInstruction(l);
909 0 : freeInstruction(r);
910 0 : return -1;
911 : }
912 :
913 465627 : getArg(q, 0) = newTmpVariable(mb, tpe1);
914 465627 : getArg(q, 1) = newTmpVariable(mb, tpe2);
915 465627 : getArg(q, p->retc + av) = getArg(mat[mv].mi, k);
916 465627 : if (mc >= 0)
917 1278 : getArg(q, p->retc + 2 + av) = getArg(mat[mc].mi, k);
918 465627 : pushInstruction(mb, q);
919 :
920 465627 : if (mb->errors
921 465627 : || propagatePartnr(ml, getArg(mat[mv].mi, k), getArg(q, av), k)
922 465627 : || 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 465627 : l = pushArgument(mb, l, getArg(q, 0));
931 465627 : r = pushArgument(mb, r, getArg(q, 1));
932 : }
933 : }
934 60053 : 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 60053 : 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 0 : mat_rangejoin(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n)
948 : {
949 0 : int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), k, nr = 1;
950 0 : mat_t *mat = ml->v;
951 0 : InstrPtr l;
952 0 : InstrPtr r;
953 :
954 : //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
955 :
956 0 : assert(m >= 0 && n >= 0 && mat[m].mi->argc == mat[n].mi->argc);
957 0 : l = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc * mat[n].mi->argc);
958 0 : r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc * mat[n].mi->argc);
959 0 : if (!l || !r) {
960 0 : freeInstruction(l);
961 0 : freeInstruction(r);
962 0 : return -1;
963 : }
964 :
965 0 : getArg(l, 0) = getArg(p, 0);
966 0 : getArg(r, 0) = getArg(p, 1);
967 :
968 0 : for (k = 1; k < mat[m].mi->argc; k++) {
969 0 : InstrPtr q = copyInstruction(p);
970 :
971 0 : if (!q) {
972 0 : freeInstruction(l);
973 0 : freeInstruction(r);
974 0 : return -1;
975 : }
976 :
977 0 : getArg(q, 0) = newTmpVariable(mb, tpe1);
978 0 : getArg(q, 1) = newTmpVariable(mb, tpe2);
979 :
980 0 : getArg(q, 3) = getArg(mat[m].mi, k);
981 0 : getArg(q, 4) = getArg(mat[n].mi, k);
982 0 : pushInstruction(mb, q);
983 :
984 0 : if (mb->errors || propagatePartnr(ml, getArg(mat[m].mi, k), getArg(q, 0), nr)
985 0 : || propagatePartnr(ml, getArg(mat[n].mi, k), getArg(q, 1), nr)) {
986 0 : freeInstruction(r);
987 0 : freeInstruction(l);
988 0 : return -1;
989 : }
990 :
991 : /* add result to mat */
992 0 : l = pushArgument(mb, l, getArg(q, 0));
993 0 : r = pushArgument(mb, r, getArg(q, 1));
994 0 : nr++;
995 : }
996 0 : if (mb->errors || mat_add(ml, l, mat_none, getFunctionId(p))) {
997 0 : freeInstruction(l);
998 0 : freeInstruction(r);
999 0 : return -1;
1000 : }
1001 0 : if (mat_add(ml, r, mat_none, getFunctionId(p))) {
1002 0 : freeInstruction(r);
1003 0 : return -1;
1004 : }
1005 : return 0;
1006 : }
1007 :
1008 : static int
1009 4 : join_split(Client cntxt, InstrPtr p, int args)
1010 : {
1011 4 : char *name = NULL;
1012 4 : size_t len;
1013 4 : int i, res = 0;
1014 4 : Symbol sym;
1015 4 : MalBlkPtr mb;
1016 4 : InstrPtr q;
1017 :
1018 4 : if (args <= 3) /* we assume there are no 2x1 joins! */
1019 : return 1;
1020 :
1021 0 : len = strlen(getFunctionId(p));
1022 0 : name = GDKmalloc(len + 3);
1023 0 : if (!name)
1024 : return -2;
1025 0 : strncpy(name, getFunctionId(p), len - 7);
1026 0 : strcpy(name + len - 7, "join");
1027 :
1028 0 : sym = findSymbol(cntxt->usermodule, getModuleId(p), name);
1029 0 : assert(sym);
1030 0 : mb = sym->def;
1031 :
1032 0 : assert(0);
1033 : q = mb->stmt[0];
1034 : for (i = q->retc; i < q->argc; i++) {
1035 : if (isaBatType(getArgType(mb, q, i)))
1036 : res++;
1037 : else
1038 : break;
1039 : }
1040 : GDKfree(name);
1041 : return res - 1;
1042 : }
1043 :
1044 : /* 1 or 2 mat lists:
1045 : * in case of one take the second half of the code
1046 : * in case of two we need to detect the list lengths.
1047 : *
1048 : * input is one list of arguments (just total length of mats)
1049 : */
1050 : static int
1051 57 : mat_joinNxM(Client cntxt, MalBlkPtr mb, InstrPtr p, matlist_t *ml, int args)
1052 : {
1053 57 : int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), j, k, nr = 1;
1054 57 : InstrPtr l;
1055 57 : InstrPtr r;
1056 57 : mat_t *mat = ml->v;
1057 57 : int *mats = (int *) GDKzalloc(sizeof(int) * args);
1058 57 : int nr_mats = 0, first = -1, res = 0;
1059 :
1060 57 : if (!mats) {
1061 : return -1;
1062 : }
1063 :
1064 238 : for (j = 0; j < args; j++) {
1065 181 : mats[j] = is_a_mat(getArg(p, p->retc + j), ml);
1066 181 : if (mats[j] != -1) {
1067 71 : nr_mats++;
1068 71 : if (first < 0)
1069 57 : first = j;
1070 : }
1071 : }
1072 :
1073 : //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
1074 :
1075 57 : if (args == nr_mats) {
1076 4 : int mv1 = mats[0], i;
1077 4 : int mv2 = mats[args - 1];
1078 4 : int split = join_split(cntxt, p, args);
1079 4 : int nr_mv1 = split;
1080 :
1081 4 : if (split == -2) {
1082 0 : GDKfree(mats);
1083 0 : return -1;
1084 : }
1085 4 : if (split < 0) {
1086 0 : GDKfree(mats);
1087 0 : mb->errors = createException(MAL, "mergetable.join",
1088 : SQLSTATE(42000) " incorrect split level");
1089 0 : return 0;
1090 : }
1091 :
1092 8 : l = newInstructionArgs(mb, matRef, packRef,
1093 4 : mat[mv1].mi->argc * mat[mv2].mi->argc);
1094 8 : r = newInstructionArgs(mb, matRef, packRef,
1095 4 : mat[mv1].mi->argc * mat[mv2].mi->argc);
1096 4 : if (l == NULL || r == NULL) {
1097 0 : freeInstruction(l);
1098 0 : freeInstruction(r);
1099 0 : GDKfree(mats);
1100 0 : return -1;
1101 : }
1102 4 : getArg(l, 0) = getArg(p, 0);
1103 4 : getArg(r, 0) = getArg(p, 1);
1104 :
1105 : /* now detect split point */
1106 16 : for (k = 1; k < mat[mv1].mi->argc; k++) {
1107 48 : for (j = 1; j < mat[mv2].mi->argc; j++) {
1108 36 : InstrPtr q = copyInstruction(p);
1109 36 : if (!q) {
1110 0 : freeInstruction(r);
1111 0 : freeInstruction(l);
1112 0 : GDKfree(mats);
1113 0 : return -1;
1114 : }
1115 :
1116 36 : getArg(q, 0) = newTmpVariable(mb, tpe1);
1117 36 : getArg(q, 1) = newTmpVariable(mb, tpe2);
1118 72 : for (i = 0; i < nr_mv1; i++)
1119 36 : getArg(q, q->retc + i) = getArg(mat[mats[i]].mi, k);
1120 108 : for (; i < nr_mats; i++)
1121 72 : getArg(q, q->retc + i) = getArg(mat[mats[i]].mi, j);
1122 36 : pushInstruction(mb, q);
1123 :
1124 36 : if (mb->errors
1125 36 : || propagatePartnr(ml, getArg(mat[mv1].mi, k), getArg(q, 0),
1126 : nr)
1127 36 : || propagatePartnr(ml, getArg(mat[mv2].mi, j), getArg(q, 1),
1128 : nr)) {
1129 0 : freeInstruction(r);
1130 0 : freeInstruction(l);
1131 0 : GDKfree(mats);
1132 0 : return -1;
1133 : }
1134 :
1135 : /* add result to mat */
1136 36 : l = pushArgument(mb, l, getArg(q, 0));
1137 36 : r = pushArgument(mb, r, getArg(q, 1));
1138 36 : nr++;
1139 : }
1140 : }
1141 : } else {
1142 : /* only one side
1143 : * mats from first..first+nr_mats
1144 : */
1145 53 : int mv = mats[first];
1146 :
1147 53 : l = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
1148 53 : r = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
1149 53 : if (l == NULL || r == NULL) {
1150 0 : freeInstruction(l);
1151 0 : freeInstruction(r);
1152 0 : GDKfree(mats);
1153 0 : return -1;
1154 : }
1155 53 : getArg(l, 0) = getArg(p, 0);
1156 53 : getArg(r, 0) = getArg(p, 1);
1157 :
1158 310 : for (k = 1; k < mat[mv].mi->argc; k++) {
1159 257 : InstrPtr q = copyInstruction(p);
1160 257 : if (!q) {
1161 0 : freeInstruction(r);
1162 0 : freeInstruction(l);
1163 0 : GDKfree(mats);
1164 0 : return -1;
1165 : }
1166 :
1167 257 : getArg(q, 0) = newTmpVariable(mb, tpe1);
1168 257 : getArg(q, 1) = newTmpVariable(mb, tpe2);
1169 529 : for (j = 0; j < nr_mats; j++) {
1170 272 : assert(mat[mats[first]].mi->argc == mat[mats[first + j]].mi->argc);
1171 272 : getArg(q, p->retc + first + j) = getArg(mat[mats[first + j]].mi, k);
1172 : }
1173 257 : if (mb->errors
1174 257 : || propagatePartnr(ml, getArg(mat[mv].mi, k),
1175 257 : getArg(q, (first != 0)), k)
1176 257 : || propagatePartnr(ml,
1177 257 : getArg(p, p->retc + (first) ? nr_mats : 0),
1178 257 : getArg(q, (first == 0)), k)) {
1179 0 : freeInstruction(q);
1180 0 : freeInstruction(r);
1181 0 : freeInstruction(l);
1182 0 : GDKfree(mats);
1183 0 : return -1;
1184 : }
1185 257 : pushInstruction(mb, q);
1186 :
1187 : /* add result to mat */
1188 257 : l = pushArgument(mb, l, getArg(q, 0));
1189 257 : r = pushArgument(mb, r, getArg(q, 1));
1190 : }
1191 : }
1192 57 : if (mb->errors || mat_add(ml, l, mat_none, getFunctionId(p))) {
1193 0 : freeInstruction(l);
1194 0 : freeInstruction(r);
1195 0 : res = -1;
1196 57 : } else if (mat_add(ml, r, mat_none, getFunctionId(p))) {
1197 0 : freeInstruction(r);
1198 0 : res = -1;
1199 : }
1200 57 : GDKfree(mats);
1201 57 : return res;
1202 : }
1203 :
1204 :
1205 : static const char *
1206 5049 : aggr_phase2(const char *aggr, int type_dbl)
1207 : {
1208 5049 : if (aggr == countRef || aggr == count_no_nilRef
1209 4747 : || (aggr == avgRef && type_dbl))
1210 : return sumRef;
1211 3742 : if (aggr == subcountRef || (aggr == subavgRef && type_dbl))
1212 2958 : return subsumRef;
1213 : /* min/max/sum/prod and unique are fine */
1214 : return aggr;
1215 : }
1216 :
1217 : static str
1218 1641 : mat_aggr(MalBlkPtr mb, InstrPtr p, mat_t *mat, int m)
1219 : {
1220 1641 : int tp = getArgType(mb, p, 0), k, tp2 = TYPE_lng, i;
1221 1641 : int battp = (getModuleId(p) == aggrRef) ? newBatType(tp) : tp, battp2 = 0;
1222 1641 : int isAvg = (getFunctionId(p) == avgRef);
1223 1641 : InstrPtr r = NULL, s = NULL, q = NULL, u = NULL, v = NULL;
1224 :
1225 : /* we pack the partial result */
1226 1641 : r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
1227 1641 : if (r == NULL)
1228 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1229 1641 : getArg(r, 0) = newTmpVariable(mb, battp);
1230 :
1231 1641 : if (isAvg) { /* remainders or counts */
1232 1026 : battp2 = newBatType(tp2);
1233 1026 : u = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
1234 1026 : if (u == NULL) {
1235 0 : freeInstruction(r);
1236 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1237 : }
1238 1026 : getArg(u, 0) = newTmpVariable(mb, battp2);
1239 : }
1240 1641 : if (isAvg && tp != TYPE_dbl) { /* counts */
1241 21 : battp2 = newBatType(tp2);
1242 21 : v = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
1243 21 : if (v == NULL) {
1244 0 : freeInstruction(r);
1245 0 : freeInstruction(u);
1246 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1247 : }
1248 21 : getArg(v, 0) = newTmpVariable(mb, battp2);
1249 : }
1250 13603 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
1251 11962 : q = newInstruction(mb, NULL, NULL);
1252 11962 : if (q == NULL) {
1253 0 : freeInstruction(r);
1254 0 : freeInstruction(u);
1255 0 : freeInstruction(v);
1256 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1257 : }
1258 11962 : if (isAvg && tp == TYPE_dbl)
1259 7947 : setModuleId(q, batcalcRef);
1260 : else
1261 4015 : setModuleId(q, getModuleId(p));
1262 11962 : setFunctionId(q, getFunctionId(p));
1263 11962 : getArg(q, 0) = newTmpVariable(mb, tp);
1264 11962 : if (isAvg)
1265 8110 : q = pushReturn(mb, q, newTmpVariable(mb, tp2));
1266 11962 : if (isAvg && tp != TYPE_dbl)
1267 163 : q = pushReturn(mb, q, newTmpVariable(mb, tp2));
1268 11962 : q = pushArgument(mb, q, getArg(mat[m].mi, k));
1269 12405 : for (i = q->argc; i < p->argc; i++)
1270 443 : q = pushArgument(mb, q, getArg(p, i));
1271 11962 : pushInstruction(mb, q);
1272 :
1273 11962 : r = pushArgument(mb, r, getArg(q, 0));
1274 11962 : if (isAvg)
1275 8110 : u = pushArgument(mb, u, getArg(q, 1));
1276 11962 : if (isAvg && tp != TYPE_dbl)
1277 163 : v = pushArgument(mb, v, getArg(q, 2));
1278 : }
1279 1641 : pushInstruction(mb, r);
1280 1641 : if (isAvg)
1281 1026 : pushInstruction(mb, u);
1282 1641 : if (isAvg && tp != TYPE_dbl)
1283 21 : pushInstruction(mb, v);
1284 :
1285 : /* Filter empty partitions */
1286 1641 : if (mb->errors == NULL && getModuleId(p) == aggrRef && !isAvg) {
1287 615 : s = newInstruction(mb, algebraRef, selectNotNilRef);
1288 615 : if (s == NULL) {
1289 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1290 : }
1291 615 : getArg(s, 0) = newTmpVariable(mb, battp);
1292 615 : s = pushArgument(mb, s, getArg(r, 0));
1293 615 : pushInstruction(mb, s);
1294 615 : r = s;
1295 : }
1296 :
1297 : /* for avg we do sum (avg*(count/sumcount) ) */
1298 1641 : if (mb->errors == NULL && isAvg && tp == TYPE_dbl) {
1299 1005 : InstrPtr v, w, x, y, cond;
1300 :
1301 : /* lng w = sum counts */
1302 1005 : w = newInstruction(mb, aggrRef, sumRef);
1303 1005 : if (w == NULL) {
1304 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1305 : }
1306 1005 : getArg(w, 0) = newTmpVariable(mb, tp2);
1307 1005 : w = pushArgument(mb, w, getArg(u, 0));
1308 1005 : pushInstruction(mb, w);
1309 :
1310 : /* y=count = ifthenelse(w=count==0,NULL,w=count) */
1311 1005 : cond = newInstruction(mb, calcRef, eqRef);
1312 1005 : if (cond == NULL) {
1313 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1314 : }
1315 1005 : getArg(cond, 0) = newTmpVariable(mb, TYPE_bit);
1316 1005 : cond = pushArgument(mb, cond, getArg(w, 0));
1317 1005 : cond = pushLng(mb, cond, 0);
1318 1005 : pushInstruction(mb, cond);
1319 :
1320 1005 : y = newInstruction(mb, calcRef, ifthenelseRef);
1321 1005 : if (y == NULL) {
1322 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1323 : }
1324 1005 : getArg(y, 0) = newTmpVariable(mb, tp2);
1325 1005 : y = pushArgument(mb, y, getArg(cond, 0));
1326 1005 : y = pushNil(mb, y, tp2);
1327 1005 : y = pushArgument(mb, y, getArg(w, 0));
1328 1005 : pushInstruction(mb, y);
1329 :
1330 : /* dbl v = double(count) */
1331 1005 : v = newInstruction(mb, batcalcRef, dblRef);
1332 1005 : if (v == NULL) {
1333 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1334 : }
1335 1005 : getArg(v, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
1336 1005 : v = pushArgument(mb, v, getArg(u, 0));
1337 1005 : pushInstruction(mb, v);
1338 :
1339 : /* dbl x = v / y */
1340 1005 : x = newInstruction(mb, batcalcRef, divRef);
1341 1005 : if (x == NULL) {
1342 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1343 : }
1344 1005 : getArg(x, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
1345 1005 : x = pushArgument(mb, x, getArg(v, 0));
1346 1005 : x = pushArgument(mb, x, getArg(y, 0));
1347 1005 : if (isaBatType(getArgType(mb, x, 0)))
1348 1005 : x = pushNilBat(mb, x);
1349 1005 : if (isaBatType(getArgType(mb, y, 0)))
1350 0 : x = pushNilBat(mb, x);
1351 1005 : pushInstruction(mb, x);
1352 :
1353 : /* dbl w = avg * x */
1354 1005 : w = newInstruction(mb, batcalcRef, mulRef);
1355 1005 : if (w == NULL) {
1356 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1357 : }
1358 1005 : getArg(w, 0) = newTmpVariable(mb, battp);
1359 1005 : w = pushArgument(mb, w, getArg(r, 0));
1360 1005 : w = pushArgument(mb, w, getArg(x, 0));
1361 1005 : if (isaBatType(getArgType(mb, r, 0)))
1362 1005 : w = pushNilBat(mb, w);
1363 1005 : if (isaBatType(getArgType(mb, x, 0)))
1364 1005 : w = pushNilBat(mb, w);
1365 1005 : pushInstruction(mb, w);
1366 :
1367 1005 : r = w;
1368 :
1369 : /* filter nils */
1370 1005 : s = newInstruction(mb, algebraRef, selectNotNilRef);
1371 1005 : if (s == NULL) {
1372 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1373 : }
1374 1005 : getArg(s, 0) = newTmpVariable(mb, battp);
1375 1005 : s = pushArgument(mb, s, getArg(r, 0));
1376 1005 : pushInstruction(mb, s);
1377 1005 : r = s;
1378 : }
1379 :
1380 1641 : if (mb->errors == NULL) {
1381 1641 : s = newInstruction(mb, getModuleId(p),
1382 : aggr_phase2(getFunctionId(p), tp == TYPE_dbl));
1383 1641 : if (s == NULL) {
1384 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
1385 : }
1386 1641 : getArg(s, 0) = getArg(p, 0);
1387 1641 : s = pushArgument(mb, s, getArg(r, 0));
1388 1641 : if (isAvg && tp != TYPE_dbl) {
1389 21 : s = pushArgument(mb, s, getArg(u, 0));
1390 21 : s = pushArgument(mb, s, getArg(v, 0));
1391 : }
1392 1641 : pushInstruction(mb, s);
1393 : }
1394 1641 : if (mb->errors) {
1395 0 : str msg = mb->errors;
1396 0 : mb->errors = NULL;
1397 0 : return msg;
1398 : }
1399 : return MAL_SUCCEED;
1400 : }
1401 :
1402 : static int
1403 7685 : chain_by_length(mat_t *mat, int g)
1404 : {
1405 7685 : int cnt = 0;
1406 19215 : while (g >= 0) {
1407 11530 : g = mat[g].pm;
1408 11530 : cnt++;
1409 : }
1410 5067 : return cnt;
1411 : }
1412 :
1413 : static int
1414 3810 : walk_n_back(mat_t *mat, int g, int cnt)
1415 : {
1416 18607 : while (cnt > 0) {
1417 7077 : g = mat[g].pm;
1418 7077 : cnt--;
1419 : }
1420 3951 : return g;
1421 : }
1422 :
1423 : static int
1424 3810 : group_by_ext(matlist_t *ml, int g)
1425 : {
1426 3810 : int i;
1427 :
1428 15199 : for (i = g; i < ml->top; i++) {
1429 22778 : if (ml->v[i].pm == g)
1430 : return i;
1431 : }
1432 : return 0;
1433 : }
1434 :
1435 : /* In some cases we have non groupby attribute columns, these require
1436 : * gext.projection(mat.pack(per partition ext.projections(x)))
1437 : */
1438 :
1439 : static int
1440 7460 : mat_group_project(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int e, int a)
1441 : {
1442 7460 : int tp = getArgType(mb, p, 0), k;
1443 7460 : mat_t *mat = ml->v;
1444 7460 : InstrPtr ai1 = newInstructionArgs(mb, matRef, packRef, mat[a].mi->argc), r;
1445 :
1446 7460 : if (!ai1)
1447 : return -1;
1448 :
1449 7460 : getArg(ai1, 0) = newTmpVariable(mb, tp);
1450 7460 : if (mb->errors) {
1451 0 : freeInstruction(ai1);
1452 0 : return -1;
1453 : }
1454 :
1455 7460 : assert(mat[e].mi->argc == mat[a].mi->argc);
1456 69849 : for (k = 1; k < mat[a].mi->argc; k++) {
1457 62389 : InstrPtr q = copyInstruction(p);
1458 62389 : if (!q) {
1459 0 : freeInstruction(ai1);
1460 0 : return -1;
1461 : }
1462 :
1463 62389 : getArg(q, 0) = newTmpVariable(mb, tp);
1464 62389 : getArg(q, 1) = getArg(mat[e].mi, k);
1465 62389 : getArg(q, 2) = getArg(mat[a].mi, k);
1466 62389 : pushInstruction(mb, q);
1467 62389 : if (mb->errors) {
1468 0 : freeInstruction(ai1);
1469 0 : return -1;
1470 : }
1471 62389 : if (setPartnr(ml, getArg(mat[a].mi, k), getArg(q, 0), k)) {
1472 0 : freeInstruction(ai1);
1473 0 : return -1;
1474 : }
1475 :
1476 : /* pack the result into a mat */
1477 62389 : ai1 = pushArgument(mb, ai1, getArg(q, 0));
1478 : }
1479 7460 : pushInstruction(mb, ai1);
1480 7460 : if (mb->errors) {
1481 : return -1;
1482 : }
1483 :
1484 7460 : if ((r = copyInstruction(p)) == NULL)
1485 : return -1;
1486 7460 : getArg(r, 1) = mat[e].mv;
1487 7460 : getArg(r, 2) = getArg(ai1, 0);
1488 7460 : pushInstruction(mb, r);
1489 7460 : return mb->errors ? -1 : 0;
1490 : }
1491 :
1492 : /* Per partition aggregates are merged and aggregated together. For
1493 : * most (handled) aggregates that's relatively simple. AVG is somewhat
1494 : * more complex. */
1495 : static int
1496 3408 : mat_group_aggr(MalBlkPtr mb, InstrPtr p, mat_t *mat, int b, int g, int e)
1497 : {
1498 3408 : int tp = getArgType(mb, p, 0), k, tp2 = 0, tpe = getBatType(tp);
1499 3408 : const char *aggr2 = aggr_phase2(getFunctionId(p), tpe == TYPE_dbl);
1500 3408 : int isAvg = (getFunctionId(p) == subavgRef);
1501 3408 : InstrPtr ai1 = newInstructionArgs(mb, matRef, packRef, mat[b].mi->argc),
1502 3408 : ai10 = NULL, ai11 = NULL, ai2;
1503 :
1504 3408 : if (!ai1)
1505 : return -1;
1506 :
1507 3408 : getArg(ai1, 0) = newTmpVariable(mb, tp);
1508 :
1509 3408 : if (mb->errors == NULL && isAvg) { /* remainders or counts */
1510 52 : tp2 = newBatType(TYPE_lng);
1511 52 : ai10 = newInstructionArgs(mb, matRef, packRef, mat[b].mi->argc);
1512 52 : if (!ai10) {
1513 0 : freeInstruction(ai1);
1514 0 : return -1;
1515 : }
1516 52 : getArg(ai10, 0) = newTmpVariable(mb, tp2);
1517 : }
1518 3408 : if (mb->errors == NULL && isAvg && tpe != TYPE_dbl) { /* counts */
1519 19 : tp2 = newBatType(TYPE_lng);
1520 19 : ai11 = newInstructionArgs(mb, matRef, packRef, mat[b].mi->argc);
1521 19 : if (!ai11) {
1522 0 : freeInstruction(ai1);
1523 0 : freeInstruction(ai10);
1524 0 : return -1;
1525 : }
1526 19 : getArg(ai11, 0) = newTmpVariable(mb, tp2);
1527 : }
1528 :
1529 34143 : for (k = 1; mb->errors == NULL && k < mat[b].mi->argc; k++) {
1530 30735 : int off = 0;
1531 30735 : InstrPtr q = copyInstructionArgs(p, p->argc + (isAvg && tpe == TYPE_dbl));
1532 30735 : if (!q) {
1533 0 : freeInstruction(ai1);
1534 0 : freeInstruction(ai10);
1535 0 : return -1;
1536 : }
1537 :
1538 30735 : getArg(q, 0) = newTmpVariable(mb, tp);
1539 30735 : if (isAvg && tpe == TYPE_dbl) {
1540 199 : off = 1;
1541 199 : getArg(q, 1) = newTmpVariable(mb, tp2);
1542 199 : q = pushArgument(mb, q, getArg(q, 1)); /* push at end, create space */
1543 199 : q->retc = 2;
1544 199 : getArg(q, q->argc - 1) = getArg(q, q->argc - 2);
1545 199 : getArg(q, q->argc - 2) = getArg(q, q->argc - 3);
1546 30536 : } else if (isAvg) {
1547 152 : getArg(q, 1) = newTmpVariable(mb, tp2);
1548 152 : getArg(q, 2) = newTmpVariable(mb, tp2);
1549 152 : off = 2;
1550 : }
1551 30735 : getArg(q, 1 + off) = getArg(mat[b].mi, k);
1552 30735 : getArg(q, 2 + off) = getArg(mat[g].mi, k);
1553 30735 : getArg(q, 3 + off) = getArg(mat[e].mi, k);
1554 30735 : pushInstruction(mb, q);
1555 :
1556 : /* pack the result into a mat */
1557 30735 : ai1 = pushArgument(mb, ai1, getArg(q, 0));
1558 30735 : if (isAvg)
1559 351 : ai10 = pushArgument(mb, ai10, getArg(q, 1));
1560 30735 : if (isAvg && tpe != TYPE_dbl)
1561 152 : ai11 = pushArgument(mb, ai11, getArg(q, 2));
1562 : }
1563 3408 : pushInstruction(mb, ai1);
1564 3408 : if (isAvg)
1565 52 : pushInstruction(mb, ai10);
1566 3408 : if (isAvg && tpe != TYPE_dbl)
1567 19 : pushInstruction(mb, ai11);
1568 :
1569 : /* for avg we do sum (avg*(count/sumcount) ) */
1570 3408 : if (mb->errors == NULL && isAvg && tpe == TYPE_dbl) {
1571 33 : InstrPtr r, s, v, w, cond;
1572 :
1573 : /* lng s = sum counts */
1574 33 : s = newInstruction(mb, aggrRef, subsumRef);
1575 33 : if (s == NULL)
1576 : return -1;
1577 33 : getArg(s, 0) = newTmpVariable(mb, tp2);
1578 33 : s = pushArgument(mb, s, getArg(ai10, 0));
1579 33 : s = pushArgument(mb, s, mat[g].mv);
1580 33 : s = pushArgument(mb, s, mat[e].mv);
1581 33 : s = pushBit(mb, s, 1); /* skip nils */
1582 33 : pushInstruction(mb, s);
1583 :
1584 : /* w=count = ifthenelse(s=count==0,NULL,s=count) */
1585 33 : cond = newInstruction(mb, batcalcRef, eqRef);
1586 33 : if (cond == NULL)
1587 : return -1;
1588 33 : getArg(cond, 0) = newTmpVariable(mb, newBatType(TYPE_bit));
1589 33 : cond = pushArgument(mb, cond, getArg(s, 0));
1590 33 : cond = pushLng(mb, cond, 0);
1591 33 : pushInstruction(mb, cond);
1592 :
1593 33 : w = newInstruction(mb, batcalcRef, ifthenelseRef);
1594 33 : if (w == NULL)
1595 : return -1;
1596 33 : getArg(w, 0) = newTmpVariable(mb, tp2);
1597 33 : w = pushArgument(mb, w, getArg(cond, 0));
1598 33 : w = pushNil(mb, w, TYPE_lng);
1599 33 : w = pushArgument(mb, w, getArg(s, 0));
1600 33 : pushInstruction(mb, w);
1601 :
1602 : /* fetchjoin with groups */
1603 33 : r = newInstruction(mb, algebraRef, projectionRef);
1604 33 : if (r == NULL)
1605 : return -1;
1606 33 : getArg(r, 0) = newTmpVariable(mb, tp2);
1607 33 : r = pushArgument(mb, r, mat[g].mv);
1608 33 : r = pushArgument(mb, r, getArg(w, 0));
1609 33 : pushInstruction(mb, r);
1610 33 : s = r;
1611 :
1612 : /* dbl v = double(count) */
1613 33 : v = newInstruction(mb, batcalcRef, dblRef);
1614 33 : if (v == NULL)
1615 : return -1;
1616 33 : getArg(v, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
1617 33 : v = pushArgument(mb, v, getArg(ai10, 0));
1618 33 : pushInstruction(mb, v);
1619 :
1620 : /* dbl r = v / s */
1621 33 : r = newInstruction(mb, batcalcRef, divRef);
1622 33 : if (r == NULL)
1623 : return -1;
1624 33 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
1625 33 : r = pushArgument(mb, r, getArg(v, 0));
1626 33 : r = pushArgument(mb, r, getArg(s, 0));
1627 33 : if (isaBatType(getArgType(mb, v, 0)))
1628 33 : r = pushNilBat(mb, r);
1629 33 : if (isaBatType(getArgType(mb, s, 0)))
1630 33 : r = pushNilBat(mb, r);
1631 33 : pushInstruction(mb, r);
1632 :
1633 : /* dbl s = avg * r */
1634 33 : s = newInstruction(mb, batcalcRef, mulRef);
1635 33 : if (s == NULL)
1636 : return -1;
1637 33 : getArg(s, 0) = newTmpVariable(mb, tp);
1638 33 : s = pushArgument(mb, s, getArg(ai1, 0));
1639 33 : s = pushArgument(mb, s, getArg(r, 0));
1640 33 : if (isaBatType(getArgType(mb, ai1, 0)))
1641 33 : s = pushNilBat(mb, s);
1642 33 : if (isaBatType(getArgType(mb, r, 0)))
1643 33 : s = pushNilBat(mb, s);
1644 33 : pushInstruction(mb, s);
1645 :
1646 33 : ai1 = s;
1647 : }
1648 3408 : ai2 = newInstruction(mb, aggrRef, aggr2);
1649 3408 : if (ai2 == NULL)
1650 : return -1;
1651 3408 : getArg(ai2, 0) = getArg(p, 0);
1652 3408 : if (isAvg && tpe != TYPE_dbl) {
1653 19 : getArg(ai2, 1) = getArg(p, 1);
1654 19 : getArg(ai2, 2) = getArg(p, 2);
1655 : }
1656 3408 : ai2 = pushArgument(mb, ai2, getArg(ai1, 0));
1657 3408 : if (isAvg && tpe != TYPE_dbl) {
1658 19 : ai2 = pushArgument(mb, ai2, getArg(ai10, 0));
1659 19 : ai2 = pushArgument(mb, ai2, getArg(ai11, 0));
1660 : }
1661 3408 : ai2 = pushArgument(mb, ai2, mat[g].mv);
1662 3408 : ai2 = pushArgument(mb, ai2, mat[e].mv);
1663 3408 : ai2 = pushBit(mb, ai2, 1); /* skip nils */
1664 3408 : pushInstruction(mb, ai2);
1665 3408 : if (mb->errors)
1666 : return -1;
1667 : return 0;
1668 : }
1669 :
1670 : /* The mat_group_{new,derive} keep an ext,attr1..attrn table.
1671 : * This is the input for the final second phase group by.
1672 : */
1673 : static int
1674 4961 : mat_pack_group(MalBlkPtr mb, matlist_t *ml, int g)
1675 : {
1676 4961 : mat_t *mat = ml->v;
1677 4961 : int cnt = chain_by_length(mat, g), i;
1678 4961 : InstrPtr cur = NULL;
1679 :
1680 12540 : for (i = cnt - 1; i >= 0; i--) {
1681 : /* if cur is non-NULL, it's a subgroup; if i is zero, it's "done" */
1682 15158 : InstrPtr grp = newInstruction(mb, groupRef,
1683 2618 : cur ? i ? subgroupRef : subgroupdoneRef : i ?
1684 4961 : groupRef : groupdoneRef);
1685 7579 : if (grp == NULL)
1686 : return -1;
1687 15158 : int ogrp = walk_n_back(mat, g, i);
1688 7579 : int oext = group_by_ext(ml, ogrp);
1689 7579 : int attr = mat[oext].im;
1690 :
1691 7579 : getArg(grp, 0) = mat[ogrp].mv;
1692 7579 : grp = pushReturn(mb, grp, mat[oext].mv);
1693 7579 : grp = pushReturn(mb, grp, newTmpVariable(mb, newBatType(TYPE_lng)));
1694 7579 : grp = pushArgument(mb, grp, getArg(mat[attr].mi, 0));
1695 7579 : if (cur)
1696 2618 : grp = pushArgument(mb, grp, getArg(cur, 0));
1697 7579 : pushInstruction(mb, grp);
1698 7579 : cur = grp;
1699 7579 : if (mb->errors)
1700 : return -1;
1701 : }
1702 4961 : mat[g].im = -1; /* only pack once */
1703 4961 : return 0;
1704 : }
1705 :
1706 : /*
1707 : * foreach parent subgroup, do the
1708 : * e2.projection(grp.projection((ext.projection(b)))
1709 : * and one for the current group
1710 : */
1711 : static int
1712 2618 : mat_group_attr(MalBlkPtr mb, matlist_t *ml, int g, InstrPtr cext, int push)
1713 : {
1714 2618 : int cnt = chain_by_length(ml->v, g), i; /* number of attributes */
1715 : int ogrp = g; /* previous group */
1716 :
1717 6428 : for (i = 0; i < cnt; i++) {
1718 3810 : int agrp = walk_n_back(ml->v, ogrp, i);
1719 3810 : int b = ml->v[agrp].im;
1720 3810 : int aext = group_by_ext(ml, agrp);
1721 3810 : int a = ml->v[aext].im;
1722 3810 : int atp = getArgType(mb, ml->v[a].mi, 0), k;
1723 3810 : InstrPtr attr = newInstructionArgs(mb, matRef, packRef, ml->v[a].mi->argc);
1724 3810 : if (attr == NULL) {
1725 : return -1;
1726 : }
1727 :
1728 : //getArg(attr,0) = newTmpVariable(mb, atp);
1729 3810 : getArg(attr, 0) = getArg(ml->v[b].mi, 0);
1730 :
1731 33576 : for (k = 1; mb->errors == NULL && k < ml->v[a].mi->argc; k++) {
1732 29766 : InstrPtr r = newInstruction(mb, algebraRef, projectionRef);
1733 29766 : InstrPtr q = newInstruction(mb, algebraRef, projectionRef);
1734 29766 : if (r == NULL || q == NULL) {
1735 0 : freeInstruction(attr);
1736 0 : freeInstruction(r);
1737 0 : freeInstruction(q);
1738 0 : return -1;
1739 : }
1740 :
1741 29766 : getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
1742 29766 : r = pushArgument(mb, r, getArg(cext, k));
1743 29766 : r = pushArgument(mb, r, getArg(ml->v[ogrp].mi, k));
1744 29766 : pushInstruction(mb, r);
1745 :
1746 29766 : getArg(q, 0) = newTmpVariable(mb, atp);
1747 29766 : q = pushArgument(mb, q, getArg(r, 0));
1748 29766 : q = pushArgument(mb, q, getArg(ml->v[a].mi, k));
1749 29766 : pushInstruction(mb, q);
1750 :
1751 29766 : attr = pushArgument(mb, attr, getArg(q, 0));
1752 : }
1753 3810 : if (push)
1754 2618 : pushInstruction(mb, attr);
1755 3810 : if (mb->errors || mat_add_var(ml, attr, NULL, getArg(attr, 0), mat_ext,
1756 : -1, -1, push)) {
1757 0 : if (!push)
1758 0 : freeInstruction(attr);
1759 0 : return -1;
1760 : }
1761 : /* keep new attribute with the group extend */
1762 3810 : ml->v[aext].im = ml->top - 1;
1763 : }
1764 : return 0;
1765 : }
1766 :
1767 : static int
1768 4961 : mat_group_new(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int b)
1769 : {
1770 4961 : int tp0 = getArgType(mb, p, 0);
1771 4961 : int tp1 = getArgType(mb, p, 1);
1772 4961 : int tp2 = getArgType(mb, p, 2);
1773 4961 : int atp = getArgType(mb, p, 3), i, a, g, push = 0;
1774 4961 : InstrPtr r0, r1, r2, attr;
1775 :
1776 4961 : if (getFunctionId(p) == subgroupdoneRef || getFunctionId(p) == groupdoneRef)
1777 2784 : push = 1;
1778 :
1779 4961 : r0 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1780 4961 : if (r0 == NULL)
1781 : return -1;
1782 4961 : getArg(r0, 0) = newTmpVariable(mb, tp0);
1783 :
1784 4961 : r1 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1785 4961 : if (r1 == NULL) {
1786 0 : freeInstruction(r0);
1787 0 : return -1;
1788 : }
1789 4961 : getArg(r1, 0) = newTmpVariable(mb, tp1);
1790 :
1791 4961 : r2 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1792 4961 : if (r2 == NULL) {
1793 0 : freeInstruction(r0);
1794 0 : freeInstruction(r1);
1795 0 : return -1;
1796 : }
1797 4961 : getArg(r2, 0) = newTmpVariable(mb, tp2);
1798 :
1799 : /* we keep an extend, attr table result, which will later be used
1800 : * when we pack the group result */
1801 4961 : attr = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1802 4961 : if (attr == NULL) {
1803 0 : freeInstruction(r0);
1804 0 : freeInstruction(r1);
1805 0 : freeInstruction(r2);
1806 0 : return -1;
1807 : }
1808 4961 : getArg(attr, 0) = getArg(ml->v[b].mi, 0);
1809 :
1810 47444 : for (i = 1; mb->errors == NULL && i < ml->v[b].mi->argc; i++) {
1811 42483 : InstrPtr q = copyInstruction(p), r;
1812 42483 : if (!q) {
1813 0 : freeInstruction(r0);
1814 0 : freeInstruction(r1);
1815 0 : freeInstruction(r2);
1816 0 : freeInstruction(attr);
1817 0 : return -1;
1818 : }
1819 :
1820 42483 : getArg(q, 0) = newTmpVariable(mb, tp0);
1821 42483 : getArg(q, 1) = newTmpVariable(mb, tp1);
1822 42483 : getArg(q, 2) = newTmpVariable(mb, tp2);
1823 42483 : getArg(q, 3) = getArg(ml->v[b].mi, i);
1824 42483 : pushInstruction(mb, q);
1825 42483 : if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 0), i)
1826 42483 : || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 1), i)
1827 42483 : || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 2), i)) {
1828 0 : freeInstruction(r0);
1829 0 : freeInstruction(r1);
1830 0 : freeInstruction(r2);
1831 0 : freeInstruction(attr);
1832 0 : return -1;
1833 : }
1834 :
1835 : /* add result to mats */
1836 42483 : r0 = pushArgument(mb, r0, getArg(q, 0));
1837 42483 : r1 = pushArgument(mb, r1, getArg(q, 1));
1838 42483 : r2 = pushArgument(mb, r2, getArg(q, 2));
1839 :
1840 42483 : r = newInstruction(mb, algebraRef, projectionRef);
1841 42483 : if (r == NULL) {
1842 0 : freeInstruction(r0);
1843 0 : freeInstruction(r1);
1844 0 : freeInstruction(r2);
1845 0 : freeInstruction(attr);
1846 0 : return -1;
1847 : }
1848 42483 : getArg(r, 0) = newTmpVariable(mb, atp);
1849 42483 : r = pushArgument(mb, r, getArg(q, 1));
1850 42483 : r = pushArgument(mb, r, getArg(ml->v[b].mi, i));
1851 42483 : if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(r, 0), i)) {
1852 0 : freeInstruction(r0);
1853 0 : freeInstruction(r1);
1854 0 : freeInstruction(r2);
1855 0 : freeInstruction(attr);
1856 0 : freeInstruction(r);
1857 0 : return -1;
1858 : }
1859 42483 : pushInstruction(mb, r);
1860 :
1861 42483 : attr = pushArgument(mb, attr, getArg(r, 0));
1862 : }
1863 4961 : pushInstruction(mb, r0);
1864 4961 : pushInstruction(mb, r1);
1865 4961 : pushInstruction(mb, r2);
1866 4961 : if (push)
1867 2784 : pushInstruction(mb, attr);
1868 :
1869 : /* create mat's for the intermediates */
1870 4961 : a = ml->top;
1871 4961 : if (mb->errors || mat_add_var(ml, attr, NULL, getArg(attr, 0), mat_ext,
1872 : -1, -1, push)) {
1873 0 : if (!push)
1874 0 : freeInstruction(attr);
1875 0 : return -1;
1876 : }
1877 4961 : g = ml->top;
1878 4961 : if (mat_add_var(ml, r0, p, getArg(p, 0), mat_grp, b, -1, 1)
1879 4961 : || mat_add_var(ml, r1, p, getArg(p, 1), mat_ext, a, ml->top - 1, 1) /* point back at group */
1880 4961 : || mat_add_var(ml, r2, p, getArg(p, 2), mat_cnt, -1, ml->top - 1, 1)) /* point back at ext */
1881 0 : return -1;
1882 4961 : if (push)
1883 2784 : return mat_pack_group(mb, ml, g);
1884 : return 0;
1885 : }
1886 :
1887 : static int
1888 2618 : mat_group_derive(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int b, int g)
1889 : {
1890 2618 : int tp0 = getArgType(mb, p, 0);
1891 2618 : int tp1 = getArgType(mb, p, 1);
1892 2618 : int tp2 = getArgType(mb, p, 2);
1893 2618 : int atp = getArgType(mb, p, 3), i, a, push = 0;
1894 2618 : InstrPtr r0, r1, r2, attr;
1895 :
1896 2618 : if (getFunctionId(p) == subgroupdoneRef || getFunctionId(p) == groupdoneRef)
1897 2177 : push = 1;
1898 :
1899 2618 : if (ml->v[g].im == -1) { /* already packed */
1900 0 : InstrPtr q = copyInstruction(p);
1901 0 : if (!q)
1902 : return -1;
1903 0 : pushInstruction(mb, q);
1904 0 : return 0;
1905 : }
1906 :
1907 2618 : r0 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1908 2618 : if (r0 == NULL)
1909 : return -1;
1910 2618 : getArg(r0, 0) = newTmpVariable(mb, tp0);
1911 :
1912 2618 : r1 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1913 2618 : if (r1 == NULL) {
1914 0 : freeInstruction(r0);
1915 0 : return -1;
1916 : }
1917 2618 : getArg(r1, 0) = newTmpVariable(mb, tp1);
1918 :
1919 2618 : r2 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1920 2618 : if (r2 == NULL) {
1921 0 : freeInstruction(r0);
1922 0 : freeInstruction(r1);
1923 0 : return -1;
1924 : }
1925 2618 : getArg(r2, 0) = newTmpVariable(mb, tp2);
1926 :
1927 : /* we keep an extend, attr table result, which will later be used
1928 : * when we pack the group result */
1929 2618 : attr = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
1930 2618 : if (attr == NULL) {
1931 0 : freeInstruction(r0);
1932 0 : freeInstruction(r1);
1933 0 : freeInstruction(r2);
1934 0 : return -1;
1935 : }
1936 2618 : getArg(attr, 0) = getArg(ml->v[b].mi, 0);
1937 :
1938 : /* we need overlapping ranges */
1939 23023 : for (i = 1; mb->errors == NULL && i < ml->v[b].mi->argc; i++) {
1940 20405 : InstrPtr q = copyInstruction(p), r;
1941 20405 : if (!q) {
1942 0 : freeInstruction(r0);
1943 0 : freeInstruction(r1);
1944 0 : freeInstruction(r2);
1945 0 : freeInstruction(attr);
1946 0 : return -1;
1947 : }
1948 :
1949 20405 : getArg(q, 0) = newTmpVariable(mb, tp0);
1950 20405 : getArg(q, 1) = newTmpVariable(mb, tp1);
1951 20405 : getArg(q, 2) = newTmpVariable(mb, tp2);
1952 20405 : getArg(q, 3) = getArg(ml->v[b].mi, i);
1953 20405 : getArg(q, 4) = getArg(ml->v[g].mi, i);
1954 20405 : pushInstruction(mb, q);
1955 20405 : if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 0), i)
1956 20405 : || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 1), i)
1957 20405 : || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 2), i)) {
1958 0 : freeInstruction(r0);
1959 0 : freeInstruction(r1);
1960 0 : freeInstruction(r2);
1961 0 : freeInstruction(attr);
1962 0 : return -1;
1963 : }
1964 :
1965 : /* add result to mats */
1966 20405 : r0 = pushArgument(mb, r0, getArg(q, 0));
1967 20405 : r1 = pushArgument(mb, r1, getArg(q, 1));
1968 20405 : r2 = pushArgument(mb, r2, getArg(q, 2));
1969 :
1970 20405 : r = newInstruction(mb, algebraRef, projectionRef);
1971 20405 : if (r == NULL) {
1972 0 : freeInstruction(r0);
1973 0 : freeInstruction(r1);
1974 0 : freeInstruction(r2);
1975 0 : freeInstruction(attr);
1976 0 : return -1;
1977 : }
1978 20405 : getArg(r, 0) = newTmpVariable(mb, atp);
1979 20405 : r = pushArgument(mb, r, getArg(q, 1));
1980 20405 : r = pushArgument(mb, r, getArg(ml->v[b].mi, i));
1981 20405 : if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(r, 0), i)) {
1982 0 : freeInstruction(r0);
1983 0 : freeInstruction(r1);
1984 0 : freeInstruction(r2);
1985 0 : freeInstruction(attr);
1986 0 : freeInstruction(r);
1987 0 : return -1;
1988 : }
1989 20405 : pushInstruction(mb, r);
1990 :
1991 20405 : attr = pushArgument(mb, attr, getArg(r, 0));
1992 : }
1993 2618 : pushInstruction(mb, r0);
1994 2618 : pushInstruction(mb, r1);
1995 2618 : pushInstruction(mb, r2);
1996 2618 : if (push)
1997 2177 : pushInstruction(mb, attr);
1998 :
1999 2618 : if (mb->errors || mat_group_attr(mb, ml, g, r1, push))
2000 0 : return -1;
2001 :
2002 : /* create mat's for the intermediates */
2003 2618 : a = ml->top;
2004 2618 : if (mat_add_var(ml, attr, NULL, getArg(attr, 0), mat_ext, -1, -1, push)) {
2005 0 : if (!push)
2006 0 : freeInstruction(attr);
2007 0 : return -1;
2008 : }
2009 2618 : if (mat_add_var(ml, r0, p, getArg(p, 0), mat_grp, b, g, 1))
2010 : return -1;
2011 2618 : g = ml->top - 1;
2012 5236 : if (mat_add_var(ml, r1, p, getArg(p, 1), mat_ext, a, ml->top - 1, 1) || /* point back at group */
2013 2618 : mat_add_var(ml, r2, p, getArg(p, 2), mat_cnt, -1, ml->top - 1, 1)) /* point back at ext */
2014 0 : return -1;
2015 2618 : if (push)
2016 2177 : return mat_pack_group(mb, ml, g);
2017 : return 0;
2018 : }
2019 :
2020 : static int
2021 622 : mat_topn_project(MalBlkPtr mb, InstrPtr p, mat_t *mat, int m, int n)
2022 : {
2023 622 : int tpe = getArgType(mb, p, 0), k;
2024 622 : InstrPtr pck, q;
2025 :
2026 622 : pck = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
2027 622 : if (pck == NULL)
2028 : return -1;
2029 622 : getArg(pck, 0) = newTmpVariable(mb, tpe);
2030 :
2031 5907 : for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
2032 5285 : InstrPtr q = copyInstruction(p);
2033 5285 : if (!q) {
2034 0 : freeInstruction(pck);
2035 0 : return -1;
2036 : }
2037 :
2038 5285 : getArg(q, 0) = newTmpVariable(mb, tpe);
2039 5285 : getArg(q, 1) = getArg(mat[m].mi, k);
2040 5285 : getArg(q, 2) = getArg(mat[n].mi, k);
2041 5285 : pushInstruction(mb, q);
2042 :
2043 5285 : pck = pushArgument(mb, pck, getArg(q, 0));
2044 : }
2045 622 : pushInstruction(mb, pck);
2046 :
2047 622 : if (mb->errors || (q = copyInstruction(p)) == NULL)
2048 0 : return -1;
2049 622 : getArg(q, 2) = getArg(pck, 0);
2050 622 : pushInstruction(mb, q);
2051 622 : if (mb->errors)
2052 : return -1;
2053 : return 0;
2054 : }
2055 :
2056 : static int
2057 106 : mat_pack_topn(MalBlkPtr mb, InstrPtr slc, mat_t *mat, int m)
2058 : {
2059 : /* find chain of topn's */
2060 106 : int cnt = chain_by_length(mat, m), i;
2061 106 : InstrPtr cur = NULL;
2062 :
2063 247 : for (i = cnt - 1; mb->errors == NULL && i >= 0; i--) {
2064 141 : int otpn = walk_n_back(mat, m, i), var = 1, k;
2065 141 : int attr = mat[otpn].im;
2066 141 : int tpe = getVarType(mb, getArg(mat[attr].mi, 0));
2067 141 : InstrPtr pck, tpn, otopn = mat[otpn].org, a;
2068 :
2069 141 : pck = newInstructionArgs(mb, matRef, packRef, mat[attr].mi->argc);
2070 141 : if (pck == NULL)
2071 : return -1;
2072 141 : getArg(pck, 0) = newTmpVariable(mb, tpe);
2073 :
2074 : /* m.projection(attr); */
2075 1215 : for (k = 1; mb->errors == NULL && k < mat[attr].mi->argc; k++) {
2076 1074 : InstrPtr q = newInstruction(mb, algebraRef, projectionRef);
2077 1074 : if (q == NULL) {
2078 0 : freeInstruction(pck);
2079 0 : return -1;
2080 : }
2081 1074 : getArg(q, 0) = newTmpVariable(mb, tpe);
2082 :
2083 1074 : q = pushArgument(mb, q, getArg(slc, k));
2084 1074 : q = pushArgument(mb, q, getArg(mat[attr].mi, k));
2085 1074 : pushInstruction(mb, q);
2086 :
2087 1074 : pck = pushArgument(mb, pck, getArg(q, 0));
2088 : }
2089 141 : pushInstruction(mb, pck);
2090 :
2091 141 : a = pck;
2092 :
2093 141 : if (mb->errors || (tpn = copyInstruction(otopn)) == NULL)
2094 0 : return -1;
2095 141 : var = 1;
2096 141 : if (cur) {
2097 35 : getArg(tpn, tpn->retc + var) = getArg(cur, 0);
2098 35 : var ++;
2099 35 : if (cur->retc == 2) {
2100 35 : getArg(tpn, tpn->retc + var) = getArg(cur, 1);
2101 35 : var ++;
2102 : }
2103 : }
2104 141 : getArg(tpn, tpn->retc) = getArg(a, 0);
2105 141 : pushInstruction(mb, tpn);
2106 141 : cur = tpn;
2107 : }
2108 106 : if (mb->errors)
2109 : return -1;
2110 : return 0;
2111 : }
2112 :
2113 : static int
2114 201 : mat_topn(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int o)
2115 : {
2116 201 : int tpe = getArgType(mb, p, 0), k, is_slice = isSlice(p), zero = -1;
2117 201 : InstrPtr pck, gpck = NULL, q, r;
2118 201 : int with_groups = (p->retc == 2), piv = 0, topn2 = (n >= 0);
2119 :
2120 201 : assert(topn2 || o < 0);
2121 : /* dummy mat instruction (needed to share result of p) */
2122 201 : pck = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
2123 201 : if (pck == NULL)
2124 : return -1;
2125 201 : getArg(pck, 0) = getArg(p, 0);
2126 :
2127 201 : if (with_groups) {
2128 35 : gpck = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
2129 35 : if (gpck == NULL) {
2130 0 : freeInstruction(pck);
2131 0 : return -1;
2132 : }
2133 35 : getArg(gpck, 0) = getArg(p, 1);
2134 : }
2135 :
2136 201 : if (is_slice) {
2137 60 : ValRecord cst;
2138 60 : cst.vtype = getArgType(mb, p, 2);
2139 60 : cst.val.lval = 0;
2140 60 : cst.len = 0;
2141 60 : zero = defConstant(mb, cst.vtype, &cst);
2142 60 : if (zero < 0) {
2143 0 : freeInstruction(pck);
2144 0 : return -1;
2145 : }
2146 : }
2147 201 : assert((n < 0 && o < 0)
2148 : || (ml->v[m].mi->argc == ml->v[n].mi->argc
2149 : && ml->v[m].mi->argc == ml->v[o].mi->argc));
2150 :
2151 1708 : for (k = 1; mb->errors == NULL && k < ml->v[m].mi->argc; k++) {
2152 1507 : if ((q = copyInstruction(p)) == NULL) {
2153 0 : freeInstruction(gpck);
2154 0 : freeInstruction(pck);
2155 0 : return -1;
2156 : }
2157 1507 : getArg(q, 0) = newTmpVariable(mb, tpe);
2158 1507 : if (with_groups)
2159 282 : getArg(q, 1) = newTmpVariable(mb, tpe);
2160 1507 : getArg(q, q->retc) = getArg(ml->v[m].mi, k);
2161 1507 : if (is_slice) /* lower bound should always be 0 on partial slices */
2162 433 : getArg(q, q->retc + 1) = zero;
2163 1074 : else if (topn2) {
2164 282 : getArg(q, q->retc + 1) = getArg(ml->v[n].mi, k);
2165 282 : getArg(q, q->retc + 2) = getArg(ml->v[o].mi, k);
2166 : }
2167 1507 : pushInstruction(mb, q);
2168 :
2169 1507 : pck = pushArgument(mb, pck, getArg(q, 0));
2170 1507 : if (with_groups)
2171 282 : gpck = pushArgument(mb, gpck, getArg(q, 1));
2172 : }
2173 :
2174 201 : piv = ml->top;
2175 342 : if (mb->errors || mat_add_var(ml, pck, p, getArg(p, 0), is_slice ? mat_slc : mat_tpn, m, n, 0)) {
2176 0 : freeInstruction(pck);
2177 0 : freeInstruction(gpck);
2178 0 : return -1;
2179 : }
2180 201 : if (with_groups
2181 35 : && mat_add_var(ml, gpck, p, getArg(p, 1), is_slice ? mat_slc : mat_tpn,
2182 : m, piv, 0)) {
2183 0 : freeInstruction(gpck);
2184 0 : return -1;
2185 : }
2186 :
2187 201 : if (is_slice || p->retc == 1 /* single result, ie last of the topn's */ ) {
2188 166 : if (ml->v[m].type == mat_tpn || !is_slice) {
2189 106 : if (mat_pack_topn(mb, pck, ml->v, (!is_slice) ? piv : m))
2190 : return -1;
2191 : }
2192 :
2193 : /* topn/slice over merged parts */
2194 106 : if (is_slice) {
2195 : /* real instruction */
2196 60 : r = newInstructionArgs(mb, matRef, packRef, pck->argc);
2197 60 : if (r == NULL)
2198 : return -1;
2199 60 : getArg(r, 0) = newTmpVariable(mb, tpe);
2200 :
2201 493 : for (k = 1; k < pck->argc; k++)
2202 433 : r = pushArgument(mb, r, getArg(pck, k));
2203 60 : pushInstruction(mb, r);
2204 :
2205 60 : if ((q = copyInstruction(p)) == NULL)
2206 : return -1;
2207 60 : setFunctionId(q, subsliceRef);
2208 60 : if (ml->v[m].type != mat_tpn || is_slice)
2209 60 : getArg(q, 1) = getArg(r, 0);
2210 60 : pushInstruction(mb, q);
2211 : }
2212 :
2213 166 : ml->v[piv].type = mat_slc;
2214 : }
2215 201 : if (mb->errors)
2216 : return -1;
2217 : return 0;
2218 : }
2219 :
2220 : static int
2221 0 : mat_sample(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m)
2222 : {
2223 : /* transform
2224 : * a := sample.subuniform(b,n);
2225 : * into
2226 : * t1 := sample.subuniform(b1,n);
2227 : * t2 := sample.subuniform(b2,n);
2228 : * ...
2229 : * t0 := mat.pack(t1,t2,...);
2230 : * tn := sample.subuniform(t0,n);
2231 : * a := algebra.projection(tn,t0);
2232 : *
2233 : * Note that this does *not* give a uniform sample of the original
2234 : * bat b!
2235 : */
2236 :
2237 0 : int tpe = getArgType(mb, p, 0), k, piv;
2238 0 : InstrPtr pck, q, r;
2239 :
2240 0 : pck = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
2241 0 : if (pck == NULL)
2242 : return -1;
2243 0 : getArg(pck, 0) = newTmpVariable(mb, tpe);
2244 :
2245 0 : for (k = 1; mb->errors == NULL && k < ml->v[m].mi->argc; k++) {
2246 0 : if ((q = copyInstruction(p)) == NULL) {
2247 0 : freeInstruction(pck);
2248 0 : return -1;
2249 : }
2250 0 : getArg(q, 0) = newTmpVariable(mb, tpe);
2251 0 : getArg(q, q->retc) = getArg(ml->v[m].mi, k);
2252 0 : pushInstruction(mb, q);
2253 0 : pck = pushArgument(mb, pck, getArg(q, 0));
2254 : }
2255 :
2256 0 : piv = ml->top;
2257 0 : if (mb->errors || mat_add_var(ml, pck, p, getArg(p, 0), mat_slc, m, -1, 1)) {
2258 0 : freeInstruction(pck);
2259 0 : return -1;
2260 : }
2261 0 : pushInstruction(mb, pck);
2262 :
2263 0 : if ((q = copyInstruction(p)) == NULL)
2264 : return -1;
2265 0 : getArg(q, 0) = newTmpVariable(mb, tpe);
2266 0 : getArg(q, q->retc) = getArg(pck, 0);
2267 0 : pushInstruction(mb, q);
2268 :
2269 0 : r = newInstruction(mb, algebraRef, projectionRef);
2270 0 : if (r == NULL)
2271 : return -1;
2272 0 : getArg(r, 0) = getArg(p, 0);
2273 0 : r = pushArgument(mb, r, getArg(q, 0));
2274 0 : r = pushArgument(mb, r, getArg(pck, 0));
2275 0 : pushInstruction(mb, r);
2276 :
2277 0 : matlist_pack(ml, piv);
2278 0 : ml->v[piv].type = mat_slc;
2279 0 : if (mb->errors)
2280 : return -1;
2281 : return 0;
2282 : }
2283 :
2284 : str
2285 539442 : OPTmergetableImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
2286 : InstrPtr pci)
2287 : {
2288 539442 : InstrPtr p, *old;
2289 539442 : matlist_t ml;
2290 539442 : int oldtop, fm, fn, fo, fe, i, k, m, n, o, e, slimit, bailout = 0;
2291 539442 : int size = 0, match, actions = 0, distinct_topn = 0, /*topn_res = 0, */ groupdone = 0, *vars; //, maxvars;
2292 539442 : char *group_input;
2293 539442 : str msg = MAL_SUCCEED;
2294 :
2295 539442 : if (isOptimizerUsed(mb, pci, mitosisRef) <= 0)
2296 33777 : goto cleanup2;
2297 505684 : old = mb->stmt;
2298 505684 : oldtop = mb->stop;
2299 :
2300 505684 : vars = (int *) GDKmalloc(sizeof(int) * mb->vtop);
2301 : //maxvars = mb->vtop;
2302 505687 : group_input = (char *) GDKzalloc(sizeof(char) * mb->vtop);
2303 505697 : if (vars == NULL || group_input == NULL) {
2304 0 : if (vars)
2305 0 : GDKfree(vars);
2306 0 : throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
2307 : }
2308 : /* check for bailout conditions */
2309 22969683 : for (i = 1; i < oldtop && !bailout; i++) {
2310 22464001 : int j;
2311 :
2312 22464001 : p = old[i];
2313 :
2314 45291661 : for (j = 0; j < p->retc; j++) {
2315 22827660 : int res = getArg(p, j);
2316 22827660 : vars[res] = i;
2317 : }
2318 :
2319 : /* pack if there is a group statement following a groupdone (ie aggr(distinct)) */
2320 22464001 : if (getModuleId(p) == algebraRef && getFunctionId(p) == groupedfirstnRef)
2321 22464001 : groupdone = 1;
2322 22464001 : if (getModuleId(p) == groupRef && p->argc == 5
2323 5608 : && (getFunctionId(p) == subgroupRef
2324 3802 : || getFunctionId(p) == subgroupdoneRef
2325 0 : || getFunctionId(p) == groupRef
2326 0 : || getFunctionId(p) == groupdoneRef)) {
2327 5608 : InstrPtr q = old[vars[getArg(p, p->argc - 1)]]; /* group result from a previous group(done) */
2328 :
2329 5608 : if (getFunctionId(q) == subgroupdoneRef
2330 5604 : || getFunctionId(q) == groupdoneRef)
2331 22464001 : groupdone = 1;
2332 : }
2333 : /* bail out if there is a input for a group, which has been used for a group already (solves problems with cube like groupings) */
2334 22464001 : if (getModuleId(p) == groupRef
2335 26677 : && (getFunctionId(p) == subgroupRef
2336 24871 : || getFunctionId(p) == subgroupdoneRef
2337 21069 : || getFunctionId(p) == groupRef
2338 17236 : || getFunctionId(p) == groupdoneRef)) {
2339 26677 : int input = getArg(p, p->retc); /* argument one is first input */
2340 :
2341 26677 : if (group_input[input]) {
2342 114 : TRC_INFO(MAL_OPTIMIZER,
2343 : "Mergetable bailout on group input reuse in group statement\n");
2344 : bailout = 1;
2345 : }
2346 :
2347 26677 : group_input[input] = 1;
2348 : }
2349 22464001 : if (getModuleId(p) == algebraRef && getFunctionId(p) == selectNotNilRef) {
2350 0 : TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout not nil ref\n");
2351 : bailout = 1;
2352 : }
2353 22464001 : if (getModuleId(p) == algebraRef && getFunctionId(p) == semijoinRef) {
2354 185 : TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout semijoin ref\n");
2355 : bailout = 1;
2356 : }
2357 22464001 : if (getModuleId(p) == algebraRef && getFunctionId(p) == thetajoinRef) {
2358 2606 : assert(p->argc == 9);
2359 2606 : if (p->argc == 9
2360 2606 : && getVarConstant(mb,
2361 : getArg(p,
2362 2606 : 6)).val.ival == 6 /* op == '<>' */ ) {
2363 0 : TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout thetajoin ref\n");
2364 : bailout = 1;
2365 : }
2366 : }
2367 22464001 : if (isSample(p)) {
2368 21 : bailout = 1;
2369 : }
2370 : /*
2371 : if (isTopn(p))
2372 : topn_res = getArg(p, 0);
2373 : */
2374 : /* not idea how to detect this yet */
2375 : //distinct_topn = 1;
2376 : }
2377 505682 : GDKfree(group_input);
2378 :
2379 505686 : ml.horigin = 0;
2380 505686 : ml.torigin = 0;
2381 505686 : ml.v = 0;
2382 505686 : ml.vars = 0;
2383 505686 : if (bailout)
2384 320 : goto cleanup;
2385 :
2386 : /* the number of MATs is limited to the variable stack */
2387 505366 : ml.size = mb->vtop;
2388 505366 : ml.top = 0;
2389 505366 : ml.v = (mat_t *) GDKzalloc(ml.size * sizeof(mat_t));
2390 505376 : ml.vsize = mb->vsize;
2391 505376 : ml.horigin = (int *) GDKmalloc(sizeof(int) * ml.vsize);
2392 505330 : ml.torigin = (int *) GDKmalloc(sizeof(int) * ml.vsize);
2393 505345 : ml.vars = (int *) GDKmalloc(sizeof(int) * ml.vsize);
2394 505352 : if (ml.v == NULL || ml.horigin == NULL || ml.torigin == NULL
2395 505352 : || ml.vars == NULL) {
2396 0 : goto cleanup;
2397 : }
2398 140771592 : for (i = 0; i < ml.vsize; i++) {
2399 140266240 : ml.horigin[i] = ml.torigin[i] = -1;
2400 140266240 : ml.vars[i] = -1;
2401 : }
2402 :
2403 505352 : slimit = mb->ssize;
2404 505352 : size = (mb->stop * 1.2 < mb->ssize) ? mb->ssize : (int) (mb->stop * 1.2);
2405 505352 : mb->stmt = (InstrPtr *) GDKzalloc(size * sizeof(InstrPtr));
2406 505377 : if (mb->stmt == NULL) {
2407 0 : mb->stmt = old;
2408 0 : msg = createException(MAL, "optimizer.mergetable",
2409 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2410 0 : goto cleanup;
2411 : }
2412 505377 : mb->ssize = size;
2413 505377 : mb->stop = 0;
2414 :
2415 7782911 : for (i = 0; i < oldtop; i++) {
2416 7782911 : int bats = 0, nilbats = 0;
2417 7782911 : InstrPtr r, cp;
2418 :
2419 7782911 : p = old[i];
2420 :
2421 7782911 : if (p->token == ENDsymbol) /* don't copy the optimizer pipeline added after final instruction */
2422 : break;
2423 7277556 : if (getModuleId(p) == matRef
2424 289302 : && (getFunctionId(p) == newRef || getFunctionId(p) == packRef)) {
2425 267513 : if (mat_set_prop(&ml, mb, p)
2426 267513 : || mat_add_var(&ml, p, NULL, getArg(p, 0), mat_none, -1, -1,
2427 : 1)) {
2428 0 : msg = createException(MAL, "optimizer.mergetable",
2429 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2430 0 : goto cleanup;
2431 : }
2432 267513 : continue;
2433 : }
2434 :
2435 : /*
2436 : * If the instruction does not contain MAT references it can simply be added.
2437 : * Otherwise we have to decide on either packing them or replacement.
2438 : */
2439 7010043 : if ((match = nr_of_mats(p, &ml)) == 0) {
2440 5640950 : cp = copyInstruction(p);
2441 5640846 : if (!cp) {
2442 0 : msg = createException(MAL, "optimizer.mergetable",
2443 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2444 0 : goto cleanup;
2445 : }
2446 5640846 : pushInstruction(mb, cp);
2447 5640918 : continue;
2448 : }
2449 1369093 : bats = nr_of_bats(mb, p);
2450 1369093 : nilbats = nr_of_nilbats(mb, p);
2451 :
2452 : /* left joins can match at isMatJoinOp, so run this check beforehand */
2453 1369093 : if (match > 0 && isMatLeftJoinOp(p) && p->argc >= 5 && p->retc == 2
2454 2466 : && (match == 1 || match == 2) && bats + nilbats == 4) {
2455 2466 : m = is_a_mat(getArg(p, p->retc), &ml);
2456 2466 : o = is_a_mat(getArg(p, p->retc + 2), &ml);
2457 :
2458 2466 : if ((match == 1 && m >= 0) || (match == 2 && m >= 0 && o >= 0)) {
2459 2458 : if (mat_join2(mb, p, &ml, m, -1, o, -1)) {
2460 0 : msg = createException(MAL, "optimizer.mergetable",
2461 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2462 0 : goto cleanup;
2463 : }
2464 2458 : actions++;
2465 2458 : continue;
2466 : }
2467 : }
2468 :
2469 : /* (l,r) Join (L, R, ..)
2470 : * 2 -> (l,r) equi/theta joins (l,r)
2471 : * 3 -> (l,r) range-joins (l,r1,r2)
2472 : * NxM -> (l,r) filter-joins (l1,..,ln,r1,..,rm)
2473 : */
2474 1366635 : if (match > 0 && isMatJoinOp(p) && !isMatLeftJoinOp(p) && p->argc >= 5
2475 59268 : && p->retc == 2 && bats + nilbats >= 4) {
2476 52440 : if (bats + nilbats == 4) {
2477 52383 : m = is_a_mat(getArg(p, p->retc), &ml);
2478 52383 : n = is_a_mat(getArg(p, p->retc + 1), &ml);
2479 52383 : o = is_a_mat(getArg(p, p->retc + 2), &ml);
2480 52383 : e = is_a_mat(getArg(p, p->retc + 3), &ml);
2481 52383 : if (mat_join2(mb, p, &ml, m, n, o, e)) {
2482 0 : msg = createException(MAL, "optimizer.mergetable",
2483 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2484 0 : goto cleanup;
2485 : }
2486 : } else {
2487 57 : if (bats + nilbats == 5 && !is_a_mat(getArg(p, p->retc), &ml) && match == 2) {
2488 0 : n = is_a_mat(getArg(p, p->retc + 1), &ml);
2489 0 : o = is_a_mat(getArg(p, p->retc + 2), &ml);
2490 0 : if (mat_rangejoin(mb, p, &ml, n, o)) {
2491 0 : msg = createException(MAL, "optimizer.mergetable",
2492 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2493 0 : goto cleanup;
2494 : }
2495 : } else
2496 57 : if (mat_joinNxM(cntxt, mb, p, &ml, bats)) {
2497 0 : msg = createException(MAL, "optimizer.mergetable",
2498 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2499 0 : goto cleanup;
2500 : }
2501 : }
2502 52440 : actions++;
2503 52440 : continue;
2504 : }
2505 1314195 : if (match > 0 && getModuleId(p) == algebraRef
2506 1008604 : && getFunctionId(p) == crossRef && p->argc == 5 && p->retc == 2
2507 6828 : && bats == 2) {
2508 1321023 : int max_one = (isVarConstant(mb, getArg(p, 4))
2509 6828 : && getVarConstant(mb, getArg(p, 4)).val.btval);
2510 10424 : if (!max_one) {
2511 5212 : m = is_a_mat(getArg(p, p->retc), &ml);
2512 5212 : n = is_a_mat(getArg(p, p->retc + 1), &ml);
2513 5212 : if (mat_join2(mb, p, &ml, m, n, -1, -1)) {
2514 0 : msg = createException(MAL, "optimizer.mergetable",
2515 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2516 0 : goto cleanup;
2517 : }
2518 5212 : actions++;
2519 5212 : continue;
2520 : }
2521 : }
2522 : /*
2523 : * Aggregate handling is a prime target for optimization.
2524 : * The simple cases are dealt with first.
2525 : * Handle the rewrite v:=aggr.count(b) and sum()
2526 : * And the min/max is as easy
2527 : */
2528 1308983 : if (match == 1 && p->argc >= 2 &&
2529 1743 : ((getModuleId(p) == aggrRef &&
2530 1743 : (getFunctionId(p) == countRef
2531 1441 : || getFunctionId(p) == count_no_nilRef
2532 1441 : || getFunctionId(p) == minRef || getFunctionId(p) == maxRef
2533 1346 : || getFunctionId(p) == avgRef || getFunctionId(p) == sumRef
2534 108 : || getFunctionId(p) == prodRef)))
2535 1641 : && (m = is_a_mat(getArg(p, p->retc + 0), &ml)) >= 0) {
2536 1641 : if ((msg = mat_aggr(mb, p, ml.v, m)) != MAL_SUCCEED)
2537 0 : goto cleanup;
2538 1641 : actions++;
2539 1641 : continue;
2540 : }
2541 :
2542 1307342 : if (match == 1 && bats == 1 && p->argc == 4 && isSlice(p)
2543 60 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
2544 60 : if (mat_topn(mb, p, &ml, m, -1, -1)) {
2545 0 : msg = createException(MAL, "optimizer.mergetable",
2546 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2547 0 : goto cleanup;
2548 : }
2549 60 : actions++;
2550 60 : continue;
2551 : }
2552 :
2553 1307282 : if (match == 1 && bats == 1 && p->argc == 3 && isSample(p)
2554 0 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
2555 0 : if (mat_sample(mb, p, &ml, m)) {
2556 0 : msg = createException(MAL, "optimizer.mergetable",
2557 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2558 0 : goto cleanup;
2559 : }
2560 0 : actions++;
2561 0 : continue;
2562 : }
2563 :
2564 1307282 : if (!distinct_topn && match == 1 && bats == 1 && isTopn(p)
2565 106 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
2566 106 : if (mat_topn(mb, p, &ml, m, -1, -1)) {
2567 0 : msg = createException(MAL, "optimizer.mergetable",
2568 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2569 0 : goto cleanup;
2570 : }
2571 106 : actions++;
2572 106 : continue;
2573 : }
2574 1307176 : if (!distinct_topn && match == 3 && bats == 3 && isTopn(p)
2575 35 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)
2576 35 : && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
2577 35 : && ((o = is_a_mat(getArg(p, p->retc + 2), &ml)) >= 0)) {
2578 35 : if (mat_topn(mb, p, &ml, m, n, o)) {
2579 0 : msg = createException(MAL, "optimizer.mergetable",
2580 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2581 0 : goto cleanup;
2582 : }
2583 35 : actions++;
2584 35 : continue;
2585 : }
2586 :
2587 : /* Now we handle subgroup and aggregation statements. */
2588 1307141 : if (!groupdone && match == 1 && bats == 1 && p->argc == 4
2589 15411 : && getModuleId(p) == groupRef &&
2590 4961 : (getFunctionId(p) == subgroupRef
2591 4961 : || getFunctionId(p) == subgroupdoneRef
2592 4961 : || getFunctionId(p) == groupRef
2593 2784 : || getFunctionId(p) == groupdoneRef)
2594 4961 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
2595 4961 : if (mat_group_new(mb, p, &ml, m)) {
2596 0 : msg = createException(MAL, "optimizer.mergetable",
2597 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2598 0 : goto cleanup;
2599 : }
2600 4961 : actions++;
2601 4961 : continue;
2602 : }
2603 1302180 : if (!groupdone && match == 2 && bats == 2 && p->argc == 5
2604 43055 : && getModuleId(p) == groupRef &&
2605 2618 : (getFunctionId(p) == subgroupRef
2606 2177 : || getFunctionId(p) == subgroupdoneRef
2607 0 : || getFunctionId(p) == groupRef
2608 0 : || getFunctionId(p) == groupdoneRef)
2609 2618 : && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)
2610 2618 : && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
2611 2618 : && ml.v[n].im >= 0 /* not packed */ ) {
2612 2618 : if (mat_group_derive(mb, p, &ml, m, n)) {
2613 0 : msg = createException(MAL, "optimizer.mergetable",
2614 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2615 0 : goto cleanup;
2616 : }
2617 2618 : actions++;
2618 2618 : continue;
2619 : }
2620 : /* TODO sub'aggr' with cand list */
2621 1299562 : if (match == 3 && bats == 3 && getModuleId(p) == aggrRef && p->argc >= 4
2622 3408 : && (getFunctionId(p) == subcountRef
2623 483 : || getFunctionId(p) == subminRef
2624 430 : || getFunctionId(p) == submaxRef
2625 379 : || getFunctionId(p) == subavgRef
2626 327 : || getFunctionId(p) == subsumRef
2627 2 : || getFunctionId(p) == subprodRef)
2628 3408 : && ((m = is_a_mat(getArg(p, p->retc + 0), &ml)) >= 0)
2629 3408 : && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
2630 3408 : && ((o = is_a_mat(getArg(p, p->retc + 2), &ml)) >= 0)) {
2631 3408 : if (mat_group_aggr(mb, p, ml.v, m, n, o)) {
2632 0 : msg = createException(MAL, "optimizer.mergetable",
2633 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2634 0 : goto cleanup;
2635 : }
2636 3408 : actions++;
2637 3408 : continue;
2638 : }
2639 : /* Handle cases of ext.projection and .projection(grp) */
2640 1296154 : if (match == 2 && getModuleId(p) == algebraRef
2641 813990 : && getFunctionId(p) == projectionRef
2642 759528 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
2643 759528 : && (n = is_a_mat(getArg(p, 2), &ml)) >= 0
2644 759528 : && (ml.v[m].type == mat_ext || ml.v[n].type == mat_grp)) {
2645 7460 : assert(ml.v[m].pushed);
2646 7460 : if (!ml.v[n].pushed) {
2647 7460 : if (mat_group_project(mb, p, &ml, m, n)) {
2648 0 : msg = createException(MAL, "optimizer.mergetable",
2649 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2650 0 : goto cleanup;
2651 : }
2652 : } else {
2653 0 : cp = copyInstruction(p);
2654 0 : if (!cp) {
2655 0 : msg = createException(MAL, "optimizer.mergetable",
2656 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2657 0 : goto cleanup;
2658 : }
2659 0 : pushInstruction(mb, cp);
2660 : }
2661 7460 : continue;
2662 : }
2663 1288694 : if (match == 1 && getModuleId(p) == algebraRef
2664 188959 : && getFunctionId(p) == projectRef
2665 29724 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
2666 29724 : && (ml.v[m].type == mat_ext)) {
2667 0 : assert(ml.v[m].pushed);
2668 0 : cp = copyInstruction(p);
2669 0 : if (!cp) {
2670 0 : msg = createException(MAL, "optimizer.mergetable",
2671 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2672 0 : goto cleanup;
2673 : }
2674 0 : pushInstruction(mb, cp);
2675 0 : continue;
2676 : }
2677 :
2678 : /* Handle cases of slice.projection */
2679 1288694 : if (match == 2 && getModuleId(p) == algebraRef
2680 806530 : && getFunctionId(p) == projectionRef
2681 752068 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
2682 752068 : && (n = is_a_mat(getArg(p, 2), &ml)) >= 0
2683 752068 : && (ml.v[m].type == mat_slc)) {
2684 622 : if (mat_topn_project(mb, p, ml.v, m, n)) {
2685 0 : msg = createException(MAL, "optimizer.mergetable",
2686 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2687 0 : goto cleanup;
2688 : }
2689 622 : actions++;
2690 622 : continue;
2691 : }
2692 :
2693 : /* Handle projection */
2694 1288072 : if (match > 0
2695 1288072 : &&
2696 1288072 : ((getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef)
2697 429917 : || ((getModuleId(p) == dictRef || getModuleId(p) == forRef)
2698 130 : && getFunctionId(p) == decompressRef))
2699 858228 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0) {
2700 844887 : n = is_a_mat(getArg(p, 2), &ml);
2701 844887 : if (mat_projection(mb, p, &ml, m, n)) {
2702 0 : msg = createException(MAL, "optimizer.mergetable",
2703 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2704 0 : goto cleanup;
2705 : }
2706 844887 : actions++;
2707 844887 : continue;
2708 : }
2709 : /* Handle setops */
2710 443185 : if (match > 0 && getModuleId(p) == algebraRef
2711 150295 : && (getFunctionId(p) == differenceRef
2712 131884 : || getFunctionId(p) == intersectRef)
2713 19912 : && (m = is_a_mat(getArg(p, 1), &ml)) >= 0) {
2714 18546 : n = is_a_mat(getArg(p, 2), &ml);
2715 18546 : o = is_a_mat(getArg(p, 3), &ml);
2716 18546 : if (mat_setop(mb, p, &ml, m, n, o)) {
2717 0 : msg = createException(MAL, "optimizer.mergetable",
2718 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2719 0 : goto cleanup;
2720 : }
2721 18546 : actions++;
2722 18546 : continue;
2723 : }
2724 :
2725 424639 : if (match == p->retc && p->argc == (p->retc * 2)
2726 18275 : && getFunctionId(p) == NULL) {
2727 2 : if ((r = mat_assign(mb, p, &ml)) == NULL) {
2728 0 : msg = createException(MAL, "optimizer.mergetable",
2729 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2730 0 : goto cleanup;
2731 : }
2732 2 : actions++;
2733 2 : continue;
2734 : }
2735 :
2736 424637 : m = n = o = e = -1;
2737 872250 : for (fm = p->argc - 1; fm >= p->retc; fm--)
2738 872250 : if ((m = is_a_mat(getArg(p, fm), &ml)) >= 0)
2739 : break;
2740 :
2741 531314 : for (fn = fm - 1; fn >= p->retc; fn--)
2742 348377 : if ((n = is_a_mat(getArg(p, fn), &ml)) >= 0)
2743 : break;
2744 :
2745 445059 : for (fo = fn - 1; fo >= p->retc; fo--)
2746 170825 : if ((o = is_a_mat(getArg(p, fo), &ml)) >= 0)
2747 : break;
2748 :
2749 461180 : for (fe = fo - 1; fe >= p->retc; fe--)
2750 88383 : if ((e = is_a_mat(getArg(p, fe), &ml)) >= 0)
2751 : break;
2752 :
2753 : /* delta* operator */
2754 424637 : if (match == 3 && bats == 3 && isDelta(p)
2755 64296 : && (m = is_a_mat(getArg(p, fm), &ml)) >= 0
2756 64296 : && (n = is_a_mat(getArg(p, fn), &ml)) >= 0
2757 64296 : && (o = is_a_mat(getArg(p, fo), &ml)) >= 0) {
2758 64296 : if ((r = mat_delta(&ml, mb, p, ml.v, m, n, o, -1, fm, fn, fo, 0)) != NULL) {
2759 64296 : actions++;
2760 : } else {
2761 0 : msg = createException(MAL, "optimizer.mergetable",
2762 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2763 0 : goto cleanup;
2764 : }
2765 :
2766 64296 : continue;
2767 : }
2768 360341 : if (match == 4 && bats == 4 && isDelta(p)
2769 47399 : && (m = is_a_mat(getArg(p, fm), &ml)) >= 0
2770 47399 : && (n = is_a_mat(getArg(p, fn), &ml)) >= 0
2771 47399 : && (o = is_a_mat(getArg(p, fo), &ml)) >= 0
2772 47399 : && (e = is_a_mat(getArg(p, fe), &ml)) >= 0) {
2773 47399 : if ((r = mat_delta(&ml, mb, p, ml.v, m, n, o, e, fm, fn, fo, fe)) != NULL) {
2774 47399 : actions++;
2775 : } else {
2776 0 : msg = createException(MAL, "optimizer.mergetable",
2777 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2778 0 : goto cleanup;
2779 : }
2780 47399 : continue;
2781 : }
2782 :
2783 : /* select on insert, should use last tid only */
2784 : #if 0
2785 : 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 */
2786 : (getArg(p, fm - 1) > maxvars
2787 : || getModuleId(old[vars[getArg(p, fm - 1)]]) == sqlRef)) {
2788 : if ((r = copyInstruction(p)) == NULL) {
2789 : msg = createException(MAL, "optimizer.mergetable",
2790 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2791 : goto cleanup;
2792 : }
2793 : getArg(r, fm) = getArg(ml.v[m].mi, ml.v[m].mi->argc - 1);
2794 : pushInstruction(mb, r);
2795 : actions++;
2796 : continue;
2797 : }
2798 : #endif
2799 :
2800 : /* select on update, with nil bat */
2801 312942 : if (match == 1 && fm == 1 && isSelect(p) && p->retc == 1
2802 41071 : && (m = is_a_mat(getArg(p, fm), &ml)) >= 0 && bats == 2
2803 4 : && isaBatType(getArgType(mb, p, 2))
2804 4 : && isVarConstant(mb, getArg(p, 2))
2805 4 : && is_bat_nil(getVarConstant(mb, getArg(p, 2)).val.bval)) {
2806 4 : if (mat_apply1(mb, p, &ml, m, fm)) {
2807 0 : msg = createException(MAL, "optimizer.mergetable",
2808 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2809 0 : goto cleanup;
2810 : }
2811 4 : actions++;
2812 4 : continue;
2813 : }
2814 :
2815 : /* handle dict select */
2816 312938 : if ((match == 1 || match == bats - 1) && p->retc == 1 && isSelect(p)
2817 41120 : && getModuleId(p) == dictRef) {
2818 49 : if (mat_apply(mb, p, &ml, match)) {
2819 0 : msg = createException(MAL, "optimizer.mergetable",
2820 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2821 0 : goto cleanup;
2822 : }
2823 49 : actions++;
2824 49 : continue;
2825 : }
2826 : /* handle dict renumber */
2827 312889 : if (match == 1 && match == bats - 1 && p->retc == 1
2828 54016 : && getFunctionId(p) == renumberRef && getModuleId(p) == dictRef) {
2829 4 : if (mat_apply(mb, p, &ml, match)) {
2830 0 : msg = createException(MAL, "optimizer.mergetable",
2831 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2832 0 : goto cleanup;
2833 : }
2834 4 : actions++;
2835 4 : continue;
2836 : }
2837 :
2838 312885 : if (match == bats && p->retc == 1
2839 230696 : && (isMap2Op(p) || isMapOp(p) || isFragmentGroup(p)
2840 35966 : || isFragmentGroup2(p))) {
2841 227463 : if (mat_apply(mb, p, &ml, match)) {
2842 0 : msg = createException(MAL, "optimizer.mergetable",
2843 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2844 0 : goto cleanup;
2845 : }
2846 227463 : actions++;
2847 227463 : continue;
2848 : }
2849 :
2850 : /*
2851 : * All other instructions should be checked for remaining MAT dependencies.
2852 : * It requires MAT materialization.
2853 : */
2854 :
2855 468490 : for (k = p->retc; msg == MAL_SUCCEED && k < p->argc; k++) {
2856 383068 : if ((m = is_a_mat(getArg(p, k), &ml)) >= 0) {
2857 135028 : msg = mat_pack(mb, &ml, m);
2858 135028 : if (msg)
2859 : break;
2860 : }
2861 : }
2862 85422 : if (msg)
2863 : break;
2864 :
2865 85422 : cp = copyInstruction(p);
2866 85422 : if (!cp) {
2867 0 : msg = createException(MAL, "optimizer.mergetable",
2868 : SQLSTATE(HY013) MAL_MALLOC_FAIL);
2869 0 : goto cleanup;
2870 : }
2871 85422 : pushInstruction(mb, cp);
2872 : }
2873 : (void) stk;
2874 :
2875 16167896 : for (; i < oldtop; i++) { /* add optimizer pipeline back again */
2876 15662525 : pushInstruction(mb, old[i]);
2877 : }
2878 :
2879 505371 : if (mb->errors == MAL_SUCCEED) {
2880 7782923 : for (i = 0; i < slimit; i++) {
2881 7782923 : if (old[i] && old[i]->token == ENDsymbol) /* don't free optimizer calls */
2882 : break;
2883 7277569 : freeInstruction(old[i]);
2884 : }
2885 505354 : GDKfree(old);
2886 : }
2887 2130121 : for (i = 0; i < ml.top; i++) {
2888 1624747 : if (ml.v[i].mi && !ml.v[i].pushed)
2889 1326918 : freeInstruction(ml.v[i].mi);
2890 : }
2891 505374 : cleanup:
2892 505694 : if (vars)
2893 505694 : GDKfree(vars);
2894 505696 : if (ml.v)
2895 505376 : GDKfree(ml.v);
2896 505686 : if (ml.horigin)
2897 505366 : GDKfree(ml.horigin);
2898 505697 : if (ml.torigin)
2899 505377 : GDKfree(ml.torigin);
2900 505694 : if (ml.vars)
2901 505374 : GDKfree(ml.vars);
2902 505683 : if (mb->errors) {
2903 0 : freeException(msg);
2904 0 : msg = mb->errors;
2905 0 : mb->errors = NULL;
2906 : }
2907 : /* Defense line against incorrect plans */
2908 505683 : if (actions > 0 && msg == MAL_SUCCEED) {
2909 31524 : msg = chkTypes(cntxt->usermodule, mb, FALSE);
2910 31524 : if (!msg)
2911 31524 : msg = chkFlow(mb);
2912 31524 : if (!msg)
2913 31524 : msg = chkDeclarations(mb);
2914 : }
2915 474159 : cleanup2:
2916 : /* keep actions taken as a fake argument */
2917 539460 : if (msg == MAL_SUCCEED) {
2918 539442 : (void) pushInt(mb, pci, actions);
2919 539509 : msg = mb->errors; /* may well be NULL */
2920 539509 : mb->errors = NULL;
2921 : }
2922 :
2923 : #ifndef NDEBUG
2924 539527 : if (bailout)
2925 320 : TRC_INFO(MAL_OPTIMIZER, "Merge table bailout\n");
2926 : #endif
2927 : return msg;
2928 : }
|