LCOV - code coverage report
Current view: top level - monetdb5/optimizer - opt_mergetable.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1357 1865 72.8 %
Date: 2024-12-19 20:05:57 Functions: 35 37 94.6 %

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

Generated by: LCOV version 1.14