LCOV - code coverage report
Current view: top level - monetdb5/modules/mal - manifold.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 109 134 81.3 %
Date: 2021-01-13 20:07:21 Functions: 4 5 80.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 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * M.L. Kersten
      11             :  */
      12             : #include "monetdb_config.h"
      13             : #include "manifold.h"
      14             : #include "mal_resolve.h"
      15             : #include "mal_builder.h"
      16             : 
      17             : /* The default iterator over known scalar commands.
      18             :  * It can be less efficient then the vector based implementations,
      19             :  * but saves quite some hacking in non-essential cases or
      20             :  * expensive user defined functions.
      21             :  *
      22             :  * To keep things simple and reasonably performant we limit the
      23             :  * implementation to those cases where a single BAT is returned.
      24             :  * Arguments may be of any type. The MAL signature should be a COMMAND.
      25             :  *
      26             :  * The functionality has been extended to also perform the manifold
      27             :  * over aligned BATs, provided the underlying scalar function carries
      28             :  * the 'manifold' property.
      29             :  */
      30             : 
      31             : typedef struct{
      32             :         BAT *b;
      33             :         void *first;
      34             :         void *last;
      35             :         int     size;
      36             :         int type;
      37             :         BUN cnt;
      38             :         BATiter bi;
      39             :         BUN  o;
      40             :         BUN  q;
      41             :         str *s;
      42             : } MULTIarg;
      43             : 
      44             : typedef struct{
      45             :         Client cntxt;
      46             :         MalBlkPtr mb;
      47             :         MalStkPtr stk;
      48             :         InstrPtr pci;
      49             :         int fvar,lvar;
      50             :         MULTIarg *args;
      51             : } MULTItask;
      52             : 
      53             : 
      54             : // Loop through the first BAT
      55             : // keep the last error message received
      56             : #define ManifoldLoop(Type, ...)                                                                                 \
      57             :         do {                                                                                                                            \
      58             :                 Type *v = (Type*) mut->args[0].first;                                                        \
      59             :                 for (;;) {                                                                                                              \
      60             :                         msg = (*mut->pci->fcn)(v, __VA_ARGS__);                                           \
      61             :                         if (msg) break;                                                                                         \
      62             :                         if (++oo == olimit)                                                                                     \
      63             :                                 break;                                                                                                  \
      64             :                         for( i = mut->fvar; i<= mut->lvar; i++) {                                      \
      65             :                                 if(ATOMstorage(mut->args[i].type) == TYPE_void ){            \
      66             :                                         args[i] = (void*)  &mut->args[i].o;                                      \
      67             :                                         mut->args[i].o++;                                                                    \
      68             :                                 } else if(mut->args[i].size == 0) {                                          \
      69             :                                         ;                                                                                                       \
      70             :                                 } else if(ATOMstorage(mut->args[i].type) < TYPE_str ) {   \
      71             :                                         args[i] += mut->args[i].size;                                                \
      72             :                                 } else if (ATOMvarsized(mut->args[i].type)) {                        \
      73             :                                         mut->args[i].o++;                                                                    \
      74             :                                         mut->args[i].s = (str *) BUNtail(mut->args[i].bi, mut->args[i].o); \
      75             :                                         args[i] = (void*)  &mut->args[i].s;                                      \
      76             :                                 } else {                                                                                                \
      77             :                                         mut->args[i].o++;                                                                    \
      78             :                                         mut->args[i].s = (str *) Tloc(mut->args[i].b, mut->args[i].o); \
      79             :                                         args[i] = (void*)  &mut->args[i].s;                                      \
      80             :                                 }                                                                                                               \
      81             :                         }                                                                                                                       \
      82             :                         v++;                                                                                                            \
      83             :                 }                                                                                                                               \
      84             :         } while (0)
      85             : 
      86             : // The target BAT tail type determines the result variable
      87             : #ifdef HAVE_HGE
      88             : #define Manifoldbody_hge(...)                                   \
      89             :         case TYPE_hge: ManifoldLoop(hge,__VA_ARGS__); break
      90             : #else
      91             : #define Manifoldbody_hge(...)
      92             : #endif
      93             : #define Manifoldbody(...)                                                                                               \
      94             :         do {                                                                                                                            \
      95             :                 switch(ATOMstorage(mut->args[0].b->ttype)){                                               \
      96             :                 case TYPE_bte: ManifoldLoop(bte,__VA_ARGS__); break;                    \
      97             :                 case TYPE_sht: ManifoldLoop(sht,__VA_ARGS__); break;                    \
      98             :                 case TYPE_int: ManifoldLoop(int,__VA_ARGS__); break;                    \
      99             :                 case TYPE_lng: ManifoldLoop(lng,__VA_ARGS__); break;                    \
     100             :                 Manifoldbody_hge(__VA_ARGS__);                                                                  \
     101             :                 case TYPE_oid: ManifoldLoop(oid,__VA_ARGS__); break;                    \
     102             :                 case TYPE_flt: ManifoldLoop(flt,__VA_ARGS__); break;                    \
     103             :                 case TYPE_dbl: ManifoldLoop(dbl,__VA_ARGS__); break;                    \
     104             :                 case TYPE_str:                                                                                                  \
     105             :                 default: {                                                                                                              \
     106             :                         for (;;) {                                                                                                      \
     107             :                                 msg = (*mut->pci->fcn)(&y, __VA_ARGS__);                              \
     108             :                                 if (msg)                                                                                                \
     109             :                                         break;                                                                                          \
     110             :                                 if (bunfastapp(mut->args[0].b, (void*) y) != GDK_SUCCEED) \
     111             :                                         goto bunins_failed;                                                                     \
     112             :                                 GDKfree(y); y = NULL;                                                                   \
     113             :                                 if (++oo == olimit)                                                                             \
     114             :                                         break;                                                                                          \
     115             :                                 for( i = mut->fvar; i<= mut->lvar; i++) {                              \
     116             :                                         if(ATOMstorage(mut->args[i].type) == TYPE_void ){    \
     117             :                                                 args[i] = (void*)  &mut->args[i].o;                              \
     118             :                                                 mut->args[i].o++;                                                            \
     119             :                                         } else if(mut->args[i].size == 0) {                                  \
     120             :                                                 ;                                                                                               \
     121             :                                         } else if (ATOMstorage(mut->args[i].type) < TYPE_str){ \
     122             :                                                 args[i] += mut->args[i].size;                                        \
     123             :                                         } else if(ATOMvarsized(mut->args[i].type)){                  \
     124             :                                                 mut->args[i].o++;                                                            \
     125             :                                                 mut->args[i].s = (str*) BUNtail(mut->args[i].bi, mut->args[i].o); \
     126             :                                                 args[i] =  (void*) & mut->args[i].s;                     \
     127             :                                         } else {                                                                                        \
     128             :                                                 mut->args[i].o++;                                                            \
     129             :                                                 mut->args[i].s = (str*) Tloc(mut->args[i].b, mut->args[i].o); \
     130             :                                                 args[i] =  (void*) & mut->args[i].s;                     \
     131             :                                         }                                                                                                       \
     132             :                                 }                                                                                                               \
     133             :                         }                                                                                                                       \
     134             :                         break;                                                                                                          \
     135             :                 }                                                                                                                               \
     136             :                 }                                                                                                                               \
     137             :                 mut->args[0].b->theap.dirty = true;                                                               \
     138             :         } while (0)
     139             : 
     140             : // single argument is preparatory step for GDK_mapreduce
     141             : // Only the last error message is returned, the value of
     142             : // an erroneous call depends on the operator itself.
     143             : static str
     144         509 : MANIFOLDjob(MULTItask *mut)
     145             : {       int i;
     146             :         char **args;
     147         509 :         str y = NULL, msg= MAL_SUCCEED;
     148         509 :         oid oo = 0, olimit = mut->args[mut->fvar].cnt;
     149             : 
     150         509 :         if (olimit == 0)
     151             :                 return msg;                             /* nothing to do */
     152             : 
     153         447 :         args = (char**) GDKzalloc(sizeof(char*) * mut->pci->argc);
     154         447 :         if( args == NULL)
     155           0 :                 throw(MAL,"mal.manifold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     156             : 
     157             :         // the mod.fcn arguments are ignored from the call
     158        1227 :         for( i = mut->pci->retc+2; i< mut->pci->argc; i++) {
     159         780 :                 if ( mut->args[i].b ){
     160         493 :                         if(ATOMstorage(mut->args[i].type) < TYPE_str){
     161          60 :                                 args[i] = (char*) mut->args[i].first;
     162         433 :                         } else if(ATOMvarsized(mut->args[i].type)){
     163         421 :                                 mut->args[i].s = (str*) BUNtail(mut->args[i].bi, mut->args[i].o);
     164         421 :                                 args[i] =  (void*) & mut->args[i].s;
     165             :                         } else {
     166          12 :                                 mut->args[i].s = (str*) Tloc(mut->args[i].b, mut->args[i].o);
     167          12 :                                 args[i] =  (void*) & mut->args[i].s;
     168             :                         }
     169             :                 } else {
     170         287 :                         args[i] = (char *) getArgReference(mut->stk,mut->pci,i);
     171             :                 }
     172             :         }
     173             : 
     174             :         /* TRC_DEBUG(MAL_SERVER, "fvar %d lvar %d type %d\n", mut->fvar,mut->lvar, ATOMstorage(mut->args[mut->fvar].b->ttype));*/
     175             : 
     176             :         // use limited argument list expansion.
     177         447 :         switch(mut->pci->argc){
     178      220723 :         case 4: Manifoldbody(args[3]); break;
     179        2106 :         case 5: Manifoldbody(args[3],args[4]); break;
     180         257 :         case 6: Manifoldbody(args[3],args[4],args[5]); break;
     181          57 :         case 7: Manifoldbody(args[3],args[4],args[5],args[6]); break;
     182          13 :         case 8: Manifoldbody(args[3],args[4],args[5],args[6],args[7]); break;
     183           0 :         default:
     184           0 :                 msg= createException(MAL,"mal.manifold","manifold call limitation ");
     185             :         }
     186         447 :         if (ATOMextern(mut->args[0].type) && y)
     187           0 :                 GDKfree(y);
     188         447 : bunins_failed:
     189         447 :         GDKfree(args);
     190         447 :         return msg;
     191             : }
     192             : 
     193             : /* The manifold optimizer should check for the possibility
     194             :  * to use this implementation instead of the MAL loop.
     195             :  */
     196             : MALfcn
     197        2886 : MANIFOLDtypecheck(Client cntxt, MalBlkPtr mb, InstrPtr pci, int checkprops){
     198             :         int i, k, tpe= 0;
     199             :         InstrPtr q=0;
     200             :         MalBlkPtr nmb;
     201             :         MALfcn fcn;
     202             : 
     203        2886 :         if (pci->retc >1 || pci->argc > 8 || getModuleId(pci) == NULL) // limitation on MANIFOLDjob
     204             :                 return NULL;
     205             :         // We need a private MAL context to resolve the function call
     206        2848 :         nmb = newMalBlk(2 );
     207        2848 :         if( nmb == NULL)
     208             :                 return NULL;
     209             :         // the scalar function
     210        2848 :         q = newStmt(nmb,
     211        2848 :                 getVarConstant(mb,getArg(pci,pci->retc)).val.sval,
     212        2848 :                 getVarConstant(mb,getArg(pci,pci->retc+1)).val.sval);
     213             : 
     214             :         // Prepare the single result variable
     215        2848 :         tpe =getBatType(getArgType(mb,pci,0));
     216        2848 :         k= getArg(q,0);
     217        2848 :         setVarType(nmb,k,tpe);
     218        2848 :         if ( isVarFixed(nmb,k))
     219           0 :                 setVarFixed(nmb,k);
     220        2848 :         if (isVarUDFtype(nmb,k))
     221           0 :                 setVarUDFtype(nmb,k);
     222             : 
     223             :         // extract their scalar argument type
     224        8102 :         for ( i = pci->retc+2; i < pci->argc; i++){
     225        5254 :                 tpe = getBatType(getArgType(mb,pci,i));
     226        5254 :                 q= pushArgument(nmb,q, k= newTmpVariable(nmb, tpe));
     227        5254 :                 setVarFixed(nmb,k);
     228        5254 :                 setVarUDFtype(nmb,k);
     229             :         }
     230             : 
     231             : /*
     232             :         TRC_DEBUG(MAL_SERVER, "Manifold operation\n");
     233             :         traceInstruction(MAL_SERVER, mb, 0, pci, LIST_MAL_ALL);
     234             :         traceInstruction(MAL_SERVER, nmb, 0, q, LIST_MAL_ALL);
     235             : */
     236             :         // Localize the underlying scalar operator
     237        2848 :         typeChecker(cntxt->usermodule, nmb, q, getPC(nmb, q), TRUE);
     238        2848 :         if (nmb->errors || q->fcn == NULL || q->token != CMDcall ||
     239         971 :                 (checkprops && q->blk && q->blk->unsafeProp) )
     240             :                 fcn = NULL;
     241             :         else {
     242             :                 fcn = q->fcn;
     243             :                 // retain the type detected
     244        2406 :                 if ( !isVarFixed(mb, getArg(pci,0)))
     245           0 :                         setVarType( mb, getArg(pci,0), newBatType(getArgType(nmb,q,0)) );
     246             :         }
     247             : 
     248             : /*
     249             :         TRC_DEBUG(MAL_SERVER, "Success? %s\n", (fcn == NULL? "no":"yes"));
     250             :         traceInstruction(MAL_SERVER, nmb, 0, q, LIST_MAL_ALL);
     251             : */
     252             : 
     253        2848 :         freeMalBlk(nmb);
     254        2848 :         return fcn;
     255             : }
     256             : 
     257             : /*
     258             :  * The manifold should support aligned BATs as well
     259             :  */
     260             : str
     261         509 : MANIFOLDevaluate(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci){
     262             :         MULTItask mut;
     263             :         MULTIarg *mat;
     264             :         int i, tpe= 0;
     265             :         BUN cnt = 0;
     266         509 :         oid o = 0;
     267             :         str msg = MAL_SUCCEED;
     268             :         MALfcn fcn;
     269             : 
     270         509 :         fcn= MANIFOLDtypecheck(cntxt,mb,pci,0);
     271         509 :         if( fcn == NULL)
     272           0 :                 throw(MAL, "mal.manifold", "Illegal manifold function call");
     273             : 
     274         509 :         mat = (MULTIarg *) GDKzalloc(sizeof(MULTIarg) * pci->argc);
     275         509 :         if( mat == NULL)
     276           0 :                 throw(MAL, "mal.manifold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     277             : 
     278             :         // mr-job structure preparation
     279         509 :         mut.fvar = mut.lvar = 0;
     280         509 :         mut.cntxt= cntxt;
     281         509 :         mut.mb= mb;
     282         509 :         mut.stk= stk;
     283         509 :         mut.args= mat;
     284         509 :         mut.pci = pci;
     285             : 
     286             :         // prepare iterators
     287        1418 :         for( i = pci->retc+2; i < pci->argc; i++){
     288         909 :                 if ( isaBatType(getArgType(mb,pci,i)) ){
     289         574 :                         mat[i].b = BATdescriptor( *getArgReference_bat(stk,pci,i));
     290         574 :                         if ( mat[i].b == NULL){
     291           0 :                                 msg = createException(MAL,"mal.manifold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     292           0 :                                 goto wrapup;
     293             :                         }
     294         574 :                         mat[i].type = tpe = getBatType(getArgType(mb,pci,i));
     295         574 :                         if (mut.fvar == 0){
     296         509 :                                 mut.fvar = i;
     297         509 :                                 cnt = BATcount(mat[i].b);
     298          65 :                         } else if (BATcount(mat[i].b)!= cnt){
     299           0 :                                 msg = createException(MAL,"mal.manifold","Columns must be of same length");
     300           0 :                                 goto wrapup;
     301             :                         }
     302         574 :                         mut.lvar = i;
     303         574 :                         if (ATOMstorage(tpe) == TYPE_str)
     304         348 :                                 mat[i].size = Tsize(mat[i].b);
     305             :                         else
     306         226 :                                 mat[i].size = ATOMsize(tpe);
     307         574 :                         mat[i].cnt = cnt;
     308         574 :                         if ( mat[i].b->ttype == TYPE_void){
     309           0 :                                 o = mat[i].b->tseqbase;
     310           0 :                                 mat[i].first = mat[i].last = (void*) &o;
     311             :                         } else {
     312         574 :                                 mat[i].first = (void*)  Tloc(mat[i].b, 0);
     313         574 :                                 mat[i].last = (void*) Tloc(mat[i].b, BUNlast(mat[i].b));
     314             :                         }
     315         574 :                         mat[i].bi = bat_iterator(mat[i].b);
     316         574 :                         mat[i].o = 0;
     317         574 :                         mat[i].q = BUNlast(mat[i].b);
     318             :                 } else {
     319         335 :                         mat[i].last = mat[i].first = (void *) getArgReference(stk,pci,i);
     320         335 :                         mat[i].type = getArgType(mb, pci, i);
     321             :                 }
     322             :         }
     323             : 
     324             :         // Then iterator over all BATs
     325         509 :         if( mut.fvar ==0){
     326           0 :                 msg= createException(MAL,"mal.manifold","At least one column required");
     327           0 :                 goto wrapup;
     328             :         }
     329             : 
     330             :         // prepare result variable
     331         509 :         mat[0].b =COLnew(mat[mut.fvar].b->hseqbase, getBatType(getArgType(mb,pci,0)), cnt, TRANSIENT);
     332         509 :         if ( mat[0].b == NULL){
     333           0 :                 msg= createException(MAL,"mal.manifold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     334           0 :                 goto wrapup;
     335             :         }
     336         509 :         mat[0].b->tnonil=false;
     337         509 :         mat[0].b->tsorted=false;
     338         509 :         mat[0].b->trevsorted=false;
     339         509 :         mat[0].bi = bat_iterator(mat[0].b);
     340         509 :         mat[0].first = (void *)  Tloc(mat[0].b, 0);
     341         509 :         mat[0].last = (void *)  Tloc(mat[0].b, BUNlast(mat[0].b));
     342             : 
     343         509 :         mut.pci = copyInstruction(pci);
     344         509 :         if ( mut.pci == NULL){
     345           0 :                 msg= createException(MAL,"mal.manifold", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     346           0 :                 goto wrapup;
     347             :         }
     348         509 :         mut.pci->fcn = fcn;
     349         509 :         msg = MANIFOLDjob(&mut);
     350         509 :         freeInstruction(mut.pci);
     351             : 
     352             :         // consolidate the properties
     353         509 :         if (ATOMstorage(mat[0].b->ttype) < TYPE_str)
     354         266 :                 BATsetcount(mat[0].b,cnt);
     355         509 :         BATsettrivprop(mat[0].b);
     356         509 :         BBPkeepref(*getArgReference_bat(stk,pci,0)=mat[0].b->batCacheid);
     357         509 : wrapup:
     358             :         // restore the argument types
     359        2435 :         for (i = pci->retc; i < pci->argc; i++){
     360        1927 :                 if ( mat[i].b)
     361         574 :                         BBPunfix(mat[i].b->batCacheid);
     362             :         }
     363         508 :         GDKfree(mat);
     364         509 :         return msg;
     365             : }
     366             : 
     367             : // The old code
     368             : str
     369           0 : MANIFOLDremapMultiplex(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr p)
     370             : {
     371             :     (void) mb;
     372             :     (void) cntxt;
     373           0 :     throw(MAL, "mal.multiplex", "Function '%s.%s' not defined",
     374           0 :                   *getArgReference_str(stk, p, p->retc),
     375           0 :                   *getArgReference_str(stk, p, p->retc + 1));
     376             : }
     377             : 
     378             : #include "mel.h"
     379             : mel_func manifold_init_funcs[] = {
     380             :  pattern("mal", "multiplex", MANIFOLDremapMultiplex, false, "", args(1,4, varargany("",0),arg("mod",str),arg("fcn",str),varargany("a",0))),
     381             :  pattern("batmal", "multiplex", MANIFOLDremapMultiplex, false, "", args(1,4, varargany("",0),arg("mod",str),arg("fcn",str),varargany("a",0))),
     382             :  pattern("mal", "manifold", MANIFOLDevaluate, false, "", args(1,4, batargany("",0),arg("mod",str),arg("fcn",str),varargany("a",0))),
     383             :  { .imp=NULL }
     384             : };
     385             : #include "mal_import.h"
     386             : #ifdef _MSC_VER
     387             : #undef read
     388             : #pragma section(".CRT$XCU",read)
     389             : #endif
     390         255 : LIB_STARTUP_FUNC(init_manifold_mal)
     391         255 : { mal_module("manifold", NULL, manifold_init_funcs); }

Generated by: LCOV version 1.14