LCOV - code coverage report
Current view: top level - gdk - gdk_project.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 343 413 83.1 %
Date: 2020-06-29 20:00:14 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2020 MonetDB B.V.
       7             :  */
       8             : 
       9             : #include "monetdb_config.h"
      10             : #include "gdk.h"
      11             : #include "gdk_private.h"
      12             : 
      13             : /*
      14             :  * BATproject returns a BAT aligned with the left input whose values
      15             :  * are the values from the right input that were referred to by the
      16             :  * OIDs in the left input.
      17             :  *
      18             :  * BATproject2 is similar, except instead of a single right input
      19             :  * there are two of which the second's hseqbase is equal to the first
      20             :  * hseqbase + its batCount.
      21             :  */
      22             : 
      23             : #define project_loop(TYPE)                                              \
      24             : static gdk_return                                                       \
      25             : project_##TYPE(BAT *restrict bn, BAT *restrict l,                       \
      26             :                struct canditer *restrict ci,                            \
      27             :                BAT *restrict r1, BAT *restrict r2)                      \
      28             : {                                                                       \
      29             :         BUN lo, hi;                                                     \
      30             :         const TYPE *restrict r1t;                                       \
      31             :         const TYPE *restrict r2t;                                       \
      32             :         TYPE *restrict bt;                                              \
      33             :         TYPE v;                                                         \
      34             :         oid r1seq, r1end;                                               \
      35             :         oid r2seq, r2end;                                               \
      36             :                                                                         \
      37             :         r1t = (const TYPE *) Tloc(r1, 0);                               \
      38             :         r2t = r2 ? (const TYPE *) Tloc(r2, 0) : NULL;                   \
      39             :         bt = (TYPE *) Tloc(bn, 0);                                      \
      40             :         r1seq = r1->hseqbase;                                                \
      41             :         r1end = r1seq + BATcount(r1);                                   \
      42             :         if (r2) {                                                       \
      43             :                 r2seq = r2->hseqbase;                                        \
      44             :                 r2end = r2seq + BATcount(r2);                           \
      45             :         } else {                                                        \
      46             :                 r2seq = r2end = r1end;                                  \
      47             :         }                                                               \
      48             :         if (ci) {                                                       \
      49             :                 for (lo = 0, hi = ci->ncand; lo < hi; lo++) {             \
      50             :                         oid o = canditer_next(ci);                      \
      51             :                         if (o < r1seq || o >= r2end) {                    \
      52             :                                 GDKerror("does not match always\n");  \
      53             :                                 return GDK_FAIL;                        \
      54             :                         }                                               \
      55             :                         if (o < r1end)                                       \
      56             :                                 v = r1t[o - r1seq];                     \
      57             :                         else                                            \
      58             :                                 v = r2t[o - r2seq];                     \
      59             :                         bt[lo] = v;                                     \
      60             :                 }                                                       \
      61             :         } else if (BATtdense(l)) {                                      \
      62             :                 for (lo = 0, hi = BATcount(l); lo < hi; lo++) {              \
      63             :                         oid o = l->tseqbase + lo;                    \
      64             :                         if (o < r1seq || o >= r2end) {                    \
      65             :                                 GDKerror("does not match always\n");  \
      66             :                                 return GDK_FAIL;                        \
      67             :                         }                                               \
      68             :                         if (o < r1end)                                       \
      69             :                                 v = r1t[o - r1seq];                     \
      70             :                         else                                            \
      71             :                                 v = r2t[o - r2seq];                     \
      72             :                         bt[lo] = v;                                     \
      73             :                 }                                                       \
      74             :         } else {                                                        \
      75             :                 const oid *restrict ot = (const oid *) Tloc(l, 0);      \
      76             :                 for (lo = 0, hi = BATcount(l); lo < hi; lo++) {              \
      77             :                         oid o = ot[lo];                                 \
      78             :                         if (is_oid_nil(o)) {                            \
      79             :                                 bt[lo] = v = TYPE##_nil;                \
      80             :                                 bn->tnil = true;                     \
      81             :                         } else if (o < r1seq || o >= r2end) {             \
      82             :                                 GDKerror("does not match always\n");  \
      83             :                                 return GDK_FAIL;                        \
      84             :                         } else if (o < r1end) {                              \
      85             :                                 v = r1t[o - r1seq];                     \
      86             :                                 bt[lo] = v;                             \
      87             :                         } else {                                        \
      88             :                                 v = r2t[o - r2seq];                     \
      89             :                                 bt[lo] = v;                             \
      90             :                         }                                               \
      91             :                 }                                                       \
      92             :         }                                                               \
      93             :         BATsetcount(bn, lo);                                            \
      94             :         return GDK_SUCCEED;                                             \
      95             : }
      96             : 
      97             : 
      98             : /* project type switch */
      99    18578000 : project_loop(bte)
     100     5624920 : project_loop(sht)
     101   536336000 : project_loop(int)
     102        3077 : project_loop(flt)
     103      533089 : project_loop(dbl)
     104     2929310 : project_loop(lng)
     105             : #ifdef HAVE_HGE
     106    14129200 : project_loop(hge)
     107             : #endif
     108             : 
     109             : static gdk_return
     110       12225 : project_oid(BAT *restrict bn, BAT *restrict l, struct canditer *restrict lci,
     111             :             BAT *restrict r1, BAT *restrict r2)
     112             : {
     113       12225 :         BUN lo, hi;
     114       12225 :         oid *restrict bt;
     115       12225 :         oid r1seq, r1end;
     116       12225 :         oid r2seq, r2end;
     117       12225 :         const oid *restrict r1t = NULL;
     118       12225 :         const oid *restrict r2t = NULL;
     119       12225 :         struct canditer r1ci = {0}, r2ci = {0};
     120             : 
     121       12225 :         if (r1->ttype == TYPE_void && r1->tvheap != NULL)
     122           3 :                 canditer_init(&r1ci, NULL, r1);
     123       12222 :         else if (!BATtdense(r1))
     124        3435 :                 r1t = (const oid *) Tloc(r1, 0);
     125       12225 :         r1seq = r1->hseqbase;
     126       12225 :         r1end = r1seq + BATcount(r1);
     127       12225 :         if (r2) {
     128          12 :                 if (r2->ttype == TYPE_void && r2->tvheap != NULL)
     129           0 :                         canditer_init(&r2ci, NULL, r2);
     130          12 :                 else if (!BATtdense(r2))
     131           1 :                         r2t = (const oid *) Tloc(r2, 0);
     132          12 :                 r2seq = r2->hseqbase;
     133          12 :                 r2end = r2seq + BATcount(r2);
     134             :         } else {
     135             :                 r2seq = r2end = r1end;
     136             :         }
     137       12225 :         bt = (oid *) Tloc(bn, 0);
     138       12225 :         if (lci) {
     139           6 :                 for (lo = 0, hi = lci->ncand; lo < hi; lo++) {
     140           3 :                         oid o = canditer_next(lci);
     141           4 :                         if (o < r1seq || o >= r2end) {
     142           0 :                                 GDKerror("does not match always\n");
     143           0 :                                 return GDK_FAIL;
     144             :                         }
     145           4 :                         if (o < r1end) {
     146           4 :                                 if (r1ci.s)
     147           0 :                                         bt[lo] = canditer_idx(&r1ci, o - r1seq);
     148           4 :                                 else if (r1t)
     149           1 :                                         bt[lo] = r1t[o - r1seq];
     150             :                                 else
     151           3 :                                         bt[lo] = o - r1seq + r1->tseqbase;
     152             :                         } else {
     153           0 :                                 if (r2ci.s)
     154           0 :                                         bt[lo] = canditer_idx(&r2ci, o - r2seq);
     155           0 :                                 else if (r2t)
     156           0 :                                         bt[lo] = r2t[o - r2seq];
     157             :                                 else
     158           0 :                                         bt[lo] = o - r2seq + r2->tseqbase;
     159             :                         }
     160             :                 }
     161       12223 :         } else if (BATtdense(l)) {
     162          42 :                 for (lo = 0, hi = BATcount(l); lo < hi; lo++) {
     163          30 :                         oid o = l->tseqbase + lo;
     164          30 :                         if (o < r1seq || o >= r2end) {
     165           0 :                                 GDKerror("does not match always\n");
     166           0 :                                 return GDK_FAIL;
     167             :                         }
     168          30 :                         if (o < r1end) {
     169          18 :                                 if (r1ci.s)
     170           0 :                                         bt[lo] = canditer_idx(&r1ci, o - r1seq);
     171          18 :                                 else if (r1t)
     172           7 :                                         bt[lo] = r1t[o - r1seq];
     173             :                                 else
     174          11 :                                         bt[lo] = o - r1seq + r1->tseqbase;
     175             :                         } else {
     176          12 :                                 if (r2ci.s)
     177           0 :                                         bt[lo] = canditer_idx(&r2ci, o - r2seq);
     178          12 :                                 else if (r2t)
     179           1 :                                         bt[lo] = r2t[o - r2seq];
     180             :                                 else
     181          11 :                                         bt[lo] = o - r2seq + r2->tseqbase;
     182             :                         }
     183             :                 }
     184             :         } else {
     185       12211 :                 const oid *ot = (const oid *) Tloc(l, 0);
     186   333549000 :                 for (lo = 0, hi = BATcount(l); lo < hi; lo++) {
     187   333537000 :                         oid o = ot[lo];
     188   333537000 :                         if (is_oid_nil(o)) {
     189           0 :                                 bt[lo] = oid_nil;
     190           0 :                                 bn->tnonil = false;
     191           0 :                                 bn->tnil = true;
     192   333537000 :                         } else if (o < r1seq || o >= r2end) {
     193           0 :                                 GDKerror("does not match always\n");
     194           0 :                                 return GDK_FAIL;
     195   333537000 :                         } else if (o < r1end) {
     196   333537000 :                                 if (r1ci.s)
     197        7778 :                                         bt[lo] = canditer_idx(&r1ci, o - r1seq);
     198   333529000 :                                 else if (r1t)
     199   127449000 :                                         bt[lo] = r1t[o - r1seq];
     200             :                                 else
     201   206080000 :                                         bt[lo] = o - r1seq + r1->tseqbase;
     202             :                         } else {
     203           0 :                                 if (r2ci.s)
     204           0 :                                         bt[lo] = canditer_idx(&r2ci, o - r2seq);
     205           0 :                                 else if (r2t)
     206           0 :                                         bt[lo] = r2t[o - r2seq];
     207             :                                 else
     208           0 :                                         bt[lo] = o - r2seq + r2->tseqbase;
     209             :                         }
     210             :                 }
     211             :         }
     212       12223 :         BATsetcount(bn, lo);
     213       12223 :         return GDK_SUCCEED;
     214             : }
     215             : 
     216             : static gdk_return
     217        1989 : project_any(BAT *restrict bn, BAT *restrict l, struct canditer *restrict ci,
     218             :             BAT *restrict r1, BAT *restrict r2)
     219             : {
     220        1989 :         BUN lo, hi;
     221        1989 :         BATiter r1i, r2i;
     222        1989 :         const void *nil = ATOMnilptr(r1->ttype);
     223        1989 :         const void *v;
     224        1989 :         oid r1seq, r1end;
     225        1989 :         oid r2seq, r2end;
     226             : 
     227        1989 :         r1i = bat_iterator(r1);
     228        1989 :         r1seq = r1->hseqbase;
     229        1989 :         r1end = r1seq + BATcount(r1);
     230        1989 :         r2i = bat_iterator(r2);
     231        1989 :         if (r2) {
     232         222 :                 r2seq = r2->hseqbase;
     233         222 :                 r2end = r2seq + BATcount(r2);
     234             :         } else {
     235             :                 r2seq = r2end = r1end;
     236             :         }
     237        1989 :         if (ci) {
     238       24962 :                 for (lo = 0, hi = ci->ncand; lo < hi; lo++) {
     239       24866 :                         oid o = canditer_next(ci);
     240       24870 :                         if (o < r1seq || o >= r2end) {
     241           0 :                                 GDKerror("does not match always\n");
     242           0 :                                 return GDK_FAIL;
     243             :                         }
     244       24870 :                         if (o < r1end)
     245       24604 :                                 v = BUNtail(r1i, o - r1seq);
     246             :                         else
     247         266 :                                 v = BUNtail(r2i, o - r2seq);
     248       24870 :                         if (tfastins_nocheck(bn, lo, v, Tsize(bn)) != GDK_SUCCEED)
     249             :                                 return GDK_FAIL;
     250             :                 }
     251        1893 :         } else if (BATtdense(l)) {
     252        8341 :                 for (lo = 0, hi = BATcount(l); lo < hi; lo++) {
     253        8233 :                         oid o = l->tseqbase + lo;
     254        8233 :                         if (o < r1seq || o >= r2end) {
     255           0 :                                 GDKerror("does not match always\n");
     256           0 :                                 return GDK_FAIL;
     257             :                         }
     258        8233 :                         if (o < r1end)
     259        7415 :                                 v = BUNtail(r1i, o - r1seq);
     260             :                         else
     261         818 :                                 v = BUNtail(r2i, o - r2seq);
     262        8233 :                         if (tfastins_nocheck(bn, lo, v, Tsize(bn)) != GDK_SUCCEED)
     263             :                                 return GDK_FAIL;
     264             :                 }
     265             :         } else {
     266        1785 :                 const oid *restrict ot = (const oid *) Tloc(l, 0);
     267             : 
     268     4626190 :                 for (lo = 0, hi = BATcount(l); lo < hi; lo++) {
     269     4624400 :                         oid o = ot[lo];
     270     4624400 :                         if (is_oid_nil(o)) {
     271           2 :                                 v = nil;
     272           2 :                                 bn->tnil = true;
     273     4624400 :                         } else if (o < r1seq || o >= r2end) {
     274           0 :                                 GDKerror("does not match always\n");
     275           0 :                                 return GDK_FAIL;
     276     4624400 :                         } else if (o < r1end) {
     277     4624400 :                                 v = BUNtail(r1i, o - r1seq);
     278             :                         } else {
     279           2 :                                 v = BUNtail(r2i, o - r2seq);
     280             :                         }
     281     4624400 :                         if (tfastins_nocheck(bn, lo, v, Tsize(bn)) != GDK_SUCCEED)
     282             :                                 return GDK_FAIL;
     283             :                 }
     284             :         }
     285        1989 :         BATsetcount(bn, lo);
     286        1989 :         bn->theap.dirty = true;
     287        1989 :         return GDK_SUCCEED;
     288             : }
     289             : 
     290             : BAT *
     291     1139360 : BATproject2(BAT *restrict l, BAT *restrict r1, BAT *restrict r2)
     292             : {
     293     1139360 :         BAT *bn;
     294     1139360 :         oid lo, hi;
     295     1139360 :         gdk_return res;
     296     1139360 :         int tpe = ATOMtype(r1->ttype);
     297     1139360 :         bool stringtrick = false;
     298     1139360 :         BUN lcount = BATcount(l);
     299     1139360 :         struct canditer ci, *lci = NULL;
     300     1139360 :         const char *msg = "";
     301     1139360 :         lng t0 = 0;
     302             : 
     303     1139360 :         TRC_DEBUG_IF(ALGO) t0 = GDKusec();
     304             : 
     305     1139360 :         assert(ATOMtype(l->ttype) == TYPE_oid);
     306     1142480 :         assert(r2 == NULL || ATOMtype(r1->ttype) == ATOMtype(r2->ttype));
     307     1139360 :         assert(r2 == NULL || r1->hseqbase + r1->batCount == r2->hseqbase);
     308             : 
     309     1139360 :         if (BATtdense(l) && lcount > 0) {
     310      478375 :                 lo = l->tseqbase;
     311      478375 :                 hi = l->tseqbase + lcount;
     312      478375 :                 if (lo >= r1->hseqbase && hi <= r1->hseqbase + r1->batCount) {
     313      477281 :                         bn = BATslice(r1, lo - r1->hseqbase, hi - r1->hseqbase);
     314      477343 :                         BAThseqbase(bn, l->hseqbase);
     315      477382 :                         msg = " (slice)";
     316      477382 :                         goto doreturn;
     317             :                 }
     318        1094 :                 if (lo < r1->hseqbase || r2 == NULL || hi > r2->hseqbase + r2->batCount) {
     319           1 :                         GDKerror("does not match always\n");
     320           1 :                         return NULL;
     321             :                 }
     322        1093 :                 if (lo >= r2->hseqbase) {
     323         281 :                         bn = BATslice(r2, lo - r2->hseqbase, hi - r2->hseqbase);
     324         281 :                         BAThseqbase(bn, l->hseqbase);
     325         281 :                         msg = " (slice2)";
     326         281 :                         goto doreturn;
     327             :                 }
     328             :         }
     329      661792 :         if (l->ttype == TYPE_void && l->tvheap != NULL) {
     330             :                 /* l is candidate list with exceptions */
     331        1485 :                 assert(!is_oid_nil(l->tseqbase));
     332        1485 :                 lcount = canditer_init(&ci, NULL, l);
     333        1485 :                 lci = &ci;
     334             :         }
     335      661792 :         if (lcount == 0 ||
     336      152877 :             (l->ttype == TYPE_void && is_oid_nil(l->tseqbase)) ||
     337      152877 :             (r1->ttype == TYPE_void && is_oid_nil(r1->tseqbase) &&
     338           0 :              (r2 == NULL ||
     339           0 :               (r2->ttype == TYPE_void && is_oid_nil(r2->tseqbase))))) {
     340             :                 /* trivial: all values are nil (includes no entries at all) */
     341      508926 :                 const void *nil = ATOMnilptr(r1->ttype);
     342             : 
     343     1010700 :                 bn = BATconstant(l->hseqbase, r1->ttype == TYPE_oid ? TYPE_void : r1->ttype,
     344             :                                  nil, lcount, TRANSIENT);
     345      509008 :                 if (bn != NULL &&
     346      509008 :                     ATOMtype(bn->ttype) == TYPE_oid &&
     347       31920 :                     BATcount(bn) == 0) {
     348       31909 :                         BATtseqbase(bn, 0);
     349             :                 }
     350      509010 :                 msg = " (constant)";
     351      509010 :                 goto doreturn;
     352             :         }
     353             : 
     354      152866 :         if (ATOMstorage(tpe) == TYPE_str &&
     355       15028 :             l->tnonil &&
     356       14809 :             r2 == NULL &&
     357       14809 :             (r1->batCount == 0 ||
     358       14809 :              lcount > (r1->batCount >> 3) ||
     359        3007 :              r1->batRestricted == BAT_READ)) {
     360             :                 /* insert strings as ints, we need to copy the string
     361             :                  * heap whole sale; we can't do this if there are nils
     362             :                  * in the left column, and we won't do it if the left
     363             :                  * is much smaller than the right and the right is
     364             :                  * writable (meaning we have to actually copy the
     365             :                  * right string heap) */
     366       13092 :                 tpe = r1->twidth == 1 ? TYPE_bte : (r1->twidth == 2 ? TYPE_sht : (r1->twidth == 4 ? TYPE_int : TYPE_lng));
     367             :                 stringtrick = true;
     368             :         }
     369      152866 :         bn = COLnew(l->hseqbase, tpe, lcount, TRANSIENT);
     370      152869 :         if (bn == NULL) {
     371           0 :                 goto doreturn;
     372             :         }
     373      152869 :         bn->tnil = false;
     374      152869 :         if (r2) {
     375        1246 :                 bn->tnonil = l->tnonil & r1->tnonil & r2->tnonil;
     376        1246 :                 bn->tsorted = l->batCount <= 1;
     377        1246 :                 bn->trevsorted = l->batCount <= 1;
     378        1246 :                 bn->tkey = l->batCount <= 1;
     379             :         } else {
     380      151623 :                 bn->tnonil = l->tnonil & r1->tnonil;
     381      303246 :                 bn->tsorted = l->batCount <= 1
     382      151449 :                         || (l->tsorted & r1->tsorted)
     383      269257 :                         || (l->trevsorted & r1->trevsorted);
     384      303246 :                 bn->trevsorted = l->batCount <= 1
     385      151449 :                         || (l->tsorted & r1->trevsorted)
     386      294196 :                         || (l->trevsorted & r1->tsorted);
     387      284853 :                 bn->tkey = l->batCount <= 1 || (l->tkey & r1->tkey);
     388             :         }
     389             : 
     390      152869 :         if (!stringtrick && tpe != TYPE_oid)
     391      127550 :                 tpe = ATOMstorage(tpe);
     392      152869 :         switch (tpe) {
     393        9388 :         case TYPE_bte:
     394        9388 :                 res = project_bte(bn, l, lci, r1, r2);
     395        9388 :                 break;
     396        8235 :         case TYPE_sht:
     397        8235 :                 res = project_sht(bn, l, lci, r1, r2);
     398        8235 :                 break;
     399      105248 :         case TYPE_int:
     400      105248 :                 res = project_int(bn, l, lci, r1, r2);
     401      105248 :                 break;
     402          56 :         case TYPE_flt:
     403          56 :                 res = project_flt(bn, l, lci, r1, r2);
     404          56 :                 break;
     405        1534 :         case TYPE_dbl:
     406        1534 :                 res = project_dbl(bn, l, lci, r1, r2);
     407        1534 :                 break;
     408       11076 :         case TYPE_lng:
     409       11076 :                 res = project_lng(bn, l, lci, r1, r2);
     410       11076 :                 break;
     411             : #ifdef HAVE_HGE
     412        3119 :         case TYPE_hge:
     413        3119 :                 res = project_hge(bn, l, lci, r1, r2);
     414        3119 :                 break;
     415             : #endif
     416       12224 :         case TYPE_oid:
     417       12224 :                 res = project_oid(bn, l, lci, r1, r2);
     418       12224 :                 break;
     419        1989 :         default:
     420        1989 :                 res = project_any(bn, l, lci, r1, r2);
     421        1989 :                 break;
     422             :         }
     423             : 
     424      152848 :         if (res != GDK_SUCCEED)
     425          13 :                 goto bailout;
     426             : 
     427             :         /* handle string trick */
     428      152835 :         if (stringtrick) {
     429       13089 :                 assert(r1->tvheap);
     430       13089 :                 if (r1->batRestricted == BAT_READ) {
     431             :                         /* really share string heap */
     432        7844 :                         assert(r1->tvheap->parentid > 0);
     433        7844 :                         BBPshare(r1->tvheap->parentid);
     434        7845 :                         bn->tvheap = r1->tvheap;
     435             :                 } else {
     436             :                         /* make copy of string heap */
     437        5245 :                         bn->tvheap = (Heap *) GDKzalloc(sizeof(Heap));
     438        5245 :                         if (bn->tvheap == NULL)
     439           0 :                                 goto bailout;
     440        5245 :                         bn->tvheap->parentid = bn->batCacheid;
     441        5245 :                         bn->tvheap->farmid = BBPselectfarm(bn->batRole, TYPE_str, varheap);
     442        5245 :                         strconcat_len(bn->tvheap->filename,
     443             :                                       sizeof(bn->tvheap->filename),
     444        5245 :                                       BBP_physical(bn->batCacheid), ".theap",
     445             :                                       NULL);
     446        5244 :                         if (HEAPcopy(bn->tvheap, r1->tvheap) != GDK_SUCCEED)
     447           0 :                                 goto bailout;
     448             :                 }
     449       13090 :                 bn->ttype = r1->ttype;
     450       13090 :                 bn->tvarsized = true;
     451       13090 :                 bn->twidth = r1->twidth;
     452       13090 :                 bn->tshift = r1->tshift;
     453             :         }
     454             : 
     455      152836 :         if (!BATtdense(r1) || (r2 && !BATtdense(r2)))
     456      144048 :                 BATtseqbase(bn, oid_nil);
     457             : 
     458        8788 :   doreturn:
     459     1139540 :         TRC_DEBUG(ALGO, "l=" ALGOBATFMT " r1=" ALGOBATFMT " r2=" ALGOOPTBATFMT
     460             :                   " -> " ALGOOPTBATFMT "%s%s " LLFMT "us\n",
     461             :                   ALGOBATPAR(l), ALGOBATPAR(r1), ALGOOPTBATPAR(r2),
     462             :                   ALGOOPTBATPAR(bn),
     463             :                   bn && bn->ttype == TYPE_str && bn->tvheap == r1->tvheap ? " sharing string heap" : "",
     464             :                   msg, GDKusec() - t0);
     465             :         return bn;
     466             : 
     467          13 :   bailout:
     468          13 :         BBPreclaim(bn);
     469           3 :         bn = NULL;
     470           3 :         goto doreturn;
     471             : }
     472             : 
     473             : BAT *
     474     1138090 : BATproject(BAT *restrict l, BAT *restrict r)
     475             : {
     476     1138090 :         return BATproject2(l, r, NULL);
     477             : }
     478             : 
     479             : /* Calculate a chain of BATproject calls.
     480             :  * The argument is a NULL-terminated array of BAT pointers.
     481             :  * This function is equivalent (apart from reference counting) to a
     482             :  * sequence of calls
     483             :  * bn = BATproject(bats[0], bats[1]);
     484             :  * bn = BATproject(bn, bats[2]);
     485             :  * ...
     486             :  * bn = BATproject(bn, bats[n-1]);
     487             :  * return bn;
     488             :  * where none of the intermediates are actually produced (and bats[n]==NULL).
     489             :  * Note that all BATs except the last must have type oid/void.
     490             :  */
     491             : BAT *
     492      251619 : BATprojectchain(BAT **bats)
     493             : {
     494      251619 :         struct ba {
     495             :                 BAT *b;
     496             :                 oid hlo;
     497             :                 BUN cnt;
     498             :                 oid *t;
     499             :                 struct canditer ci; /* used if .ci.s != NULL */
     500             :         } *ba;
     501      251619 :         int n;
     502      251619 :         BAT *b = NULL, *bn;
     503      251619 :         bool allnil = false;
     504      251619 :         bool issorted = true;
     505      251619 :         bool nonil = true;
     506      251619 :         bool stringtrick = false;
     507      251619 :         const void *nil;
     508      251619 :         int tpe;
     509      251619 :         lng t0 = 0;
     510             : 
     511      251619 :         TRC_DEBUG_IF(ALGO) t0 = GDKusec();
     512             :         /* count number of participating BATs and allocate some
     513             :          * temporary work space */
     514     3092520 :         for (n = 0; bats[n]; n++) {
     515     2840940 :                 b = bats[n];
     516     2840940 :                 TRC_DEBUG(ALGO, "arg %d: " ALGOBATFMT "\n",
     517             :                           n + 1, ALGOBATPAR(b));
     518             :         }
     519      251582 :         if (n == 0) {
     520           0 :                 GDKerror("must have BAT arguments\n");
     521           0 :                 return NULL;
     522             :         }
     523      251582 :         if (n == 1) {
     524           0 :                 bn = COLcopy(b, b->ttype, true, TRANSIENT);
     525           0 :                 TRC_DEBUG(ALGO, "single bat: copy -> " ALGOOPTBATFMT
     526             :                           " " LLFMT " usec\n",
     527             :                           ALGOOPTBATPAR(bn), GDKusec() - t0);
     528           0 :                 return bn;
     529             :         }
     530             : 
     531      251582 :         ba = GDKmalloc(sizeof(*ba) * n);
     532      251519 :         if (ba == NULL)
     533             :                 return NULL;
     534             : 
     535     3085560 :         for (n = 0; bats[n]; n++) {
     536     2833950 :                 b = bats[n];
     537     2833950 :                 ba[n] = (struct ba) {
     538             :                         .b = b,
     539     2833950 :                         .hlo = b->hseqbase,
     540     2833950 :                         .cnt = b->batCount,
     541     2833950 :                         .t = (oid *) b->theap.base,
     542             :                 };
     543     2833950 :                 allnil |= b->ttype == TYPE_void && is_oid_nil(b->tseqbase);
     544     2833950 :                 issorted &= b->tsorted;
     545     2833950 :                 nonil &= b->tnonil;
     546     2833950 :                 if (b->tnonil && b->tkey && b->tsorted &&
     547     2613520 :                     ATOMtype(b->ttype) == TYPE_oid) {
     548     2560320 :                         canditer_init(&ba[n].ci, NULL, b);
     549             :                 }
     550             :         }
     551             :         /* b is last BAT in bats array */
     552      251611 :         tpe = ATOMtype(b->ttype);
     553      251611 :         nil = ATOMnilptr(tpe);
     554      251611 :         if (allnil || ba[0].cnt == 0) {
     555      175047 :                 bn = BATconstant(ba[0].hlo, tpe == TYPE_oid ? TYPE_void : tpe,
     556             :                                  nil, ba[0].cnt, TRANSIENT);
     557      170133 :                 GDKfree(ba);
     558      170134 :                 TRC_DEBUG(ALGO, "with %d bats: nil/empty -> " ALGOOPTBATFMT
     559             :                           " " LLFMT " usec\n",
     560             :                           n, ALGOOPTBATPAR(bn), GDKusec() - t0);
     561      170134 :                 return bn;
     562             :         }
     563             : 
     564       81485 :         if (nonil && ATOMstorage(tpe) == TYPE_str && b->batRestricted == BAT_READ) {
     565       36950 :                 stringtrick = true;
     566       36950 :                 tpe = b->twidth == 1 ? TYPE_bte : (b->twidth == 2 ? TYPE_sht : (b->twidth == 4 ? TYPE_int : TYPE_lng));
     567             :         }
     568             : 
     569       81485 :         bn = COLnew(ba[0].hlo, tpe, ba[0].cnt, TRANSIENT);
     570       81494 :         if (bn == NULL) {
     571           0 :                 GDKfree(ba);
     572           0 :                 return NULL;
     573             :         }
     574             : 
     575       81494 :         if (ATOMtype(b->ttype) == TYPE_oid) {
     576             :                 /* oid all the way */
     577        1616 :                 oid *d = (oid *) Tloc(bn, 0);
     578        1616 :                 assert(!stringtrick);
     579    36619600 :                 for (BUN p = 0; p < ba[0].cnt; p++) {
     580    36618000 :                         oid o = ba[0].ci.s ? canditer_next(&ba[0].ci) : ba[0].t[p];
     581   117224000 :                         for (int i = 1; i < n; i++) {
     582    80605500 :                                 if (is_oid_nil(o)) {
     583           0 :                                         bn->tnil = true;
     584           0 :                                         break;
     585             :                                 }
     586    80605500 :                                 if (o < ba[i].hlo || o >= ba[i].hlo + ba[i].cnt) {
     587           0 :                                         GDKerror("does not match always\n");
     588           0 :                                         goto bunins_failed;
     589             :                                 }
     590    80605500 :                                 o -= ba[i].hlo;
     591    80605500 :                                 o = ba[i].ci.s ? canditer_idx(&ba[i].ci, o) : ba[i].t[o];
     592             :                         }
     593    36618400 :                         if (bunfastappTYPE(oid, bn, &o) != GDK_SUCCEED)
     594           0 :                                 goto bunins_failed;
     595    36618400 :                         if (ATOMputFIX(bn->ttype, d, &o) != GDK_SUCCEED)
     596           0 :                                 goto bunins_failed;
     597    36618000 :                         d++;
     598             :                 }
     599       79878 :         } else if (!ATOMvarsized(tpe)) {
     600       76212 :                 const void *v;
     601       76212 :                 char *d = Tloc(bn, 0);
     602             : 
     603       76212 :                 bn->tnil = false;
     604       76212 :                 n--;    /* stop one before the end, also ba[n] is last */
     605   250438000 :                 for (BUN p = 0; p < ba[0].cnt; p++) {
     606   250362000 :                         oid o = ba[0].ci.s ? canditer_next(&ba[0].ci) : ba[0].t[p];
     607             : 
     608   586669000 :                         for (int i = 1; i < n; i++) {
     609   336343000 :                                 if (is_oid_nil(o)) {
     610           0 :                                         bn->tnil = true;
     611           0 :                                         break;
     612             :                                 }
     613   336343000 :                                 if (o < ba[i].hlo || o >= ba[i].hlo + ba[i].cnt) {
     614           0 :                                         GDKerror("does not match always\n");
     615           0 :                                         goto bunins_failed;
     616             :                                 }
     617   336343000 :                                 o -= ba[i].hlo;
     618   336343000 :                                 o = ba[i].ci.s ? canditer_idx(&ba[i].ci, o) : ba[i].t[o];
     619             :                         }
     620   250325000 :                         if (is_oid_nil(o)) {
     621           0 :                                 assert(!stringtrick);
     622           0 :                                 bn->tnil = true;
     623           0 :                                 v = nil;
     624   250325000 :                         } else if (o < ba[n].hlo || o >= ba[n].hlo + ba[n].cnt) {
     625           0 :                                 GDKerror("does not match always\n");
     626           0 :                                 goto bunins_failed;
     627             :                         } else {
     628   250325000 :                                 o -= ba[n].hlo;
     629   250325000 :                                 v = Tloc(b, o);
     630             :                         }
     631   250325000 :                         if (ATOMputFIX(tpe, d, v) != GDK_SUCCEED)
     632           0 :                                 goto bunins_failed;
     633   250362000 :                         d += b->twidth;
     634             :                 }
     635       76168 :                 if (stringtrick) {
     636       36946 :                         bn->tnil = false;
     637       36946 :                         bn->tnonil = nonil;
     638       36946 :                         bn->tkey = false;
     639       36946 :                         BBPshare(b->tvheap->parentid);
     640       36951 :                         bn->tvheap = b->tvheap;
     641       36951 :                         bn->ttype = b->ttype;
     642       36951 :                         bn->tvarsized = true;
     643       36951 :                         assert(bn->twidth == b->twidth);
     644       36951 :                         assert(bn->tshift == b->tshift);
     645             :                 }
     646             :                 n++;            /* undo for debug print */
     647             :         } else {
     648        3666 :                 BATiter bi = bat_iterator(b);
     649        3666 :                 const void *v;
     650             : 
     651        3666 :                 assert(!stringtrick);
     652        3666 :                 bn->tnil = false;
     653        3666 :                 n--;    /* stop one before the end, also ba[n] is last */
     654    79881400 :                 for (BUN p = 0; p < ba[0].cnt; p++) {
     655    79877700 :                         oid o = ba[0].ci.s ? canditer_next(&ba[0].ci) : ba[0].t[p];
     656   171290000 :                         for (int i = 1; i < n; i++) {
     657    92434700 :                                 if (is_oid_nil(o)) {
     658           0 :                                         bn->tnil = true;
     659           0 :                                         break;
     660             :                                 }
     661    92434700 :                                 if (o < ba[i].hlo || o >= ba[i].hlo + ba[i].cnt) {
     662           0 :                                         GDKerror("does not match always\n");
     663           0 :                                         goto bunins_failed;
     664             :                                 }
     665    92434700 :                                 o -= ba[i].hlo;
     666    92434700 :                                 o = ba[i].ci.s ? canditer_idx(&ba[i].ci, o) : ba[i].t[o];
     667             :                         }
     668    78855600 :                         if (is_oid_nil(o)) {
     669           0 :                                 bn->tnil = true;
     670           0 :                                 v = nil;
     671    78855600 :                         } else if (o < ba[n].hlo || o >= ba[n].hlo + ba[n].cnt) {
     672           0 :                                 GDKerror("does not match always\n");
     673           0 :                                 goto bunins_failed;
     674             :                         } else {
     675    78855600 :                                 o -= ba[n].hlo;
     676    78855600 :                                 v = BUNtail(bi, o);
     677             :                         }
     678    78855600 :                         if (bunfastapp(bn, v) != GDK_SUCCEED)
     679           0 :                                 goto bunins_failed;
     680             :                 }
     681        3666 :                 n++;            /* undo for debug print */
     682             :         }
     683       81455 :         BATsetcount(bn, ba[0].cnt);
     684       81460 :         bn->tsorted = (ba[0].cnt <= 1) | issorted;
     685       81460 :         bn->trevsorted = ba[0].cnt <= 1;
     686       81460 :         bn->tnonil = nonil;
     687       81460 :         bn->tseqbase = oid_nil;
     688       81460 :         GDKfree(ba);
     689       81497 :         TRC_DEBUG(ALGO, "with %d bats: " ALGOOPTBATFMT " " LLFMT " usec\n",
     690             :                   n, ALGOOPTBATPAR(bn), GDKusec() - t0);
     691             :         return bn;
     692             : 
     693           0 :   bunins_failed:
     694           0 :         GDKfree(ba);
     695           0 :         BBPreclaim(bn);
     696           0 :         TRC_DEBUG(ALGO, "failed " LLFMT "usec\n", GDKusec() - t0);
     697             :         return NULL;
     698             : }

Generated by: LCOV version 1.14