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-11-15 19:37:45 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      299541 :         mat_type_t type = mat_none;
      52             :         (void) mat;
      53             :         (void) n;
      54             :         return type;
      55             : }
      56             : 
      57             : static inline int
      58    28047597 : is_a_mat(int idx, const matlist_t *ml)
      59             : {
      60    28047597 :         if (ml->vars[idx] >= 0 && !ml->v[ml->vars[idx]].packed)
      61     8525784 :                 return ml->vars[idx];
      62             :         return -1;
      63             : }
      64             : 
      65             : static int
      66     5380744 : nr_of_mats(InstrPtr p, const matlist_t *ml)
      67             : {
      68     5380744 :         int j, cnt = 0;
      69    25979818 :         for (j = p->retc; j < p->argc; j++)
      70    20599074 :                 if (is_a_mat(getArg(p, j), ml) >= 0)
      71     2418755 :                         cnt++;
      72     5380744 :         return cnt;
      73             : }
      74             : 
      75             : static int
      76     1264089 : nr_of_bats(MalBlkPtr mb, InstrPtr p)
      77             : {
      78     1264089 :         int j, cnt = 0;
      79     4660029 :         for (j = p->retc; j < p->argc; j++)
      80     3395940 :                 if (isaBatType(getArgType(mb, p, j))
      81     2900363 :                         && !isVarConstant(mb, getArg(p, j)))
      82     2694625 :                         cnt++;
      83     1264089 :         return cnt;
      84             : }
      85             : 
      86             : static int
      87     1264089 : nr_of_nilbats(MalBlkPtr mb, InstrPtr p)
      88             : {
      89     1264089 :         int j, cnt = 0;
      90     4660029 :         for (j = p->retc; j < p->argc; j++)
      91     3395940 :                 if (isaBatType(getArgType(mb, p, j))
      92     3395940 :                                 && isVarConstant(mb, getArg(p, j))
      93      205738 :                                 && getVarConstant(mb, getArg(p, j)).val.bval == bat_nil)
      94      205738 :                         cnt++;
      95     1264089 :         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     1477231 : 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     1477231 :         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     1477231 :         mat_t *dst = &ml->v[ml->top];
     115     1477231 :         dst->mi = q;
     116     1477231 :         dst->org = p;
     117     1477231 :         dst->mv = var;
     118     1477231 :         dst->type = type;
     119     1477231 :         dst->im = inputmat;
     120     1477231 :         dst->pm = parentmat;
     121     1477231 :         dst->packed = 0;
     122     1477231 :         dst->pushed = pushed;
     123     1477231 :         if (ml->vars[var] < 0 || dst->type != mat_ext) {
     124     1466965 :                 if (ml->vars[var] >= 0) {
     125           0 :                         ml->v[ml->vars[var]].packed = 1;
     126             :                 }
     127     1466965 :                 ml->vars[var] = ml->top;
     128             :         }
     129     1477231 :         ++ml->top;
     130     1477231 :         return 0;
     131             : }
     132             : 
     133             : inline static int
     134      942754 : mat_add(matlist_t *ml, InstrPtr q, mat_type_t type, const char *func)
     135             : {
     136      942754 :         (void) func;
     137             :         //printf (" ml.top %d %s\n", ml.top, func);
     138      942754 :         return mat_add_var(ml, q, NULL, getArg(q, 0), type, -1, -1, 0);
     139             : }
     140             : 
     141             : static void
     142      116765 : matlist_pack(matlist_t *ml, int m)
     143             : {
     144      116765 :         int i, idx = ml->v[m].mv;
     145             : 
     146      116765 :         assert(ml->v[m].packed == 0);
     147      116765 :         ml->v[m].packed = 1;
     148      116765 :         ml->vars[idx] = -1;
     149             : 
     150    34271176 :         for (i = 0; i < ml->top; i++)
     151    34154411 :                 if (!ml->v[i].packed && ml->v[i].mv == idx) {
     152           0 :                         ml->vars[idx] = i;
     153           0 :                         break;
     154             :                 }
     155      116765 : }
     156             : 
     157             : static str
     158      116765 : mat_pack(MalBlkPtr mb, matlist_t *ml, int m)
     159             : {
     160      116765 :         InstrPtr r;
     161             : 
     162      116765 :         if (ml->v[m].packed)
     163             :                 return MAL_SUCCEED;
     164             : 
     165      116765 :         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      116765 :                 int l;
     177             : 
     178      116765 :                 r = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
     179      116765 :                 if (r == NULL) {
     180           0 :                         throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     181             :                 }
     182      116765 :                 getArg(r, 0) = getArg(ml->v[m].mi, 0);
     183      998579 :                 for (l = ml->v[m].mi->retc; l < ml->v[m].mi->argc; l++)
     184      881814 :                         r = pushArgument(mb, r, getArg(ml->v[m].mi, l));
     185      116765 :                 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      116765 :         matlist_pack(ml, m);
     193      116765 :         pushInstruction(mb, r);
     194      116765 :         return MAL_SUCCEED;
     195             : }
     196             : 
     197             : static int
     198    79164598 : checksize(matlist_t *ml, int v)
     199             : {
     200    79164598 :         if (v >= ml->vsize) {
     201       13167 :                 int sz = ml->vsize, i, *nhorigin, *ntorigin, *nvars;
     202             : 
     203       13167 :                 int nvsize = ml->vsize * 2;
     204       13167 :                 assert(v < nvsize);
     205       13167 :                 if (v >= nvsize)
     206             :                         nvsize = v + 10;
     207       13167 :                 nhorigin = (int *) GDKrealloc(ml->horigin, sizeof(int) * nvsize);
     208       13167 :                 if (nhorigin == NULL)
     209             :                         return -1;
     210       13167 :                 ml->horigin = nhorigin;
     211       13167 :                 ntorigin = (int *) GDKrealloc(ml->torigin, sizeof(int) * nvsize);
     212       13167 :                 if (ntorigin == NULL)
     213             :                         return -1;
     214       13167 :                 ml->torigin = ntorigin;
     215       13167 :                 nvars = (int *) GDKrealloc(ml->vars, sizeof(int) * nvsize);
     216       13167 :                 if (nvars == NULL)
     217             :                         return -1;
     218       13167 :                 ml->vars = nvars;
     219       13167 :                 ml->vsize = nvsize;
     220             : 
     221    15475055 :                 for (i = sz; i < ml->vsize; i++) {
     222    15461888 :                         ml->horigin[i] = ml->torigin[i] = -1;
     223    15461888 :                         ml->vars[i] = -1;
     224             :                 }
     225             :         }
     226             :         return 0;
     227             : }
     228             : 
     229             : static int
     230    10463690 : setPartnr(matlist_t *ml, int ivar, int ovar, int pnr)
     231             : {
     232    10463690 :         int tpnr = -1;
     233             : 
     234    10463690 :         if (checksize(ml, ivar) || checksize(ml, ovar))
     235           0 :                 return -1;
     236    10463690 :         if (ivar >= 0)
     237     6912078 :                 tpnr = ml->torigin[ivar];
     238     6912078 :         if (tpnr >= 0)
     239      373725 :                 ml->torigin[ovar] = tpnr;
     240    10463690 :         assert(ovar < ml->vsize);
     241    10463690 :         ml->horigin[ovar] = pnr;
     242             :         //printf("%d %d ", pnr, tpnr);
     243    10463690 :         return 0;
     244             : }
     245             : 
     246             : static int
     247      921328 : propagatePartnr(matlist_t *ml, int ivar, int ovar, int pnr)
     248             : {
     249             :         /* prop head ids to tail */
     250      921328 :         int tpnr = -1;
     251             : 
     252      921328 :         if (checksize(ml, ivar) || checksize(ml, ovar))
     253           0 :                 return -1;
     254      921328 :         if (ivar >= 0)
     255      921328 :                 tpnr = ml->horigin[ivar];
     256      921328 :         if (tpnr >= 0)
     257      500926 :                 ml->torigin[ovar] = tpnr;
     258      921328 :         assert(ovar < ml->vsize);
     259      921328 :         ml->horigin[ovar] = pnr;
     260             :         //printf("%d %d ", pnr, tpnr);
     261      921328 :         return 0;
     262             : }
     263             : 
     264             : static int
     265      664972 : propagateMirror(matlist_t *ml, int ivar, int ovar)
     266             : {
     267             :         /* prop head ids to head and tail */
     268      664972 :         int tpnr;
     269             : 
     270      664972 :         if (checksize(ml, ivar) || checksize(ml, ovar))
     271           0 :                 return -1;
     272      664972 :         tpnr = ml->horigin[ivar];
     273      664972 :         if (tpnr >= 0) {
     274      664972 :                 assert(ovar < ml->vsize);
     275      664972 :                 ml->horigin[ovar] = tpnr;
     276      664972 :                 ml->torigin[ovar] = tpnr;
     277             :         }
     278             :         return 0;
     279             : }
     280             : 
     281             : static int
     282    27532309 : overlap(matlist_t *ml, int lv, int rv, int lnr, int rnr, int ontails)
     283             : {
     284    27532309 :         int lpnr, rpnr;
     285             : 
     286    27532309 :         if (checksize(ml, lv) || checksize(ml, rv))
     287           0 :                 return -1;
     288    27532309 :         lpnr = ml->torigin[lv];
     289    27532309 :         rpnr = (ontails) ? ml->torigin[rv] : ml->horigin[rv];
     290             : 
     291    27532309 :         if (lpnr < 0 && rpnr < 0)
     292           0 :                 return lnr == rnr;
     293    27532309 :         if (rpnr < 0)
     294      567609 :                 return lpnr == rnr;
     295    26964700 :         if (lpnr < 0)
     296     2637715 :                 return rpnr == lnr;
     297    24326985 :         return lpnr == rpnr;
     298             : }
     299             : 
     300             : static int
     301      216584 : mat_set_prop(matlist_t *ml, MalBlkPtr mb, InstrPtr p)
     302             : {
     303      216584 :         int k, tpe = getArgType(mb, p, 0);
     304             : 
     305      216584 :         tpe = getBatType(tpe);
     306     1778854 :         for (k = 1; k < p->argc; k++) {
     307     1562270 :                 if (setPartnr(ml, -1, getArg(p, k), k))
     308             :                         return -1;
     309     1562270 :                 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       87395 : 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       87395 :         int tpe, k, j, is_subdelta = (getFunctionId(p) == subdeltaRef),
     320       87395 :                 is_projectdelta = (getFunctionId(p) == projectdeltaRef);
     321       87395 :         InstrPtr r = NULL;
     322       87395 :         int pushed = 0;
     323             : 
     324             :         //printf("# %s.%s(%d,%d,%d,%d)", getModuleId(p), getFunctionId(p), m, n, o, e);
     325             : 
     326       87395 :         if ((r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
     327             :                 return NULL;
     328       87395 :         getArg(r, 0) = getArg(p, 0);
     329       87395 :         tpe = getArgType(mb, p, 0);
     330             : 
     331             :         /* Handle like mat_projection, ie overlapping partitions */
     332       87395 :         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      652296 :                 for (k = 1; k < mat[m].mi->argc; k++) {
     371      564901 :                         InstrPtr q = copyInstruction(p);
     372      564901 :                         if (!q) {
     373           0 :                                 freeInstruction(r);
     374           0 :                                 return NULL;
     375             :                         }
     376      564901 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
     377      564901 :                         getArg(q, mvar) = getArg(mat[m].mi, k);
     378      564901 :                         getArg(q, nvar) = getArg(mat[n].mi, k);
     379      564901 :                         getArg(q, ovar) = getArg(mat[o].mi, k);
     380      564901 :                         if (e >= 0)
     381      213470 :                                 getArg(q, evar) = getArg(mat[e].mi, k);
     382      564901 :                         pushInstruction(mb, q);
     383      564901 :                         if (mb->errors) {
     384           0 :                                 freeInstruction(r);
     385           0 :                                 return NULL;
     386             :                         }
     387      564901 :                         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      564901 :                         r = pushArgument(mb, r, getArg(q, 0));
     392             :                 }
     393       87395 :                 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       87395 :         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       87395 :         if (pushed)
     416           0 :                 matlist_pack(ml, ml->top - 1);
     417             :         return r;
     418             : }
     419             : 
     420             : static InstrPtr
     421           4 : mat_assign(MalBlkPtr mb, InstrPtr p, matlist_t *ml)
     422             : {
     423           4 :         InstrPtr r = NULL;
     424           4 :         mat_t *mat = ml->v;
     425             : 
     426          12 :         for (int i = 0; i < p->retc; i++) {
     427           8 :                 int m = is_a_mat(getArg(p, p->retc + i), ml);
     428           8 :                 assert(is_a_mat(getArg(p, i), ml) < 0 && m >= 0);
     429             : 
     430           8 :                 if ((r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
     431             :                         return NULL;
     432           8 :                 getArg(r, 0) = getArg(p, i);
     433          62 :                 for (int k = 1; k < mat[m].mi->argc; k++) {
     434             :                         /* reuse inputs of old mat */
     435          54 :                         r = pushArgument(mb, r, getArg(mat[m].mi, k));
     436          54 :                         if (setPartnr(ml, -1, getArg(mat[m].mi, k), k)) {
     437           0 :                                 freeInstruction(r);
     438           0 :                                 return NULL;
     439             :                         }
     440             :                 }
     441           8 :                 if (mat_add(ml, r, mat_none, getFunctionId(p))) {
     442           0 :                         freeInstruction(r);
     443           0 :                         return NULL;
     444             :                 }
     445             :         }
     446             :         return r;
     447             : }
     448             : 
     449             : static int
     450       13042 : mat_apply1(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int var)
     451             : {
     452       13042 :         int tpe, k, is_select = isSelect(p),
     453       13042 :                 is_mirror = (getFunctionId(p) == mirrorRef);
     454       26084 :         int is_identity = (getFunctionId(p) == identityRef
     455       13042 :                                            && getModuleId(p) == batcalcRef);
     456       13042 :         int ident_var = 0, is_assign = (getFunctionId(p) == NULL), n = 0;
     457       13042 :         InstrPtr r = NULL, q;
     458       13042 :         mat_t *mat = ml->v;
     459             : 
     460       13042 :         assert(!is_assign);
     461             : 
     462       13042 :         assert(p->retc == 1);
     463             : 
     464             :         /* Find the mat we overwrite */
     465       13042 :         if (is_assign) {
     466             :                 n = is_a_mat(getArg(p, 0), ml);
     467             :                 is_assign = (n >= 0);
     468             :         }
     469             : 
     470       13042 :         if (m < 0
     471       13042 :                 || (r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc)) == NULL)
     472           0 :                 return -1;
     473       13042 :         getArg(r, 0) = getArg(p, 0);
     474       13042 :         tpe = getArgType(mb, p, 0);
     475             : 
     476       13042 :         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      115569 :         for (k = 1; k < mat[m].mi->argc; k++) {
     493      102527 :                 int res = 0;
     494      102527 :                 if ((q = copyInstruction(p)) == NULL) {
     495           0 :                         freeInstruction(r);
     496           0 :                         return -1;
     497             :                 }
     498             : 
     499      102527 :                 if (is_assign)
     500             :                         getArg(q, 0) = getArg(mat[n].mi, k);
     501             :                 else
     502      102527 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
     503      102527 :                 if (is_identity)
     504           4 :                         getArg(q, 1) = newTmpVariable(mb, TYPE_oid);
     505      102527 :                 getArg(q, var +is_identity) = getArg(mat[m].mi, k);
     506      102527 :                 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      102527 :                 ident_var = getArg(q, 1);
     517      102527 :                 pushInstruction(mb, q);
     518      102527 :                 if (mb->errors) {
     519           0 :                         freeInstruction(r);
     520           0 :                         return -1;
     521             :                 }
     522      102527 :                 if (is_mirror || is_identity) {
     523      102495 :                         res = propagateMirror(ml, getArg(mat[m].mi, k), getArg(q, 0));
     524          32 :                 } else if (is_select)
     525          32 :                         res = propagatePartnr(ml, getArg(mat[m].mi, k), getArg(q, 0), k);
     526             :                 else
     527           0 :                         res = setPartnr(ml, -1, getArg(q, 0), k);
     528      102527 :                 if (res) {
     529           0 :                         freeInstruction(r);
     530           0 :                         return -1;
     531             :                 }
     532      102527 :                 r = pushArgument(mb, r, getArg(q, 0));
     533             :         }
     534       13042 :         if (mb->errors) {
     535           0 :                 freeInstruction(r);
     536           0 :                 return -1;
     537             :         }
     538       13042 :         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      212142 : mat_apply(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int nrmats)
     547             : {
     548      212142 :         int matvar[8], fargument[8], k, l, parts = 0;
     549             : 
     550      212142 :         if (nrmats == 1
     551      101329 :                 && ((getModuleId(p) == batcalcRef && getFunctionId(p) == identityRef)
     552      101328 :                         || (getModuleId(p) == batRef && getFunctionId(p) == mirrorRef)))
     553       13038 :                 return mat_apply1(mb, p, ml, is_a_mat(getArg(p, 1), ml), 1);
     554      199104 :         assert(nrmats <= 8);
     555             : 
     556      199104 :         assert(p->retc < p->argc);     /* i.e. matvar[0] gets initialized */
     557      891283 :         for (k = p->retc, l = 0; k < p->argc; k++) {
     558      692179 :                 int mv = is_a_mat(getArg(p, k), ml);
     559      692179 :                 if (mv >= 0) {
     560      340371 :                         matvar[l] = mv;
     561      340371 :                         fargument[l] = k;
     562      340371 :                         l++;
     563      340371 :                         if (parts == 0)
     564      199104 :                                 parts = ml->v[mv].mi->argc;
     565      340371 :                         if (parts != ml->v[mv].mi->argc)
     566             :                                 return -1;
     567             :                 }
     568             :         }
     569             : 
     570      199104 :         InstrPtr *r = (InstrPtr *) GDKmalloc(sizeof(InstrPtr) * p->retc);
     571      199104 :         if (!r)
     572             :                 return -1;
     573      398208 :         for (k = 0; k < p->retc; k++) {
     574      199104 :                 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      199104 :                 getArg(r[k], 0) = getArg(p, k);
     581             :         }
     582             : 
     583     1678920 :         for (k = 1; k < ml->v[matvar[0]].mi->argc; k++) {
     584     1479816 :                 int tpe;
     585     1479816 :                 InstrPtr q = copyInstruction(p);
     586     1479816 :                 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     2959632 :                 for (l = 0; l < p->retc; l++) {
     594     1479816 :                         tpe = getArgType(mb, p, l);
     595     1479816 :                         getArg(q, l) = newTmpVariable(mb, tpe);
     596             :                 }
     597     4032533 :                 for (l = 0; l < nrmats; l++)
     598     2552717 :                         getArg(q, fargument[l]) = getArg(ml->v[matvar[l]].mi, k);
     599     1479816 :                 pushInstruction(mb, q);
     600     4439448 :                 for (l = 0; l < p->retc; l++) {
     601     1479816 :                         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     1479816 :                         r[l] = pushArgument(mb, r[l], getArg(q, l));
     608             :                 }
     609     1479816 :                 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      398208 :         for (k = 0; k < p->retc; k++) {
     617      199104 :                 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      199104 :         GDKfree(r);
     626      199104 :         return 0;
     627             : }
     628             : 
     629             : 
     630             : static int
     631       17192 : mat_setop(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int o)
     632             : {
     633       17192 :         int tpe = getArgType(mb, p, 0), k, j;
     634       17192 :         mat_t *mat = ml->v;
     635       17192 :         InstrPtr r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
     636             : 
     637       17192 :         if (!r)
     638             :                 return -1;
     639             : 
     640       17192 :         getArg(r, 0) = getArg(p, 0);
     641             : 
     642             :         //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
     643       17192 :         assert(m >= 0 || n >= 0);
     644       17192 :         if (m >= 0 && n >= 0) {
     645       17035 :                 int nr = 1;
     646             : 
     647       17035 :                 assert(o < 0 || mat[m].mi->argc == mat[o].mi->argc);
     648             : 
     649      151342 :                 for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
     650      134307 :                         InstrPtr q = copyInstruction(p);
     651      268614 :                         InstrPtr s = newInstructionArgs(mb, matRef, packRef,
     652      134307 :                                                                                         mat[n].mi->argc);
     653      134307 :                         int ttpe = 0;
     654             : 
     655      134307 :                         if (q == NULL
     656      134307 :                                 || s == NULL
     657      134307 :                                 || (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      134307 :                         ttpe = getArgType(mb, mat[n].mi, 0);
     665     1438584 :                         for (j = 1; j < mat[n].mi->argc; j++) {
     666     1304277 :                                 int ov = 0;
     667     1304277 :                                 if (getBatType(ttpe) != TYPE_oid
     668     1303605 :                                         || (ov = overlap(ml, getArg(mat[m].mi, k),
     669             :                                                                          getArg(mat[n].mi, j), k, j, 1)) == 1) {
     670      164759 :                                         s = pushArgument(mb, s, getArg(mat[n].mi, j));
     671             :                                 }
     672     1304277 :                                 if (ov == -1) {
     673           0 :                                         freeInstruction(q);
     674           0 :                                         freeInstruction(s);
     675           0 :                                         freeInstruction(r);
     676           0 :                                         return -1;
     677             :                                 }
     678             :                         }
     679      134307 :                         if (s->retc == 1 && s->argc == 2) {       /* only one input, change into an assignment */
     680      129857 :                                 getFunctionId(s) = NULL;
     681      129857 :                                 getModuleId(s) = NULL;
     682      129857 :                                 s->token = ASSIGNsymbol;
     683      129857 :                                 s->typeresolved = false;
     684      129857 :                                 s->fcn = NULL;
     685      129857 :                                 s->blk = NULL;
     686             :                         }
     687      134307 :                         pushInstruction(mb, s);
     688             : 
     689      134307 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
     690      134307 :                         getArg(q, 1) = getArg(mat[m].mi, k);
     691      134307 :                         getArg(q, 2) = getArg(s, 0);
     692      134307 :                         if (o >= 0)
     693        1358 :                                 getArg(q, 3) = getArg(mat[o].mi, k);
     694      134307 :                         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      134307 :                         pushInstruction(mb, q);
     700             : 
     701      134307 :                         r = pushArgument(mb, r, getArg(q, 0));
     702      134307 :                         nr++;
     703             :                 }
     704             :         } else {
     705         157 :                 assert(m >= 0);
     706         157 :                 assert(o < 0 || mat[m].mi->argc == mat[o].mi->argc);
     707             : 
     708        1313 :                 for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
     709        1156 :                         InstrPtr q = copyInstruction(p);
     710        1156 :                         if (!q) {
     711           0 :                                 freeInstruction(r);
     712           0 :                                 return -1;
     713             :                         }
     714             : 
     715        1156 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
     716        1156 :                         getArg(q, 1) = getArg(mat[m].mi, k);
     717        1156 :                         if (o >= 0)
     718          16 :                                 getArg(q, 3) = getArg(mat[o].mi, k);
     719        1156 :                         pushInstruction(mb, q);
     720             : 
     721        1156 :                         if (setPartnr(ml, getArg(q, 2), getArg(q, 0), k)) {
     722           0 :                                 freeInstruction(r);
     723           0 :                                 return -1;
     724             :                         }
     725        1156 :                         r = pushArgument(mb, r, getArg(q, 0));
     726             :                 }
     727             :         }
     728             : 
     729       17192 :         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      803940 : mat_projection(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n)
     738             : {
     739      803940 :         int tpe = getArgType(mb, p, 0), k, j;
     740      803940 :         mat_t *mat = ml->v;
     741      803940 :         InstrPtr r;
     742             : 
     743             :         //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
     744      803940 :         assert(m >= 0 || n >= 0);
     745      803940 :         if (m >= 0 && n >= 0) {
     746      719011 :                 int nr = 1;
     747     1438022 :                 r = newInstructionArgs(mb, matRef, packRef,
     748      719011 :                                                            mat[m].mi->argc * mat[n].mi->argc);
     749             : 
     750      719011 :                 if (!r)
     751             :                         return -1;
     752             : 
     753      719011 :                 getArg(r, 0) = getArg(p, 0);
     754             : 
     755     6478411 :                 for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
     756    26228704 :                         for (j = 1; j < mat[n].mi->argc; j++) {
     757    26228704 :                                 InstrPtr q;
     758    26228704 :                                 switch (overlap(ml, getArg(mat[m].mi, k),
     759             :                                                                 getArg(mat[n].mi, j), k, j, 0)) {
     760    20469304 :                                 case 0:
     761    20469304 :                                         continue;
     762           0 :                                 case -1:
     763           0 :                                         freeInstruction(r);
     764           0 :                                         return -1;
     765     5759400 :                                 case 1:
     766     5759400 :                                         q = copyInstruction(p);
     767             : 
     768     5759400 :                                         if (!q) {
     769           0 :                                                 freeInstruction(r);
     770           0 :                                                 return -1;
     771             :                                         }
     772             : 
     773     5759400 :                                         getArg(q, 0) = newTmpVariable(mb, tpe);
     774     5759400 :                                         getArg(q, 1) = getArg(mat[m].mi, k);
     775     5759400 :                                         getArg(q, 2) = getArg(mat[n].mi, j);
     776     5759400 :                                         pushInstruction(mb, q);
     777             : 
     778     5759400 :                                         if (mb->errors || setPartnr(ml, getArg(mat[n].mi, j), getArg(q, 0), nr)) {
     779           0 :                                                 freeInstruction(r);
     780           0 :                                                 return -1;
     781             :                                         }
     782     5759400 :                                         r = pushArgument(mb, r, getArg(q, 0));
     783             : 
     784     5759400 :                                         nr++;
     785     5759400 :                                         break;
     786             :                                 }
     787             :                                 break;                  /* only in case of overlap */
     788             :                         }
     789             :                 }
     790             :         } else {
     791       84929 :                 assert(m >= 0);
     792       84929 :                 r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
     793             : 
     794       84929 :                 if (!r)
     795             :                         return -1;
     796             : 
     797       84929 :                 getArg(r, 0) = getArg(p, 0);
     798             : 
     799      755225 :                 for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
     800      670296 :                         InstrPtr q = copyInstruction(p);
     801             : 
     802      670296 :                         if (!q) {
     803           0 :                                 freeInstruction(r);
     804           0 :                                 return -1;
     805             :                         }
     806             : 
     807      670296 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
     808      670296 :                         getArg(q, 1) = getArg(mat[m].mi, k);
     809      670296 :                         pushInstruction(mb, q);
     810             : 
     811      670296 :                         if (mb->errors || setPartnr(ml, getArg(q, 2), getArg(q, 0), k)) {
     812           0 :                                 freeInstruction(r);
     813           0 :                                 return -1;
     814             :                         }
     815      670296 :                         r = pushArgument(mb, r, getArg(q, 0));
     816             :                 }
     817             :         }
     818             : 
     819      803940 :         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       54228 : mat_join2(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int lc, int rc)
     828             : {
     829       54228 :         int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), j, k, nr = 1;
     830       54228 :         mat_t *mat = ml->v;
     831       54228 :         InstrPtr l;
     832       54228 :         InstrPtr r;
     833             : 
     834             :         //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
     835             : 
     836       54228 :         assert(m >= 0 || n >= 0);
     837       54228 :         if (m >= 0 && n >= 0) {
     838        1312 :                 l = newInstructionArgs(mb, matRef, packRef,
     839         656 :                                                            mat[m].mi->argc * mat[n].mi->argc);
     840        1312 :                 r = newInstructionArgs(mb, matRef, packRef,
     841         656 :                                                            mat[m].mi->argc * mat[n].mi->argc);
     842         656 :                 if (!l || !r) {
     843           0 :                         freeInstruction(l);
     844           0 :                         freeInstruction(r);
     845           0 :                         return -1;
     846             :                 }
     847             : 
     848         656 :                 getArg(l, 0) = getArg(p, 0);
     849         656 :                 getArg(r, 0) = getArg(p, 1);
     850             : 
     851        5750 :                 for (k = 1; k < mat[m].mi->argc; k++) {
     852       45304 :                         for (j = 1; j < mat[n].mi->argc; j++) {
     853       40210 :                                 InstrPtr q = copyInstruction(p);
     854             : 
     855       40210 :                                 if (!q) {
     856           0 :                                         freeInstruction(l);
     857           0 :                                         freeInstruction(r);
     858           0 :                                         return -1;
     859             :                                 }
     860             : 
     861       40210 :                                 getArg(q, 0) = newTmpVariable(mb, tpe1);
     862       40210 :                                 getArg(q, 1) = newTmpVariable(mb, tpe2);
     863       40210 :                                 getArg(q, 2) = getArg(mat[m].mi, k);
     864       40210 :                                 getArg(q, 3) = getArg(mat[n].mi, j);
     865       40210 :                                 if (lc >= 0)
     866         241 :                                         getArg(q, 4) = getArg(mat[lc].mi, k);
     867       40210 :                                 if (rc >= 0)
     868           0 :                                         getArg(q, 5) = getArg(mat[rc].mi, j);
     869       40210 :                                 pushInstruction(mb, q);
     870             : 
     871       40210 :                                 if (mb->errors
     872       40210 :                                         || propagatePartnr(ml, getArg(mat[m].mi, k), getArg(q, 0),
     873             :                                                                            nr)
     874       40210 :                                         || 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       40210 :                                 l = pushArgument(mb, l, getArg(q, 0));
     883       40210 :                                 r = pushArgument(mb, r, getArg(q, 1));
     884       40210 :                                 nr++;
     885             :                         }
     886             :                 }
     887             :         } else {
     888       53572 :                 int mv = (m >= 0) ? m : n;
     889       53572 :                 int av = (m < 0);
     890       53572 :                 int bv = (m >= 0);
     891       53572 :                 int mc = (lc >= 0) ? lc : rc;
     892             : 
     893       53572 :                 l = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
     894       53572 :                 r = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
     895       53572 :                 if (!l || !r) {
     896           0 :                         freeInstruction(l);
     897           0 :                         freeInstruction(r);
     898           0 :                         return -1;
     899             :                 }
     900             : 
     901       53572 :                 getArg(l, 0) = getArg(p, 0);
     902       53572 :                 getArg(r, 0) = getArg(p, 1);
     903             : 
     904      473709 :                 for (k = 1; k < mat[mv].mi->argc; k++) {
     905      420137 :                         InstrPtr q = copyInstruction(p);
     906             : 
     907      420137 :                         if (!q) {
     908           0 :                                 freeInstruction(l);
     909           0 :                                 freeInstruction(r);
     910           0 :                                 return -1;
     911             :                         }
     912             : 
     913      420137 :                         getArg(q, 0) = newTmpVariable(mb, tpe1);
     914      420137 :                         getArg(q, 1) = newTmpVariable(mb, tpe2);
     915      420137 :                         getArg(q, p->retc + av) = getArg(mat[mv].mi, k);
     916      420137 :                         if (mc >= 0)
     917        1214 :                                 getArg(q, p->retc + 2 + av) = getArg(mat[mc].mi, k);
     918      420137 :                         pushInstruction(mb, q);
     919             : 
     920      420137 :                         if (mb->errors
     921      420137 :                                 || propagatePartnr(ml, getArg(mat[mv].mi, k), getArg(q, av), k)
     922      420137 :                                 || 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      420137 :                         l = pushArgument(mb, l, getArg(q, 0));
     931      420137 :                         r = pushArgument(mb, r, getArg(q, 1));
     932             :                 }
     933             :         }
     934       54228 :         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       54228 :         if (mat_add(ml, r, mat_none, getFunctionId(p))) {
     940           0 :                 freeInstruction(r);
     941           0 :                 return -1;
     942             :         }
     943             :         return 0;
     944             : }
     945             : 
     946             : static int
     947           0 : mat_rangejoin(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n)
     948             : {
     949           0 :         int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), k, nr = 1;
     950           0 :         mat_t *mat = ml->v;
     951           0 :         InstrPtr l;
     952           0 :         InstrPtr r;
     953             : 
     954             :         //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
     955             : 
     956           0 :         assert(m >= 0 && n >= 0 && mat[m].mi->argc == mat[n].mi->argc);
     957           0 :         l = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc * mat[n].mi->argc);
     958           0 :         r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc * mat[n].mi->argc);
     959           0 :         if (!l || !r) {
     960           0 :                 freeInstruction(l);
     961           0 :                 freeInstruction(r);
     962           0 :                 return -1;
     963             :         }
     964             : 
     965           0 :         getArg(l, 0) = getArg(p, 0);
     966           0 :         getArg(r, 0) = getArg(p, 1);
     967             : 
     968           0 :         for (k = 1; k < mat[m].mi->argc; k++) {
     969           0 :                 InstrPtr q = copyInstruction(p);
     970             : 
     971           0 :                 if (!q) {
     972           0 :                         freeInstruction(l);
     973           0 :                         freeInstruction(r);
     974           0 :                         return -1;
     975             :                 }
     976             : 
     977           0 :                 getArg(q, 0) = newTmpVariable(mb, tpe1);
     978           0 :                 getArg(q, 1) = newTmpVariable(mb, tpe2);
     979             : 
     980           0 :                 getArg(q, 3) = getArg(mat[m].mi, k);
     981           0 :                 getArg(q, 4) = getArg(mat[n].mi, k);
     982           0 :                 pushInstruction(mb, q);
     983             : 
     984           0 :                 if (mb->errors || propagatePartnr(ml, getArg(mat[m].mi, k), getArg(q, 0), nr)
     985           0 :                                        || propagatePartnr(ml, getArg(mat[n].mi, k), getArg(q, 1), nr)) {
     986           0 :                         freeInstruction(r);
     987           0 :                         freeInstruction(l);
     988           0 :                         return -1;
     989             :                 }
     990             : 
     991             :                 /* add result to mat */
     992           0 :                 l = pushArgument(mb, l, getArg(q, 0));
     993           0 :                 r = pushArgument(mb, r, getArg(q, 1));
     994           0 :                 nr++;
     995             :         }
     996           0 :         if (mb->errors || mat_add(ml, l, mat_none, getFunctionId(p))) {
     997           0 :                 freeInstruction(l);
     998           0 :                 freeInstruction(r);
     999           0 :                 return -1;
    1000             :         }
    1001           0 :         if (mat_add(ml, r, mat_none, getFunctionId(p))) {
    1002           0 :                 freeInstruction(r);
    1003           0 :                 return -1;
    1004             :         }
    1005             :         return 0;
    1006             : }
    1007             : 
    1008             : static int
    1009           4 : join_split(Client cntxt, InstrPtr p, int args)
    1010             : {
    1011           4 :         char *name = NULL;
    1012           4 :         size_t len;
    1013           4 :         int i, res = 0;
    1014           4 :         Symbol sym;
    1015           4 :         MalBlkPtr mb;
    1016           4 :         InstrPtr q;
    1017             : 
    1018           4 :         if (args <= 3)                               /* we assume there are no 2x1 joins! */
    1019             :                 return 1;
    1020             : 
    1021           0 :         len = strlen(getFunctionId(p));
    1022           0 :         name = GDKmalloc(len + 3);
    1023           0 :         if (!name)
    1024             :                 return -2;
    1025           0 :         strncpy(name, getFunctionId(p), len - 7);
    1026           0 :         strcpy(name + len - 7, "join");
    1027             : 
    1028           0 :         sym = findSymbol(cntxt->usermodule, getModuleId(p), name);
    1029           0 :         assert(sym);
    1030           0 :         mb = sym->def;
    1031             : 
    1032           0 :         assert(0);
    1033             :         q = mb->stmt[0];
    1034             :         for (i = q->retc; i < q->argc; i++) {
    1035             :                 if (isaBatType(getArgType(mb, q, i)))
    1036             :                         res++;
    1037             :                 else
    1038             :                         break;
    1039             :         }
    1040             :         GDKfree(name);
    1041             :         return res - 1;
    1042             : }
    1043             : 
    1044             : /* 1 or 2 mat lists:
    1045             :  *      in case of one take the second half of the code
    1046             :  *      in case of two we need to detect the list lengths.
    1047             :  *
    1048             :  * input is one list of arguments (just total length of mats)
    1049             :  */
    1050             : static int
    1051          58 : mat_joinNxM(Client cntxt, MalBlkPtr mb, InstrPtr p, matlist_t *ml, int args)
    1052             : {
    1053          58 :         int tpe1 = getArgType(mb, p, 0), tpe2 = getArgType(mb, p, 1), j, k, nr = 1;
    1054          58 :         InstrPtr l;
    1055          58 :         InstrPtr r;
    1056          58 :         mat_t *mat = ml->v;
    1057          58 :         int *mats = (int *) GDKzalloc(sizeof(int) * args);
    1058          58 :         int nr_mats = 0, first = -1, res = 0;
    1059             : 
    1060          58 :         if (!mats) {
    1061             :                 return -1;
    1062             :         }
    1063             : 
    1064         243 :         for (j = 0; j < args; j++) {
    1065         185 :                 mats[j] = is_a_mat(getArg(p, p->retc + j), ml);
    1066         185 :                 if (mats[j] != -1) {
    1067          72 :                         nr_mats++;
    1068          72 :                         if (first < 0)
    1069          58 :                                 first = j;
    1070             :                 }
    1071             :         }
    1072             : 
    1073             :         //printf("# %s.%s(%d,%d)", getModuleId(p), getFunctionId(p), m, n);
    1074             : 
    1075          58 :         if (args == nr_mats) {
    1076           4 :                 int mv1 = mats[0], i;
    1077           4 :                 int mv2 = mats[args - 1];
    1078           4 :                 int split = join_split(cntxt, p, args);
    1079           4 :                 int nr_mv1 = split;
    1080             : 
    1081           4 :                 if (split == -2) {
    1082           0 :                         GDKfree(mats);
    1083           0 :                         return -1;
    1084             :                 }
    1085           4 :                 if (split < 0) {
    1086           0 :                         GDKfree(mats);
    1087           0 :                         mb->errors = createException(MAL, "mergetable.join",
    1088             :                                                                                  SQLSTATE(42000) " incorrect split level");
    1089           0 :                         return 0;
    1090             :                 }
    1091             : 
    1092           8 :                 l = newInstructionArgs(mb, matRef, packRef,
    1093           4 :                                                            mat[mv1].mi->argc * mat[mv2].mi->argc);
    1094           8 :                 r = newInstructionArgs(mb, matRef, packRef,
    1095           4 :                                                            mat[mv1].mi->argc * mat[mv2].mi->argc);
    1096           4 :                 if (l == NULL || r == NULL) {
    1097           0 :                         freeInstruction(l);
    1098           0 :                         freeInstruction(r);
    1099           0 :                         GDKfree(mats);
    1100           0 :                         return -1;
    1101             :                 }
    1102           4 :                 getArg(l, 0) = getArg(p, 0);
    1103           4 :                 getArg(r, 0) = getArg(p, 1);
    1104             : 
    1105             :                 /* now detect split point */
    1106          16 :                 for (k = 1; k < mat[mv1].mi->argc; k++) {
    1107          48 :                         for (j = 1; j < mat[mv2].mi->argc; j++) {
    1108          36 :                                 InstrPtr q = copyInstruction(p);
    1109          36 :                                 if (!q) {
    1110           0 :                                         freeInstruction(r);
    1111           0 :                                         freeInstruction(l);
    1112           0 :                                         GDKfree(mats);
    1113           0 :                                         return -1;
    1114             :                                 }
    1115             : 
    1116          36 :                                 getArg(q, 0) = newTmpVariable(mb, tpe1);
    1117          36 :                                 getArg(q, 1) = newTmpVariable(mb, tpe2);
    1118          72 :                                 for (i = 0; i < nr_mv1; i++)
    1119          36 :                                         getArg(q, q->retc + i) = getArg(mat[mats[i]].mi, k);
    1120         108 :                                 for (; i < nr_mats; i++)
    1121          72 :                                         getArg(q, q->retc + i) = getArg(mat[mats[i]].mi, j);
    1122          36 :                                 pushInstruction(mb, q);
    1123             : 
    1124          36 :                                 if (mb->errors
    1125          36 :                                         || propagatePartnr(ml, getArg(mat[mv1].mi, k), getArg(q, 0),
    1126             :                                                                            nr)
    1127          36 :                                         || propagatePartnr(ml, getArg(mat[mv2].mi, j), getArg(q, 1),
    1128             :                                                                            nr)) {
    1129           0 :                                         freeInstruction(r);
    1130           0 :                                         freeInstruction(l);
    1131           0 :                                         GDKfree(mats);
    1132           0 :                                         return -1;
    1133             :                                 }
    1134             : 
    1135             :                                 /* add result to mat */
    1136          36 :                                 l = pushArgument(mb, l, getArg(q, 0));
    1137          36 :                                 r = pushArgument(mb, r, getArg(q, 1));
    1138          36 :                                 nr++;
    1139             :                         }
    1140             :                 }
    1141             :         } else {
    1142             :                 /* only one side
    1143             :                  * mats from first..first+nr_mats
    1144             :                  */
    1145          54 :                 int mv = mats[first];
    1146             : 
    1147          54 :                 l = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
    1148          54 :                 r = newInstructionArgs(mb, matRef, packRef, mat[mv].mi->argc);
    1149          54 :                 if (l == NULL || r == NULL) {
    1150           0 :                         freeInstruction(l);
    1151           0 :                         freeInstruction(r);
    1152           0 :                         GDKfree(mats);
    1153           0 :                         return -1;
    1154             :                 }
    1155          54 :                 getArg(l, 0) = getArg(p, 0);
    1156          54 :                 getArg(r, 0) = getArg(p, 1);
    1157             : 
    1158         319 :                 for (k = 1; k < mat[mv].mi->argc; k++) {
    1159         265 :                         InstrPtr q = copyInstruction(p);
    1160         265 :                         if (!q) {
    1161           0 :                                 freeInstruction(r);
    1162           0 :                                 freeInstruction(l);
    1163           0 :                                 GDKfree(mats);
    1164           0 :                                 return -1;
    1165             :                         }
    1166             : 
    1167         265 :                         getArg(q, 0) = newTmpVariable(mb, tpe1);
    1168         265 :                         getArg(q, 1) = newTmpVariable(mb, tpe2);
    1169         545 :                         for (j = 0; j < nr_mats; j++) {
    1170         280 :                                 assert(mat[mats[first]].mi->argc == mat[mats[first + j]].mi->argc);
    1171         280 :                                 getArg(q, p->retc + first + j) = getArg(mat[mats[first + j]].mi, k);
    1172             :                         }
    1173         265 :                         if (mb->errors
    1174         265 :                                 || propagatePartnr(ml, getArg(mat[mv].mi, k),
    1175         265 :                                                                    getArg(q, (first != 0)), k)
    1176         265 :                                 || propagatePartnr(ml,
    1177         265 :                                                                    getArg(p, p->retc + (first) ? nr_mats : 0),
    1178         265 :                                                                    getArg(q, (first == 0)), k)) {
    1179           0 :                                 freeInstruction(q);
    1180           0 :                                 freeInstruction(r);
    1181           0 :                                 freeInstruction(l);
    1182           0 :                                 GDKfree(mats);
    1183           0 :                                 return -1;
    1184             :                         }
    1185         265 :                         pushInstruction(mb, q);
    1186             : 
    1187             :                         /* add result to mat */
    1188         265 :                         l = pushArgument(mb, l, getArg(q, 0));
    1189         265 :                         r = pushArgument(mb, r, getArg(q, 1));
    1190             :                 }
    1191             :         }
    1192          58 :         if (mb->errors || mat_add(ml, l, mat_none, getFunctionId(p))) {
    1193           0 :                 freeInstruction(l);
    1194           0 :                 freeInstruction(r);
    1195           0 :                 res = -1;
    1196          58 :         } else if (mat_add(ml, r, mat_none, getFunctionId(p))) {
    1197           0 :                 freeInstruction(r);
    1198           0 :                 res = -1;
    1199             :         }
    1200          58 :         GDKfree(mats);
    1201          58 :         return res;
    1202             : }
    1203             : 
    1204             : 
    1205             : static const char *
    1206        4655 : aggr_phase2(const char *aggr, int type_dbl)
    1207             : {
    1208        4655 :         if (aggr == countRef || aggr == count_no_nilRef
    1209        4354 :                 || (aggr == avgRef && type_dbl))
    1210        1306 :                 return sumRef;
    1211        3349 :         if (aggr == subcountRef || (aggr == subavgRef && type_dbl))
    1212        2565 :                 return subsumRef;
    1213             :         /* min/max/sum/prod and unique are fine */
    1214             :         return aggr;
    1215             : }
    1216             : 
    1217             : static str
    1218        1638 : mat_aggr(MalBlkPtr mb, InstrPtr p, mat_t *mat, int m)
    1219             : {
    1220        1638 :         int tp = getArgType(mb, p, 0), k, tp2 = TYPE_lng, i;
    1221        1638 :         int battp = (getModuleId(p) == aggrRef) ? newBatType(tp) : tp, battp2 = 0;
    1222        1638 :         int isAvg = (getFunctionId(p) == avgRef);
    1223        1638 :         InstrPtr r = NULL, s = NULL, q = NULL, u = NULL, v = NULL;
    1224             : 
    1225             :         /* we pack the partial result */
    1226        1638 :         r = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
    1227        1638 :         if (r == NULL)
    1228           0 :                 throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1229        1638 :         getArg(r, 0) = newTmpVariable(mb, battp);
    1230             : 
    1231        1638 :         if (isAvg) {                            /* remainders or counts */
    1232        1026 :                 battp2 = newBatType(tp2);
    1233        1026 :                 u = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
    1234        1026 :                 if (u == NULL) {
    1235           0 :                         freeInstruction(r);
    1236           0 :                         throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1237             :                 }
    1238        1026 :                 getArg(u, 0) = newTmpVariable(mb, battp2);
    1239             :         }
    1240        1638 :         if (isAvg && tp != TYPE_dbl) {  /* counts */
    1241          21 :                 battp2 = newBatType(tp2);
    1242          21 :                 v = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
    1243          21 :                 if (v == NULL) {
    1244           0 :                         freeInstruction(r);
    1245           0 :                         freeInstruction(u);
    1246           0 :                         throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1247             :                 }
    1248          21 :                 getArg(v, 0) = newTmpVariable(mb, battp2);
    1249             :         }
    1250       13589 :         for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
    1251       11951 :                 q = newInstruction(mb, NULL, NULL);
    1252       11951 :                 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       11951 :                 if (isAvg && tp == TYPE_dbl)
    1259        7947 :                         setModuleId(q, batcalcRef);
    1260             :                 else
    1261        4004 :                         setModuleId(q, getModuleId(p));
    1262       11951 :                 setFunctionId(q, getFunctionId(p));
    1263       11951 :                 getArg(q, 0) = newTmpVariable(mb, tp);
    1264       11951 :                 if (isAvg)
    1265        8110 :                         q = pushReturn(mb, q, newTmpVariable(mb, tp2));
    1266       11951 :                 if (isAvg && tp != TYPE_dbl)
    1267         163 :                         q = pushReturn(mb, q, newTmpVariable(mb, tp2));
    1268       11951 :                 q = pushArgument(mb, q, getArg(mat[m].mi, k));
    1269       12394 :                 for (i = q->argc; i < p->argc; i++)
    1270         443 :                         q = pushArgument(mb, q, getArg(p, i));
    1271       11951 :                 pushInstruction(mb, q);
    1272             : 
    1273       11951 :                 r = pushArgument(mb, r, getArg(q, 0));
    1274       11951 :                 if (isAvg)
    1275        8110 :                         u = pushArgument(mb, u, getArg(q, 1));
    1276       11951 :                 if (isAvg && tp != TYPE_dbl)
    1277         163 :                         v = pushArgument(mb, v, getArg(q, 2));
    1278             :         }
    1279        1638 :         pushInstruction(mb, r);
    1280        1638 :         if (isAvg)
    1281        1026 :                 pushInstruction(mb, u);
    1282        1638 :         if (isAvg && tp != TYPE_dbl)
    1283          21 :                 pushInstruction(mb, v);
    1284             : 
    1285             :         /* Filter empty partitions */
    1286        1638 :         if (mb->errors == NULL && getModuleId(p) == aggrRef && !isAvg) {
    1287         612 :                 s = newInstruction(mb, algebraRef, selectNotNilRef);
    1288         612 :                 if (s == NULL) {
    1289           0 :                         throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1290             :                 }
    1291         612 :                 getArg(s, 0) = newTmpVariable(mb, battp);
    1292         612 :                 s = pushArgument(mb, s, getArg(r, 0));
    1293         612 :                 pushInstruction(mb, s);
    1294         612 :                 r = s;
    1295             :         }
    1296             : 
    1297             :         /* for avg we do sum (avg*(count/sumcount) ) */
    1298        1638 :         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        1638 :         if (mb->errors == NULL) {
    1381        1638 :                 s = newInstruction(mb, getModuleId(p),
    1382             :                                                    aggr_phase2(getFunctionId(p), tp == TYPE_dbl));
    1383        1638 :                 if (s == NULL) {
    1384           0 :                         throw(MAL, "optimizer.mergetable", SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1385             :                 }
    1386        1638 :                 getArg(s, 0) = getArg(p, 0);
    1387        1638 :                 s = pushArgument(mb, s, getArg(r, 0));
    1388        1638 :                 if (isAvg && tp != TYPE_dbl) {
    1389          21 :                         s = pushArgument(mb, s, getArg(u, 0));
    1390          21 :                         s = pushArgument(mb, s, getArg(v, 0));
    1391             :                 }
    1392        1638 :                 pushInstruction(mb, s);
    1393             :         }
    1394        1638 :         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        7078 : chain_by_length(mat_t *mat, int g)
    1404             : {
    1405        7078 :         int cnt = 0;
    1406       17472 :         while (g >= 0) {
    1407       10394 :                 g = mat[g].pm;
    1408       10394 :                 cnt++;
    1409             :         }
    1410        4664 :         return cnt;
    1411             : }
    1412             : 
    1413             : static int
    1414        3293 : walk_n_back(mat_t *mat, int g, int cnt)
    1415             : {
    1416       15891 :         while (cnt > 0) {
    1417        5497 :                 g = mat[g].pm;
    1418        5497 :                 cnt--;
    1419             :         }
    1420        3421 :         return g;
    1421             : }
    1422             : 
    1423             : static int
    1424        3293 : group_by_ext(matlist_t *ml, int g)
    1425             : {
    1426        3293 :         int i;
    1427             : 
    1428       13559 :         for (i = g; i < ml->top; i++) {
    1429       20532 :                 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        6857 : mat_group_project(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int e, int a)
    1441             : {
    1442        6857 :         int tp = getArgType(mb, p, 0), k;
    1443        6857 :         mat_t *mat = ml->v;
    1444        6857 :         InstrPtr ai1 = newInstructionArgs(mb, matRef, packRef, mat[a].mi->argc), r;
    1445             : 
    1446        6857 :         if (!ai1)
    1447             :                 return -1;
    1448             : 
    1449        6857 :         getArg(ai1, 0) = newTmpVariable(mb, tp);
    1450        6857 :         if (mb->errors) {
    1451           0 :                 freeInstruction(ai1);
    1452           0 :                 return -1;
    1453             :         }
    1454             : 
    1455        6857 :         assert(mat[e].mi->argc == mat[a].mi->argc);
    1456       64767 :         for (k = 1; k < mat[a].mi->argc; k++) {
    1457       57910 :                 InstrPtr q = copyInstruction(p);
    1458       57910 :                 if (!q) {
    1459           0 :                         freeInstruction(ai1);
    1460           0 :                         return -1;
    1461             :                 }
    1462             : 
    1463       57910 :                 getArg(q, 0) = newTmpVariable(mb, tp);
    1464       57910 :                 getArg(q, 1) = getArg(mat[e].mi, k);
    1465       57910 :                 getArg(q, 2) = getArg(mat[a].mi, k);
    1466       57910 :                 pushInstruction(mb, q);
    1467       57910 :                 if (mb->errors) {
    1468           0 :                         freeInstruction(ai1);
    1469           0 :                         return -1;
    1470             :                 }
    1471       57910 :                 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       57910 :                 ai1 = pushArgument(mb, ai1, getArg(q, 0));
    1478             :         }
    1479        6857 :         pushInstruction(mb, ai1);
    1480        6857 :         if (mb->errors) {
    1481             :                 return -1;
    1482             :         }
    1483             : 
    1484        6857 :         if ((r = copyInstruction(p)) == NULL)
    1485             :                 return -1;
    1486        6857 :         getArg(r, 1) = mat[e].mv;
    1487        6857 :         getArg(r, 2) = getArg(ai1, 0);
    1488        6857 :         pushInstruction(mb, r);
    1489        6857 :         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        3017 : mat_group_aggr(MalBlkPtr mb, InstrPtr p, mat_t *mat, int b, int g, int e)
    1497             : {
    1498        3017 :         int tp = getArgType(mb, p, 0), k, tp2 = 0, tpe = getBatType(tp);
    1499        3017 :         const char *aggr2 = aggr_phase2(getFunctionId(p), tpe == TYPE_dbl);
    1500        3017 :         int isAvg = (getFunctionId(p) == subavgRef);
    1501        3017 :         InstrPtr ai1 = newInstructionArgs(mb, matRef, packRef, mat[b].mi->argc),
    1502        3017 :                 ai10 = NULL, ai11 = NULL, ai2;
    1503             : 
    1504        3017 :         if (!ai1)
    1505             :                 return -1;
    1506             : 
    1507        3017 :         getArg(ai1, 0) = newTmpVariable(mb, tp);
    1508             : 
    1509        3017 :         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        3017 :         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       30950 :         for (k = 1; mb->errors == NULL && k < mat[b].mi->argc; k++) {
    1530       27933 :                 int off = 0;
    1531       27933 :                 InstrPtr q = copyInstructionArgs(p, p->argc + (isAvg && tpe == TYPE_dbl));
    1532       27933 :                 if (!q) {
    1533           0 :                         freeInstruction(ai1);
    1534           0 :                         freeInstruction(ai10);
    1535           0 :                         return -1;
    1536             :                 }
    1537             : 
    1538       27933 :                 getArg(q, 0) = newTmpVariable(mb, tp);
    1539       27933 :                 if (isAvg && tpe == TYPE_dbl) {
    1540         189 :                         off = 1;
    1541         189 :                         getArg(q, 1) = newTmpVariable(mb, tp2);
    1542         189 :                         q = pushArgument(mb, q, getArg(q, 1));  /* push at end, create space */
    1543         189 :                         q->retc = 2;
    1544         189 :                         getArg(q, q->argc - 1) = getArg(q, q->argc - 2);
    1545         189 :                         getArg(q, q->argc - 2) = getArg(q, q->argc - 3);
    1546       27744 :                 } else if (isAvg) {
    1547         152 :                         getArg(q, 1) = newTmpVariable(mb, tp2);
    1548         152 :                         getArg(q, 2) = newTmpVariable(mb, tp2);
    1549         152 :                         off = 2;
    1550             :                 }
    1551       27933 :                 getArg(q, 1 + off) = getArg(mat[b].mi, k);
    1552       27933 :                 getArg(q, 2 + off) = getArg(mat[g].mi, k);
    1553       27933 :                 getArg(q, 3 + off) = getArg(mat[e].mi, k);
    1554       27933 :                 pushInstruction(mb, q);
    1555             : 
    1556             :                 /* pack the result into a mat */
    1557       27933 :                 ai1 = pushArgument(mb, ai1, getArg(q, 0));
    1558       27933 :                 if (isAvg)
    1559         341 :                         ai10 = pushArgument(mb, ai10, getArg(q, 1));
    1560       27933 :                 if (isAvg && tpe != TYPE_dbl)
    1561         152 :                         ai11 = pushArgument(mb, ai11, getArg(q, 2));
    1562             :         }
    1563        3017 :         pushInstruction(mb, ai1);
    1564        3017 :         if (isAvg)
    1565          50 :                 pushInstruction(mb, ai10);
    1566        3017 :         if (isAvg && tpe != TYPE_dbl)
    1567          19 :                 pushInstruction(mb, ai11);
    1568             : 
    1569             :         /* for avg we do sum (avg*(count/sumcount) ) */
    1570        3017 :         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        3017 :         ai2 = newInstruction(mb, aggrRef, aggr2);
    1649        3017 :         if (ai2 == NULL)
    1650             :                 return -1;
    1651        3017 :         getArg(ai2, 0) = getArg(p, 0);
    1652        3017 :         if (isAvg && tpe != TYPE_dbl) {
    1653          19 :                 getArg(ai2, 1) = getArg(p, 1);
    1654          19 :                 getArg(ai2, 2) = getArg(p, 2);
    1655             :         }
    1656        3017 :         ai2 = pushArgument(mb, ai2, getArg(ai1, 0));
    1657        3017 :         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        3017 :         ai2 = pushArgument(mb, ai2, mat[g].mv);
    1662        3017 :         ai2 = pushArgument(mb, ai2, mat[e].mv);
    1663        3017 :         ai2 = pushBit(mb, ai2, 1);      /* skip nils */
    1664        3017 :         pushInstruction(mb, ai2);
    1665        3017 :         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        4559 : mat_pack_group(MalBlkPtr mb, matlist_t *ml, int g)
    1675             : {
    1676        4559 :         mat_t *mat = ml->v;
    1677        4559 :         int cnt = chain_by_length(mat, g), i;
    1678        4559 :         InstrPtr cur = NULL;
    1679             : 
    1680       11532 :         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       13946 :                 InstrPtr grp = newInstruction(mb, groupRef,
    1683        2414 :                                                                           cur ? i ? subgroupRef : subgroupdoneRef : i ?
    1684        4559 :                                                                           groupRef : groupdoneRef);
    1685        6973 :                 if (grp == NULL)
    1686             :                         return -1;
    1687       13946 :                 int ogrp = walk_n_back(mat, g, i);
    1688        6973 :                 int oext = group_by_ext(ml, ogrp);
    1689        6973 :                 int attr = mat[oext].im;
    1690             : 
    1691        6973 :                 getArg(grp, 0) = mat[ogrp].mv;
    1692        6973 :                 grp = pushReturn(mb, grp, mat[oext].mv);
    1693        6973 :                 grp = pushReturn(mb, grp, newTmpVariable(mb, newBatType(TYPE_lng)));
    1694        6973 :                 grp = pushArgument(mb, grp, getArg(mat[attr].mi, 0));
    1695        6973 :                 if (cur)
    1696        2414 :                         grp = pushArgument(mb, grp, getArg(cur, 0));
    1697        6973 :                 pushInstruction(mb, grp);
    1698        6973 :                 cur = grp;
    1699        6973 :                 if (mb->errors)
    1700             :                         return -1;
    1701             :         }
    1702        4559 :         mat[g].im = -1;                         /* only pack once */
    1703        4559 :         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        2414 : mat_group_attr(MalBlkPtr mb, matlist_t *ml, int g, InstrPtr cext, int push)
    1713             : {
    1714        2414 :         int cnt = chain_by_length(ml->v, g), i;      /* number of attributes */
    1715             :         int ogrp = g;                           /* previous group */
    1716             : 
    1717        5707 :         for (i = 0; i < cnt; i++) {
    1718        3293 :                 int agrp = walk_n_back(ml->v, ogrp, i);
    1719        3293 :                 int b = ml->v[agrp].im;
    1720        3293 :                 int aext = group_by_ext(ml, agrp);
    1721        3293 :                 int a = ml->v[aext].im;
    1722        3293 :                 int atp = getArgType(mb, ml->v[a].mi, 0), k;
    1723        3293 :                 InstrPtr attr = newInstructionArgs(mb, matRef, packRef, ml->v[a].mi->argc);
    1724        3293 :                 if (attr == NULL) {
    1725             :                         return -1;
    1726             :                 }
    1727             : 
    1728             :                 //getArg(attr,0) = newTmpVariable(mb, atp);
    1729        3293 :                 getArg(attr, 0) = getArg(ml->v[b].mi, 0);
    1730             : 
    1731       28927 :                 for (k = 1; mb->errors == NULL && k < ml->v[a].mi->argc; k++) {
    1732       25634 :                         InstrPtr r = newInstruction(mb, algebraRef, projectionRef);
    1733       25634 :                         InstrPtr q = newInstruction(mb, algebraRef, projectionRef);
    1734       25634 :                         if (r == NULL || q == NULL) {
    1735           0 :                                 freeInstruction(attr);
    1736           0 :                                 freeInstruction(r);
    1737           0 :                                 freeInstruction(q);
    1738           0 :                                 return -1;
    1739             :                         }
    1740             : 
    1741       25634 :                         getArg(r, 0) = newTmpVariable(mb, newBatType(TYPE_oid));
    1742       25634 :                         r = pushArgument(mb, r, getArg(cext, k));
    1743       25634 :                         r = pushArgument(mb, r, getArg(ml->v[ogrp].mi, k));
    1744       25634 :                         pushInstruction(mb, r);
    1745             : 
    1746       25634 :                         getArg(q, 0) = newTmpVariable(mb, atp);
    1747       25634 :                         q = pushArgument(mb, q, getArg(r, 0));
    1748       25634 :                         q = pushArgument(mb, q, getArg(ml->v[a].mi, k));
    1749       25634 :                         pushInstruction(mb, q);
    1750             : 
    1751       25634 :                         attr = pushArgument(mb, attr, getArg(q, 0));
    1752             :                 }
    1753        3293 :                 if (push)
    1754        2414 :                         pushInstruction(mb, attr);
    1755        3293 :                 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        3293 :                 ml->v[aext].im = ml->top - 1;
    1763             :         }
    1764             :         return 0;
    1765             : }
    1766             : 
    1767             : static int
    1768        4559 : mat_group_new(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int b)
    1769             : {
    1770        4559 :         int tp0 = getArgType(mb, p, 0);
    1771        4559 :         int tp1 = getArgType(mb, p, 1);
    1772        4559 :         int tp2 = getArgType(mb, p, 2);
    1773        4559 :         int atp = getArgType(mb, p, 3), i, a, g, push = 0;
    1774        4559 :         InstrPtr r0, r1, r2, attr;
    1775             : 
    1776        4559 :         if (getFunctionId(p) == subgroupdoneRef || getFunctionId(p) == groupdoneRef)
    1777        2497 :                 push = 1;
    1778             : 
    1779        4559 :         r0 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1780        4559 :         if (r0 == NULL)
    1781             :                 return -1;
    1782        4559 :         getArg(r0, 0) = newTmpVariable(mb, tp0);
    1783             : 
    1784        4559 :         r1 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1785        4559 :         if (r1 == NULL) {
    1786           0 :                 freeInstruction(r0);
    1787           0 :                 return -1;
    1788             :         }
    1789        4559 :         getArg(r1, 0) = newTmpVariable(mb, tp1);
    1790             : 
    1791        4559 :         r2 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1792        4559 :         if (r2 == NULL) {
    1793           0 :                 freeInstruction(r0);
    1794           0 :                 freeInstruction(r1);
    1795           0 :                 return -1;
    1796             :         }
    1797        4559 :         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        4559 :         attr = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1802        4559 :         if (attr == NULL) {
    1803           0 :                 freeInstruction(r0);
    1804           0 :                 freeInstruction(r1);
    1805           0 :                 freeInstruction(r2);
    1806           0 :                 return -1;
    1807             :         }
    1808        4559 :         getArg(attr, 0) = getArg(ml->v[b].mi, 0);
    1809             : 
    1810       44182 :         for (i = 1; mb->errors == NULL && i < ml->v[b].mi->argc; i++) {
    1811       39623 :                 InstrPtr q = copyInstruction(p), r;
    1812       39623 :                 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       39623 :                 getArg(q, 0) = newTmpVariable(mb, tp0);
    1821       39623 :                 getArg(q, 1) = newTmpVariable(mb, tp1);
    1822       39623 :                 getArg(q, 2) = newTmpVariable(mb, tp2);
    1823       39623 :                 getArg(q, 3) = getArg(ml->v[b].mi, i);
    1824       39623 :                 pushInstruction(mb, q);
    1825       39623 :                 if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 0), i)
    1826       39623 :                         || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 1), i)
    1827       39623 :                         || 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       39623 :                 r0 = pushArgument(mb, r0, getArg(q, 0));
    1837       39623 :                 r1 = pushArgument(mb, r1, getArg(q, 1));
    1838       39623 :                 r2 = pushArgument(mb, r2, getArg(q, 2));
    1839             : 
    1840       39623 :                 r = newInstruction(mb, algebraRef, projectionRef);
    1841       39623 :                 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       39623 :                 getArg(r, 0) = newTmpVariable(mb, atp);
    1849       39623 :                 r = pushArgument(mb, r, getArg(q, 1));
    1850       39623 :                 r = pushArgument(mb, r, getArg(ml->v[b].mi, i));
    1851       39623 :                 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       39623 :                 pushInstruction(mb, r);
    1860             : 
    1861       39623 :                 attr = pushArgument(mb, attr, getArg(r, 0));
    1862             :         }
    1863        4559 :         pushInstruction(mb, r0);
    1864        4559 :         pushInstruction(mb, r1);
    1865        4559 :         pushInstruction(mb, r2);
    1866        4559 :         if (push)
    1867        2497 :                 pushInstruction(mb, attr);
    1868             : 
    1869             :         /* create mat's for the intermediates */
    1870        4559 :         a = ml->top;
    1871        4559 :         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        4559 :         g = ml->top;
    1878        4559 :         if (mat_add_var(ml, r0, p, getArg(p, 0), mat_grp, b, -1, 1)
    1879        4559 :                 || mat_add_var(ml, r1, p, getArg(p, 1), mat_ext, a, ml->top - 1, 1)  /* point back at group */
    1880        4559 :                 || 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        4559 :         if (push)
    1883        2497 :                 return mat_pack_group(mb, ml, g);
    1884             :         return 0;
    1885             : }
    1886             : 
    1887             : static int
    1888        2414 : mat_group_derive(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int b, int g)
    1889             : {
    1890        2414 :         int tp0 = getArgType(mb, p, 0);
    1891        2414 :         int tp1 = getArgType(mb, p, 1);
    1892        2414 :         int tp2 = getArgType(mb, p, 2);
    1893        2414 :         int atp = getArgType(mb, p, 3), i, a, push = 0;
    1894        2414 :         InstrPtr r0, r1, r2, attr;
    1895             : 
    1896        2414 :         if (getFunctionId(p) == subgroupdoneRef || getFunctionId(p) == groupdoneRef)
    1897        2062 :                 push = 1;
    1898             : 
    1899        2414 :         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        2414 :         r0 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1908        2414 :         if (r0 == NULL)
    1909             :                 return -1;
    1910        2414 :         getArg(r0, 0) = newTmpVariable(mb, tp0);
    1911             : 
    1912        2414 :         r1 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1913        2414 :         if (r1 == NULL) {
    1914           0 :                 freeInstruction(r0);
    1915           0 :                 return -1;
    1916             :         }
    1917        2414 :         getArg(r1, 0) = newTmpVariable(mb, tp1);
    1918             : 
    1919        2414 :         r2 = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1920        2414 :         if (r2 == NULL) {
    1921           0 :                 freeInstruction(r0);
    1922           0 :                 freeInstruction(r1);
    1923           0 :                 return -1;
    1924             :         }
    1925        2414 :         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        2414 :         attr = newInstructionArgs(mb, matRef, packRef, ml->v[b].mi->argc);
    1930        2414 :         if (attr == NULL) {
    1931           0 :                 freeInstruction(r0);
    1932           0 :                 freeInstruction(r1);
    1933           0 :                 freeInstruction(r2);
    1934           0 :                 return -1;
    1935             :         }
    1936        2414 :         getArg(attr, 0) = getArg(ml->v[b].mi, 0);
    1937             : 
    1938             :         /* we need overlapping ranges */
    1939       21186 :         for (i = 1; mb->errors == NULL && i < ml->v[b].mi->argc; i++) {
    1940       18772 :                 InstrPtr q = copyInstruction(p), r;
    1941       18772 :                 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       18772 :                 getArg(q, 0) = newTmpVariable(mb, tp0);
    1950       18772 :                 getArg(q, 1) = newTmpVariable(mb, tp1);
    1951       18772 :                 getArg(q, 2) = newTmpVariable(mb, tp2);
    1952       18772 :                 getArg(q, 3) = getArg(ml->v[b].mi, i);
    1953       18772 :                 getArg(q, 4) = getArg(ml->v[g].mi, i);
    1954       18772 :                 pushInstruction(mb, q);
    1955       18772 :                 if (setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 0), i)
    1956       18772 :                         || setPartnr(ml, getArg(ml->v[b].mi, i), getArg(q, 1), i)
    1957       18772 :                         || 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       18772 :                 r0 = pushArgument(mb, r0, getArg(q, 0));
    1967       18772 :                 r1 = pushArgument(mb, r1, getArg(q, 1));
    1968       18772 :                 r2 = pushArgument(mb, r2, getArg(q, 2));
    1969             : 
    1970       18772 :                 r = newInstruction(mb, algebraRef, projectionRef);
    1971       18772 :                 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       18772 :                 getArg(r, 0) = newTmpVariable(mb, atp);
    1979       18772 :                 r = pushArgument(mb, r, getArg(q, 1));
    1980       18772 :                 r = pushArgument(mb, r, getArg(ml->v[b].mi, i));
    1981       18772 :                 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       18772 :                 pushInstruction(mb, r);
    1990             : 
    1991       18772 :                 attr = pushArgument(mb, attr, getArg(r, 0));
    1992             :         }
    1993        2414 :         pushInstruction(mb, r0);
    1994        2414 :         pushInstruction(mb, r1);
    1995        2414 :         pushInstruction(mb, r2);
    1996        2414 :         if (push)
    1997        2062 :                 pushInstruction(mb, attr);
    1998             : 
    1999        2414 :         if (mb->errors || mat_group_attr(mb, ml, g, r1, push))
    2000           0 :                 return -1;
    2001             : 
    2002             :         /* create mat's for the intermediates */
    2003        2414 :         a = ml->top;
    2004        2414 :         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        2414 :         if (mat_add_var(ml, r0, p, getArg(p, 0), mat_grp, b, g, 1))
    2010             :                 return -1;
    2011        2414 :         g = ml->top - 1;
    2012        4828 :         if (mat_add_var(ml, r1, p, getArg(p, 1), mat_ext, a, ml->top - 1, 1) ||      /* point back at group */
    2013        2414 :                 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        2414 :         if (push)
    2016        2062 :                 return mat_pack_group(mb, ml, g);
    2017             :         return 0;
    2018             : }
    2019             : 
    2020             : static int
    2021         607 : mat_topn_project(MalBlkPtr mb, InstrPtr p, mat_t *mat, int m, int n)
    2022             : {
    2023         607 :         int tpe = getArgType(mb, p, 0), k;
    2024         607 :         InstrPtr pck, q;
    2025             : 
    2026         607 :         pck = newInstructionArgs(mb, matRef, packRef, mat[m].mi->argc);
    2027         607 :         if (pck == NULL)
    2028             :                 return -1;
    2029         607 :         getArg(pck, 0) = newTmpVariable(mb, tpe);
    2030             : 
    2031        5776 :         for (k = 1; mb->errors == NULL && k < mat[m].mi->argc; k++) {
    2032        5169 :                 InstrPtr q = copyInstruction(p);
    2033        5169 :                 if (!q) {
    2034           0 :                         freeInstruction(pck);
    2035           0 :                         return -1;
    2036             :                 }
    2037             : 
    2038        5169 :                 getArg(q, 0) = newTmpVariable(mb, tpe);
    2039        5169 :                 getArg(q, 1) = getArg(mat[m].mi, k);
    2040        5169 :                 getArg(q, 2) = getArg(mat[n].mi, k);
    2041        5169 :                 pushInstruction(mb, q);
    2042             : 
    2043        5169 :                 pck = pushArgument(mb, pck, getArg(q, 0));
    2044             :         }
    2045         607 :         pushInstruction(mb, pck);
    2046             : 
    2047         607 :         if (mb->errors || (q = copyInstruction(p)) == NULL)
    2048           0 :                 return -1;
    2049         607 :         getArg(q, 2) = getArg(pck, 0);
    2050         607 :         pushInstruction(mb, q);
    2051         607 :         if (mb->errors)
    2052             :                 return -1;
    2053             :         return 0;
    2054             : }
    2055             : 
    2056             : static int
    2057         105 : mat_pack_topn(MalBlkPtr mb, InstrPtr slc, mat_t *mat, int m)
    2058             : {
    2059             :         /* find chain of topn's */
    2060         105 :         int cnt = chain_by_length(mat, m), i;
    2061         105 :         InstrPtr cur = NULL;
    2062             : 
    2063         233 :         for (i = cnt - 1; mb->errors == NULL && i >= 0; i--) {
    2064         128 :                 int otpn = walk_n_back(mat, m, i), var = 1, k;
    2065         128 :                 int attr = mat[otpn].im;
    2066         128 :                 int tpe = getVarType(mb, getArg(mat[attr].mi, 0));
    2067         128 :                 InstrPtr pck, tpn, otopn = mat[otpn].org, a;
    2068             : 
    2069         128 :                 pck = newInstructionArgs(mb, matRef, packRef, mat[attr].mi->argc);
    2070         128 :                 if (pck == NULL)
    2071             :                         return -1;
    2072         128 :                 getArg(pck, 0) = newTmpVariable(mb, tpe);
    2073             : 
    2074             :                 /* m.projection(attr); */
    2075        1098 :                 for (k = 1; mb->errors == NULL && k < mat[attr].mi->argc; k++) {
    2076         970 :                         InstrPtr q = newInstruction(mb, algebraRef, projectionRef);
    2077         970 :                         if (q == NULL) {
    2078           0 :                                 freeInstruction(pck);
    2079           0 :                                 return -1;
    2080             :                         }
    2081         970 :                         getArg(q, 0) = newTmpVariable(mb, tpe);
    2082             : 
    2083         970 :                         q = pushArgument(mb, q, getArg(slc, k));
    2084         970 :                         q = pushArgument(mb, q, getArg(mat[attr].mi, k));
    2085         970 :                         pushInstruction(mb, q);
    2086             : 
    2087         970 :                         pck = pushArgument(mb, pck, getArg(q, 0));
    2088             :                 }
    2089         128 :                 pushInstruction(mb, pck);
    2090             : 
    2091         128 :                 a = pck;
    2092             : 
    2093         128 :                 if (mb->errors || (tpn = copyInstruction(otopn)) == NULL)
    2094           0 :                         return -1;
    2095         128 :                 var = 1;
    2096         128 :                 if (cur) {
    2097          23 :                         getArg(tpn, tpn->retc + var) = getArg(cur, 0);
    2098          23 :                         var ++;
    2099          23 :                         if (cur->retc == 2) {
    2100          23 :                                 getArg(tpn, tpn->retc + var) = getArg(cur, 1);
    2101          23 :                                 var ++;
    2102             :                         }
    2103             :                 }
    2104         128 :                 getArg(tpn, tpn->retc) = getArg(a, 0);
    2105         128 :                 pushInstruction(mb, tpn);
    2106         128 :                 cur = tpn;
    2107             :         }
    2108         105 :         if (mb->errors)
    2109             :                 return -1;
    2110             :         return 0;
    2111             : }
    2112             : 
    2113             : static int
    2114         186 : mat_topn(MalBlkPtr mb, InstrPtr p, matlist_t *ml, int m, int n, int o)
    2115             : {
    2116         186 :         int tpe = getArgType(mb, p, 0), k, is_slice = isSlice(p), zero = -1;
    2117         186 :         InstrPtr pck, gpck = NULL, q, r;
    2118         186 :         int with_groups = (p->retc == 2), piv = 0, topn2 = (n >= 0);
    2119             : 
    2120         186 :         assert(topn2 || o < 0);
    2121             :         /* dummy mat instruction (needed to share result of p) */
    2122         186 :         pck = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
    2123         186 :         if (pck == NULL)
    2124             :                 return -1;
    2125         186 :         getArg(pck, 0) = getArg(p, 0);
    2126             : 
    2127         186 :         if (with_groups) {
    2128          23 :                 gpck = newInstructionArgs(mb, matRef, packRef, ml->v[m].mi->argc);
    2129          23 :                 if (gpck == NULL) {
    2130           0 :                         freeInstruction(pck);
    2131           0 :                         return -1;
    2132             :                 }
    2133          23 :                 getArg(gpck, 0) = getArg(p, 1);
    2134             :         }
    2135             : 
    2136         186 :         if (is_slice) {
    2137          58 :                 ValRecord cst;
    2138          58 :                 cst.vtype = getArgType(mb, p, 2);
    2139          58 :                 cst.val.lval = 0;
    2140          58 :                 cst.len = 0;
    2141          58 :                 zero = defConstant(mb, cst.vtype, &cst);
    2142          58 :                 if (zero < 0) {
    2143           0 :                         freeInstruction(pck);
    2144           0 :                         return -1;
    2145             :                 }
    2146             :         }
    2147         186 :         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        1577 :         for (k = 1; mb->errors == NULL && k < ml->v[m].mi->argc; k++) {
    2152        1391 :                 if ((q = copyInstruction(p)) == NULL) {
    2153           0 :                         freeInstruction(gpck);
    2154           0 :                         freeInstruction(pck);
    2155           0 :                         return -1;
    2156             :                 }
    2157        1391 :                 getArg(q, 0) = newTmpVariable(mb, tpe);
    2158        1391 :                 if (with_groups)
    2159         186 :                         getArg(q, 1) = newTmpVariable(mb, tpe);
    2160        1391 :                 getArg(q, q->retc) = getArg(ml->v[m].mi, k);
    2161        1391 :                 if (is_slice)                   /* lower bound should always be 0 on partial slices */
    2162         421 :                         getArg(q, q->retc + 1) = zero;
    2163         970 :                 else if (topn2) {
    2164         186 :                         getArg(q, q->retc + 1) = getArg(ml->v[n].mi, k);
    2165         186 :                         getArg(q, q->retc + 2) = getArg(ml->v[o].mi, k);
    2166             :                 }
    2167        1391 :                 pushInstruction(mb, q);
    2168             : 
    2169        1391 :                 pck = pushArgument(mb, pck, getArg(q, 0));
    2170        1391 :                 if (with_groups)
    2171         186 :                         gpck = pushArgument(mb, gpck, getArg(q, 1));
    2172             :         }
    2173             : 
    2174         186 :         piv = ml->top;
    2175         314 :         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         186 :         if (with_groups
    2181          23 :                 && 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         186 :         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         105 :                         if (mat_pack_topn(mb, pck, ml->v, (!is_slice) ? piv : m))
    2190             :                                 return -1;
    2191             :                 }
    2192             : 
    2193             :                 /* topn/slice over merged parts */
    2194         105 :                 if (is_slice) {
    2195             :                         /* real instruction */
    2196          58 :                         r = newInstructionArgs(mb, matRef, packRef, pck->argc);
    2197          58 :                         if (r == NULL)
    2198             :                                 return -1;
    2199          58 :                         getArg(r, 0) = newTmpVariable(mb, tpe);
    2200             : 
    2201         479 :                         for (k = 1; k < pck->argc; k++)
    2202         421 :                                 r = pushArgument(mb, r, getArg(pck, k));
    2203          58 :                         pushInstruction(mb, r);
    2204             : 
    2205          58 :                         if ((q = copyInstruction(p)) == NULL)
    2206             :                                 return -1;
    2207          58 :                         setFunctionId(q, subsliceRef);
    2208          58 :                         if (ml->v[m].type != mat_tpn || is_slice)
    2209          58 :                                 getArg(q, 1) = getArg(r, 0);
    2210          58 :                         pushInstruction(mb, q);
    2211             :                 }
    2212             : 
    2213         163 :                 ml->v[piv].type = mat_slc;
    2214             :         }
    2215         186 :         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      445866 : OPTmergetableImplementation(Client cntxt, MalBlkPtr mb, MalStkPtr stk,
    2286             :                                                         InstrPtr pci)
    2287             : {
    2288      445866 :         InstrPtr p, *old;
    2289      445866 :         matlist_t ml;
    2290      445866 :         int oldtop, fm, fn, fo, fe, i, k, m, n, o, e, slimit, bailout = 0;
    2291      445866 :         int size = 0, match, actions = 0, distinct_topn = 0, /*topn_res = 0, */ groupdone = 0, *vars;   //, maxvars;
    2292      445866 :         char *group_input;
    2293      445866 :         str msg = MAL_SUCCEED;
    2294             : 
    2295      445866 :         if (isOptimizerUsed(mb, pci, mitosisRef) <= 0)
    2296       33739 :                 goto cleanup2;
    2297      412145 :         old = mb->stmt;
    2298      412145 :         oldtop = mb->stop;
    2299             : 
    2300      412145 :         vars = (int *) GDKmalloc(sizeof(int) * mb->vtop);
    2301             :         //maxvars = mb->vtop;
    2302      412147 :         group_input = (char *) GDKzalloc(sizeof(char) * mb->vtop);
    2303      412149 :         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    18391251 :         for (i = 1; i < oldtop && !bailout; i++) {
    2310    17979105 :                 int j;
    2311             : 
    2312    17979105 :                 p = old[i];
    2313             : 
    2314    36183064 :                 for (j = 0; j < p->retc; j++) {
    2315    18203959 :                         int res = getArg(p, j);
    2316    18203959 :                         vars[res] = i;
    2317             :                 }
    2318             : 
    2319             :                 /* pack if there is a group statement following a groupdone (ie aggr(distinct)) */
    2320    17979105 :                 if (getModuleId(p) == groupRef && p->argc == 5
    2321        5155 :                         && (getFunctionId(p) == subgroupRef
    2322        3515 :                                 || getFunctionId(p) == subgroupdoneRef
    2323           0 :                                 || getFunctionId(p) == groupRef
    2324           0 :                                 || getFunctionId(p) == groupdoneRef)) {
    2325        5155 :                         InstrPtr q = old[vars[getArg(p, p->argc - 1)]];      /* group result from a previous group(done) */
    2326             : 
    2327        5155 :                         if (getFunctionId(q) == subgroupdoneRef
    2328        5151 :                                 || getFunctionId(q) == groupdoneRef)
    2329    17979105 :                                 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    17979105 :                 if (getModuleId(p) == groupRef
    2333       25274 :                         && (getFunctionId(p) == subgroupRef
    2334       23634 :                                 || getFunctionId(p) == subgroupdoneRef
    2335       20119 :                                 || getFunctionId(p) == groupRef
    2336       16573 :                                 || getFunctionId(p) == groupdoneRef)) {
    2337       25274 :                         int input = getArg(p, p->retc);      /* argument one is first input */
    2338             : 
    2339       25274 :                         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       25274 :                         group_input[input] = 1;
    2346             :                 }
    2347    17979105 :                 if (getModuleId(p) == algebraRef && getFunctionId(p) == selectNotNilRef) {
    2348           0 :                         TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout not nil ref\n");
    2349             :                         bailout = 1;
    2350             :                 }
    2351    17979105 :                 if (getModuleId(p) == algebraRef && getFunctionId(p) == semijoinRef) {
    2352         181 :                         TRC_INFO(MAL_OPTIMIZER, "Mergetable bailout semijoin ref\n");
    2353             :                         bailout = 1;
    2354             :                 }
    2355    17979105 :                 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    17979105 :                 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      412146 :         GDKfree(group_input);
    2376             : 
    2377      412142 :         ml.horigin = 0;
    2378      412142 :         ml.torigin = 0;
    2379      412142 :         ml.v = 0;
    2380      412142 :         ml.vars = 0;
    2381      412142 :         if (bailout)
    2382         316 :                 goto cleanup;
    2383             : 
    2384             :         /* the number of MATs is limited to the variable stack */
    2385      411826 :         ml.size = mb->vtop;
    2386      411826 :         ml.top = 0;
    2387      411826 :         ml.v = (mat_t *) GDKzalloc(ml.size * sizeof(mat_t));
    2388      411837 :         ml.vsize = mb->vsize;
    2389      411837 :         ml.horigin = (int *) GDKmalloc(sizeof(int) * ml.vsize);
    2390      411817 :         ml.torigin = (int *) GDKmalloc(sizeof(int) * ml.vsize);
    2391      411811 :         ml.vars = (int *) GDKmalloc(sizeof(int) * ml.vsize);
    2392      411817 :         if (ml.v == NULL || ml.horigin == NULL || ml.torigin == NULL
    2393      411817 :                 || ml.vars == NULL) {
    2394           0 :                 goto cleanup;
    2395             :         }
    2396   115262121 :         for (i = 0; i < ml.vsize; i++) {
    2397   114850304 :                 ml.horigin[i] = ml.torigin[i] = -1;
    2398   114850304 :                 ml.vars[i] = -1;
    2399             :         }
    2400             : 
    2401      411817 :         slimit = mb->ssize;
    2402      411817 :         size = (mb->stop * 1.2 < mb->ssize) ? mb->ssize : (int) (mb->stop * 1.2);
    2403      411817 :         mb->stmt = (InstrPtr *) GDKzalloc(size * sizeof(InstrPtr));
    2404      411835 :         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      411835 :         mb->ssize = size;
    2411      411835 :         mb->stop = 0;
    2412             : 
    2413     6009178 :         for (i = 0; i < oldtop; i++) {
    2414     6009178 :                 int bats = 0, nilbats = 0;
    2415     6009178 :                 InstrPtr r, cp;
    2416             : 
    2417     6009178 :                 p = old[i];
    2418             : 
    2419     6009178 :                 if (p->token == ENDsymbol)   /* don't copy the optimizer pipeline added after final instruction */
    2420             :                         break;
    2421     5597354 :                 if (getModuleId(p) == matRef
    2422      234537 :                         && (getFunctionId(p) == newRef || getFunctionId(p) == packRef)) {
    2423      216584 :                         if (mat_set_prop(&ml, mb, p)
    2424      216584 :                                 || 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      216584 :                         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     5380770 :                 if ((match = nr_of_mats(p, &ml)) == 0) {
    2438     4116681 :                         cp = copyInstruction(p);
    2439     4116648 :                         if (!cp) {
    2440           0 :                                 msg = createException(MAL, "optimizer.mergetable",
    2441             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2442           0 :                                 goto cleanup;
    2443             :                         }
    2444     4116648 :                         pushInstruction(mb, cp);
    2445     4116659 :                         continue;
    2446             :                 }
    2447     1264089 :                 bats = nr_of_bats(mb, p);
    2448     1264089 :                 nilbats = nr_of_nilbats(mb, p);
    2449             : 
    2450             :                 /* left joins can match at isMatJoinOp, so run this check beforehand */
    2451     1264089 :                 if (match > 0 && isMatLeftJoinOp(p) && p->argc >= 5 && p->retc == 2
    2452        2417 :                         && (match == 1 || match == 2) && bats + nilbats == 4) {
    2453        2417 :                         m = is_a_mat(getArg(p, p->retc), &ml);
    2454        2417 :                         o = is_a_mat(getArg(p, p->retc + 2), &ml);
    2455             : 
    2456        2417 :                         if ((match == 1 && m >= 0) || (match == 2 && m >= 0 && o >= 0)) {
    2457        2409 :                                 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        2409 :                                 actions++;
    2463        2409 :                                 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     1261680 :                 if (match > 0 && isMatJoinOp(p) && !isMatLeftJoinOp(p) && p->argc >= 5
    2473       52954 :                         && p->retc == 2 && bats + nilbats >= 4) {
    2474       46676 :                         if (bats + nilbats == 4) {
    2475       46618 :                                 m = is_a_mat(getArg(p, p->retc), &ml);
    2476       46618 :                                 n = is_a_mat(getArg(p, p->retc + 1), &ml);
    2477       46618 :                                 o = is_a_mat(getArg(p, p->retc + 2), &ml);
    2478       46618 :                                 e = is_a_mat(getArg(p, p->retc + 3), &ml);
    2479       46618 :                                 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       46676 :                         actions++;
    2501       46676 :                         continue;
    2502             :                 }
    2503     1215004 :                 if (match > 0 && getModuleId(p) == algebraRef
    2504      948134 :                         && getFunctionId(p) == crossRef && p->argc == 5 && p->retc == 2
    2505        6278 :                         && bats == 2) {
    2506     1221282 :                         int max_one = (isVarConstant(mb, getArg(p, 4))
    2507        6278 :                                                    && getVarConstant(mb, getArg(p, 4)).val.btval);
    2508       10402 :                         if (!max_one) {
    2509        5201 :                                 m = is_a_mat(getArg(p, p->retc), &ml);
    2510        5201 :                                 n = is_a_mat(getArg(p, p->retc + 1), &ml);
    2511        5201 :                                 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        5201 :                                 actions++;
    2517        5201 :                                 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     1209803 :                 if (match == 1 && p->argc >= 2 &&
    2527      251149 :                         ((getModuleId(p) == aggrRef &&
    2528        1740 :                           (getFunctionId(p) == countRef
    2529        1439 :                            || getFunctionId(p) == count_no_nilRef
    2530        1439 :                            || getFunctionId(p) == minRef || getFunctionId(p) == maxRef
    2531        1344 :                            || getFunctionId(p) == avgRef || getFunctionId(p) == sumRef
    2532         108 :                            || getFunctionId(p) == prodRef)))
    2533        1638 :                         && (m = is_a_mat(getArg(p, p->retc + 0), &ml)) >= 0) {
    2534        1638 :                         if ((msg = mat_aggr(mb, p, ml.v, m)) != MAL_SUCCEED)
    2535           0 :                                 goto cleanup;
    2536        1638 :                         actions++;
    2537        1638 :                         continue;
    2538             :                 }
    2539             : 
    2540     1208165 :                 if (match == 1 && bats == 1 && p->argc == 4 && isSlice(p)
    2541          58 :                         && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
    2542          58 :                         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          58 :                         actions++;
    2548          58 :                         continue;
    2549             :                 }
    2550             : 
    2551     1208107 :                 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     1208107 :                 if (!distinct_topn && match == 1 && bats == 1 && isTopn(p)
    2563         105 :                         && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
    2564         105 :                         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         105 :                         actions++;
    2570         105 :                         continue;
    2571             :                 }
    2572     1208002 :                 if (!distinct_topn && match == 3 && bats == 3 && isTopn(p)
    2573          23 :                         && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)
    2574          23 :                         && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
    2575          23 :                         && ((o = is_a_mat(getArg(p, p->retc + 2), &ml)) >= 0)) {
    2576          23 :                         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          23 :                         actions++;
    2582          23 :                         continue;
    2583             :                 }
    2584             : 
    2585             :                 /* Now we handle subgroup and aggregation statements. */
    2586     1207979 :                 if (!groupdone && match == 1 && bats == 1 && p->argc == 4
    2587       14943 :                         && getModuleId(p) == groupRef &&
    2588        4559 :                         (getFunctionId(p) == subgroupRef
    2589        4559 :                          || getFunctionId(p) == subgroupdoneRef
    2590        4559 :                          || getFunctionId(p) == groupRef
    2591        2497 :                          || getFunctionId(p) == groupdoneRef)
    2592        4559 :                         && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)) {
    2593        4559 :                         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        4559 :                         actions++;
    2599        4559 :                         continue;
    2600             :                 }
    2601     1203420 :                 if (!groupdone && match == 2 && bats == 2 && p->argc == 5
    2602       39641 :                         && getModuleId(p) == groupRef &&
    2603        2414 :                         (getFunctionId(p) == subgroupRef
    2604        2062 :                          || getFunctionId(p) == subgroupdoneRef
    2605           0 :                          || getFunctionId(p) == groupRef
    2606           0 :                          || getFunctionId(p) == groupdoneRef)
    2607        2414 :                         && ((m = is_a_mat(getArg(p, p->retc), &ml)) >= 0)
    2608        2414 :                         && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
    2609        2414 :                         && ml.v[n].im >= 0 /* not packed */ ) {
    2610        2414 :                         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        2414 :                         actions++;
    2616        2414 :                         continue;
    2617             :                 }
    2618             :                 /* TODO sub'aggr' with cand list */
    2619     1201006 :                 if (match == 3 && bats == 3 && getModuleId(p) == aggrRef && p->argc >= 4
    2620        3017 :                         && (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        3017 :                         && ((m = is_a_mat(getArg(p, p->retc + 0), &ml)) >= 0)
    2627        3017 :                         && ((n = is_a_mat(getArg(p, p->retc + 1), &ml)) >= 0)
    2628        3017 :                         && ((o = is_a_mat(getArg(p, p->retc + 2), &ml)) >= 0)) {
    2629        3017 :                         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        3017 :                         actions++;
    2635        3017 :                         continue;
    2636             :                 }
    2637             :                 /* Handle cases of ext.projection and .projection(grp) */
    2638     1197989 :                 if (match == 2 && getModuleId(p) == algebraRef
    2639      776337 :                         && getFunctionId(p) == projectionRef
    2640      726475 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
    2641      726475 :                         && (n = is_a_mat(getArg(p, 2), &ml)) >= 0
    2642      726475 :                         && (ml.v[m].type == mat_ext || ml.v[n].type == mat_grp)) {
    2643        6857 :                         assert(ml.v[m].pushed);
    2644        6857 :                         if (!ml.v[n].pushed) {
    2645        6857 :                                 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        6857 :                         continue;
    2660             :                 }
    2661     1191132 :                 if (match == 1 && getModuleId(p) == algebraRef
    2662      166184 :                         && getFunctionId(p) == projectRef
    2663       27865 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
    2664       27865 :                         && (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     1191132 :                 if (match == 2 && getModuleId(p) == algebraRef
    2678      769480 :                         && getFunctionId(p) == projectionRef
    2679      719618 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0
    2680      719618 :                         && (n = is_a_mat(getArg(p, 2), &ml)) >= 0
    2681      719618 :                         && (ml.v[m].type == mat_slc)) {
    2682         607 :                         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         607 :                         actions++;
    2688         607 :                         continue;
    2689             :                 }
    2690             : 
    2691             :                 /* Handle projection */
    2692     1190525 :                 if (match > 0
    2693     1190525 :                         &&
    2694     1190525 :                         ((getModuleId(p) == algebraRef && getFunctionId(p) == projectionRef)
    2695      378399 :                          || ((getModuleId(p) == dictRef || getModuleId(p) == forRef)
    2696         130 :                                  && getFunctionId(p) == decompressRef))
    2697      812199 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0) {
    2698      803940 :                         n = is_a_mat(getArg(p, 2), &ml);
    2699      803940 :                         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      803940 :                         actions++;
    2705      803940 :                         continue;
    2706             :                 }
    2707             :                 /* Handle setops */
    2708      386585 :                 if (match > 0 && getModuleId(p) == algebraRef
    2709      131416 :                         && (getFunctionId(p) == differenceRef
    2710      114734 :                                 || getFunctionId(p) == intersectRef)
    2711       17810 :                         && (m = is_a_mat(getArg(p, 1), &ml)) >= 0) {
    2712       17192 :                         n = is_a_mat(getArg(p, 2), &ml);
    2713       17192 :                         o = is_a_mat(getArg(p, 3), &ml);
    2714       17192 :                         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       17192 :                         actions++;
    2720       17192 :                         continue;
    2721             :                 }
    2722             : 
    2723      369393 :                 if (match == p->retc && p->argc == (p->retc * 2)
    2724       16607 :                         && 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      369389 :                 m = n = o = e = -1;
    2735      772653 :                 for (fm = p->argc - 1; fm >= p->retc; fm--)
    2736      772653 :                         if ((m = is_a_mat(getArg(p, fm), &ml)) >= 0)
    2737             :                                 break;
    2738             : 
    2739      455210 :                 for (fn = fm - 1; fn >= p->retc; fn--)
    2740      295505 :                         if ((n = is_a_mat(getArg(p, fn), &ml)) >= 0)
    2741             :                                 break;
    2742             : 
    2743      385938 :                 for (fo = fn - 1; fo >= p->retc; fo--)
    2744      140911 :                         if ((o = is_a_mat(getArg(p, fo), &ml)) >= 0)
    2745             :                                 break;
    2746             : 
    2747      398340 :                 for (fe = fo - 1; fe >= p->retc; fe--)
    2748       71701 :                         if ((e = is_a_mat(getArg(p, fe), &ml)) >= 0)
    2749             :                                 break;
    2750             : 
    2751             :                 /* delta* operator */
    2752      369389 :                 if (match == 3 && bats == 3 && isDelta(p)
    2753       48838 :                         && (m = is_a_mat(getArg(p, fm), &ml)) >= 0
    2754       48838 :                         && (n = is_a_mat(getArg(p, fn), &ml)) >= 0
    2755       48838 :                         && (o = is_a_mat(getArg(p, fo), &ml)) >= 0) {
    2756       48838 :                         if ((r = mat_delta(&ml, mb, p, ml.v, m, n, o, -1, fm, fn, fo, 0)) != NULL) {
    2757       48838 :                                 actions++;
    2758             :                         } else {
    2759           0 :                                 msg = createException(MAL, "optimizer.mergetable",
    2760             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2761           0 :                                 goto cleanup;
    2762             :                         }
    2763             : 
    2764       48838 :                         continue;
    2765             :                 }
    2766      320551 :                 if (match == 4 && bats == 4 && isDelta(p)
    2767       38557 :                         && (m = is_a_mat(getArg(p, fm), &ml)) >= 0
    2768       38557 :                         && (n = is_a_mat(getArg(p, fn), &ml)) >= 0
    2769       38557 :                         && (o = is_a_mat(getArg(p, fo), &ml)) >= 0
    2770       38557 :                         && (e = is_a_mat(getArg(p, fe), &ml)) >= 0) {
    2771       38557 :                         if ((r = mat_delta(&ml, mb, p, ml.v, m, n, o, e, fm, fn, fo, fe)) != NULL) {
    2772       38557 :                                 actions++;
    2773             :                         } else {
    2774           0 :                                 msg = createException(MAL, "optimizer.mergetable",
    2775             :                                                                           SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2776           0 :                                 goto cleanup;
    2777             :                         }
    2778       38557 :                         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      281994 :                 if (match == 1 && fm == 1 && isSelect(p) && p->retc == 1
    2800       36991 :                         && (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      281990 :                 if ((match == 1 || match == bats - 1) && p->retc == 1 && isSelect(p)
    2815       37040 :                         && 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      281941 :                 if (match == 1 && match == bats - 1 && p->retc == 1
    2826       42436 :                         && 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      281937 :                 if (match == bats && p->retc == 1
    2837      214663 :                         && (isMap2Op(p) || isMapOp(p) || isFragmentGroup(p)
    2838       34048 :                                 || isFragmentGroup2(p))) {
    2839      212089 :                         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      212089 :                         actions++;
    2845      212089 :                         continue;
    2846             :                 }
    2847             : 
    2848             :                 /*
    2849             :                  * All other instructions should be checked for remaining MAT dependencies.
    2850             :                  * It requires MAT materialization.
    2851             :                  */
    2852             : 
    2853      381922 :                 for (k = p->retc; msg == MAL_SUCCEED && k < p->argc; k++) {
    2854      312074 :                         if ((m = is_a_mat(getArg(p, k), &ml)) >= 0) {
    2855      116765 :                                 msg = mat_pack(mb, &ml, m);
    2856      116765 :                                 if (msg)
    2857             :                                         break;
    2858             :                         }
    2859             :                 }
    2860       69848 :                 if (msg)
    2861             :                         break;
    2862             : 
    2863       69848 :                 cp = copyInstruction(p);
    2864       69848 :                 if (!cp) {
    2865           0 :                         msg = createException(MAL, "optimizer.mergetable",
    2866             :                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2867           0 :                         goto cleanup;
    2868             :                 }
    2869       69848 :                 pushInstruction(mb, cp);
    2870             :         }
    2871             :         (void) stk;
    2872             : 
    2873    13176093 :         for (; i < oldtop; i++) {    /* add optimizer pipeline back again */
    2874    12764261 :                 pushInstruction(mb, old[i]);
    2875             :         }
    2876             : 
    2877      411832 :         if (mb->errors == MAL_SUCCEED) {
    2878     6009132 :                 for (i = 0; i < slimit; i++) {
    2879     6009132 :                         if (old[i] && old[i]->token == ENDsymbol)    /* don't free optimizer calls */
    2880             :                                 break;
    2881     5597328 :                         freeInstruction(old[i]);
    2882             :                 }
    2883      411804 :                 GDKfree(old);
    2884             :         }
    2885     1889060 :         for (i = 0; i < ml.top; i++) {
    2886     1477231 :                 if (ml.v[i].mi && !ml.v[i].pushed)
    2887     1232755 :                         freeInstruction(ml.v[i].mi);
    2888             :         }
    2889      411829 :   cleanup:
    2890      412145 :         if (vars)
    2891      412145 :                 GDKfree(vars);
    2892      412153 :         if (ml.v)
    2893      411837 :                 GDKfree(ml.v);
    2894      412154 :         if (ml.horigin)
    2895      411838 :                 GDKfree(ml.horigin);
    2896      412153 :         if (ml.torigin)
    2897      411837 :                 GDKfree(ml.torigin);
    2898      412153 :         if (ml.vars)
    2899      411837 :                 GDKfree(ml.vars);
    2900      412151 :         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      412151 :         if (actions > 0 && msg == MAL_SUCCEED) {
    2907       27320 :                 msg = chkTypes(cntxt->usermodule, mb, FALSE);
    2908       27320 :                 if (!msg)
    2909       27320 :                         msg = chkFlow(mb);
    2910       27320 :                 if (!msg)
    2911       27320 :                         msg = chkDeclarations(mb);
    2912             :         }
    2913      384831 :   cleanup2:
    2914             :         /* keep actions taken as a fake argument */
    2915      445890 :         if (msg == MAL_SUCCEED) {
    2916      445883 :                 (void) pushInt(mb, pci, actions);
    2917      445924 :                 msg = mb->errors;            /* may well be NULL */
    2918      445924 :                 mb->errors = NULL;
    2919             :         }
    2920             : 
    2921             : #ifndef NDEBUG
    2922      445931 :         if (bailout)
    2923         316 :                 TRC_INFO(MAL_OPTIMIZER, "Merge table bailout\n");
    2924             : #endif
    2925             :         return msg;
    2926             : }

Generated by: LCOV version 1.14