LCOV - code coverage report
Current view: top level - sql/backends/monet5/vaults/netcdf - netcdf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2 488 0.4 %
Date: 2021-10-13 02:24:04 Functions: 1 9 11.1 %

          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             : #include "monetdb_config.h"
      10             : #include <netcdf.h>
      11             : #include "sql_mvc.h"
      12             : #include "sql.h"
      13             : #include "sql_execute.h"
      14             : #include "sql_scenario.h"
      15             : #include "mal_exception.h"
      16             : #include "netcdf_vault.h"
      17             : 
      18             : /* SQL statements for population of NetCDF catalog */
      19             : #define INSFILE \
      20             :         "INSERT INTO netcdf_files(file_id,location) VALUES(%d, '%s');"
      21             : 
      22             : #define INSDIM \
      23             :         "INSERT INTO netcdf_dims(dim_id,file_id,name,length) VALUES(%d, %d, '%s', %d);"
      24             : 
      25             : #define INSVAR \
      26             :     "INSERT INTO netcdf_vars(var_id,file_id,name,vartype,ndim,coord_dim_id) VALUES(%d, %d, '%s', '%s', %d, %d);"
      27             : 
      28             : #define INSVARDIM \
      29             :     "INSERT INTO netcdf_vardim (var_id,dim_id,file_id,dimpos) VALUES(%d, %d, %d, %d);"
      30             : 
      31             : #define INSATTR \
      32             :     "INSERT INTO netcdf_attrs (obj_name,att_name,att_type,value,file_id,gr_name) VALUES('%s', '%s', '%s', '%s', %d, '%s');"
      33             : 
      34             : #define LOAD_NCDF_VAR(tpe,ncdftpe) \
      35             :         { \
      36             :         tpe *databuf; \
      37             :         res = COLnew(0, TYPE_##tpe, sz, TRANSIENT); \
      38             :         if ( res == NULL ) \
      39             :                 return createException(MAL, "netcdf.importvar", SQLSTATE(HY013) MAL_MALLOC_FAIL); \
      40             :         databuf = (tpe *)Tloc(res, 0); \
      41             :         if ( (retval = nc_get_var_##ncdftpe(ncid, varid, databuf)) ) \
      42             :                 return createException(MAL, "netcdf.importvar", \
      43             :                                                    SQLSTATE(NC000) "Cannot read variable %d values: %s", \
      44             :                                                    varid, nc_strerror(retval)); \
      45             :         }
      46             : 
      47             : static void
      48             : fix_quote( char *n, int l)
      49             : {
      50             :         int i;
      51             : 
      52           0 :         for(i=0;i<l;i++)
      53           0 :                 if (n[i]=='\'')
      54           0 :                         n[i] = ' ';
      55             : }
      56             : 
      57             : 
      58             : /* simple test for netcdf library */
      59             : str
      60           0 : NCDFtest(int *vars, str *fname)
      61             : {
      62             :     int ncid;   /* dataset id */
      63             :         int dims, ngatts, unlimdim;
      64             :         int retval;
      65             : 
      66             :         str msg = MAL_SUCCEED;
      67             : 
      68             :         /* Open NetCDF file  */
      69           0 :         if ((retval = nc_open(*fname, NC_NOWRITE, &ncid)))
      70           0 :             return createException(MAL, "netcdf.test", SQLSTATE(NC000) "Cannot open NetCDF file %s: %s", *fname, nc_strerror(retval));
      71             : 
      72           0 :     if ((retval = nc_inq(ncid, &dims, vars, &ngatts, &unlimdim)))
      73           0 :             return createException(MAL, "netcdf.test", SQLSTATE(NC000) "Cannot read NetCDF header: %s", nc_strerror(retval));
      74             : 
      75           0 :     if ((retval = nc_close(ncid)))
      76           0 :             return createException(MAL, "netcdf.test", SQLSTATE(NC000) "Cannot close file %s: \
      77             : %s", *fname, nc_strerror(retval));
      78             : 
      79             :     return msg;
      80             : }
      81             : 
      82             : /* the following function is from ncdump utility: NetCDF type number to name */
      83             : static const char *
      84           0 : prim_type_name(nc_type type)
      85             : {
      86           0 :         switch (type) {
      87             :         case NC_BYTE:
      88             :           return "byte";
      89           0 :         case NC_CHAR:
      90           0 :           return "char";
      91           0 :         case NC_SHORT:
      92           0 :           return "short";
      93           0 :         case NC_INT:
      94           0 :           return "int";
      95           0 :         case NC_FLOAT:
      96           0 :           return "float";
      97           0 :         case NC_DOUBLE:
      98           0 :           return "double";
      99             : #ifdef USE_NETCDF4
     100             :         case NC_UBYTE:
     101             :           return "ubyte";
     102             :         case NC_USHORT:
     103             :           return "ushort";
     104             :         case NC_UINT:
     105             :           return "uint";
     106             :         case NC_INT64:
     107             :           return "int64";
     108             :         case NC_UINT64:
     109             :           return "uint64";
     110             :         case NC_STRING:
     111             :           return "string";
     112             : #endif /* USE_NETCDF4 */
     113           0 :         default:
     114           0 :           return "bad type";
     115             :         }
     116             : }
     117             : 
     118             : /* Mapping NetCDF to SQL data type */
     119             : 
     120             : static const char *
     121           0 : NCDF2SQL(nc_type type)
     122             : {
     123           0 :     switch (type) {
     124             :     case NC_BYTE:
     125             :                 return "tinyint";
     126           0 :     case NC_CHAR:
     127           0 :                 return "char(1)";
     128           0 :     case NC_SHORT:
     129           0 :                 return "smallint";
     130           0 :     case NC_INT:
     131           0 :                 return "int";
     132           0 :     case NC_FLOAT:
     133           0 :                 return "float";
     134           0 :     case NC_DOUBLE:
     135           0 :                 return "double";
     136             : #ifdef USE_NETCDF4
     137             : /* ?? mapping of unsigned types */
     138             :     case NC_UBYTE:
     139             :                 return "ubyte";
     140             :     case NC_USHORT:
     141             :                 return "ushort";
     142             :     case NC_UINT:
     143             :                 return "uint";
     144             :     case NC_INT64:
     145             :                 return "bigint";
     146             :     case NC_UINT64:
     147             :                 return "uint64";
     148             :         case NC_STRING:
     149             :                 return "string";
     150             : #endif /* USE_NETCDF4 */
     151           0 :     default:
     152           0 :                 return "type not supported";
     153             :     }
     154             : }
     155             : 
     156             : #define array_series(sta, ste, sto, TYPE) {                             \
     157             :         int s,g;                                                        \
     158             :         TYPE i, *o = (TYPE*)Tloc(bn, 0);                                \
     159             :         TYPE start = sta, step = ste, stop = sto;                       \
     160             :         if ( start < stop && step > 0) {                          \
     161             :                 for ( s = 0; s < series; s++)                                \
     162             :                         for ( i = start; i < stop; i += step)                \
     163             :                                 for( g = 0; g < group; g++){         \
     164             :                                         *o = i;                         \
     165             :                                         o++;                            \
     166             :                                 }                                       \
     167             :         } else {                                                        \
     168             :                 for ( s = 0; s < series; s++)                                \
     169             :                         for ( i = start; i > stop; i += step)                \
     170             :                                 for( g = 0; g < group; g++){         \
     171             :                                         *o = i;                         \
     172             :                                         o++;                            \
     173             :                                 }                                       \
     174             :         }                                                               \
     175             : }
     176             : 
     177             : /* create and populate a dimension bat */
     178             : static str
     179           0 : NCDFARRAYseries(bat *bid, bte start, bte step, int stop, int group, int series)
     180             : {
     181             :         BAT *bn = NULL;
     182             :         BUN cnt = 0;
     183             : 
     184           0 :         cnt =  (BUN) ceil(((stop * 1.0 - start) / step)) * group * series ;
     185           0 :         if (stop <= (int) GDK_bte_max ) {
     186           0 :                 bte sta = (bte) start, ste = (bte) step, sto = (bte) stop;
     187             : 
     188           0 :                 bn = COLnew(0, TYPE_bte, cnt, TRANSIENT);
     189           0 :                 if ( bn == NULL)
     190           0 :                         throw(MAL, "ntcdf.loadvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     191           0 :                 array_series(sta, ste, sto, bte);
     192           0 :         } else if (stop <= (int) GDK_sht_max) {
     193           0 :                 sht sta = (sht) start, ste = (sht) step, sto = (sht) stop;
     194             : 
     195           0 :                 bn = COLnew(0, TYPE_sht, cnt, TRANSIENT);
     196           0 :                 if ( bn == NULL)
     197           0 :                         throw(MAL, "netcdf.loadvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     198           0 :                 array_series(sta, ste, sto, sht);
     199             :         } else {
     200           0 :                 int sta = (int) start, ste = (int) step, sto = (int) stop;
     201             : 
     202           0 :                 bn = COLnew(0, TYPE_int, cnt, TRANSIENT);
     203           0 :                 if ( bn == NULL)
     204           0 :                         throw(MAL, "netcdf.loadvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     205           0 :                 array_series(sta, ste, sto, int);
     206             :         }
     207             : 
     208           0 :         BATsetcount(bn, cnt);
     209           0 :         bn->tsorted = (cnt <= 1 || (series == 1 && step > 0));
     210           0 :         bn->trevsorted = (cnt <= 1 || (series == 1 && step < 0));
     211           0 :         bn->tnonil = true;
     212           0 :         BBPkeepref(*bid= bn->batCacheid);
     213           0 :         return MAL_SUCCEED;
     214             : }
     215             : 
     216             : str
     217           0 : NCDFattach(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     218             : {
     219           0 :         mvc *m = NULL;
     220             :         sql_schema *sch = NULL;
     221             :         sql_table *tfiles = NULL, *tdims = NULL, *tvars = NULL, *tvardim = NULL, *tattrs = NULL;
     222             :         sql_column *col;
     223             :         str msg = MAL_SUCCEED;
     224           0 :         str fname = *getArgReference_str(stk, pci, 1);
     225             :         char buf[BUFSIZ], *s= buf;
     226             :         oid fid, rid = oid_nil;
     227             :         sql_trans *tr;
     228             : 
     229             :         int ncid;   /* dataset id */
     230             :         int ndims, nvars, ngatts, unlimdim;
     231             :         int didx, vidx, vndims, vnatts, i, aidx, coord_dim_id = -1;
     232             :         int vdims[NC_MAX_VAR_DIMS];
     233             : 
     234             :         size_t dlen, alen;
     235             :         char dname[NC_MAX_NAME+1], vname[NC_MAX_NAME+1], aname[NC_MAX_NAME +1],
     236             :                 abuf[80], *aval;
     237             :         char **dims = NULL;
     238             :         nc_type vtype, atype; /* == int */
     239             : 
     240             :         int retval, avalint;
     241             :         float avalfl;
     242             :         double avaldbl;
     243             :         str esc_str0, esc_str1;
     244             : 
     245           0 :         msg = getSQLContext(cntxt, mb, &m, NULL);
     246           0 :         if (msg)
     247             :         return msg;
     248             : 
     249           0 :         tr = m->session->tr;
     250           0 :         sqlstore *store = tr->store;
     251           0 :         sch = mvc_bind_schema(m, "sys");
     252           0 :         if ( !sch )
     253           0 :         return createException(MAL, "netcdf.attach", SQLSTATE(NC000) "Cannot get schema sys\n");
     254             : 
     255           0 :         tfiles = mvc_bind_table(m, sch, "netcdf_files");
     256           0 :         tdims = mvc_bind_table(m, sch, "netcdf_dims");
     257           0 :         tvars = mvc_bind_table(m, sch, "netcdf_vars");
     258           0 :         tvardim = mvc_bind_table(m, sch, "netcdf_vardim");
     259           0 :         tattrs = mvc_bind_table(m, sch, "netcdf_attrs");
     260             : 
     261           0 :         if (tfiles == NULL || tdims == NULL || tvars == NULL ||
     262           0 :             tvardim == NULL || tattrs == NULL)
     263           0 :         return createException(MAL, "netcdf.attach", SQLSTATE(NC000) "Catalog table missing\n");
     264             : 
     265             :         /* check if the file is already attached */
     266           0 :         col = mvc_bind_column(m, tfiles, "location");
     267           0 :         rid = store->table_api.column_find_row(m->session->tr, col, fname, NULL);
     268           0 :         if (!is_oid_nil(rid))
     269           0 :             return createException(SQL, "netcdf.attach", SQLSTATE(NC000) "File %s is already attached\n", fname);
     270             : 
     271             :         /* Open NetCDF file  */
     272           0 :         if ((retval = nc_open(fname, NC_NOWRITE, &ncid)))
     273           0 :         return createException(MAL, "netcdf.test", SQLSTATE(NC000) "Cannot open NetCDF \
     274             : file %s: %s", fname, nc_strerror(retval));
     275             : 
     276           0 :         if ((retval = nc_inq(ncid, &ndims, &nvars, &ngatts, &unlimdim)))
     277           0 :         return createException(MAL, "netcdf.test", SQLSTATE(NC000) "Cannot read NetCDF \
     278             : header: %s", nc_strerror(retval));
     279             : 
     280             :         /* Insert row into netcdf_files table */
     281           0 :         col = mvc_bind_column(m, tfiles, "file_id");
     282           0 :         fid = store->storage_api.count_col(tr, col, 1) + 1;
     283             : 
     284           0 :         esc_str0 = SQLescapeString(fname);
     285           0 :         if (!esc_str0) {
     286           0 :                 msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     287           0 :                 goto finish;
     288             :         }
     289           0 :         snprintf(buf, BUFSIZ, INSFILE, (int)fid, esc_str0);
     290           0 :         GDKfree(esc_str0);
     291           0 :         if ( ( msg = SQLstatementIntern(cntxt, s, "netcdf.attach", TRUE, FALSE, NULL))
     292             :                  != MAL_SUCCEED )
     293           0 :             goto finish;
     294             : 
     295             :         /* Read dimensions from NetCDF header and insert a row for each one into netcdf_dims table */
     296             : 
     297           0 :         dims = (char **)GDKzalloc(sizeof(char *) * ndims);
     298           0 :         if (!dims) {
     299           0 :                 msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     300           0 :                 goto finish;
     301             :         }
     302           0 :         for (didx = 0; didx < ndims; didx++){
     303           0 :                 if ((retval = nc_inq_dim(ncid, didx, dname, &dlen)) != 0)
     304           0 :                 return createException(MAL, "netcdf.attach", SQLSTATE(NC000) "Cannot read dimension %d : %s", didx, nc_strerror(retval));
     305             : 
     306           0 :                 esc_str0 = SQLescapeString(dname);
     307           0 :                 if (!esc_str0) {
     308           0 :                         msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     309           0 :                         goto finish;
     310             :                 }
     311             : 
     312           0 :                 snprintf(buf, BUFSIZ, INSDIM, didx, (int)fid, esc_str0, (int)dlen);
     313           0 :                 GDKfree(esc_str0);
     314           0 :             if ( ( msg = SQLstatementIntern(cntxt, s, "netcdf.attach", TRUE, FALSE, NULL))
     315             :                          != MAL_SUCCEED )
     316           0 :                 goto finish;
     317             : 
     318           0 :             dims[didx] = GDKstrdup(dname);
     319           0 :                 if (!dims[didx]) {
     320           0 :                         msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     321           0 :                         goto finish;
     322             :                 }
     323             :         }
     324             : 
     325             :         /* Read variables and attributes from the header and insert rows in netcdf_vars, netcdf_vardims, and netcdf_attrs tables */
     326           0 :         for (vidx = 0; vidx < nvars; vidx++){
     327           0 :             if ( (retval = nc_inq_var(ncid, vidx, vname, &vtype, &vndims, vdims, &vnatts)))
     328           0 :                 return createException(MAL, "netcdf.attach",
     329             :                                                                    SQLSTATE(NC000) "Cannot read variable %d : %s",
     330             :                                                                    vidx, nc_strerror(retval));
     331             : 
     332             :         /* Check if this is coordinate variable */
     333           0 :         if ( (vndims == 1) && ( strcmp(vname, dims[vdims[0]]) == 0 ))
     334           0 :                 coord_dim_id = vdims[0];
     335             :         else coord_dim_id = -1;
     336             : 
     337           0 :                 esc_str0 = SQLescapeString(vname);
     338           0 :                 if (!esc_str0) {
     339           0 :                         msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     340           0 :                         goto finish;
     341             :                 }
     342             : 
     343           0 :                 snprintf(buf, BUFSIZ, INSVAR, vidx, (int)fid, esc_str0, prim_type_name(vtype), vndims, coord_dim_id);
     344           0 :                 GDKfree(esc_str0);
     345           0 :             if ( ( msg = SQLstatementIntern(cntxt, s, "netcdf.attach", TRUE, FALSE, NULL))
     346             :                          != MAL_SUCCEED )
     347           0 :             goto finish;
     348             : 
     349           0 :             if ( coord_dim_id < 0 ){
     350           0 :                 for (i = 0; i < vndims; i++){
     351           0 :                 snprintf(buf, BUFSIZ, INSVARDIM, vidx, vdims[i], (int)fid, i);
     352           0 :                 if ( ( msg = SQLstatementIntern(cntxt, s, "netcdf.attach", TRUE, FALSE, NULL))
     353             :                                          != MAL_SUCCEED )
     354           0 :                         goto finish;
     355             :                 }
     356             :             }
     357             : 
     358           0 :         if ( vnatts > 0 ) { /* fill in netcdf_attrs table */
     359             : 
     360           0 :             for (aidx = 0; aidx < vnatts; aidx++){
     361           0 :                 if ((retval = nc_inq_attname(ncid,vidx,aidx,aname)))
     362           0 :                     return createException(MAL, "netcdf.attach",
     363             :                                                                                    SQLSTATE(NC000) "Cannot read attribute %d of variable %d: %s",
     364             :                                                                                    aidx, vidx, nc_strerror(retval));
     365             : 
     366           0 :                                 if ((retval = nc_inq_att(ncid,vidx,aname,&atype,&alen)))
     367           0 :                     return createException(MAL, "netcdf.attach",
     368             :                                                                                    SQLSTATE(NC000) "Cannot read attribute %s type and length: %s",
     369             :                                                                                    aname, nc_strerror(retval));
     370             : 
     371           0 :                                 esc_str0 = SQLescapeString(vname);
     372           0 :                                 if (!esc_str0) {
     373           0 :                                         msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     374           0 :                                         goto finish;
     375             :                                 }
     376           0 :                                 esc_str1 = SQLescapeString(aname);
     377           0 :                                 if (!esc_str1) {
     378           0 :                                         GDKfree(esc_str0);
     379           0 :                                         msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     380           0 :                                         goto finish;
     381             :                                 }
     382           0 :                                 switch ( atype ) {
     383           0 :                                 case NC_CHAR:
     384           0 :                                         aval = (char *) GDKzalloc(alen + 1);
     385           0 :                                         if (!aval) {
     386           0 :                                                 GDKfree(esc_str0);
     387           0 :                                                 GDKfree(esc_str1);
     388           0 :                                                 msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     389           0 :                                                 goto finish;
     390             :                                         }
     391           0 :                                         if ((retval = nc_get_att_text(ncid,vidx,aname,aval)))
     392           0 :                                                 return createException(MAL, "netcdf.attach",
     393             :                                                                                            SQLSTATE(NC000) "Cannot read attribute %s value: %s",
     394             :                                                                                            aname, nc_strerror(retval));
     395           0 :                                         fix_quote(aval, alen);
     396           0 :                                         aval[alen] = '\0';
     397           0 :                                         snprintf(buf, BUFSIZ, INSATTR, esc_str0, esc_str1, "string", aval, (int)fid, "root");
     398           0 :                                         GDKfree(aval);
     399           0 :                                         break;
     400             : 
     401           0 :                                 case NC_INT:
     402           0 :                                         if ((retval = nc_get_att_int(ncid,vidx,aname,&avalint)))
     403           0 :                                                 return createException(MAL, "netcdf.attach",
     404             :                                                                                            SQLSTATE(NC000) "Cannot read attribute %s value: %s",
     405             :                                                                                            aname, nc_strerror(retval));
     406           0 :                                         snprintf(abuf,80,"%d",avalint);
     407           0 :                                         snprintf(buf, BUFSIZ, INSATTR, esc_str0, esc_str1, prim_type_name(atype), abuf, (int)fid, "root");
     408           0 :                                         break;
     409             : 
     410           0 :                                 case NC_FLOAT:
     411           0 :                                         if ((retval = nc_get_att_float(ncid,vidx,aname,&avalfl)))
     412           0 :                                                 return createException(MAL, "netcdf.attach",
     413             :                                                                                            SQLSTATE(NC000) "Cannot read attribute %s value: %s",
     414             :                                                                                            aname, nc_strerror(retval));
     415           0 :                                         snprintf(abuf,80,"%7.2f",avalfl);
     416           0 :                                         snprintf(buf, BUFSIZ, INSATTR, esc_str0, esc_str1, prim_type_name(atype), abuf, (int)fid, "root");
     417           0 :                                         break;
     418             : 
     419           0 :                                 case NC_DOUBLE:
     420           0 :                                         if ((retval = nc_get_att_double(ncid,vidx,aname,&avaldbl)))
     421           0 :                                                 return createException(MAL, "netcdf.attach",
     422             :                                                                                            SQLSTATE(NC000) "Cannot read attribute %s value: %s",
     423             :                                                                                            aname, nc_strerror(retval));
     424           0 :                                         snprintf(abuf,80,"%7.2e",avaldbl);
     425           0 :                                         snprintf(buf, BUFSIZ, INSATTR, esc_str0, esc_str1, prim_type_name(atype), abuf, (int)fid, "root");
     426           0 :                                         break;
     427             : 
     428           0 :                                 default: continue; /* next attribute */
     429             :                                 }
     430           0 :                                 GDKfree(esc_str1);
     431           0 :                                 GDKfree(esc_str0);
     432             : 
     433           0 :                                 printf("statement: '%s'\n", s);
     434           0 :                                 if ( ( msg = SQLstatementIntern(cntxt, s, "netcdf.attach", TRUE, FALSE, NULL))
     435             :                                          != MAL_SUCCEED )
     436           0 :                                         goto finish;
     437             : 
     438             :                 } /* attr loop */
     439             : 
     440             :             }
     441             :         } /* var loop */
     442             : 
     443             :         /* Extract global attributes */
     444             : 
     445           0 :         for (aidx = 0; aidx < ngatts; aidx++){
     446           0 :                 if ((retval = nc_inq_attname(ncid,NC_GLOBAL,aidx,aname)) != 0)
     447           0 :                 return createException(MAL, "netcdf.attach",
     448             :                                                                    SQLSTATE(NC000) "Cannot read global attribute %d: %s",
     449             :                                                                    aidx, nc_strerror(retval));
     450             : 
     451           0 :                 if ((retval = nc_inq_att(ncid,NC_GLOBAL,aname,&atype,&alen)) != 0){
     452             :                         if (dims != NULL ){
     453           0 :                                 for (didx = 0; didx < ndims; didx++)
     454           0 :                                         GDKfree(dims[didx]);
     455           0 :                                 GDKfree(dims);
     456             :                         }
     457           0 :                 return createException(MAL, "netcdf.attach",
     458             :                                                                    SQLSTATE(NC000) "Cannot read global attribute %s type and length: %s",
     459             :                                                                    aname, nc_strerror(retval));
     460             :                 }
     461             : 
     462           0 :                 esc_str0 = SQLescapeString(aname);
     463           0 :                 if (!esc_str0) {
     464           0 :                         msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     465           0 :                         goto finish;
     466             :                 }
     467             : 
     468           0 :                 switch ( atype ) {
     469           0 :                 case NC_CHAR:
     470           0 :                         aval = (char *) GDKzalloc(alen + 1);
     471           0 :                         if (!aval) {
     472           0 :                                 GDKfree(esc_str0);
     473           0 :                                 msg = createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     474           0 :                                 goto finish;
     475             :                         }
     476           0 :                         if ((retval = nc_get_att_text(ncid,NC_GLOBAL,aname,aval))) {
     477           0 :                                 GDKfree(esc_str0);
     478             :                                 if (dims != NULL ){
     479           0 :                                         for (didx = 0; didx < ndims; didx++)
     480           0 :                                                 GDKfree(dims[didx]);
     481           0 :                                         GDKfree(dims);
     482             :                                 }
     483           0 :                                 return createException(MAL, "netcdf.attach",
     484             :                                                        SQLSTATE(NC000) "Cannot read global attribute %s value: %s",
     485             :                                                        aname, nc_strerror(retval));
     486             :                         }
     487           0 :                         fix_quote(aval, alen);
     488           0 :                         aval[alen] = '\0';
     489           0 :                         snprintf(buf, BUFSIZ, INSATTR, "GLOBAL", esc_str0, "string", aval, (int)fid, "root");
     490           0 :                         GDKfree(aval);
     491           0 :                         break;
     492             : 
     493           0 :                 case NC_INT:
     494           0 :                         if ((retval = nc_get_att_int(ncid,NC_GLOBAL,aname,&avalint))){
     495           0 :                                 GDKfree(esc_str0);
     496             :                                 if (dims != NULL ){
     497           0 :                                         for (didx = 0; didx < ndims; didx++)
     498           0 :                                                 GDKfree(dims[didx]);
     499           0 :                                         GDKfree(dims);
     500             :                                 }
     501           0 :                                 return createException(MAL, "netcdf.attach",
     502             :                                                                            SQLSTATE(NC000) "Cannot read global attribute %s of type %s : %s",
     503             :                                                                            aname, prim_type_name(atype), nc_strerror(retval));
     504             :                         }
     505           0 :                         snprintf(abuf,80,"%d",avalint);
     506           0 :                         snprintf(buf, BUFSIZ, INSATTR, "GLOBAL", esc_str0, prim_type_name(atype), abuf, (int)fid, "root");
     507           0 :                         break;
     508             : 
     509           0 :                 case NC_FLOAT:
     510           0 :                         if ((retval = nc_get_att_float(ncid,NC_GLOBAL,aname,&avalfl))){
     511           0 :                                 GDKfree(esc_str0);
     512             :                                 if (dims != NULL ){
     513           0 :                                         for (didx = 0; didx < ndims; didx++)
     514           0 :                                                 GDKfree(dims[didx]);
     515           0 :                                         GDKfree(dims);
     516             :                                 }
     517           0 :                                 return createException(MAL, "netcdf.attach",
     518             :                                                                            SQLSTATE(NC000) "Cannot read global attribute %s of type %s: %s",
     519             :                                                                            aname, prim_type_name(atype), nc_strerror(retval));
     520             :                         }
     521           0 :                         snprintf(abuf,80,"%7.2f",avalfl);
     522           0 :                         snprintf(buf, BUFSIZ, INSATTR, "GLOBAL", esc_str0, prim_type_name(atype), abuf, (int)fid, "root");
     523           0 :                         break;
     524             : 
     525           0 :                 case NC_DOUBLE:
     526           0 :                         if ((retval = nc_get_att_double(ncid,NC_GLOBAL,aname,&avaldbl))){
     527           0 :                                 GDKfree(esc_str0);
     528             :                                 if (dims != NULL ){
     529           0 :                                         for (didx = 0; didx < ndims; didx++)
     530           0 :                                                 GDKfree(dims[didx]);
     531           0 :                                         GDKfree(dims);
     532             :                                 }
     533           0 :                                 return createException(MAL, "netcdf.attach",
     534             :                                                                            SQLSTATE(NC000) "Cannot read global attribute %s value: %s",
     535             :                                                                            aname, nc_strerror(retval));
     536             :                         }
     537           0 :                         snprintf(abuf,80,"%7.2e",avaldbl);
     538           0 :                         snprintf(buf, BUFSIZ, INSATTR, "GLOBAL", esc_str0, prim_type_name(atype), abuf, (int)fid, "root");
     539           0 :                         break;
     540             : 
     541           0 :                 default: continue; /* next attribute */
     542             :                 }
     543           0 :                 GDKfree(esc_str0);
     544             : 
     545           0 :                 printf("global: '%s'\n", s);
     546           0 :         if ( ( msg = SQLstatementIntern(cntxt, s, "netcdf.attach", TRUE, FALSE, NULL))
     547             :                          != MAL_SUCCEED )
     548           0 :                 goto finish;
     549             : 
     550             :     } /* global attr loop */
     551             : 
     552             : 
     553           0 : finish:
     554           0 :     nc_close(ncid);
     555             : 
     556           0 :     if (dims != NULL ){
     557           0 :         for (didx = 0; didx < ndims; didx++)
     558           0 :             GDKfree(dims[didx]);
     559           0 :         GDKfree(dims);
     560             :     }
     561             : 
     562             :         return msg;
     563             : }
     564             : 
     565             : 
     566             : /* Compose create table statement to create table representing NetCDF variable in the
     567             :  * database. Used for testing, can be removed from release. */
     568             : str
     569           0 : NCDFimportVarStmt(str *sciqlstmt, str *fname, int *varid)
     570             : {
     571             :         int ncid;   /* dataset id */
     572             :         int vndims, vnatts, i, j, retval;
     573             :         int vdims[NC_MAX_VAR_DIMS];
     574             : 
     575             :         size_t dlen;
     576             :         char dname[NC_MAX_NAME+1], vname[NC_MAX_NAME+1];
     577             :         nc_type vtype; /* == int */
     578             : 
     579             :         char buf[BUFSIZ];
     580             :         str msg = MAL_SUCCEED;
     581             : 
     582             :         /* Open NetCDF file  */
     583           0 :         if ((retval = nc_open(*fname, NC_NOWRITE, &ncid)))
     584           0 :         return createException(MAL, "netcdf.importvar",
     585             :             SQLSTATE(NC000) "Cannot open NetCDF file %s: %s", *fname, nc_strerror(retval));
     586             : 
     587           0 :         if ( (retval = nc_inq_var(ncid, *varid, vname, &vtype, &vndims, vdims, &vnatts)))
     588           0 :             return createException(MAL, "netcdf.attach",
     589             :                     SQLSTATE(NC000) "Cannot read variable %d : %s", *varid, nc_strerror(retval));
     590             : 
     591             : 
     592           0 :         j = snprintf(buf, BUFSIZ,"create table %s( ", vname);
     593             : 
     594           0 :         for (i = 0; i < vndims; i++){
     595           0 :             if ((retval = nc_inq_dim(ncid, vdims[i], dname, &dlen)))
     596           0 :                 return createException(MAL, "netcdf.attach",
     597             :                             SQLSTATE(NC000) "Cannot read dimension %d : %s", vdims[i], nc_strerror(retval));
     598             : 
     599             :           (void)dlen;
     600           0 :           j += snprintf(buf + j, BUFSIZ - j, "%s INTEGER, ", dname);
     601             : 
     602             :         }
     603             : 
     604           0 :         j += snprintf(buf + j, BUFSIZ - j, "value %s);", NCDF2SQL(vtype));
     605             : 
     606           0 :         nc_close(ncid);
     607             : 
     608           0 :         *sciqlstmt = GDKstrdup(buf);
     609           0 :         if(*sciqlstmt == NULL)
     610           0 :                 return createException(MAL, "netcdf.importvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     611             :         return msg;
     612             : }
     613             : 
     614             : /* Load variable varid from data set ncid into the bat v. Generate dimension
     615             :  * bats dim using NCDFARRAYseries */
     616             : static str
     617           0 : NCDFloadVar(bat **dim, bat *v, int ncid, int varid, nc_type vtype, int vndims, int *vdims)
     618             : {
     619             : 
     620             :         BAT *res;
     621             :         bat vbid, *dim_bids;
     622             :         int retval, i, j;
     623             :         char *sermsg = NULL;
     624             :         size_t sz = 1;
     625             :         size_t *dlen = NULL, *val_rep = NULL, *grp_rep = NULL;
     626             : 
     627           0 :         if ( dim == NULL )
     628           0 :                 return createException(MAL, "netcdf.importvar", SQLSTATE(NC000) "array of dimension bat is NULL");
     629           0 :         dim_bids = *dim;
     630             : 
     631           0 :         dlen = (size_t *)GDKzalloc(sizeof(size_t) * vndims);
     632           0 :         if (!dlen)
     633           0 :                 return createException(MAL, "netcdf.attach", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     634             : 
     635           0 :         for (i = 0; i < vndims; i++){
     636           0 :                 if ((retval = nc_inq_dimlen(ncid, vdims[i], &dlen[i])))
     637           0 :                         return createException(MAL, "netcdf.importvar",
     638             :                                                                    SQLSTATE(NC000) "Cannot read dimension %d : %s",
     639             :                                                                    vdims[i], nc_strerror(retval));
     640           0 :                 sz *= dlen[i];
     641             :         }
     642             : 
     643           0 :         switch (vtype) {
     644           0 :         case NC_INT:
     645             :         {
     646           0 :                 LOAD_NCDF_VAR(int,int);
     647             :                 break;
     648             :         }
     649           0 :         case NC_FLOAT:
     650             :         case NC_DOUBLE:
     651             :         {
     652           0 :                 LOAD_NCDF_VAR(dbl,double);
     653             :                 break;
     654             :         }
     655             : 
     656             :         default:
     657           0 :                 GDKfree(dlen);
     658           0 :                 return createException(MAL, "netcdf.importvar",
     659             :                            SQLSTATE(NC000) "Type %s not supported yet",
     660             :                            prim_type_name(vtype));
     661             : 
     662             :         }
     663             : 
     664           0 :         BATsetcount(res, sz);
     665           0 :         res->tnonil = true;
     666           0 :         res->tnil = false;
     667           0 :         res->tsorted = false;
     668           0 :         res->trevsorted = false;
     669           0 :         BATkey(res, false);
     670           0 :         BBPkeepref(vbid = res->batCacheid);
     671             : 
     672             :         res = NULL;
     673             : 
     674             :         /* Manually create dimensions with range [0:1:dlen[i]] */
     675           0 :         val_rep = (size_t *)GDKmalloc(sizeof(size_t) * vndims);
     676           0 :         grp_rep = (size_t *)GDKmalloc(sizeof(size_t) * vndims);
     677           0 :         if (val_rep == NULL || grp_rep == NULL) {
     678           0 :                 GDKfree(dlen);
     679           0 :                 GDKfree(val_rep);
     680           0 :                 GDKfree(grp_rep);
     681           0 :                 throw(MAL, "netcdf.loadvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     682             :         }
     683             : 
     684             :         /* compute the repetition factor inside of the series (val_rep) and of series (grp_rep) */
     685           0 :         for (i = 0; i < vndims; i++) {
     686           0 :                 val_rep[i] = grp_rep[i] = 1;
     687           0 :                 for (j = 0; j < i; j++)
     688           0 :                         grp_rep[i] *= dlen[j];
     689           0 :         for (j = i + 1; j < vndims; j++)
     690           0 :             val_rep[i] *= dlen[j];
     691             :         }
     692             : 
     693           0 :         for (i = 0; i < vndims; i++) {
     694           0 :                 sermsg = NCDFARRAYseries(&dim_bids[i], 0, 1, dlen[i], val_rep[i], grp_rep[i]);
     695             : 
     696           0 :                 if (sermsg != MAL_SUCCEED) {
     697           0 :                         BBPrelease(vbid); /* undo the BBPkeepref(vbid) above */
     698           0 :                         for ( j = 0; j < i; j++) /* undo log. ref of previous dimensions */
     699           0 :                                 BBPrelease(dim_bids[j]);
     700           0 :                         GDKfree(dlen);
     701           0 :                         GDKfree(val_rep);
     702           0 :                         GDKfree(grp_rep);
     703           0 :                         return sermsg;
     704             :                 }
     705             :         }
     706             :         /* to do : is descriptor check of dim_bids is needed? */
     707             : 
     708           0 :         GDKfree(dlen);
     709           0 :         GDKfree(val_rep);
     710           0 :         GDKfree(grp_rep);
     711             : 
     712           0 :         *v = vbid;
     713             : 
     714           0 :         return MAL_SUCCEED;
     715             : }
     716             : 
     717             : /* import variable given file id and variable name */
     718             : str
     719           0 : NCDFimportVariable(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     720             : {
     721           0 :         mvc *m = NULL;
     722             :         sql_schema *sch = NULL;
     723             :         sql_table *tfiles = NULL, *arr_table = NULL;
     724             :         sql_column *col;
     725             : 
     726           0 :         str msg = MAL_SUCCEED, vname = *getArgReference_str(stk, pci, 2);
     727             :         str fname = NULL, dimtype = NULL, aname_sys = NULL;
     728           0 :         int fid = *getArgReference_int(stk, pci, 1);
     729             :         int varid, vndims, vnatts, i, j, retval;
     730             :         char buf[BUFSIZ], *s= buf, aname[256], **dname;
     731             :         oid rid = oid_nil;
     732             :         int vdims[NC_MAX_VAR_DIMS];
     733             :         nc_type vtype;
     734             :         int ncid;   /* dataset id */
     735             :         size_t dlen;
     736           0 :         bat vbatid = 0, *dim_bids;
     737             :         BAT *vbat = NULL, *dimbat;
     738             : 
     739           0 :         msg = getSQLContext(cntxt, mb, &m, NULL);
     740           0 :         if (msg)
     741             :                 return msg;
     742             : 
     743           0 :         sqlstore *store = m->session->tr->store;
     744           0 :         sch = mvc_bind_schema(m, "sys");
     745           0 :         if ( !sch )
     746           0 :                 return createException(MAL, "netcdf.importvar", SQLSTATE(NC000) "Cannot get schema sys\n");
     747             : 
     748           0 :         tfiles = mvc_bind_table(m, sch, "netcdf_files");
     749           0 :         if (tfiles == NULL)
     750           0 :                 return createException(MAL, "netcdf.importvar", SQLSTATE(NC000) "Catalog table missing\n");
     751             : 
     752             :         /* get the name of the attached NetCDF file */
     753           0 :         col = mvc_bind_column(m, tfiles, "file_id");
     754           0 :         if (col == NULL)
     755           0 :                 return createException(MAL, "netcdf.importvar", SQLSTATE(NC000) "Could not find \"netcdf_files\".\"file_id\"\n");
     756           0 :         rid = store->table_api.column_find_row(m->session->tr, col, (void *)&fid, NULL);
     757           0 :         if (is_oid_nil(rid))
     758           0 :                 return createException(MAL, "netcdf.importvar", SQLSTATE(NC000) "File %d not in the NetCDF vault\n", fid);
     759             : 
     760             : 
     761           0 :         col = mvc_bind_column(m, tfiles, "location");
     762           0 :         fname = (str)store->table_api.column_find_value(m->session->tr, col, rid);
     763             : 
     764             :         /* Open NetCDF file  */
     765           0 :         if ((retval = nc_open(fname, NC_NOWRITE, &ncid))) {
     766           0 :                 char *msg = createException(MAL, "netcdf.importvar", SQLSTATE(NC000) "Cannot open NetCDF file %s: %s",
     767             :                            fname, nc_strerror(retval));
     768           0 :                 GDKfree(fname);
     769           0 :                 return msg;
     770             :         }
     771           0 :         GDKfree(fname);
     772             : 
     773             :         /* Get info for variable vname from NetCDF file */
     774           0 :         if ( (retval = nc_inq_varid(ncid, vname, &varid)) ) {
     775           0 :                 nc_close(ncid);
     776           0 :                 return createException(MAL, "netcdf.importvar",
     777             :                            SQLSTATE(NC000) "Cannot read variable %s: %s",
     778             :                            vname, nc_strerror(retval));
     779             :         }
     780           0 :         if ( (retval = nc_inq_var(ncid, varid, vname, &vtype, &vndims, vdims, &vnatts))) {
     781           0 :                 nc_close(ncid);
     782           0 :                 return createException(MAL, "netcdf.importvar",
     783             :                                 SQLSTATE(NC000) "Cannot read variable %d : %s",
     784             :                                 varid, nc_strerror(retval));
     785             :         }
     786             : 
     787             :         /* compose 'create table' statement in the buffer */
     788           0 :         dname = (char **) GDKzalloc( sizeof(char *) * vndims);
     789           0 :         if (dname == NULL) {
     790           0 :                 nc_close(ncid);
     791           0 :                 throw(MAL, "netcdf.importvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     792             :         }
     793           0 :         for (i = 0; i < vndims; i++) {
     794           0 :                 dname[i] = (char *) GDKzalloc(NC_MAX_NAME + 1);
     795           0 :                 if(!dname[i]) {
     796           0 :                         for (j = 0; j < i; j++)
     797           0 :                                 GDKfree(dname[j]);
     798           0 :                         GDKfree(dname);
     799           0 :                         nc_close(ncid);
     800           0 :                         throw(MAL, "netcdf.importvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     801             :                 }
     802             :         }
     803             : 
     804           0 :         snprintf(aname, 256, "%s%d", vname, fid);
     805             : 
     806           0 :         j = snprintf(buf, BUFSIZ,"create table %s.%s( ", sch->base.name, aname);
     807             : 
     808           0 :         for (i = 0; i < vndims; i++){
     809           0 :                 if ((retval = nc_inq_dim(ncid, vdims[i], dname[i], &dlen))) {
     810           0 :                         for (j = 0; j < vndims; j++)
     811           0 :                                 GDKfree(dname[j]);
     812           0 :                         GDKfree(dname);
     813           0 :                         nc_close(ncid);
     814           0 :                         return createException(MAL, "netcdf.importvar",
     815             :                                                                    SQLSTATE(NC000) "Cannot read dimension %d : %s",
     816             :                                                                    vdims[i], nc_strerror(retval));
     817             :                 }
     818             : 
     819           0 :                 if ( dlen <= (int) GDK_bte_max )
     820             :                         dimtype = "TINYINT";
     821           0 :                 else if ( dlen <= (int) GDK_sht_max )
     822             :                         dimtype = "SMALLINT";
     823             :                 else
     824             :                         dimtype = "INT";
     825             : 
     826             :                 (void)dlen;
     827           0 :                 j += snprintf(buf + j, BUFSIZ - j, "%s %s, ", dname[i], dimtype);
     828             :         }
     829             : 
     830           0 :         j += snprintf(buf + j, BUFSIZ - j, "value %s);", NCDF2SQL(vtype));
     831             : 
     832             : /* execute 'create table ' */
     833           0 :         msg = SQLstatementIntern(cntxt, s, "netcdf.importvar", TRUE, FALSE, NULL);
     834           0 :         if (msg != MAL_SUCCEED){
     835           0 :                 for (i = 0; i < vndims; i++)
     836           0 :                         GDKfree(dname[i]);
     837           0 :                 GDKfree(dname);
     838           0 :                 nc_close(ncid);
     839           0 :                 return msg;
     840             :         }
     841             : 
     842             : /* load variable data */
     843           0 :         dim_bids = (bat *)GDKmalloc(sizeof(bat) * vndims);
     844           0 :         if (dim_bids == NULL){
     845           0 :                 for (i = 0; i < vndims; i++)
     846           0 :                         GDKfree(dname[i]);
     847           0 :                 GDKfree(dname);
     848           0 :                 nc_close(ncid);
     849           0 :                 throw(MAL, "netcdf.importvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     850             :         }
     851             : 
     852           0 :         msg = NCDFloadVar(&dim_bids, &vbatid, ncid, varid, vtype, vndims, vdims);
     853           0 :         if ( msg != MAL_SUCCEED ) {
     854           0 :                 for (i = 0; i < vndims; i++)
     855           0 :                         GDKfree(dname[i]);
     856           0 :                 GDKfree(dname);
     857           0 :                 GDKfree(dim_bids);
     858           0 :                 nc_close(ncid);
     859           0 :                 return msg;
     860             :         }
     861             : 
     862             :         /* associate columns in the table with loaded variable data */
     863           0 :         aname_sys = toLower(aname);
     864           0 :         arr_table = mvc_bind_table(m, sch, aname_sys);
     865           0 :         if (arr_table == NULL){
     866           0 :                 for (i = 0; i < vndims; i++)
     867           0 :                         GDKfree(dname[i]);
     868           0 :                 GDKfree(dname);
     869           0 :                 GDKfree(dim_bids);
     870           0 :                 nc_close(ncid);
     871           0 :                 throw(MAL, "netcdf.importvar", SQLSTATE(NC000) "netcdf table %s missing\n", aname_sys);
     872             :         }
     873             : 
     874           0 :         col = mvc_bind_column(m, arr_table, "value");
     875           0 :         if (col == NULL){
     876           0 :                 for (i = 0; i < vndims; i++)
     877           0 :                         GDKfree(dname[i]);
     878           0 :                 GDKfree(dname);
     879           0 :                 GDKfree(dim_bids);
     880           0 :                 nc_close(ncid);
     881           0 :                 throw(MAL, "netcdf.importvar", SQLSTATE(NC000) "Cannot find column %s.value\n", aname_sys);
     882             :         }
     883             : 
     884           0 :         vbat = BATdescriptor(vbatid);
     885           0 :         if(vbat == NULL) {
     886           0 :                 for (i = 0; i < vndims; i++)
     887           0 :                         GDKfree(dname[i]);
     888           0 :                 GDKfree(dname);
     889           0 :                 GDKfree(dim_bids);
     890           0 :                 nc_close(ncid);
     891           0 :                 throw(MAL, "netcdf.importvar", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     892             :         }
     893             :         BUN offset;
     894           0 :         BAT *pos = NULL;
     895           0 :         if (store->storage_api.claim_tab(m->session->tr, arr_table, BATcount(vbat), &offset, &pos) != LOG_OK) {
     896           0 :                 for (i = 0; i < vndims; i++)
     897           0 :                         GDKfree(dname[i]);
     898           0 :                 GDKfree(dname);
     899           0 :                 GDKfree(dim_bids);
     900           0 :                 BBPunfix(vbatid);
     901           0 :                 BBPrelease(vbatid);
     902           0 :                 nc_close(ncid);
     903           0 :                 throw(MAL, "netcdf.importvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     904             :         }
     905           0 :         if (!isNew(arr_table) && sql_trans_add_dependency_change(m->session->tr, arr_table->base.id, dml) != LOG_OK) {
     906           0 :                 for (i = 0; i < vndims; i++)
     907           0 :                         GDKfree(dname[i]);
     908           0 :                 GDKfree(dname);
     909           0 :                 GDKfree(dim_bids);
     910           0 :                 BBPunfix(vbatid);
     911           0 :                 BBPrelease(vbatid);
     912           0 :                 bat_destroy(pos);
     913           0 :                 nc_close(ncid);
     914           0 :                 throw(MAL, "netcdf.importvar", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     915             :         }
     916           0 :         store->storage_api.append_col(m->session->tr, col, offset, pos, vbat, BATcount(vbat), TYPE_bat);
     917           0 :         BBPunfix(vbatid);
     918           0 :         BBPrelease(vbatid);
     919             :         vbat = NULL;
     920             : 
     921             :         /* associate dimension bats  */
     922           0 :         for (i = 0; i < vndims; i++){
     923           0 :                 col = mvc_bind_column(m, arr_table, dname[i]);
     924           0 :                 if (col == NULL){
     925           0 :                         for (i = 0; i < vndims; i++)
     926           0 :                                 GDKfree(dname[i]);
     927           0 :                         GDKfree(dname);
     928           0 :                         GDKfree(dim_bids);
     929           0 :                         bat_destroy(pos);
     930           0 :                         nc_close(ncid);
     931           0 :                         throw(MAL, "netcdf.importvar", SQLSTATE(NC000) "Cannot find column %s.%s\n", aname_sys, dname[i]);
     932             :                 }
     933             : 
     934           0 :                 dimbat = BATdescriptor(dim_bids[i]);
     935           0 :                 if(dimbat == NULL) {
     936           0 :                         for (i = 0; i < vndims; i++)
     937           0 :                                 GDKfree(dname[i]);
     938           0 :                         GDKfree(dname);
     939           0 :                         GDKfree(dim_bids);
     940           0 :                         bat_destroy(pos);
     941           0 :                         nc_close(ncid);
     942           0 :                         throw(MAL, "netcdf.importvar", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     943             :                 }
     944           0 :                 store->storage_api.append_col(m->session->tr, col, offset, pos, dimbat, BATcount(dimbat), TYPE_bat);
     945           0 :                 BBPunfix(dim_bids[i]); /* phys. ref from BATdescriptor */
     946           0 :                 BBPrelease(dim_bids[i]); /* log. ref. from loadVar */
     947             :                 dimbat = NULL;
     948             :         }
     949             : 
     950           0 :         for (i = 0; i < vndims; i++)
     951           0 :                 GDKfree(dname[i]);
     952           0 :         GDKfree(dname);
     953           0 :         GDKfree(dim_bids);
     954           0 :         bat_destroy(pos);
     955           0 :         nc_close(ncid);
     956           0 :         return msg;
     957             : }
     958             : 
     959             : #include "mel.h"
     960             : static mel_func netcdf_init_funcs[] = {
     961             :  command("netcdf", "test", NCDFtest, false, "Returns number of variables in a given NetCDF dataset (file)", args(1,2, arg("",int),arg("filename",str))),
     962             :  pattern("netcdf", "attach", NCDFattach, false, "Register a NetCDF file in the vault", args(1,2, arg("",void),arg("filename",str))),
     963             :  command("netcdf", "importvar", NCDFimportVarStmt, false, "Import variable: compose create array string", args(1,3, arg("",str),arg("filename",str),arg("varid",int))),
     964             :  pattern("netcdf", "importvariable", NCDFimportVariable, false, "Import variable: create array and load data from variable varname of file fileid", args(1,3, arg("",void),arg("fileid",int),arg("varname",str))),
     965             :  { .imp=NULL }
     966             : };
     967             : #include "mal_import.h"
     968             : #ifdef _MSC_VER
     969             : #undef read
     970             : #pragma section(".CRT$XCU",read)
     971             : #endif
     972         254 : LIB_STARTUP_FUNC(init_netcdf_mal)
     973         254 : { mal_module("netcdf", NULL, netcdf_init_funcs); }

Generated by: LCOV version 1.14