LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_mergetable.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1356 1819 74.5 %
Date: 2024-04-26 00:35:57 Functions: 35 36 97.2 %

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

Generated by: LCOV version 1.14