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 555 0.4 %
Date: 2024-10-03 20:03:20 Functions: 1 9 11.1 %

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

Generated by: LCOV version 1.14