LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_mergetable.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1358 1866 72.8 %
Date: 2024-12-20 21:24:02 Functions: 35 37 94.6 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "opt_mergetable.h"
      15             : 
      16             : typedef enum mat_type_t {
      17             :         mat_none = 0,                           /* Simple mat aligned operations (ie batcalc etc) */
      18             :         mat_grp = 1,                            /* result of phase one of a mat - group.new/derive */
      19             :         mat_ext = 2,                            /* mat_grp extend */
      20             :         mat_cnt = 3,                            /* mat_grp count */
      21             :         mat_tpn = 4,                            /* Phase one of topn on a mat */
      22             :         mat_slc = 5,                            /* Last phase of topn (or just slice) on a mat */
      23             :         mat_rdr = 6                                     /* Phase one of sorting, ie sorted the parts so far */
      24             : } mat_type_t;
      25             : 
      26             : typedef struct mat {
      27             :         InstrPtr mi;                            /* mat instruction */
      28             :         InstrPtr org;                           /* 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      334813 :         mat_type_t type = mat_none;
      52             :         (void) mat;
      53             :         (void) n;
      54             :         return type;
      55             : }
      56             : 
      57             : static inline int
      58    35070423 : is_a_mat(int idx, const matlist_t *ml)
      59             : {
      60    35070423 :         if (ml->vars[idx] >= 0 && !ml->v[ml->vars[idx]].packed)
      61     9126018 :                 return ml->vars[idx];
      62             :         return -1;
      63             : }
      64             : 
      65             : static int
      66     6718363 : nr_of_mats(InstrPtr p, const matlist_t *ml)
      67             : {
      68     6718363 :         int j, cnt = 0;
      69    33787158 :         for (j = p->retc; j < p->argc; j++)
      70    27068795 :                 if (is_a_mat(getArg(p, j), ml) >= 0)
      71     2605377 :                         cnt++;
      72     6718363 :         return cnt;
      73             : }
      74             : 
      75             : static int
      76     1358701 : nr_of_bats(MalBlkPtr mb, InstrPtr p)
      77             : {
      78     1358701 :         int j, cnt = 0;
      79     5038134 :         for (j = p->retc; j < p->argc; j++)
      80     3679433 :                 if (isaBatType(getArgType(mb, p, j))
      81     3135033 :                         && !isVarConstant(mb, getArg(p, j)))
      82     2912594 :                         cnt++;
      83     1358701 :         return cnt;
      84             : }
      85             : 
      86             : static int
      87     1358701 : nr_of_nilbats(MalBlkPtr mb, InstrPtr p)
      88             : {
      89     1358701 :         int j, cnt = 0;
      90     5038134 :         for (j = p->retc; j < p->argc; j++)
      91     3679433 :                 if (isaBatType(getArgType(mb, p, j))
      92     3679433 :                                 && isVarConstant(mb, getArg(p, j))
      93      222439 :                                 && getVarConstant(mb, getArg(p, j)).val.bval == bat_nil)
      94      222439 :                         cnt++;
      95     1358701 :         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     1610632 : 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     1610632 :         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     1610632 :         mat_t *dst = &ml->v[ml->top];
     115     1610632 :         dst->mi = q;
     116     1610632 :         dst->org = p;
     117     1610632 :         dst->mv = var;
     118     1610632 :         dst->type = type;
     119     1610632 :         dst->im = inputmat;
     120     1610632 :         dst->pm = parentmat;
     121     1610632 :         dst->packed = 0;
     122     1610632 :         dst->pushed = pushed;
     123     1610632 :         if (ml->vars[var] < 0 || dst->type != mat_ext) {
     124     1599243 :                 if (ml->vars[var] >= 0) {
     125           0 :                         ml->v[ml->vars[var]].packed = 1;
     126             :                 }
     127     1599243 :                 ml->vars[var] = ml->top;
     128             :         }
     129     1610632 :         ++ml->top;
     130     1610632 :         return 0;
     131             : }
     132             : 
     133             : inline static int
     134      991691 : mat_add(matlist_t *ml, InstrPtr q, mat_type_t type, const char *func)
     135             : {
     136      991691 :         (void) func;
     137             :         //printf (" ml.top %d %s\n", ml.top, func);
     138      991691 :         return mat_add_var(ml, q, NULL, getArg(q, 0), type, -1, -1, 0);
     139             : }
     140             : 
     141             : static void
     142      134283 : matlist_pack(matlist_t *ml, int m)
     143             : {
     144      134283 :         int i, idx = ml->v[m].mv;
     145             : 
     146      134283 :         assert(ml->v[m].packed == 0);
     147      134283 :         ml->v[m].packed = 1;
     148      134283 :         ml->vars[idx] = -1;
     149             : 
     150    35045178 :         for (i = 0; i < ml->top; i++)
     151    34910895 :                 if (!ml->v[i].packed && ml->v[i].mv == idx) {
     152           0 :                         ml->vars[idx] = i;
     153           0 :                         break;
     154             :                 }
     155      134283 : }
     156             : 
     157             : static str
     158      134283 : mat_pack(MalBlkPtr mb, matlist_t *ml, int m)
     159             : {
     160      134283 :         InstrPtr r;
     161             : 
     162      134283 :         if (ml->v[m].packed)
     163             :                 return MAL_SUCCEED;
     164             : 
     165      134283 :         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      134283 :                 int l;
     177             : 
     178      134283 :                 r = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
     179      134283 :                 if (r == NULL) {
     180           0 :                         throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     181             :                 }
     182      134283 :                 getArg(r, 0) = getArg(ml->v[m].mi, 0);
     183     1152729 :                 for (l = ml->v[m].mi->retc; l < ml->v[m].mi->argc; l++)
     184     1018446 :                         r = pushArgument(mb, r, getArg(ml->v[m].mi, l));
     185      134283 :                 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      134283 :         matlist_pack(ml, m);
     193      134283 :         pushInstruction(mb, r);
     194      134283 :         return MAL_SUCCEED;
     195             : }
     196             : 
     197             : static int
     198    84071574 : checksize(matlist_t *ml, int v)
     199             : {
     200    84071574 :         if (v >= ml->vsize) {
     201       15149 :                 int sz = ml->vsize, i, *nhorigin, *ntorigin, *nvars;
     202             : 
     203       15149 :                 int nvsize = ml->vsize * 2;
     204       15149 :                 assert(v < nvsize);
     205       15149 :                 if (v >= nvsize)
     206             :                         nvsize = v + 10;
     207       15149 :                 nhorigin = (int *) GDKrealloc(ml->horigin, sizeof(int) * nvsize);
     208       15149 :                 if (nhorigin == NULL)
     209             :                         return -1;
     210       15149 :                 ml->horigin = nhorigin;
     211       15149 :                 ntorigin = (int *) GDKrealloc(ml->torigin, sizeof(int) * nvsize);
     212       15149 :                 if (ntorigin == NULL)
     213             :                         return -1;
     214       15149 :                 ml->torigin = ntorigin;
     215       15149 :                 nvars = (int *) GDKrealloc(ml->vars, sizeof(int) * nvsize);
     216       15149 :                 if (nvars == NULL)
     217             :                         return -1;
     218       15149 :                 ml->vars = nvars;
     219       15149 :                 ml->vsize = nvsize;
     220             : 
     221    16752429 :                 for (i = sz; i < ml->vsize; i++) {
     222    16737280 :                         ml->horigin[i] = ml->torigin[i] = -1;
     223    16737280 :                         ml->vars[i] = -1;
     224             :                 }
     225             :         }
     226             :         return 0;
     227             : }
     228             : 
     229             : static int
     230    11433788 : setPartnr(matlist_t *ml, int ivar, int ovar, int pnr)
     231             : {
     232    11433788 :         int tpnr = -1;
     233             : 
     234    11433788 :         if (checksize(ml, ivar) || checksize(ml, ovar))
     235           0 :                 return -1;
     236    11433788 :         if (ivar >= 0)
     237     7249735 :                 tpnr = ml->torigin[ivar];
     238     7249735 :         if (tpnr >= 0)
     239      399119 :                 ml->torigin[ovar] = tpnr;
     240    11433788 :         assert(ovar < ml->vsize);
     241    11433788 :         ml->horigin[ovar] = pnr;
     242             :         //printf("%d %d ", pnr, tpnr);
     243    11433788 :         return 0;
     244             : }
     245             : 
     246             : static int
     247     1006878 : propagatePartnr(matlist_t *ml, int ivar, int ovar, int pnr)
     248             : {
     249             :         /* prop head ids to tail */
     250     1006878 :         int tpnr = -1;
     251             : 
     252     1006878 :         if (checksize(ml, ivar) || checksize(ml, ovar))
     253           0 :                 return -1;
     254     1006878 :         if (ivar >= 0)
     255     1006878 :                 tpnr = ml->horigin[ivar];
     256     1006878 :         if (tpnr >= 0)
     257      545365 :                 ml->torigin[ovar] = tpnr;
     258     1006878 :         assert(ovar < ml->vsize);
     259     1006878 :         ml->horigin[ovar] = pnr;
     260             :         //printf("%d %d ", pnr, tpnr);
     261     1006878 :         return 0;
     262             : }
     263             : 
     264             : static int
     265      817721 : propagateMirror(matlist_t *ml, int ivar, int ovar)
     266             : {
     267             :         /* prop head ids to head and tail */
     268      817721 :         int tpnr;
     269             : 
     270      817721 :         if (checksize(ml, ivar) || checksize(ml, ovar))
     271           0 :                 return -1;
     272      817721 :         tpnr = ml->horigin[ivar];
     273      817721 :         if (tpnr >= 0) {
     274      817721 :                 assert(ovar < ml->vsize);
     275      817721 :                 ml->horigin[ovar] = tpnr;
     276      817721 :                 ml->torigin[ovar] = tpnr;
     277             :         }
     278             :         return 0;
     279             : }
     280             : 
     281             : static int
     282    28777400 : overlap(matlist_t *ml, int lv, int rv, int lnr, int rnr, int ontails)
     283             : {
     284    28777400 :         int lpnr, rpnr;
     285             : 
     286    28777400 :         if (checksize(ml, lv) || checksize(ml, rv))
     287           0 :                 return -1;
     288    28777400 :         lpnr = ml->torigin[lv];
     289    28777400 :         rpnr = (ontails) ? ml->torigin[rv] : ml->horigin[rv];
     290             : 
     291    28777400 :         if (lpnr < 0 && rpnr < 0)
     292           0 :                 return lnr == rnr;
     293    28777400 :         if (rpnr < 0)
     294      598841 :                 return lpnr == rnr;
     295    28178559 :         if (lpnr < 0)
     296     3047627 :                 return rpnr == lnr;
     297    25130932 :         return lpnr == rpnr;
     298             : }
     299             : 
     300             : static int
     301      263860 : mat_set_prop(matlist_t *ml, MalBlkPtr mb, InstrPtr p)
     302             : {
     303      263860 :         int k, tpe = getArgType(mb, p, 0);
     304             : 
     305      263860 :         tpe = getBatType(tpe);
     306     2196631 :         for (k = 1; k < p->argc; k++) {
     307     1932771 :                 if (setPartnr(ml, -1, getArg(p, k), k))
     308             :                         return -1;
     309     1932771 :                 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      109217 : 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      109217 :         int tpe, k, j, is_subdelta = (getFunctionId(p) == subdeltaRef),
     320      109217 :                 is_projectdelta = (getFunctionId(p) == projectdeltaRef);
     321      109217 :         InstrPtr r = NULL;
     322      109217 :         int pushed = 0;
     323             : 
     324             :         //printf("# %s.%s(%d,%d,%d,%d)", getModuleId(p), getFunctionId(p), m, n, o, e);
     325             : 
     326      109217 :         if ((r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
     327             :                 return NULL;
     328      109217 :         getArg(r, 0) = getArg(p, 0);
     329      109217 :         tpe = getArgType(mb, p, 0);
     330             : 
     331             :         /* Handle like mat_projection, ie overlapping partitions */
     332      109217 :         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      845278 :                 for (k = 1; k < mat[m].mi->argc; k++) {
     371      736061 :                         InstrPtr q = copyInstruction(p);
     372      736061 :                         if (!q) {
     373           0 :                                 freeInstruction(r);
     374           0 :                                 return NULL;
     375             :                         }
     376      736061 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
     377      736061 :                         getArg(q, mvar) = getArg(mat[m].mi, k);
     378      736061 :                         getArg(q, nvar) = getArg(mat[n].mi, k);
     379      736061 :                         getArg(q, ovar) = getArg(mat[o].mi, k);
     380      736061 :                         if (e >= 0)
     381      272454 :                                 getArg(q, evar) = getArg(mat[e].mi, k);
     382      736061 :                         pushInstruction(mb, q);
     383      736061 :                         if (mb->errors) {
     384           0 :                                 freeInstruction(r);
     385           0 :                                 return NULL;
     386             :                         }
     387      736061 :                         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      736061 :                         r = pushArgument(mb, r, getArg(q, 0));
     392             :                 }
     393      109217 :                 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      109217 :         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      109217 :         if (pushed)
     416           0 :                 matlist_pack(ml, ml->top - 1);
     417             :         return r;
     418             : }
     419             : 
     420             : static InstrPtr
     421           4 : mat_assign(MalBlkPtr mb, InstrPtr p, matlist_t *ml)
     422             : {
     423           4 :         InstrPtr r = NULL;
     424           4 :         mat_t *mat = ml->v;
     425             : 
     426          12 :         for (int i = 0; i < p->retc; i++) {
     427           8 :                 int m = is_a_mat(getArg(p, p->retc + i), ml);
     428           8 :                 assert(is_a_mat(getArg(p, i), ml) < 0 && m >= 0);
     429             : 
     430           8 :                 if ((r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
     431             :                         return NULL;
     432           8 :                 getArg(r, 0) = getArg(p, i);
     433          62 :                 for (int k = 1; k < mat[m].mi->argc; k++) {
     434             :                         /* reuse inputs of old mat */
     435          54 :                         r = pushArgument(mb, r, getArg(mat[m].mi, k));
     436          54 :                         if (setPartnr(ml, -1, getArg(mat[m].mi, k), k)) {
     437           0 :                                 freeInstruction(r);
     438           0 :                                 return NULL;
     439             :                         }
     440             :                 }
     441           8 :                 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       14085 : mat_apply1(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int var)
     451             : {
     452       14085 :         int tpe, k, is_select = isSelect(p),
     453       14085 :                 is_mirror = (getFunctionId(p) == mirrorRef);
     454       28170 :         int is_identity = (getFunctionId(p) == identityRef
     455       14085 :                                            && getModuleId(p) == batcalcRef);
     456       14085 :         int ident_var = 0, is_assign = (getFunctionId(p) == NULL), n = 0;
     457       14085 :         InstrPtr r = NULL, q;
     458       14085 :         mat_t *mat = ml->v;
     459             : 
     460       14085 :         assert(!is_assign);
     461             : 
     462       14085 :         assert(p->retc == 1);
     463             : 
     464             :         /* Find the mat we overwrite */
     465       14085 :         if (is_assign) {
     466             :                 n = is_a_mat(getArg(p, 0), ml);
     467             :                 is_assign = (n >= 0);
     468             :         }
     469             : 
     470       14085 :         if (m < 0
     471       14085 :                 || (r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
     472           0 :                 return -1;
     473       14085 :         getArg(r, 0) = getArg(p, 0);
     474       14085 :         tpe = getArgType(mb, p, 0);
     475             : 
     476       14085 :         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      124768 :         for (k = 1; k < mat[m].mi->argc; k++) {
     493      110683 :                 int res = 0;
     494      110683 :                 if ((q = copyInstruction(p)) == NULL) {
     495           0 :                         freeInstruction(r);
     496           0 :                         return -1;
     497             :                 }
     498             : 
     499      110683 :                 if (is_assign)
     500             :                         getArg(q, 0) = getArg(mat[n].mi, k);
     501             :                 else
     502      110683 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
     503      110683 :                 if (is_identity)
     504           8 :                         getArg(q, 1) = newTmpVariable(mb, TYPE_oid);
     505      110683 :                 getArg(q, var +is_identity) = getArg(mat[m].mi, k);
     506      110683 :                 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      110683 :                 ident_var = getArg(q, 1);
     517      110683 :                 pushInstruction(mb, q);
     518      110683 :                 if (mb->errors) {
     519           0 :                         freeInstruction(r);
     520           0 :                         return -1;
     521             :                 }
     522      110683 :                 if (is_mirror || is_identity) {
     523      110651 :                         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      110683 :                 if (res) {
     529           0 :                         freeInstruction(r);
     530           0 :                         return -1;
     531             :                 }
     532      110683 :                 r = pushArgument(mb, r, getArg(q, 0));
     533             :         }
     534       14085 :         if (mb->errors) {
     535           0 :                 freeInstruction(r);
     536           0 :                 return -1;
     537             :         }
     538       14085 :         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      225592 : mat_apply(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int nrmats)
     547             : {
     548      225592 :         int matvar[8], fargument[8], k, l, parts = 0;
     549             : 
     550      225592 :         if (nrmats == 1
     551      108491 :                 && ((getModuleId(p) == batcalcRef && getFunctionId(p) == identityRef)
     552      108489 :                         || (getModuleId(p) == batRef && getFunctionId(p) == mirrorRef)))
     553       14081 :                 return mat_apply1(mb, p, ml, is_a_mat(getArg(p, 1), ml), 1);
     554      211511 :         assert(nrmats <= 8);
     555             : 
     556      211511 :         assert(p->retc < p->argc);     /* i.e. matvar[0] gets initialized */
     557      945676 :         for (k = p->retc, l = 0; k < p->argc; k++) {
     558      734165 :                 int mv = is_a_mat(getArg(p, k), ml);
     559      734165 :                 if (mv >= 0) {
     560      360118 :                         matvar[l] = mv;
     561      360118 :                         fargument[l] = k;
     562      360118 :                         l++;
     563      360118 :                         if (parts == 0)
     564      211511 :                                 parts = ml->v[mv].mi->argc;
     565      360118 :                         if (parts != ml->v[mv].mi->argc)
     566             :                                 return -1;
     567             :                 }
     568             :         }
     569             : 
     570      211511 :         InstrPtr *r = (InstrPtr *) GDKmalloc(sizeof(InstrPtr) * p->retc);
     571      211511 :         if (!r)
     572             :                 return -1;
     573      423022 :         for (k = 0; k < p->retc; k++) {
     574      211511 :                 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      211511 :                 getArg(r[k], 0) = getArg(p, k);
     581             :         }
     582             : 
     583     1794107 :         for (k = 1; k < ml->v[matvar[0]].mi->argc; k++) {
     584     1582596 :                 int tpe;
     585     1582596 :                 InstrPtr q = copyInstruction(p);
     586     1582596 :                 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     3165192 :                 for (l = 0; l < p->retc; l++) {
     594     1582596 :                         tpe = getArgType(mb, p, l);
     595     1582596 :                         getArg(q, l) = newTmpVariable(mb, tpe);
     596             :                 }
     597     4298489 :                 for (l = 0; l < nrmats; l++)
     598     2715893 :                         getArg(q, fargument[l]) = getArg(ml->v[matvar[l]].mi, k);
     599     1582596 :                 pushInstruction(mb, q);
     600     4747788 :                 for (l = 0; l < p->retc; l++) {
     601     1582596 :                         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     1582596 :                         r[l] = pushArgument(mb, r[l], getArg(q, l));
     608             :                 }
     609     1582596 :                 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      423022 :         for (k = 0; k < p->retc; k++) {
     617      211511 :                 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      211511 :         GDKfree(r);
     626      211511 :         return 0;
     627             : }
     628             : 
     629             : 
     630             : static int
     631       18501 : mat_setop(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int o)
     632             : {
     633       18501 :         int tpe = getArgType(mb, p, 0), k, j;
     634       18501 :         mat_t *mat = ml->v;
     635       18501 :         InstrPtr r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
     636             : 
     637       18501 :         if (!r)
     638             :                 return -1;
     639             : 
     640       18501 :         getArg(r, 0) = getArg(p, 0);
     641             : 
     642             :         //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
     643       18501 :         assert(m >= 0 || n >= 0);
     644       18501 :         if (m >= 0 && n >= 0) {
     645       18125 :                 int nr = 1;
     646             : 
     647       18125 :                 assert(o < 0 || mat[m].mi->argc == mat[o].mi->argc);
     648             : 
     649      160920 :                 for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
     650      142795 :                         InstrPtr q = copyInstruction(p);
     651      285590 :                         InstrPtr s = newInstructionArgs(mb, matRef, packRef,
     652      142795 :                                                                                         mat[n].mi->argc);
     653      142795 :                         int ttpe = 0;
     654             : 
     655      142795 :                         if (q == NULL
     656      142795 :                                 || s == NULL
     657      142795 :                                 || (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      142795 :                         ttpe = getArgType(mb, mat[n].mi, 0);
     665     1525504 :                         for (j = 1; j < mat[n].mi->argc; j++) {
     666     1382709 :                                 int ov = 0;
     667     1382709 :                                 if (getBatType(ttpe) != TYPE_oid
     668     1381397 :                                         || (ov = overlap(ml, getArg(mat[m].mi, k),
     669             :                                                                          getArg(mat[n].mi, j), k, j, 1)) == 1) {
     670      175247 :                                         s = pushArgument(mb, s, getArg(mat[n].mi, j));
     671             :                                 }
     672     1382709 :                                 if (ov == -1) {
     673           0 :                                         freeInstruction(q);
     674           0 :                                         freeInstruction(s);
     675           0 :                                         freeInstruction(r);
     676           0 :                                         return -1;
     677             :                                 }
     678             :                         }
     679      142795 :                         if (s->retc == 1 && s->argc == 2) {       /* only one input, change into an assignment */
     680      138041 :                                 getFunctionId(s) = NULL;
     681      138041 :                                 getModuleId(s) = NULL;
     682      138041 :                                 s->token = ASSIGNsymbol;
     683      138041 :                                 s->typeresolved = false;
     684      138041 :                                 s->fcn = NULL;
     685      138041 :                                 s->blk = NULL;
     686             :                         }
     687      142795 :                         pushInstruction(mb, s);
     688             : 
     689      142795 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
     690      142795 :                         getArg(q, 1) = getArg(mat[m].mi, k);
     691      142795 :                         getArg(q, 2) = getArg(s, 0);
     692      142795 :                         if (o >= 0)
     693        1422 :                                 getArg(q, 3) = getArg(mat[o].mi, k);
     694      142795 :                         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      142795 :                         pushInstruction(mb, q);
     700             : 
     701      142795 :                         r = pushArgument(mb, r, getArg(q, 0));
     702      142795 :                         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       18501 :         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      839987 : mat_projection(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n)
     738             : {
     739      839987 :         int tpe = getArgType(mb, p, 0), k, j;
     740      839987 :         mat_t *mat = ml->v;
     741      839987 :         InstrPtr r;
     742             : 
     743             :         //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
     744      839987 :         assert(m >= 0 || n >= 0);
     745      839987 :         if (m >= 0 && n >= 0) {
     746      747032 :                 int nr = 1;
     747     1494064 :                 r = newInstructionArgs(mb, matRef, packRef,
     748      747032 :                                                            mat[m].mi->argc * mat[n].mi->argc);
     749             : 
     750      747032 :                 if (!r)
     751             :                         return -1;
     752             : 
     753      747032 :                 getArg(r, 0) = getArg(p, 0);
     754             : 
     755     6736879 :                 for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
     756    27396003 :                         for (j = 1; j < mat[n].mi->argc; j++) {
     757    27396003 :                                 InstrPtr q;
     758    27396003 :                                 switch (overlap(ml, getArg(mat[m].mi, k),
     759             :                                                                 getArg(mat[n].mi, j), k, j, 0)) {
     760    21406156 :                                 case 0:
     761    21406156 :                                         continue;
     762           0 :                                 case -1:
     763           0 :                                         freeInstruction(r);
     764           0 :                                         return -1;
     765     5989847 :                                 case 1:
     766     5989847 :                                         q = copyInstruction(p);
     767             : 
     768     5989847 :                                         if (!q) {
     769           0 :                                                 freeInstruction(r);
     770           0 :                                                 return -1;
     771             :                                         }
     772             : 
     773     5989847 :                                         getArg(q, 0) = newTmpVariable(mb, tpe);
     774     5989847 :                                         getArg(q, 1) = getArg(mat[m].mi, k);
     775     5989847 :                                         getArg(q, 2) = getArg(mat[n].mi, j);
     776     5989847 :                                         pushInstruction(mb, q);
     777             : 
     778     5989847 :                                         if (mb->errors || setPartnr(ml, getArg(mat[n].mi, j), getArg(q, 0), nr)) {
     779           0 :                                                 freeInstruction(r);
     780           0 :                                                 return -1;
     781             :                                         }
     782     5989847 :                                         r = pushArgument(mb, r, getArg(q, 0));
     783             : 
     784     5989847 :                                         nr++;
     785     5989847 :                                         break;
     786             :                                 }
     787             :                                 break;                  /* only in case of overlap */
     788             :                         }
     789             :                 }
     790             :         } else {
     791       92955 :                 assert(m >= 0);
     792       92955 :                 r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
     793             : 
     794       92955 :                 if (!r)
     795             :                         return -1;
     796             : 
     797       92955 :                 getArg(r, 0) = getArg(p, 0);
     798             : 
     799      825666 :                 for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
     800      732711 :                         InstrPtr q = copyInstruction(p);
     801             : 
     802      732711 :                         if (!q) {
     803           0 :                                 freeInstruction(r);
     804           0 :                                 return -1;
     805             :                         }
     806             : 
     807      732711 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
     808      732711 :                         getArg(q, 1) = getArg(mat[m].mi, k);
     809      732711 :                         pushInstruction(mb, q);
     810             : 
     811      732711 :                         if (mb->errors || setPartnr(ml, getArg(q, 2), getArg(q, 0), k)) {
     812           0 :                                 freeInstruction(r);
     813           0 :                                 return -1;
     814             :                         }
     815      732711 :                         r = pushArgument(mb, r, getArg(q, 0));
     816             :                 }
     817             :         }
     818             : 
     819      839987 :         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       59497 : mat_join2(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int lc, int rc)
     828             : {
     829       59497 :         int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), j, k, nr = 1;
     830       59497 :         mat_t *mat = ml->v;
     831       59497 :         InstrPtr l;
     832       59497 :         InstrPtr r;
     833             : 
     834             :         //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
     835             : 
     836       59497 :         assert(m >= 0 || n >= 0);
     837       59497 :         if (m >= 0 && n >= 0) {
     838        1364 :                 l = newInstructionArgs(mb, matRef, packRef,
     839         682 :                                                            mat[m].mi->argc * mat[n].mi->argc);
     840        1364 :                 r = newInstructionArgs(mb, matRef, packRef,
     841         682 :                                                            mat[m].mi->argc * mat[n].mi->argc);
     842         682 :                 if (!l || !r) {
     843           0 :                         freeInstruction(l);
     844           0 :                         freeInstruction(r);
     845           0 :                         return -1;
     846             :                 }
     847             : 
     848         682 :                 getArg(l, 0) = getArg(p, 0);
     849         682 :                 getArg(r, 0) = getArg(p, 1);
     850             : 
     851        5984 :                 for (k = 1; k < mat[m].mi->argc; k++) {
     852       47176 :                         for (j = 1; j < mat[n].mi->argc; j++) {
     853       41874 :                                 InstrPtr q = copyInstruction(p);
     854             : 
     855       41874 :                                 if (!q) {
     856           0 :                                         freeInstruction(l);
     857           0 :                                         freeInstruction(r);
     858           0 :                                         return -1;
     859             :                                 }
     860             : 
     861       41874 :                                 getArg(q, 0) = newTmpVariable(mb, tpe1);
     862       41874 :                                 getArg(q, 1) = newTmpVariable(mb, tpe2);
     863       41874 :                                 getArg(q, 2) = getArg(mat[m].mi, k);
     864       41874 :                                 getArg(q, 3) = getArg(mat[n].mi, j);
     865       41874 :                                 if (lc >= 0)
     866         241 :                                         getArg(q, 4) = getArg(mat[lc].mi, k);
     867       41874 :                                 if (rc >= 0)
     868           0 :                                         getArg(q, 5) = getArg(mat[rc].mi, j);
     869       41874 :                                 pushInstruction(mb, q);
     870             : 
     871       41874 :                                 if (mb->errors
     872       41874 :                                         || propagatePartnr(ml, getArg(mat[m].mi, k), getArg(q, 0),
     873             :                                                                            nr)
     874       41874 :                                         || 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       41874 :                                 l = pushArgument(mb, l, getArg(q, 0));
     883       41874 :                                 r = pushArgument(mb, r, getArg(q, 1));
     884       41874 :                                 nr++;
     885             :                         }
     886             :                 }
     887             :         } else {
     888       58815 :                 int mv = (m >= 0) ? m : n;
     889       58815 :                 int av = (m < 0);
     890       58815 :                 int bv = (m >= 0);
     891       58815 :                 int mc = (lc >= 0) ? lc : rc;
     892             : 
     893       58815 :                 l = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
     894       58815 :                 r = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
     895       58815 :                 if (!l || !r) {
     896           0 :                         freeInstruction(l);
     897           0 :                         freeInstruction(r);
     898           0 :                         return -1;
     899             :                 }
     900             : 
     901       58815 :                 getArg(l, 0) = getArg(p, 0);
     902       58815 :                 getArg(r, 0) = getArg(p, 1);
     903             : 
     904      520063 :                 for (k = 1; k < mat[mv].mi->argc; k++) {
     905      461248 :                         InstrPtr q = copyInstruction(p);
     906             : 
     907      461248 :                         if (!q) {
     908           0 :                                 freeInstruction(l);
     909           0 :                                 freeInstruction(r);
     910           0 :                                 return -1;
     911             :                         }
     912             : 
     913      461248 :                         getArg(q, 0) = newTmpVariable(mb, tpe1);
     914      461248 :                         getArg(q, 1) = newTmpVariable(mb, tpe2);
     915      461248 :                         getArg(q, p->retc + av) = getArg(mat[mv].mi, k);
     916      461248 :                         if (mc >= 0)
     917        1278 :                                 getArg(q, p->retc + 2 + av) = getArg(mat[mc].mi, k);
     918      461248 :                         pushInstruction(mb, q);
     919             : 
     920      461248 :                         if (mb->errors
     921      461248 :                                 || propagatePartnr(ml, getArg(mat[mv].mi, k), getArg(q, av), k)
     922      461248 :                                 || 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      461248 :                         l = pushArgument(mb, l, getArg(q, 0));
     931      461248 :                         r = pushArgument(mb, r, getArg(q, 1));
     932             :                 }
     933             :         }
     934       59497 :         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       59497 :         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          58 : mat_joinNxM(Client cntxt, MalBlkPtr mb, InstrPtr p, matlist_t *ml, int args)
    1052             : {
    1053          58 :         int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), j, k, nr = 1;
    1054          58 :         InstrPtr l;
    1055          58 :         InstrPtr r;
    1056          58 :         mat_t *mat = ml->v;
    1057          58 :         int *mats = (int *) GDKzalloc(sizeof(int) * args);
    1058          58 :         int nr_mats = 0, first = -1, res = 0;
    1059             : 
    1060          58 :         if (!mats) {
    1061             :                 return -1;
    1062             :         }
    1063             : 
    1064         243 :         for (j = 0; j < args; j++) {
    1065         185 :                 mats[j] = is_a_mat(getArg(p, p->retc + j), ml);
    1066         185 :                 if (mats[j] != -1) {
    1067          72 :                         nr_mats++;
    1068          72 :                         if (first < 0)
    1069          58 :                                 first = j;
    1070             :                 }
    1071             :         }
    1072             : 
    1073             :         //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
    1074             : 
    1075          58 :         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          54 :                 int mv = mats[first];
    1146             : 
    1147          54 :                 l = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
    1148          54 :                 r = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
    1149          54 :                 if (l == NULL || r == NULL) {
    1150           0 :                         freeInstruction(l);
    1151           0 :                         freeInstruction(r);
    1152           0 :                         GDKfree(mats);
    1153           0 :                         return -1;
    1154             :                 }
    1155          54 :                 getArg(l, 0) = getArg(p, 0);
    1156          54 :                 getArg(r, 0) = getArg(p, 1);
    1157             : 
    1158         319 :                 for (k = 1; k < mat[mv].mi->argc; k++) {
    1159         265 :                         InstrPtr q = copyInstruction(p);
    1160         265 :                         if (!q) {
    1161           0 :                                 freeInstruction(r);
    1162           0 :                                 freeInstruction(l);
    1163           0 :                                 GDKfree(mats);
    1164           0 :                                 return -1;
    1165             :                         }
    1166             : 
    1167         265 :                         getArg(q, 0) = newTmpVariable(mb, tpe1);
    1168         265 :                         getArg(q, 1) = newTmpVariable(mb, tpe2);
    1169         545 :                         for (j = 0; j < nr_mats; j++) {
    1170         280 :                                 assert(mat[mats[first]].mi->argc == mat[mats[first + j]].mi->argc);
    1171         280 :                                 getArg(q, p->retc + first + j) = getArg(mat[mats[first + j]].mi, k);
    1172             :                         }
    1173         265 :                         if (mb->errors
    1174         265 :                                 || propagatePartnr(ml, getArg(mat[mv].mi, k),
    1175         265 :                                                                    getArg(q, (first != 0)), k)
    1176         265 :                                 || propagatePartnr(ml,
    1177         265 :                                                                    getArg(p, p->retc + (first) ? nr_mats : 0),
    1178         265 :                                                                    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         265 :                         pushInstruction(mb, q);
    1186             : 
    1187             :                         /* add result to mat */
    1188         265 :                         l = pushArgument(mb, l, getArg(q, 0));
    1189         265 :                         r = pushArgument(mb, r, getArg(q, 1));
    1190             :                 }
    1191             :         }
    1192          58 :         if (mb->errors || mat_add(ml, l, mat_none, getFunctionId(p))) {
    1193           0 :                 freeInstruction(l);
    1194           0 :                 freeInstruction(r);
    1195           0 :                 res = -1;
    1196          58 :         } else if (mat_add(ml, r, mat_none, getFunctionId(p))) {
    1197           0 :                 freeInstruction(r);
    1198           0 :                 res = -1;
    1199             :         }
    1200          58 :         GDKfree(mats);
    1201          58 :         return res;
    1202             : }
    1203             : 
    1204             : 
    1205             : static const char *
    1206        5050 : aggr_phase2(const char *aggr, int type_dbl)
    1207             : {
    1208        5050 :         if (aggr == countRef || aggr == count_no_nilRef
    1209        4749 :                 || (aggr == avgRef && type_dbl))
    1210             :                 return sumRef;
    1211        3744 :         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        1640 : mat_aggr(MalBlkPtr mb, InstrPtr p, mat_t *mat, int m)
    1219             : {
    1220        1640 :         int tp = getArgType(mb, p, 0), k, tp2 = TYPE_lng, i;
    1221        1640 :         int battp = (getModuleId(p) == aggrRef) ? newBatType(tp) : tp, battp2 = 0;
    1222        1640 :         int isAvg = (getFunctionId(p) == avgRef);
    1223        1640 :         InstrPtr r = NULL, s = NULL, q = NULL, u = NULL, v = NULL;
    1224             : 
    1225             :         /* we pack the partial result */
    1226        1640 :         r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
    1227        1640 :         if (r == NULL)
    1228           0 :                 throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1229        1640 :         getArg(r, 0) = newTmpVariable(mb, battp);
    1230             : 
    1231        1640 :         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        1640 :         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       13599 :         for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
    1251       11959 :                 q = newInstruction(mb, NULL, NULL);
    1252       11959 :                 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       11959 :                 if (isAvg && tp == TYPE_dbl)
    1259        7947 :                         setModuleId(q, batcalcRef);
    1260             :                 else
    1261        4012 :                         setModuleId(q, getModuleId(p));
    1262       11959 :                 setFunctionId(q, getFunctionId(p));
    1263       11959 :                 getArg(q, 0) = newTmpVariable(mb, tp);
    1264       11959 :                 if (isAvg)
    1265        8110 :                         q = pushReturn(mb, q, newTmpVariable(mb, tp2));
    1266       11959 :                 if (isAvg && tp != TYPE_dbl)
    1267         163 :                         q = pushReturn(mb, q, newTmpVariable(mb, tp2));
    1268       11959 :                 q = pushArgument(mb, q, getArg(mat[m].mi, k));
    1269       12402 :                 for (i = q->argc; i < p->argc; i++)
    1270         443 :                         q = pushArgument(mb, q, getArg(p, i));
    1271       11959 :                 pushInstruction(mb, q);
    1272             : 
    1273       11959 :                 r = pushArgument(mb, r, getArg(q, 0));
    1274       11959 :                 if (isAvg)
    1275        8110 :                         u = pushArgument(mb, u, getArg(q, 1));
    1276       11959 :                 if (isAvg && tp != TYPE_dbl)
    1277         163 :                         v = pushArgument(mb, v, getArg(q, 2));
    1278             :         }
    1279        1640 :         pushInstruction(mb, r);
    1280        1640 :         if (isAvg)
    1281        1026 :                 pushInstruction(mb, u);
    1282        1640 :         if (isAvg && tp != TYPE_dbl)
    1283          21 :                 pushInstruction(mb, v);
    1284             : 
    1285             :         /* Filter empty partitions */
    1286        1640 :         if (mb->errors == NULL && getModuleId(p) == aggrRef && !isAvg) {
    1287         614 :                 s = newInstruction(mb, algebraRef, selectNotNilRef);
    1288         614 :                 if (s == NULL) {
    1289           0 :                         throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1290             :                 }
    1291         614 :                 getArg(s, 0) = newTmpVariable(mb, battp);
    1292         614 :                 s = pushArgument(mb, s, getArg(r, 0));
    1293         614 :                 pushInstruction(mb, s);
    1294         614 :                 r = s;
    1295             :         }
    1296             : 
    1297             :         /* for avg we do sum (avg*(count/sumcount) ) */
    1298        1640 :         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        1640 :         if (mb->errors == NULL) {
    1381        1640 :                 s = newInstruction(mb, getModuleId(p),
    1382             :                                                    aggr_phase2(getFunctionId(p), tp == TYPE_dbl));
    1383        1640 :                 if (s == NULL) {
    1384           0 :                         throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1385             :                 }
    1386        1640 :                 getArg(s, 0) = getArg(p, 0);
    1387        1640 :                 s = pushArgument(mb, s, getArg(r, 0));
    1388        1640 :                 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        1640 :                 pushInstruction(mb, s);
    1393             :         }
    1394        1640 :         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        7682 : chain_by_length(mat_t *mat, int g)
    1404             : {
    1405        7682 :         int cnt = 0;
    1406       19212 :         while (g >= 0) {
    1407       11530 :                 g = mat[g].pm;
    1408       11530 :                 cnt++;
    1409             :         }
    1410        5060 :         return cnt;
    1411             : }
    1412             : 
    1413             : static int
    1414        3813 : walk_n_back(mat_t *mat, int g, int cnt)
    1415             : {
    1416       18609 :         while (cnt > 0) {
    1417        7079 :                 g = mat[g].pm;
    1418        7079 :                 cnt--;
    1419             :         }
    1420        3954 :         return g;
    1421             : }
    1422             : 
    1423             : static int
    1424        3813 : group_by_ext(matlist_t *ml, int g)
    1425             : {
    1426        3813 :         int i;
    1427             : 
    1428       15202 :         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       69901 :         for (k = 1; k < mat[a].mi->argc; k++) {
    1457       62441 :                 InstrPtr q = copyInstruction(p);
    1458       62441 :                 if (!q) {
    1459           0 :                         freeInstruction(ai1);
    1460           0 :                         return -1;
    1461             :                 }
    1462             : 
    1463       62441 :                 getArg(q, 0) = newTmpVariable(mb, tp);
    1464       62441 :                 getArg(q, 1) = getArg(mat[e].mi, k);
    1465       62441 :                 getArg(q, 2) = getArg(mat[a].mi, k);
    1466       62441 :                 pushInstruction(mb, q);
    1467       62441 :                 if (mb->errors) {
    1468           0 :                         freeInstruction(ai1);
    1469           0 :                         return -1;
    1470             :                 }
    1471       62441 :                 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       62441 :                 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        3410 : mat_group_aggr(MalBlkPtr mb, InstrPtr p, mat_t *mat, int b, int g, int e)
    1497             : {
    1498        3410 :         int tp = getArgType(mb, p, 0), k, tp2 = 0, tpe = getBatType(tp);
    1499        3410 :         const char *aggr2 = aggr_phase2(getFunctionId(p), tpe == TYPE_dbl);
    1500        3410 :         int isAvg = (getFunctionId(p) == subavgRef);
    1501        3410 :         InstrPtr ai1 = newInstructionArgs(mb, matRef, packRef, mat[b].mi->argc),
    1502        3410 :                 ai10 = NULL, ai11 = NULL, ai2;
    1503             : 
    1504        3410 :         if (!ai1)
    1505             :                 return -1;
    1506             : 
    1507        3410 :         getArg(ai1, 0) = newTmpVariable(mb, tp);
    1508             : 
    1509        3410 :         if (mb->errors == NULL && isAvg) {                           /* remainders or counts */
    1510          50 :                 tp2 = newBatType(TYPE_lng);
    1511          50 :                 ai10 = newInstructionArgs(mb, matRef, packRef, mat[b].mi->argc);
    1512          50 :                 if (!ai10) {
    1513           0 :                         freeInstruction(ai1);
    1514           0 :                         return -1;
    1515             :                 }
    1516          50 :                 getArg(ai10, 0) = newTmpVariable(mb, tp2);
    1517             :         }
    1518        3410 :         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       34183 :         for (k = 1; mb->errors == NULL && k < mat[b].mi->argc; k++) {
    1530       30773 :                 int off = 0;
    1531       30773 :                 InstrPtr q = copyInstructionArgs(p, p->argc + (isAvg && tpe == TYPE_dbl));
    1532       30773 :                 if (!q) {
    1533           0 :                         freeInstruction(ai1);
    1534           0 :                         freeInstruction(ai10);
    1535           0 :                         return -1;
    1536             :                 }
    1537             : 
    1538       30773 :                 getArg(q, 0) = newTmpVariable(mb, tp);
    1539       30773 :                 if (isAvg && tpe == TYPE_dbl) {
    1540         189 :                         off = 1;
    1541         189 :                         getArg(q, 1) = newTmpVariable(mb, tp2);
    1542         189 :                         q = pushArgument(mb, q, getArg(q, 1));  /* push at end, create space */
    1543         189 :                         q->retc = 2;
    1544         189 :                         getArg(q, q->argc - 1) = getArg(q, q->argc - 2);
    1545         189 :                         getArg(q, q->argc - 2) = getArg(q, q->argc - 3);
    1546       30584 :                 } 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       30773 :                 getArg(q, 1 + off) = getArg(mat[b].mi, k);
    1552       30773 :                 getArg(q, 2 + off) = getArg(mat[g].mi, k);
    1553       30773 :                 getArg(q, 3 + off) = getArg(mat[e].mi, k);
    1554       30773 :                 pushInstruction(mb, q);
    1555             : 
    1556             :                 /* pack the result into a mat */
    1557       30773 :                 ai1 = pushArgument(mb, ai1, getArg(q, 0));
    1558       30773 :                 if (isAvg)
    1559         341 :                         ai10 = pushArgument(mb, ai10, getArg(q, 1));
    1560       30773 :                 if (isAvg && tpe != TYPE_dbl)
    1561         152 :                         ai11 = pushArgument(mb, ai11, getArg(q, 2));
    1562             :         }
    1563        3410 :         pushInstruction(mb, ai1);
    1564        3410 :         if (isAvg)
    1565          50 :                 pushInstruction(mb, ai10);
    1566        3410 :         if (isAvg && tpe != TYPE_dbl)
    1567          19 :                 pushInstruction(mb, ai11);
    1568             : 
    1569             :         /* for avg we do sum (avg*(count/sumcount) ) */
    1570        3410 :         if (mb->errors == NULL && isAvg && tpe == TYPE_dbl) {
    1571          31 :                 InstrPtr r, s, v, w, cond;
    1572             : 
    1573             :                 /* lng s = sum counts */
    1574          31 :                 s = newInstruction(mb, aggrRef, subsumRef);
    1575          31 :                 if (s == NULL)
    1576             :                         return -1;
    1577          31 :                 getArg(s, 0) = newTmpVariable(mb, tp2);
    1578          31 :                 s = pushArgument(mb, s, getArg(ai10, 0));
    1579          31 :                 s = pushArgument(mb, s, mat[g].mv);
    1580          31 :                 s = pushArgument(mb, s, mat[e].mv);
    1581          31 :                 s = pushBit(mb, s, 1);  /* skip nils */
    1582          31 :                 pushInstruction(mb, s);
    1583             : 
    1584             :                 /*  w=count = ifthenelse(s=count==0,NULL,s=count)  */
    1585          31 :                 cond = newInstruction(mb, batcalcRef, eqRef);
    1586          31 :                 if (cond == NULL)
    1587             :                         return -1;
    1588          31 :                 getArg(cond, 0) = newTmpVariable(mb, newBatType(TYPE_bit));
    1589          31 :                 cond = pushArgument(mb, cond, getArg(s, 0));
    1590          31 :                 cond = pushLng(mb, cond, 0);
    1591          31 :                 pushInstruction(mb, cond);
    1592             : 
    1593          31 :                 w = newInstruction(mb, batcalcRef, ifthenelseRef);
    1594          31 :                 if (w == NULL)
    1595             :                         return -1;
    1596          31 :                 getArg(w, 0) = newTmpVariable(mb, tp2);
    1597          31 :                 w = pushArgument(mb, w, getArg(cond, 0));
    1598          31 :                 w = pushNil(mb, w, TYPE_lng);
    1599          31 :                 w = pushArgument(mb, w, getArg(s, 0));
    1600          31 :                 pushInstruction(mb, w);
    1601             : 
    1602             :                 /* fetchjoin with groups */
    1603          31 :                 r = newInstruction(mb, algebraRef, projectionRef);
    1604          31 :                 if (r == NULL)
    1605             :                         return -1;
    1606          31 :                 getArg(r, 0) = newTmpVariable(mb, tp2);
    1607          31 :                 r = pushArgument(mb, r, mat[g].mv);
    1608          31 :                 r = pushArgument(mb, r, getArg(w, 0));
    1609          31 :                 pushInstruction(mb, r);
    1610          31 :                 s = r;
    1611             : 
    1612             :                 /* dbl v = double(count) */
    1613          31 :                 v = newInstruction(mb, batcalcRef, dblRef);
    1614          31 :                 if (v == NULL)
    1615             :                         return -1;
    1616          31 :                 getArg(v, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
    1617          31 :                 v = pushArgument(mb, v, getArg(ai10, 0));
    1618          31 :                 pushInstruction(mb, v);
    1619             : 
    1620             :                 /* dbl r = v / s */
    1621          31 :                 r = newInstruction(mb, batcalcRef, divRef);
    1622          31 :                 if (r == NULL)
    1623             :                         return -1;
    1624          31 :                 getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_dbl));
    1625          31 :                 r = pushArgument(mb, r, getArg(v, 0));
    1626          31 :                 r = pushArgument(mb, r, getArg(s, 0));
    1627          31 :                 if (isaBatType(getArgType(mb, v, 0)))
    1628          31 :                         r = pushNilBat(mb, r);
    1629          31 :                 if (isaBatType(getArgType(mb, s, 0)))
    1630          31 :                         r = pushNilBat(mb, r);
    1631          31 :                 pushInstruction(mb, r);
    1632             : 
    1633             :                 /* dbl s = avg * r */
    1634          31 :                 s = newInstruction(mb, batcalcRef, mulRef);
    1635          31 :                 if (s == NULL)
    1636             :                         return -1;
    1637          31 :                 getArg(s, 0) = newTmpVariable(mb, tp);
    1638          31 :                 s = pushArgument(mb, s, getArg(ai1, 0));
    1639          31 :                 s = pushArgument(mb, s, getArg(r, 0));
    1640          31 :                 if (isaBatType(getArgType(mb, ai1, 0)))
    1641          31 :                         s = pushNilBat(mb, s);
    1642          31 :                 if (isaBatType(getArgType(mb, r, 0)))
    1643          31 :                         s = pushNilBat(mb, s);
    1644          31 :                 pushInstruction(mb, s);
    1645             : 
    1646          31 :                 ai1 = s;
    1647             :         }
    1648        3410 :         ai2 = newInstruction(mb, aggrRef, aggr2);
    1649        3410 :         if (ai2 == NULL)
    1650             :                 return -1;
    1651        3410 :         getArg(ai2, 0) = getArg(p, 0);
    1652        3410 :         if (isAvg && tpe != TYPE_dbl) {
    1653          19 :                 getArg(ai2, 1) = getArg(p, 1);
    1654          19 :                 getArg(ai2, 2) = getArg(p, 2);
    1655             :         }
    1656        3410 :         ai2 = pushArgument(mb, ai2, getArg(ai1, 0));
    1657        3410 :         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        3410 :         ai2 = pushArgument(mb, ai2, mat[g].mv);
    1662        3410 :         ai2 = pushArgument(mb, ai2, mat[e].mv);
    1663        3410 :         ai2 = pushBit(mb, ai2, 1);      /* skip nils */
    1664        3410 :         pushInstruction(mb, ai2);
    1665        3410 :         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        4954 : mat_pack_group(MalBlkPtr mb, matlist_t *ml, int g)
    1675             : {
    1676        4954 :         mat_t *mat = ml->v;
    1677        4954 :         int cnt = chain_by_length(mat, g), i;
    1678        4954 :         InstrPtr cur = NULL;
    1679             : 
    1680       12530 :         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       15152 :                 InstrPtr grp = newInstruction(mb, groupRef,
    1683        2622 :                                                                           cur ? i ? subgroupRef : subgroupdoneRef : i ?
    1684        4954 :                                                                           groupRef : groupdoneRef);
    1685        7576 :                 if (grp == NULL)
    1686             :                         return -1;
    1687       15152 :                 int ogrp = walk_n_back(mat, g, i);
    1688        7576 :                 int oext = group_by_ext(ml, ogrp);
    1689        7576 :                 int attr = mat[oext].im;
    1690             : 
    1691        7576 :                 getArg(grp, 0) = mat[ogrp].mv;
    1692        7576 :                 grp = pushReturn(mb, grp, mat[oext].mv);
    1693        7576 :                 grp = pushReturn(mb, grp, newTmpVariable(mb, newBatType(TYPE_lng)));
    1694        7576 :                 grp = pushArgument(mb, grp, getArg(mat[attr].mi, 0));
    1695        7576 :                 if (cur)
    1696        2622 :                         grp = pushArgument(mb, grp, getArg(cur, 0));
    1697        7576 :                 pushInstruction(mb, grp);
    1698        7576 :                 cur = grp;
    1699        7576 :                 if (mb->errors)
    1700             :                         return -1;
    1701             :         }
    1702        4954 :         mat[g].im = -1;                         /* only pack once */
    1703        4954 :         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        2622 : mat_group_attr(MalBlkPtr mb, matlist_t *ml, int g, InstrPtr cext, int push)
    1713             : {
    1714        2622 :         int cnt = chain_by_length(ml->v, g), i;      /* number of attributes */
    1715             :         int ogrp = g;                           /* previous group */
    1716             : 
    1717        6435 :         for (i = 0; i < cnt; i++) {
    1718        3813 :                 int agrp = walk_n_back(ml->v, ogrp, i);
    1719        3813 :                 int b = ml->v[agrp].im;
    1720        3813 :                 int aext = group_by_ext(ml, agrp);
    1721        3813 :                 int a = ml->v[aext].im;
    1722        3813 :                 int atp = getArgType(mb, ml->v[a].mi, 0), k;
    1723        3813 :                 InstrPtr attr = newInstructionArgs(mb, matRef, packRef, ml->v[a].mi->argc);
    1724        3813 :                 if (attr == NULL) {
    1725             :                         return -1;
    1726             :                 }
    1727             : 
    1728             :                 //getArg(attr,0) = newTmpVariable(mb, atp);
    1729        3813 :                 getArg(attr, 0) = getArg(ml->v[b].mi, 0);
    1730             : 
    1731       33618 :                 for (k = 1; mb->errors == NULL && k < ml->v[a].mi->argc; k++) {
    1732       29805 :                         InstrPtr r = newInstruction(mb, algebraRef, projectionRef);
    1733       29805 :                         InstrPtr q = newInstruction(mb, algebraRef, projectionRef);
    1734       29805 :                         if (r == NULL || q == NULL) {
    1735           0 :                                 freeInstruction(attr);
    1736           0 :                                 freeInstruction(r);
    1737           0 :                                 freeInstruction(q);
    1738           0 :                                 return -1;
    1739             :                         }
    1740             : 
    1741       29805 :                         getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
    1742       29805 :                         r = pushArgument(mb, r, getArg(cext, k));
    1743       29805 :                         r = pushArgument(mb, r, getArg(ml->v[ogrp].mi, k));
    1744       29805 :                         pushInstruction(mb, r);
    1745             : 
    1746       29805 :                         getArg(q, 0) = newTmpVariable(mb, atp);
    1747       29805 :                         q = pushArgument(mb, q, getArg(r, 0));
    1748       29805 :                         q = pushArgument(mb, q, getArg(ml->v[a].mi, k));
    1749       29805 :                         pushInstruction(mb, q);
    1750             : 
    1751       29805 :                         attr = pushArgument(mb, attr, getArg(q, 0));
    1752             :                 }
    1753        3813 :                 if (push)
    1754        2622 :                         pushInstruction(mb, attr);
    1755        3813 :                 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        3813 :                 ml->v[aext].im = ml->top - 1;
    1763             :         }
    1764             :         return 0;
    1765             : }
    1766             : 
    1767             : static int
    1768        4954 : mat_group_new(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int b)
    1769             : {
    1770        4954 :         int tp0 = getArgType(mb, p, 0);
    1771        4954 :         int tp1 = getArgType(mb, p, 1);
    1772        4954 :         int tp2 = getArgType(mb, p, 2);
    1773        4954 :         int atp = getArgType(mb, p, 3), i, a, g, push = 0;
    1774        4954 :         InstrPtr r0, r1, r2, attr;
    1775             : 
    1776        4954 :         if (getFunctionId(p) == subgroupdoneRef || getFunctionId(p) == groupdoneRef)
    1777        2772 :                 push = 1;
    1778             : 
    1779        4954 :         r0 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1780        4954 :         if (r0 == NULL)
    1781             :                 return -1;
    1782        4954 :         getArg(r0, 0) = newTmpVariable(mb, tp0);
    1783             : 
    1784        4954 :         r1 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1785        4954 :         if (r1 == NULL) {
    1786           0 :                 freeInstruction(r0);
    1787           0 :                 return -1;
    1788             :         }
    1789        4954 :         getArg(r1, 0) = newTmpVariable(mb, tp1);
    1790             : 
    1791        4954 :         r2 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1792        4954 :         if (r2 == NULL) {
    1793           0 :                 freeInstruction(r0);
    1794           0 :                 freeInstruction(r1);
    1795           0 :                 return -1;
    1796             :         }
    1797        4954 :         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        4954 :         attr = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1802        4954 :         if (attr == NULL) {
    1803           0 :                 freeInstruction(r0);
    1804           0 :                 freeInstruction(r1);
    1805           0 :                 freeInstruction(r2);
    1806           0 :                 return -1;
    1807             :         }
    1808        4954 :         getArg(attr, 0) = getArg(ml->v[b].mi, 0);
    1809             : 
    1810       47433 :         for (i = 1; mb->errors == NULL && i < ml->v[b].mi->argc; i++) {
    1811       42479 :                 InstrPtr q = copyInstruction(p), r;
    1812       42479 :                 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       42479 :                 getArg(q, 0) = newTmpVariable(mb, tp0);
    1821       42479 :                 getArg(q, 1) = newTmpVariable(mb, tp1);
    1822       42479 :                 getArg(q, 2) = newTmpVariable(mb, tp2);
    1823       42479 :                 getArg(q, 3) = getArg(ml->v[b].mi, i);
    1824       42479 :                 pushInstruction(mb, q);
    1825       42479 :                 if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 0), i)
    1826       42479 :                         || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 1), i)
    1827       42479 :                         || 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       42479 :                 r0 = pushArgument(mb, r0, getArg(q, 0));
    1837       42479 :                 r1 = pushArgument(mb, r1, getArg(q, 1));
    1838       42479 :                 r2 = pushArgument(mb, r2, getArg(q, 2));
    1839             : 
    1840       42479 :                 r = newInstruction(mb, algebraRef, projectionRef);
    1841       42479 :                 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       42479 :                 getArg(r, 0) = newTmpVariable(mb, atp);
    1849       42479 :                 r = pushArgument(mb, r, getArg(q, 1));
    1850       42479 :                 r = pushArgument(mb, r, getArg(ml->v[b].mi, i));
    1851       42479 :                 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       42479 :                 pushInstruction(mb, r);
    1860             : 
    1861       42479 :                 attr = pushArgument(mb, attr, getArg(r, 0));
    1862             :         }
    1863        4954 :         pushInstruction(mb, r0);
    1864        4954 :         pushInstruction(mb, r1);
    1865        4954 :         pushInstruction(mb, r2);
    1866        4954 :         if (push)
    1867        2772 :                 pushInstruction(mb, attr);
    1868             : 
    1869             :         /* create mat's for the intermediates */
    1870        4954 :         a = ml->top;
    1871        4954 :         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        4954 :         g = ml->top;
    1878        4954 :         if (mat_add_var(ml, r0, p, getArg(p, 0), mat_grp, b, -1, 1)
    1879        4954 :                 || mat_add_var(ml, r1, p, getArg(p, 1), mat_ext, a, ml->top - 1, 1)  /* point back at group */
    1880        4954 :                 || 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        4954 :         if (push)
    1883        2772 :                 return mat_pack_group(mb, ml, g);
    1884             :         return 0;
    1885             : }
    1886             : 
    1887             : static int
    1888        2622 : mat_group_derive(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int b, int g)
    1889             : {
    1890        2622 :         int tp0 = getArgType(mb, p, 0);
    1891        2622 :         int tp1 = getArgType(mb, p, 1);
    1892        2622 :         int tp2 = getArgType(mb, p, 2);
    1893        2622 :         int atp = getArgType(mb, p, 3), i, a, push = 0;
    1894        2622 :         InstrPtr r0, r1, r2, attr;
    1895             : 
    1896        2622 :         if (getFunctionId(p) == subgroupdoneRef || getFunctionId(p) == groupdoneRef)
    1897        2182 :                 push = 1;
    1898             : 
    1899        2622 :         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        2622 :         r0 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1908        2622 :         if (r0 == NULL)
    1909             :                 return -1;
    1910        2622 :         getArg(r0, 0) = newTmpVariable(mb, tp0);
    1911             : 
    1912        2622 :         r1 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1913        2622 :         if (r1 == NULL) {
    1914           0 :                 freeInstruction(r0);
    1915           0 :                 return -1;
    1916             :         }
    1917        2622 :         getArg(r1, 0) = newTmpVariable(mb, tp1);
    1918             : 
    1919        2622 :         r2 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1920        2622 :         if (r2 == NULL) {
    1921           0 :                 freeInstruction(r0);
    1922           0 :                 freeInstruction(r1);
    1923           0 :                 return -1;
    1924             :         }
    1925        2622 :         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        2622 :         attr = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1930        2622 :         if (attr == NULL) {
    1931           0 :                 freeInstruction(r0);
    1932           0 :                 freeInstruction(r1);
    1933           0 :                 freeInstruction(r2);
    1934           0 :                 return -1;
    1935             :         }
    1936        2622 :         getArg(attr, 0) = getArg(ml->v[b].mi, 0);
    1937             : 
    1938             :         /* we need overlapping ranges */
    1939       23069 :         for (i = 1; mb->errors == NULL && i < ml->v[b].mi->argc; i++) {
    1940       20447 :                 InstrPtr q = copyInstruction(p), r;
    1941       20447 :                 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       20447 :                 getArg(q, 0) = newTmpVariable(mb, tp0);
    1950       20447 :                 getArg(q, 1) = newTmpVariable(mb, tp1);
    1951       20447 :                 getArg(q, 2) = newTmpVariable(mb, tp2);
    1952       20447 :                 getArg(q, 3) = getArg(ml->v[b].mi, i);
    1953       20447 :                 getArg(q, 4) = getArg(ml->v[g].mi, i);
    1954       20447 :                 pushInstruction(mb, q);
    1955       20447 :                 if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 0), i)
    1956       20447 :                         || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 1), i)
    1957       20447 :                         || 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       20447 :                 r0 = pushArgument(mb, r0, getArg(q, 0));
    1967       20447 :                 r1 = pushArgument(mb, r1, getArg(q, 1));
    1968       20447 :                 r2 = pushArgument(mb, r2, getArg(q, 2));
    1969             : 
    1970       20447 :                 r = newInstruction(mb, algebraRef, projectionRef);
    1971       20447 :                 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       20447 :                 getArg(r, 0) = newTmpVariable(mb, atp);
    1979       20447 :                 r = pushArgument(mb, r, getArg(q, 1));
    1980       20447 :                 r = pushArgument(mb, r, getArg(ml->v[b].mi, i));
    1981       20447 :                 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       20447 :                 pushInstruction(mb, r);
    1990             : 
    1991       20447 :                 attr = pushArgument(mb, attr, getArg(r, 0));
    1992             :         }
    1993        2622 :         pushInstruction(mb, r0);
    1994        2622 :         pushInstruction(mb, r1);
    1995        2622 :         pushInstruction(mb, r2);
    1996        2622 :         if (push)
    1997        2182 :                 pushInstruction(mb, attr);
    1998             : 
    1999        2622 :         if (mb->errors || mat_group_attr(mb, ml, g, r1, push))
    2000           0 :                 return -1;
    2001             : 
    2002             :         /* create mat's for the intermediates */
    2003        2622 :         a = ml->top;
    2004        2622 :         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        2622 :         if (mat_add_var(ml, r0, p, getArg(p, 0), mat_grp, b, g, 1))
    2010             :                 return -1;
    2011        2622 :         g = ml->top - 1;
    2012        5244 :         if (mat_add_var(ml, r1, p, getArg(p, 1), mat_ext, a, ml->top - 1, 1) ||      /* point back at group */
    2013        2622 :                 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        2622 :         if (push)
    2016        2182 :                 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      499070 : OPTmergetableImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    2286             :                                                         InstrPtr pci)
    2287             : {
    2288      499070 :         InstrPtr p, *old;
    2289      499070 :         matlist_t ml;
    2290      499070 :         int oldtop, fm, fn, fo, fe, i, k, m, n, o, e, slimit, bailout = 0;
    2291      499070 :         int size = 0, match, actions = 0, distinct_topn = 0, /*topn_res = 0, */ groupdone = 0, *vars;   //, maxvars;
    2292      499070 :         char *group_input;
    2293      499070 :         str msg = MAL_SUCCEED;
    2294             : 
    2295      499070 :         if (isOptimizerUsed(mb, pci, mitosisRef) <= 0)
    2296       33785 :                 goto cleanup2;
    2297      465320 :         old = mb->stmt;
    2298      465320 :         oldtop = mb->stop;
    2299             : 
    2300      465320 :         vars = (int *) GDKmalloc(sizeof(int) * mb->vtop);
    2301             :         //maxvars = mb->vtop;
    2302      465315 :         group_input = (char *) GDKzalloc(sizeof(char) * mb->vtop);
    2303      465312 :         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    21422100 :         for (i = 1; i < oldtop && !bailout; i++) {
    2310    20956808 :                 int j;
    2311             : 
    2312    20956808 :                 p = old[i];
    2313             : 
    2314    42300335 :                 for (j = 0; j < p->retc; j++) {
    2315    21343527 :                         int res = getArg(p, j);
    2316    21343527 :                         vars[res] = i;
    2317             :                 }
    2318             : 
    2319             :                 /* pack if there is a group statement following a groupdone (ie aggr(distinct)) */
    2320    20956808 :                 if (getModuleId(p) == algebraRef && getFunctionId(p) == groupedfirstnRef)
    2321    20956808 :                                 groupdone = 1;
    2322    20956808 :                 if (getModuleId(p) == groupRef && p->argc == 5
    2323        5628 :                         && (getFunctionId(p) == subgroupRef
    2324        3812 :                                 || getFunctionId(p) == subgroupdoneRef
    2325           0 :                                 || getFunctionId(p) == groupRef
    2326           0 :                                 || getFunctionId(p) == groupdoneRef)) {
    2327        5628 :                         InstrPtr q = old[vars[getArg(p, p->argc - 1)]];      /* group result from a previous group(done) */
    2328             : 
    2329        5628 :                         if (getFunctionId(q) == subgroupdoneRef
    2330        5624 :                                 || getFunctionId(q) == groupdoneRef)
    2331    20956808 :                                 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    20956808 :                 if (getModuleId(p) == groupRef
    2335       26660 :                         && (getFunctionId(p) == subgroupRef
    2336       24844 :                                 || getFunctionId(p) == subgroupdoneRef
    2337       21032 :                                 || getFunctionId(p) == groupRef
    2338       17189 :                                 || getFunctionId(p) == groupdoneRef)) {
    2339       26660 :                         int input = getArg(p, p->retc);      /* argument one is first input */
    2340             : 
    2341       26660 :                         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       26660 :                         group_input[input] = 1;
    2348             :                 }
    2349    20956808 :                 if (getModuleId(p) == algebraRef && getFunctionId(p) == selectNotNilRef) {
    2350           0 :                         TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout not nil ref\n");
    2351             :                         bailout = 1;
    2352             :                 }
    2353    20956808 :                 if (getModuleId(p) == algebraRef && getFunctionId(p) == semijoinRef) {
    2354         185 :                         TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout semijoin ref\n");
    2355             :                         bailout = 1;
    2356             :                 }
    2357    20956808 :                 if (getModuleId(p) == algebraRef && getFunctionId(p) == thetajoinRef) {
    2358        2608 :                         assert(p->argc == 9);
    2359        2608 :                         if (p->argc == 9
    2360        2608 :                                 && getVarConstant(mb,
    2361             :                                                                   getArg(p,
    2362        2608 :                                                                                  6)).val.ival == 6 /* op == '<>' */ ) {
    2363           0 :                                 TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout thetajoin ref\n");
    2364             :                                 bailout = 1;
    2365             :                         }
    2366             :                 }
    2367    20956808 :                 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      465292 :         GDKfree(group_input);
    2378             : 
    2379      465276 :         ml.horigin = 0;
    2380      465276 :         ml.torigin = 0;
    2381      465276 :         ml.v = 0;
    2382      465276 :         ml.vars = 0;
    2383      465276 :         if (bailout)
    2384         320 :                 goto cleanup;
    2385             : 
    2386             :         /* the number of MATs is limited to the variable stack */
    2387      464956 :         ml.size = mb->vtop;
    2388      464956 :         ml.top = 0;
    2389      464956 :         ml.v = (mat_t *) GDKzalloc(ml.size * sizeof(mat_t));
    2390      465003 :         ml.vsize = mb->vsize;
    2391      465003 :         ml.horigin = (int *) GDKmalloc(sizeof(int) * ml.vsize);
    2392      464980 :         ml.torigin = (int *) GDKmalloc(sizeof(int) * ml.vsize);
    2393      464967 :         ml.vars = (int *) GDKmalloc(sizeof(int) * ml.vsize);
    2394      464985 :         if (ml.v == NULL || ml.horigin == NULL || ml.torigin == NULL
    2395      464985 :                 || ml.vars == NULL) {
    2396           0 :                 goto cleanup;
    2397             :         }
    2398   130253145 :         for (i = 0; i < ml.vsize; i++) {
    2399   129788160 :                 ml.horigin[i] = ml.torigin[i] = -1;
    2400   129788160 :                 ml.vars[i] = -1;
    2401             :         }
    2402             : 
    2403      464985 :         slimit = mb->ssize;
    2404      464985 :         size = (mb->stop * 1.2 < mb->ssize) ? mb->ssize : (int) (mb->stop * 1.2);
    2405      464985 :         mb->stmt = (InstrPtr *) GDKzalloc(size * sizeof(InstrPtr));
    2406      465003 :         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      465003 :         mb->ssize = size;
    2413      465003 :         mb->stop = 0;
    2414             : 
    2415     7447208 :         for (i = 0; i < oldtop; i++) {
    2416     7447208 :                 int bats = 0, nilbats = 0;
    2417     7447208 :                 InstrPtr r, cp;
    2418             : 
    2419     7447208 :                 p = old[i];
    2420             : 
    2421     7447208 :                 if (p->token == ENDsymbol)   /* don't copy the optimizer pipeline added after final instruction */
    2422             :                         break;
    2423     6982242 :                 if (getModuleId(p) == matRef
    2424      285605 :                         && (getFunctionId(p) == newRef || getFunctionId(p) == packRef)) {
    2425      263860 :                         if (mat_set_prop(&ml, mb, p)
    2426      263860 :                                 || 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      263860 :                         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     6718382 :                 if ((match = nr_of_mats(p, &ml)) == 0) {
    2440     5359681 :                         cp = copyInstruction(p);
    2441     5359615 :                         if (!cp) {
    2442           0 :                                 msg = createException(MAL, "optimizer.mergetable",
    2443             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2444           0 :                                 goto cleanup;
    2445             :                         }
    2446     5359615 :                         pushInstruction(mb, cp);
    2447     5359681 :                         continue;
    2448             :                 }
    2449     1358701 :                 bats = nr_of_bats(mb, p);
    2450     1358701 :                 nilbats = nr_of_nilbats(mb, p);
    2451             : 
    2452             :                 /* left joins can match at isMatJoinOp, so run this check beforehand */
    2453     1358701 :                 if (match > 0 && isMatLeftJoinOp(p) && p->argc >= 5 && p->retc == 2
    2454        2445 :                         && (match == 1 || match == 2) && bats + nilbats == 4) {
    2455        2445 :                         m = is_a_mat(getArg(p, p->retc), &ml);
    2456        2445 :                         o = is_a_mat(getArg(p, p->retc + 2), &ml);
    2457             : 
    2458        2445 :                         if ((match == 1 && m >= 0) || (match == 2 && m >= 0 && o >= 0)) {
    2459        2437 :                                 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        2437 :                                 actions++;
    2465        2437 :                                 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     1356264 :                 if (match > 0 && isMatJoinOp(p) && !isMatLeftJoinOp(p) && p->argc >= 5
    2475       58834 :                         && p->retc == 2 && bats + nilbats >= 4) {
    2476       51911 :                         if (bats + nilbats == 4) {
    2477       51853 :                                 m = is_a_mat(getArg(p, p->retc), &ml);
    2478       51853 :                                 n = is_a_mat(getArg(p, p->retc + 1), &ml);
    2479       51853 :                                 o = is_a_mat(getArg(p, p->retc + 2), &ml);
    2480       51853 :                                 e = is_a_mat(getArg(p, p->retc + 3), &ml);
    2481       51853 :                                 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          58 :                                 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          58 :                                 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       51911 :                         actions++;
    2503       51911 :                         continue;
    2504             :                 }
    2505     1304353 :                 if (match > 0 && getModuleId(p) == algebraRef
    2506     1001742 :                         && getFunctionId(p) == crossRef && p->argc == 5 && p->retc == 2
    2507        6923 :                         && bats == 2) {
    2508     1311276 :                         int max_one = (isVarConstant(mb, getArg(p, 4))
    2509        6923 :                                                    && getVarConstant(mb, getArg(p, 4)).val.btval);
    2510       10414 :                         if (!max_one) {
    2511        5207 :                                 m = is_a_mat(getArg(p, p->retc), &ml);
    2512        5207 :                                 n = is_a_mat(getArg(p, p->retc + 1), &ml);
    2513        5207 :                                 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        5207 :                                 actions++;
    2519        5207 :                                 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     1299146 :                 if (match == 1 && p->argc >= 2 &&
    2529        1742 :                         ((getModuleId(p) == aggrRef &&
    2530        1742 :                           (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        1640 :                         && (m = is_a_mat(getArg(p, p->retc + 0), &ml)) >= 0) {
    2536        1640 :                         if ((msg = mat_aggr(mb, p, ml.v, m)) != MAL_SUCCEED)
    2537           0 :                                 goto cleanup;
    2538        1640 :                         actions++;
    2539        1640 :                         continue;
    2540             :                 }
    2541             : 
    2542     1297506 :                 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     1297446 :                 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     1297446 :                 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     1297340 :                 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     1297305 :                 if (!groupdone && match == 1 && bats == 1 && p->argc == 4
    2589       15403 :                         && getModuleId(p) == groupRef &&
    2590        4954 :                         (getFunctionId(p) == subgroupRef
    2591        4954 :                          || getFunctionId(p) == subgroupdoneRef
    2592        4954 :                          || getFunctionId(p) == groupRef
    2593        2772 :                          || getFunctionId(p) == groupdoneRef)
    2594        4954 :                         && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
    2595        4954 :                         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        4954 :                         actions++;
    2601        4954 :                         continue;
    2602             :                 }
    2603     1292351 :                 if (!groupdone && match == 2 && bats == 2 && p->argc == 5
    2604       42877 :                         && getModuleId(p) == groupRef &&
    2605        2622 :                         (getFunctionId(p) == subgroupRef
    2606        2182 :                          || getFunctionId(p) == subgroupdoneRef
    2607           0 :                          || getFunctionId(p) == groupRef
    2608           0 :                          || getFunctionId(p) == groupdoneRef)
    2609        2622 :                         && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)
    2610        2622 :                         && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
    2611        2622 :                         && ml.v[n].im >= 0 /* not packed */ ) {
    2612        2622 :                         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        2622 :                         actions++;
    2618        2622 :                         continue;
    2619             :                 }
    2620             :                 /* TODO sub'aggr' with cand list */
    2621     1289729 :                 if (match == 3 && bats == 3 && getModuleId(p) == aggrRef && p->argc >= 4
    2622        3410 :                         && (getFunctionId(p) == subcountRef
    2623         483 :                                 || getFunctionId(p) == subminRef
    2624         430 :                                 || getFunctionId(p) == submaxRef
    2625         377 :                                 || getFunctionId(p) == subavgRef
    2626         327 :                                 || getFunctionId(p) == subsumRef
    2627           2 :                                 || getFunctionId(p) == subprodRef)
    2628        3410 :                         && ((m = is_a_mat(getArg(p, p->retc + 0), &ml)) >= 0)
    2629        3410 :                         && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
    2630        3410 :                         && ((o = is_a_mat(getArg(p, p->retc + 2), &ml)) >= 0)) {
    2631        3410 :                         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        3410 :                         actions++;
    2637        3410 :                         continue;
    2638             :                 }
    2639             :                 /* Handle cases of ext.projection and .projection(grp) */
    2640     1286319 :                 if (match == 2 && getModuleId(p) == algebraRef
    2641      808958 :                         && getFunctionId(p) == projectionRef
    2642      755114 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
    2643      755114 :                         && (n = is_a_mat(getArg(p, 2), &ml)) >= 0
    2644      755114 :                         && (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     1278859 :                 if (match == 1 && getModuleId(p) == algebraRef
    2664      187134 :                         && getFunctionId(p) == projectRef
    2665       29631 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
    2666       29631 :                         && (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     1278859 :                 if (match == 2 && getModuleId(p) == algebraRef
    2680      801498 :                         && getFunctionId(p) == projectionRef
    2681      747654 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
    2682      747654 :                         && (n = is_a_mat(getArg(p, 2), &ml)) >= 0
    2683      747654 :                         && (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     1278237 :                 if (match > 0
    2695     1278237 :                         &&
    2696     1278237 :                         ((getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef)
    2697      425367 :                          || ((getModuleId(p) == dictRef || getModuleId(p) == forRef)
    2698         130 :                                  && getFunctionId(p) == decompressRef))
    2699      852943 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0) {
    2700      839987 :                         n = is_a_mat(getArg(p, 2), &ml);
    2701      839987 :                         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      839987 :                         actions++;
    2707      839987 :                         continue;
    2708             :                 }
    2709             :                 /* Handle setops */
    2710      438250 :                 if (match > 0 && getModuleId(p) == algebraRef
    2711      148338 :                         && (getFunctionId(p) == differenceRef
    2712      129997 :                                 || getFunctionId(p) == intersectRef)
    2713       19829 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0) {
    2714       18501 :                         n = is_a_mat(getArg(p, 2), &ml);
    2715       18501 :                         o = is_a_mat(getArg(p, 3), &ml);
    2716       18501 :                         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       18501 :                         actions++;
    2722       18501 :                         continue;
    2723             :                 }
    2724             : 
    2725      419749 :                 if (match == p->retc && p->argc == (p->retc * 2)
    2726       18215 :                         && getFunctionId(p) == NULL) {
    2727           4 :                         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           4 :                         actions++;
    2733           4 :                         continue;
    2734             :                 }
    2735             : 
    2736      419745 :                 m = n = o = e = -1;
    2737      861509 :                 for (fm = p->argc - 1; fm >= p->retc; fm--)
    2738      861509 :                         if ((m = is_a_mat(getArg(p, fm), &ml)) >= 0)
    2739             :                                 break;
    2740             : 
    2741      519423 :                 for (fn = fm - 1; fn >= p->retc; fn--)
    2742      337998 :                         if ((n = is_a_mat(getArg(p, fn), &ml)) >= 0)
    2743             :                                 break;
    2744             : 
    2745      436839 :                 for (fo = fn - 1; fo >= p->retc; fo--)
    2746      164828 :                         if ((o = is_a_mat(getArg(p, fo), &ml)) >= 0)
    2747             :                                 break;
    2748             : 
    2749      449956 :                 for (fe = fo - 1; fe >= p->retc; fe--)
    2750       80769 :                         if ((e = is_a_mat(getArg(p, fe), &ml)) >= 0)
    2751             :                                 break;
    2752             : 
    2753             :                 /* delta* operator */
    2754      419745 :                 if (match == 3 && bats == 3 && isDelta(p)
    2755       63098 :                         && (m = is_a_mat(getArg(p, fm), &ml)) >= 0
    2756       63098 :                         && (n = is_a_mat(getArg(p, fn), &ml)) >= 0
    2757       63098 :                         && (o = is_a_mat(getArg(p, fo), &ml)) >= 0) {
    2758       63098 :                         if ((r = mat_delta(&ml, mb, p, ml.v, m, n, o, -1, fm, fn, fo, 0)) != NULL) {
    2759       63098 :                                 actions++;
    2760             :                         } else {
    2761           0 :                                 msg = createException(MAL, "optimizer.mergetable",
    2762             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2763           0 :                                 goto cleanup;
    2764             :                         }
    2765             : 
    2766       63098 :                         continue;
    2767             :                 }
    2768      356647 :                 if (match == 4 && bats == 4 && isDelta(p)
    2769       46119 :                         && (m = is_a_mat(getArg(p, fm), &ml)) >= 0
    2770       46119 :                         && (n = is_a_mat(getArg(p, fn), &ml)) >= 0
    2771       46119 :                         && (o = is_a_mat(getArg(p, fo), &ml)) >= 0
    2772       46119 :                         && (e = is_a_mat(getArg(p, fe), &ml)) >= 0) {
    2773       46119 :                         if ((r = mat_delta(&ml, mb, p, ml.v, m, n, o, e, fm, fn, fo, fe)) != NULL) {
    2774       46119 :                                 actions++;
    2775             :                         } else {
    2776           0 :                                 msg = createException(MAL, "optimizer.mergetable",
    2777             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2778           0 :                                 goto cleanup;
    2779             :                         }
    2780       46119 :                         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      310528 :                 if (match == 1 && fm == 1 && isSelect(p) && p->retc == 1
    2802       40151 :                         && (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      310524 :                 if ((match == 1 || match == bats - 1) && p->retc == 1 && isSelect(p)
    2817       40200 :                         && 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      310475 :                 if (match == 1 && match == bats - 1 && p->retc == 1
    2828       53569 :                         && 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      310471 :                 if (match == bats && p->retc == 1
    2839      228762 :                         && (isMap2Op(p) || isMapOp(p) || isFragmentGroup(p)
    2840       35847 :                                 || isFragmentGroup2(p))) {
    2841      225539 :                         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      225539 :                         actions++;
    2847      225539 :                         continue;
    2848             :                 }
    2849             : 
    2850             :                 /*
    2851             :                  * All other instructions should be checked for remaining MAT dependencies.
    2852             :                  * It requires MAT materialization.
    2853             :                  */
    2854             : 
    2855      447899 :                 for (k = p->retc; msg == MAL_SUCCEED && k < p->argc; k++) {
    2856      362967 :                         if ((m = is_a_mat(getArg(p, k), &ml)) >= 0) {
    2857      134283 :                                 msg = mat_pack(mb, &ml, m);
    2858      134283 :                                 if (msg)
    2859             :                                         break;
    2860             :                         }
    2861             :                 }
    2862       84932 :                 if (msg)
    2863             :                         break;
    2864             : 
    2865       84932 :                 cp = copyInstruction(p);
    2866       84932 :                 if (!cp) {
    2867           0 :                         msg = createException(MAL, "optimizer.mergetable",
    2868             :                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2869           0 :                         goto cleanup;
    2870             :                 }
    2871       84932 :                 pushInstruction(mb, cp);
    2872             :         }
    2873             :         (void) stk;
    2874             : 
    2875    14876334 :         for (; i < oldtop; i++) {    /* add optimizer pipeline back again */
    2876    14411344 :                 pushInstruction(mb, old[i]);
    2877             :         }
    2878             : 
    2879      464990 :         if (mb->errors == MAL_SUCCEED) {
    2880     7447251 :                 for (i = 0; i < slimit; i++) {
    2881     7447251 :                         if (old[i] && old[i]->token == ENDsymbol)    /* don't free optimizer calls */
    2882             :                                 break;
    2883     6982260 :                         freeInstruction(old[i]);
    2884             :                 }
    2885      464991 :                 GDKfree(old);
    2886             :         }
    2887     2075621 :         for (i = 0; i < ml.top; i++) {
    2888     1610632 :                 if (ml.v[i].mi && !ml.v[i].pushed)
    2889     1316468 :                         freeInstruction(ml.v[i].mi);
    2890             :         }
    2891      464989 :   cleanup:
    2892      465309 :         if (vars)
    2893      465309 :                 GDKfree(vars);
    2894      465322 :         if (ml.v)
    2895      465002 :                 GDKfree(ml.v);
    2896      465324 :         if (ml.horigin)
    2897      465004 :                 GDKfree(ml.horigin);
    2898      465318 :         if (ml.torigin)
    2899      464998 :                 GDKfree(ml.torigin);
    2900      465323 :         if (ml.vars)
    2901      465003 :                 GDKfree(ml.vars);
    2902      465318 :         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      465318 :         if (actions > 0 && msg == MAL_SUCCEED) {
    2909       31476 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
    2910       31476 :                 if (!msg)
    2911       31476 :                         msg = chkFlow(mb);
    2912       31476 :                 if (!msg)
    2913       31476 :                         msg = chkDeclarations(mb);
    2914             :         }
    2915      433842 :   cleanup2:
    2916             :         /* keep actions taken as a fake argument */
    2917      499103 :         if (msg == MAL_SUCCEED) {
    2918      499091 :                 (void) pushInt(mb, pci, actions);
    2919      499153 :                 msg = mb->errors;            /* may well be NULL */
    2920      499153 :                 mb->errors = NULL;
    2921             :         }
    2922             : 
    2923             : #ifndef NDEBUG
    2924      499165 :         if (bailout)
    2925         320 :                 TRC_INFO(MAL_OPTIMIZER, "Merge table bailout\n");
    2926             : #endif
    2927             :         return msg;
    2928             : }

Generated by: LCOV version 1.14