ported rename fix changes from branch ejh_fill_values for easy merging

This commit is contained in:
Ed Hartnett 2018-01-05 06:01:22 -07:00
parent 2281f3e133
commit 3fa3d3f9f9
5 changed files with 543 additions and 213 deletions

View File

@ -102,6 +102,12 @@ typedef enum {VAR, DIM, ATT} NC_OBJ_T;
* as the netCDF dimid. */
#define NC_DIMID_ATT_NAME "_Netcdf4Dimid"
/** This is the name of the class HDF5 dimension scale attribute. */
#define HDF5_DIMSCALE_CLASS_ATT_NAME "CLASS"
/** This is the name of the name HDF5 dimension scale attribute. */
#define HDF5_DIMSCALE_NAME_ATT_NAME "NAME"
/* Boolean type, to make the code easier to read */
typedef enum {NC_FALSE = 0, NC_TRUE = 1} nc_bool_t;
@ -126,7 +132,7 @@ typedef struct NC_DIM_INFO
nc_bool_t unlimited; /* True if the dimension is unlimited */
nc_bool_t extended; /* True if the dimension needs to be extended */
nc_bool_t too_long; /* True if len is too big to fit in local size_t. */
hid_t hdf_dimscaleid;
hid_t hdf_dimscaleid; /* Non-zero if a DIM_WITHOUT_VARIABLE dataset is in use (no coord var). */
HDF5_OBJID_T hdf5_objid;
struct NC_VAR_INFO *coord_var; /* The coord var, if it exists. */
} NC_DIM_INFO_T;
@ -344,6 +350,7 @@ int nc4_convert_type(const void *src, void *dest,
/* These functions do HDF5 things. */
int rec_detach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid);
int rec_reattach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid);
int delete_existing_dimscale_dataset(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T *dim);
int nc4_open_var_grp2(NC_GRP_INFO_T *grp, int varid, hid_t *dataset);
int nc4_put_vara(NC *nc, int ncid, int varid, const size_t *startp,
const size_t *countp, nc_type xtype, int is_long, void *op);

View File

@ -1,3 +1,6 @@
/* Copyright 2003-2018, University Corporation for Atmospheric
* Research. See the COPYRIGHT file for copying and redistribution
* conditions. */
/**
* @file
* @internal This file is part of netcdf-4, a netCDF-like interface
@ -6,9 +9,6 @@
*
* This file handles the nc4 dimension functions.
*
* Copyright 2003-5, University Corporation for Atmospheric Research. See
* the COPYRIGHT file for copying and redistribution conditions.
*
* @author Ed Hartnett
*/
@ -103,8 +103,7 @@ NC4_def_dim(int ncid, const char *name, size_t len, int *idp)
/* Find our global metadata structure. */
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
return retval;
assert(h5 && nc /*& grp*/);
assert(h5 && nc && grp);
/* If the file is read-only, return an error. */
if (h5->no_write)
@ -327,9 +326,7 @@ NC4_rename_dim(int ncid, int dimid, const char *name)
/* Find info for this file and group, and set pointer to each. */
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
return retval;
assert(nc);
assert(h5 && grp);
assert(nc && h5 && grp);
/* Trying to write to a read-only file? No way, Jose! */
if (h5->no_write)
@ -352,33 +349,30 @@ NC4_rename_dim(int ncid, int dimid, const char *name)
return NC_EBADDIM;
dim = tmp_dim;
/* Check for renaming dimension w/o variable */
/* Check for renaming dimension w/o variable. */
if (dim->hdf_dimscaleid)
{
/* Sanity check */
assert(!dim->coord_var);
LOG((3, "dim %s is a dim without variable", dim->name));
/* Close the HDF5 dataset */
if (H5Dclose(dim->hdf_dimscaleid) < 0)
return NC_EHDFERR;
dim->hdf_dimscaleid = 0;
/* Now delete the dataset (it will be recreated later, if necessary) */
if (H5Gunlink(grp->hdf_grpid, dim->name) < 0)
return NC_EDIMMETA;
/* Delete the dimscale-only dataset. */
if ((retval = delete_existing_dimscale_dataset(grp, dimid, dim)))
return retval;
}
/* Give the dimension its new name in metadata. UTF8 normalization
* has been done. */
if(dim->name)
free(dim->name);
assert(dim->name);
free(dim->name);
if (!(dim->name = malloc((strlen(norm_name) + 1) * sizeof(char))))
return NC_ENOMEM;
strcpy(dim->name, norm_name);
dim->hash = hash_fast(norm_name, strlen(norm_name));
LOG((3, "dim is now named %s", dim->name));
/* Check if dimension was a coordinate variable, but names are different now */
/* Check if dimension was a coordinate variable, but names are
* different now */
if (dim->coord_var && strcmp(dim->name, dim->coord_var->name))
{
/* Break up the coordinate variable */
@ -386,24 +380,24 @@ NC4_rename_dim(int ncid, int dimid, const char *name)
return retval;
}
/* Check if dimension should become a coordinate variable */
/* Check if dimension should become a coordinate variable. */
if (!dim->coord_var)
{
NC_VAR_INFO_T *var;
/* Attempt to find a variable with the same name as the dimension in
* the current group. */
/* Attempt to find a variable with the same name as the
* dimension in the current group. */
if ((retval = nc4_find_var(grp, dim->name, &var)))
return retval;
/* Check if we found a variable and the variable has the dimension in
* index 0. */
/* Check if we found a variable and the variable has the
* dimension in index 0. */
if (var && var->dim[0] == dim)
{
/* Sanity check */
assert(var->dimids[0] == dim->dimid);
/* Reform the coordinate variable */
/* Reform the coordinate variable. */
if ((retval = nc4_reform_coord_var(grp, var, dim)))
return retval;
}

View File

@ -1526,7 +1526,9 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp)
while (dim)
{
LOG((4, "%s: deleting dim %s", __func__, dim->name));
/* Close HDF5 dataset associated with this dim. */
/* If this is a dim without a coordinate variable, then close
* the HDF5 DIM_WITHOUT_VARIABLE dataset associated with this
* dim. */
if (dim->hdf_dimscaleid && H5Dclose(dim->hdf_dimscaleid) < 0)
return NC_EHDFERR;
d = dim->l.next;
@ -1620,7 +1622,12 @@ nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att)
/**
* @internal Break a coordinate variable to separate the dimension and
* the variable.
* the variable.
*
* This is called from nc_rename_dim() and nc_rename_var(). In some
* renames, the coord variable must stay, but it is no longer a coord
* variable. This function changes a coord var into an ordinary
* variable.
*
* @param grp Pointer to group info struct.
* @param coord_var Pointer to variable info struct.
@ -1628,7 +1635,7 @@ nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att)
*
* @return ::NC_NOERR No error.
* @return ::NC_ENOMEM Out of memory.
* @author Quincey Koziol
* @author Quincey Koziol, Ed Hartnett
*/
int
nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T *dim)
@ -1636,10 +1643,11 @@ nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T
int retval = NC_NOERR;
/* Sanity checks */
assert(dim->coord_var == coord_var);
assert(coord_var->dim[0] == dim);
assert(coord_var->dimids[0] == dim->dimid);
assert(0 == dim->hdf_dimscaleid);
assert(grp && coord_var && dim && dim->coord_var == coord_var &&
coord_var->dim[0] == dim && coord_var->dimids[0] == dim->dimid &&
!dim->hdf_dimscaleid);
LOG((3, "%s dim %s was associated with var %s, but now has different name",
__func__, dim->name, coord_var->name));
/* If we're replacing an existing dimscale dataset, go to
* every var in the file and detach this dimension scale. */
@ -1647,17 +1655,23 @@ nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T
dim->dimid, coord_var->hdf_datasetid)))
return retval;
/* Allow attached dimscales to be tracked on the [former] coordinate variable */
/* Allow attached dimscales to be tracked on the [former]
* coordinate variable */
if (coord_var->ndims)
{
/* Coordinate variables shouldn't have dimscales attached */
assert(NULL == coord_var->dimscale_attached);
/* Coordinate variables shouldn't have dimscales attached. */
assert(!coord_var->dimscale_attached);
/* Allocate space for tracking them */
if (NULL == (coord_var->dimscale_attached = calloc(coord_var->ndims, sizeof(nc_bool_t))))
if (!(coord_var->dimscale_attached = calloc(coord_var->ndims,
sizeof(nc_bool_t))))
return NC_ENOMEM;
}
/* Remove the atts that go with being a coordinate var. */
/* if ((retval = remove_coord_atts(coord_var->hdf_datasetid))) */
/* return retval; */
/* Detach dimension from variable */
coord_var->dimscale = NC_FALSE;
dim->coord_var = NULL;
@ -1669,9 +1683,54 @@ nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T
return NC_NOERR;
}
/**
* @internal Delete an existing dimscale-only dataset.
*
* A dimscale-only HDF5 dataset is created when a dim is defined
* without an accompanying coordinate variable.
*
* Sometimes, during renames, or late creation of variables, an
* existing, dimscale-only dataset must be removed. This means
* detatching all variables that use the dataset, then closing and
* unlinking it.
*
* @param grp The grp of the dimscale-only dataset to be deleted, or a
* higher group in the heirarchy (ex. root group).
* @param dim Pointer to the dim with the dimscale-only dataset to be
* deleted.
*
* @return ::NC_NOERR No error.
* @return ::NC_EHDFERR HDF5 error.
* @author Ed Hartnett
*/
int
delete_existing_dimscale_dataset(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T *dim)
{
int retval;
assert(grp && dim);
LOG((2, "%s: deleting dimscale dataset %s dimid %d", __func__, dim->name,
dimid));
/* Detach dimscale from any variables using it */
if ((retval = rec_detach_scales(grp, dimid, dim->hdf_dimscaleid)) < 0)
return retval;
/* Close the HDF5 dataset */
if (H5Dclose(dim->hdf_dimscaleid) < 0)
return NC_EHDFERR;
dim->hdf_dimscaleid = 0;
/* Now delete the dataset. */
if (H5Gunlink(grp->hdf_grpid, dim->name) < 0)
return NC_EHDFERR;
return NC_NOERR;
}
/**
* @internal Reform a coordinate variable from a dimension and a
* variable
* variable.
*
* @param grp Pointer to group info struct.
* @param var Pointer to variable info struct.
@ -1683,8 +1742,12 @@ nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T
int
nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim)
{
int need_to_reattach_scales = 0;
int retval = NC_NOERR;
assert(grp && var && dim);
LOG((3, "%s: dim->name %s var->name %s", __func__, dim->name, var->name));
/* Detach dimscales from the [new] coordinate variable */
if(var->dimscale_attached)
{
@ -1694,6 +1757,7 @@ nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim)
/* Loop over all dimensions for variable */
for (d = 0; d < var->ndims && !finished; d++)
{
/* Is there a dimscale attached to this axis? */
if(var->dimscale_attached[d])
{
@ -1704,6 +1768,7 @@ nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim)
NC_DIM_INFO_T *dim1;
for (dim1 = g->dim; dim1 && !finished; dim1 = dim1->l.next)
{
if (var->dimids[d] == dim1->dimid)
{
hid_t dim_datasetid; /* Dataset ID for dimension */
@ -1713,24 +1778,36 @@ nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim)
dim_datasetid = dim1->coord_var->hdf_datasetid;
else
dim_datasetid = dim1->hdf_dimscaleid;
assert(dim_datasetid > 0);
if (H5DSdetach_scale(var->hdf_datasetid, dim_datasetid, d) < 0)
BAIL(NC_EHDFERR);
/* dim_datasetid may be 0 in some cases when
* renames of dims and vars are happening. In
* this case, the scale has already been
* detached. */
if (dim_datasetid > 0)
{
LOG((3, "detaching scale from %s", var->name));
if (H5DSdetach_scale(var->hdf_datasetid, dim_datasetid, d) < 0)
BAIL(NC_EHDFERR);
}
var->dimscale_attached[d] = NC_FALSE;
if (dims_detached++ == var->ndims)
finished++;
}
}
}
}
} /* next variable dimension */
/* Release & reset the array tracking attached dimscales */
free(var->dimscale_attached);
var->dimscale_attached = NULL;
need_to_reattach_scales++;
}
/* Use variable's dataset ID for the dimscale ID */
/* Use variable's dataset ID for the dimscale ID. */
if (dim->hdf_dimscaleid && grp != NULL)
{
LOG((3, "closing and unlinking dimscale dataset %s", dim->name));
if (H5Dclose(dim->hdf_dimscaleid) < 0)
BAIL(NC_EHDFERR);
dim->hdf_dimscaleid = 0;
@ -1746,7 +1823,7 @@ nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim)
dim->coord_var = var;
/* Check if this variable used to be a coord. var */
if (var->was_coord_var && grp != NULL)
if (need_to_reattach_scales || (var->was_coord_var && grp != NULL))
{
/* Reattach the scale everywhere it is used. */
/* (Recall that netCDF dimscales are always 1-D) */

View File

@ -597,7 +597,7 @@ NC4_def_var(int ncid, const char *name, nc_type xtype,
BAIL(NC_EBADTYPE);
}
/* Add a new var. */
/* Create a new var and fill in some HDF5 cache setting values. */
if ((retval = nc4_var_add(&var)))
BAIL(retval);
@ -653,19 +653,23 @@ NC4_def_var(int ncid, const char *name, nc_type xtype,
{
var->dimscale = NC_TRUE;
dim->coord_var = var;
/* Use variable's dataset ID for the dimscale ID */
/* Use variable's dataset ID for the dimscale ID. So delete
* the HDF5 DIM_WITHOUT_VARIABLE dataset that was created for
* this dim. */
if (dim->hdf_dimscaleid)
{
/* Detach dimscale from any variables using it */
if ((retval = rec_detach_scales(grp, dimidsp[d], dim->hdf_dimscaleid)) < 0)
BAIL(retval);
/* Close the HDF5 DIM_WITHOUT_VARIABLE dataset. */
if (H5Dclose(dim->hdf_dimscaleid) < 0)
BAIL(NC_EHDFERR);
dim->hdf_dimscaleid = 0;
/* Now delete the dataset (it will be recreated later, if necessary) */
/* Now delete the DIM_WITHOUT_VARIABLE dataset (it will be
* recreated later, if necessary). */
if (H5Gunlink(grp->hdf_grpid, dim->name) < 0)
BAIL(NC_EDIMMETA);
}
@ -686,7 +690,7 @@ NC4_def_var(int ncid, const char *name, nc_type xtype,
}
/* Determine default chunksizes for this variable. (Even for
* variables which may be contiguous. */
* variables which may be contiguous.) */
LOG((4, "allocating array of %d size_t to hold chunksizes for var %s",
var->ndims, var->name));
if (var->ndims)
@ -743,8 +747,12 @@ exit:
}
/**
* @internal Get all the information about a variable. Pass NULL for whatever
* you don't care about.
* @internal Get all the information about a variable. Pass NULL for
* whatever you don't care about. This is the internal function called
* by nc_inq_var(), nc_inq_var_deflate(), nc_inq_var_fletcher32(),
* nc_inq_var_chunking(), nc_inq_var_chunking_ints(),
* nc_inq_var_fill(), nc_inq_var_endian(), nc_inq_var_filter(), and
* nc_inq_var_szip().
*
* @param ncid File ID.
* @param varid Variable ID.
@ -1567,14 +1575,16 @@ NC4_rename_var(int ncid, int varid, const char *name)
int retval = NC_NOERR;
int i;
LOG((2, "%s: ncid 0x%x varid %d name %s",
__func__, ncid, varid, name));
if (!name)
return NC_EINVAL;
LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid,
name));
/* Find info for this file and group, and set pointer to each. */
if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5)))
return retval;
assert(h5);
assert(h5 && grp && h5);
/* Is the new name too long? */
if (strlen(name) > NC_MAX_NAME)
@ -1612,9 +1622,19 @@ NC4_rename_var(int ncid, int varid, const char *name)
return NC_ENOTINDEFINE;
/* Change the HDF5 file, if this var has already been created
there. */
there. Should we check here to ensure there is not already a
dimscale dataset of name name??? */
if (var->created)
{
/* Is there an existing dimscale-only dataset of this name? If
* so, it must be deleted. */
if (var->ndims && var->dim[0]->hdf_dimscaleid)
{
if ((retval = delete_existing_dimscale_dataset(grp, var->dim[0]->dimid, var->dim[0])))
return retval;
}
LOG((3, "Moving dataset %s to %s", var->name, name));
if (H5Gmove(grp->hdf_grpid, var->name, name) < 0)
BAIL(NC_EHDFERR);
}
@ -1625,6 +1645,7 @@ NC4_rename_var(int ncid, int varid, const char *name)
return NC_ENOMEM;
strcpy(var->name, name);
var->hash = nn_hash;
LOG((3, "var is now %s", var->name));
/* Check if this was a coordinate variable previously, but names are different now */
if (var->dimscale && strcmp(var->name, var->dim[0]->name))

View File

@ -1,167 +1,398 @@
/*
* Demonstrate netcdf-4 rename bug.
* Test renames of vars and dims. It's a surprisingly tricky business.
*
* Quincey Koziol, Ed Hartnett
*/
#include <netcdf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nc_tests.h"
#include "err_macros.h"
/* On error, prints line number and file of test program. */
#define ERR do { \
fflush(stdout); \
fprintf(stderr, "Unexpected result, %s, line: %d\n", \
__FILE__, __LINE__); \
return 2; \
} while (0)
#define FILE_NAME3 "tst_rename_fix3.nc"
#define FILE_NAME4 "tst_rename_fix4.nc"
#define ODIM_NAME "lat" /* name for coord dim */
#define LAT "lat"
#define TAL "tal"
#define TAL1 "tal1"
#define TAL2 "tal2"
#define RH "rh"
#define NDIM_NAME "tal" /* new name for coord dim */
#define OVAR_NAME "lat" /* name for coord var */
#define NVAR_NAME "tal" /* new name for coord var */
#define OVAR2_NAME "rh" /* name for non-coord var that uses coord dim */
#define VAR_RANK 1 /* all vars in this test are of same rank */
#define DIM_LEN 2 /* all dims in this test are of same len */
#define FILE_NAME3 "tst_rnfix3.nc"
#define FILE_NAME4 "tst_rnfix4.nc"
#define ODIM_NAME "lat" /* name for coord dim */
#define NDIM_NAME "tal" /* new name for coord dim */
#define OVAR_NAME "lat" /* name for coord var */
#define NVAR_NAME "tal" /* new name for coord var */
#define OVAR2_NAME "rh" /* name for non-coord var that uses coord dim */
#define VAR_RANK 1 /* all vars in this test are of same rank */
#define DIM_LEN 2 /* all dims in this test are of same len */
/* Test data. */
int lats[DIM_LEN] = {-90, 90};
float rh[DIM_LEN] = {0.25, 0.75};
/* For renaming tests. Create small test file of specified format
* with a coordinate dimension, corresponding coordinate variable, and
* a non-coordinate variable that uses the coordinate dimension.
*/
* a non-coordinate variable that uses the coordinate dimension. */
int
create_test_file(
char *path, /* filename */
int format /* NC_FORMAT_CLASSIC, NC_FORMAT_64BIT,
NC_FORMAT_NETCDF4, or NC_FORMAT_NETCDF4_CLASSIC */
)
create_test_file(char *path, int format)
{
int ncid, dimid, varid, var2id;
int dims[VAR_RANK];
int lats[DIM_LEN] = {-90, 90};
float rh[DIM_LEN] = {0.25, 0.75};
switch (format) {
case (NC_FORMAT_CLASSIC):
if (nc_create(path, 0, &ncid)) ERR;
break;
case (NC_FORMAT_64BIT_OFFSET):
if (nc_create(path, NC_64BIT_OFFSET, &ncid)) ERR;
break;
case (NC_FORMAT_NETCDF4):
if (nc_create(path, NC_NETCDF4, &ncid)) ERR;
break;
case(NC_FORMAT_NETCDF4_CLASSIC):
if (nc_create(path, NC_NETCDF4 | NC_CLASSIC_MODEL, &ncid)) ERR;
break;
default:
ERR;
return NC_ENOTNC;
}
if (nc_def_dim(ncid, ODIM_NAME, DIM_LEN, &dimid)) ERR;
dims[0] = dimid;
if (nc_def_var(ncid, OVAR_NAME, NC_INT, VAR_RANK, dims, &varid)) ERR;
if (nc_def_var(ncid, OVAR2_NAME, NC_FLOAT, VAR_RANK, dims, &var2id)) ERR;
if (nc_enddef(ncid)) ERR; /* not necessary for netCDF-4 files */
if (nc_put_var_int(ncid, varid, lats)) ERR;
if (nc_put_var_float(ncid, var2id, rh)) ERR;
if (nc_close(ncid)) ERR;
return 0;
int ncid, varid, var2id;
int dims[VAR_RANK];
if (nc_set_default_format(format, NULL)) ERR;
if (nc_create(path, 0, &ncid)) ERR;
if (nc_def_dim(ncid, LAT, DIM_LEN, &dims[0])) ERR;
if (nc_def_var(ncid, LAT, NC_INT, VAR_RANK, dims, &varid)) ERR;
if (nc_def_var(ncid, RH, NC_FLOAT, VAR_RANK, dims, &var2id)) ERR;
if (nc_enddef(ncid)) ERR; /* not necessary for netCDF-4 files */
if (nc_put_var_int(ncid, varid, lats)) ERR;
if (nc_put_var_float(ncid, var2id, rh)) ERR;
if (nc_close(ncid)) ERR;
return 0;
}
/* Check the file that was produced by create_test_file(). Only the
* names have been changed... */
int
check_file(int ncid, char *var0_name, char *var1_name, char *dim_name)
{
int varid;
int var2id;
int dimid;
int lats_in[DIM_LEN];
float rh_in[DIM_LEN];
int ii;
/* printf("checking for vars %s and %s, dim %s\n", var0_name, var1_name, */
/* dim_name); */
/* Check vars. Ids will change because of rename. */
if (nc_inq_varid(ncid, var0_name, &varid)) ERR;
if (nc_inq_varid(ncid, var1_name, &var2id)) ERR;
/* Check dim. */
if (nc_inq_dimid(ncid, dim_name, &dimid)) ERR;
if (dimid != 0) ERR;
/* Check the lats. */
if (nc_get_var_int(ncid, varid, lats_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++)
if (lats_in[ii] != lats[ii])
ERR;
/* Check the RH. */
if (nc_get_var_float(ncid, var2id, rh_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++)
if (rh_in[ii] != rh[ii])
ERR;
return 0;
}
/* Check the file created in Charlie Zender's test. See github
* #597. */
int
check_charlies_file(char *file, char *dim_name, char *var_name)
{
int ncid;
int varid, dimid;
if (nc_open(file, 0, &ncid)) ERR;
if (nc_inq_varid(ncid, var_name, &varid)) ERR;
if (nc_inq_dimid(ncid, dim_name, &dimid)) ERR;
if (varid || dimid) ERR;
if (nc_close(ncid)) ERR;
return NC_NOERR;
}
int
main(int argc, char **argv)
{
#define NUM_FORMATS 2
int formats[NUM_FORMATS] = {NC_FORMAT_NETCDF4, NC_FORMAT_NETCDF4_CLASSIC};
char *fmt_names[] = {"netCDF-4", "netCDF-4 classic model"};
char *file_names[] = {FILE_NAME3, FILE_NAME4};
int format;
int formats[NUM_FORMATS] = {NC_FORMAT_NETCDF4, NC_FORMAT_NETCDF4_CLASSIC};
char *fmt_names[] = {"netCDF-4", "netCDF-4 classic model"};
char *file_names[] = {FILE_NAME3, FILE_NAME4};
int format;
fprintf(stderr,"*** Testing netcdf rename bugs and fixes.\n");
fprintf(stderr,"*** Testing netcdf rename bugs and fixes.\n");
nc_set_log_level(5);
for(format = 0; format < NUM_FORMATS; format++)
{
for (format = 0; format < NUM_FORMATS; format++)
/* for (format = 0; format < 1; format++) */
{
int ncid, dimid, varid, var2id;
int lats[DIM_LEN] = {-90, 90};
int lats_in[DIM_LEN];
float rh[DIM_LEN] = {0.25, 0.75};
float rh_in[DIM_LEN];
int ii;
fprintf(stderr,"*** Test Charlie's test for renaming...");
{
#define CHARLIE_TEST_FILE "tst_charlie_rename_coord_dim.nc"
#define LON "lon"
#define LONGITUDE "longitude"
#define DIM1_LEN 4
#define NDIM1 1
int ncid, dimid, varid;
float data[DIM1_LEN] = {0, 90.0, 180.0, 270.0};
/* Create a nice, simple file. This file will contain one
* dataset, "lon", which is a dimscale. */
if (nc_create(CHARLIE_TEST_FILE, NC_NETCDF4, &ncid)) ERR;
if (nc_def_dim(ncid, LON, DIM1_LEN, &dimid)) ERR;
if (nc_def_var(ncid, LON, NC_FLOAT, NDIM1, &dimid, &varid)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_put_var_float(ncid, varid, data)) ERR;
if (nc_close(ncid)) ERR;
/* Check the file. */
if (check_charlies_file(CHARLIE_TEST_FILE, LON, LON)) ERR;
/* Open the file and rename the dimension. This will cause
* lon to stop being a coord var and dimscale, and create a
* new dimscale without var dataset "longitude". Dataset
* "lon" will point to "longitude" as its dimscale. */
if (nc_open(CHARLIE_TEST_FILE, NC_WRITE, &ncid)) ERR;
if (nc_redef(ncid)) ERR;
if (nc_rename_dim(ncid, 0, LONGITUDE)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_close(ncid)) ERR;
/* Reopen the file to check. */
if (check_charlies_file(CHARLIE_TEST_FILE, LONGITUDE, LON)) ERR;
/* Open the file and rename the variable. This will remove
* the dimscale-only dataset "longitude" and rename the
* extisting dataset "lon" to "longitude". Variable
* "longitude" will become a coordinate var. */
/* if (nc_open(CHARLIE_TEST_FILE, NC_WRITE, &ncid)) ERR; */
/* if (nc_redef(ncid)) ERR; */
/* if (nc_rename_var(ncid, 0, LONGITUDE)) ERR; */
/* if (nc_enddef(ncid)) ERR; */
/* if (nc_close(ncid)) ERR; */
/* Reopen the file to check. */
/* if (check_charlies_file(CHARLIE_TEST_FILE, LONGITUDE, LONGITUDE)) ERR; */
}
SUMMARIZE_ERR;
printf("*** testing renaming before enddef for %s...", fmt_names[format]);
{
int ncid, varid, var2id;
int dimid;
if (nc_set_default_format(formats[format], NULL)) ERR;
if (nc_create(file_names[format], 0, &ncid)) ERR;
if (nc_def_dim(ncid, LAT, DIM_LEN, &dimid)) ERR;
if (nc_def_var(ncid, LAT, NC_INT, VAR_RANK, &dimid, &varid)) ERR;
if (nc_def_var(ncid, RH, NC_FLOAT, VAR_RANK, &dimid, &var2id)) ERR;
/* Now rename the dim. */
if (nc_rename_dim(ncid, dimid, TAL)) ERR;
if (nc_rename_var(ncid, varid, TAL)) ERR;
if (nc_enddef(ncid)) ERR; /* not necessary for netCDF-4 files */
if (nc_put_var_int(ncid, varid, lats)) ERR;
if (nc_put_var_float(ncid, var2id, rh)) ERR;
if (nc_close(ncid)) ERR;
/* Reopen and check. */
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
if (check_file(ncid, TAL, RH, TAL)) ERR;
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
printf("*** testing renaming after enddef for %s...", fmt_names[format]);
{
int ncid, varid, var2id;
int dimid;
if (nc_set_default_format(formats[format], NULL)) ERR;
if (nc_create(file_names[format], 0, &ncid)) ERR;
if (nc_def_dim(ncid, LAT, DIM_LEN, &dimid)) ERR;
if (nc_def_var(ncid, TAL1, NC_INT, VAR_RANK, &dimid, &varid)) ERR;
if (nc_def_var(ncid, RH, NC_FLOAT, VAR_RANK, &dimid, &var2id)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_redef(ncid)) ERR;
if (nc_rename_var(ncid, varid, TAL2)) ERR;
if (nc_rename_dim(ncid, dimid, TAL)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_put_var_int(ncid, varid, lats)) ERR;
if (nc_put_var_float(ncid, var2id, rh)) ERR;
if (nc_close(ncid)) ERR;
/* Reopen and check. */
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
if (check_file(ncid, TAL2, RH, TAL)) ERR;
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
printf("*** testing more renaming after enddef for %s...", fmt_names[format]);
{
int ncid, varid, var2id;
int dimid;
/* This will create a HDF5 file with two datasets, RH, and
* LAT. LAT is a dimscale. RH points to dimscale LAT. Life is
* so simple. */
if (nc_set_default_format(formats[format], NULL)) ERR;
if (nc_create(file_names[format], 0, &ncid)) ERR;
if (nc_def_dim(ncid, LAT, DIM_LEN, &dimid)) ERR;
if (nc_def_var(ncid, LAT, NC_INT, VAR_RANK, &dimid, &varid)) ERR;
if (nc_def_var(ncid, RH, NC_FLOAT, VAR_RANK, &dimid, &var2id)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_redef(ncid)) ERR;
/* This will cause dataset LAT to be renamed TAL. It will no
* longer be a dimscale. Dataset LAT will be created as a
* dimscale without a variable. Datasets RH and TAL will
* re-point to (new) dimscale LAT. */
if (nc_rename_var(ncid, varid, TAL)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_redef(ncid)) ERR;
/* This will cause dimscale-only dataset LAT to be
* deleted. Existing dataset TAL will become the dimscale
* dataset. Dataset RH will re-point to dimscale TAL. */
if (nc_rename_dim(ncid, dimid, TAL)) ERR;
if (nc_enddef(ncid)) ERR;
/* Varids have changed, so get them again. */
if (nc_inq_varid(ncid, TAL, &varid)) ERR;
if (nc_inq_varid(ncid, RH, &var2id)) ERR;
/* Write some data. */
if (nc_put_var_int(ncid, varid, lats)) ERR;
if (nc_put_var_float(ncid, var2id, rh)) ERR;
if (nc_close(ncid)) ERR;
/* Reopen and check. */
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
if (check_file(ncid, TAL, RH, TAL)) ERR;
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
printf("*** testing renaming after enddef for %s...", fmt_names[format]);
{
int ncid, varid, var2id;
int dimid;
if (nc_set_default_format(formats[format], NULL)) ERR;
if (nc_create(file_names[format], 0, &ncid)) ERR;
if (nc_def_dim(ncid, LAT, DIM_LEN, &dimid)) ERR;
if (nc_def_var(ncid, LAT, NC_INT, VAR_RANK, &dimid, &varid)) ERR;
if (nc_def_var(ncid, RH, NC_FLOAT, VAR_RANK, &dimid, &var2id)) ERR;
if (nc_enddef(ncid)) ERR; /* not necessary for netCDF-4 files */
if (nc_redef(ncid)) ERR; /* not necessary for netCDF-4 files */
/* Now rename the dim. */
if (nc_rename_dim(ncid, dimid, TAL)) ERR;
if (nc_rename_var(ncid, varid, TAL)) ERR;
if (nc_enddef(ncid)) ERR; /* not necessary for netCDF-4 files */
if (nc_put_var_int(ncid, varid, lats)) ERR;
if (nc_put_var_float(ncid, var2id, rh)) ERR;
if (nc_close(ncid)) ERR;
/* Reopen and check. */
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
/* if (check_file(ncid, LAT, RH, TAL)) ERR; */
/* if (check_file(ncid, TAL, RH, TAL)) ERR; */
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
fprintf(stderr,"*** Test renaming coordinate variable and its dimension for %s...\n",
fmt_names[format]);
if (create_test_file(file_names[format], formats[format])) ERR;
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
if (nc_inq_dimid(ncid, ODIM_NAME, &dimid)) ERR;
if (nc_inq_varid(ncid, OVAR_NAME, &varid)) ERR;
if (nc_inq_varid(ncid, OVAR2_NAME, &var2id)) ERR;
if (nc_redef(ncid)) ERR; /* omitting this and nc_enddef call eliminates bug */
if (nc_rename_dim(ncid, dimid, NDIM_NAME)) ERR;
if (nc_rename_var(ncid, varid, NVAR_NAME)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_get_var_int(ncid, varid, lats_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (lats_in[ii] != lats[ii])
fprintf(stderr, "\tlats_in[%d] is %d, should be %d\n", ii, lats_in[ii], lats[ii]);
}
if (nc_get_var_float(ncid, var2id, rh_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (rh_in[ii] != rh[ii])
fprintf(stderr, "\trh_in[%d] is %g, should be %g\n", ii, rh_in[ii], rh[ii]);
}
if (nc_close(ncid)) ERR;
printf("*** testing renaming after enddef for %s...", fmt_names[format]);
{
/* Create a file with datasets LAT, RH. LAT is a dimscale. RH
* points to LAT. */
if (create_test_file(file_names[format], formats[format])) ERR;
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
if (nc_inq_dimid(ncid, LAT, &dimid)) ERR;
if (nc_inq_varid(ncid, LAT, &varid)) ERR;
if (nc_inq_varid(ncid, RH, &var2id)) ERR;
if (check_file(ncid, LAT, RH, LAT)) ERR;
if (nc_redef(ncid)) ERR;
fprintf(stderr,"*** Test renaming just coordinate variable for %s...\n",
fmt_names[format]);
if (create_test_file(file_names[format], formats[format])) ERR;
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
if (nc_inq_dimid(ncid, ODIM_NAME, &dimid)) ERR;
if (nc_inq_varid(ncid, OVAR_NAME, &varid)) ERR;
if (nc_inq_varid(ncid, OVAR2_NAME, &var2id)) ERR;
if (nc_redef(ncid)) ERR; /* omitting this and nc_enddef call eliminates bug */
/* if (nc_rename_dim(ncid, dimid, NDIM_NAME)) ERR; */
if (nc_rename_var(ncid, varid, NVAR_NAME)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_get_var_int(ncid, varid, lats_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (lats_in[ii] != lats[ii])
fprintf(stderr, "\tlats_in[%d] is %d, should be %d\n", ii, lats_in[ii], lats[ii]);
}
if (nc_get_var_float(ncid, var2id, rh_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (rh_in[ii] != rh[ii])
fprintf(stderr, "\trh_in[%d] is %g, should be %g\n", ii, rh_in[ii], rh[ii]);
}
if (nc_close(ncid)) ERR;
/* Rename the dim. This creates new dataset TAL. LAT is no
* longer a dimscale. RH is repointed to TAL. LAT is pointed
* to TAL. */
if (nc_rename_dim(ncid, dimid, TAL)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_redef(ncid)) ERR;
fprintf(stderr,"*** Test renaming just coordinate dimension for %s...\n",
fmt_names[format]);
if (create_test_file(file_names[format], formats[format])) ERR;
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
if (nc_inq_dimid(ncid, ODIM_NAME, &dimid)) ERR;
if (nc_inq_varid(ncid, OVAR_NAME, &varid)) ERR;
if (nc_inq_varid(ncid, OVAR2_NAME, &var2id)) ERR;
if (nc_redef(ncid)) ERR; /* omitting this and nc_enddef call eliminates bug */
if (nc_rename_dim(ncid, dimid, NDIM_NAME)) ERR;
/* if (nc_rename_var(ncid, varid, NVAR_NAME)) ERR; */
if (nc_enddef(ncid)) ERR;
if (nc_get_var_int(ncid, varid, lats_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (lats_in[ii] != lats[ii])
fprintf(stderr, "\tlats_in[%d] is %d, should be %d\n", ii, lats_in[ii], lats[ii]);
}
if (nc_get_var_float(ncid, var2id, rh_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (rh_in[ii] != rh[ii])
fprintf(stderr, "\trh_in[%d] is %g, should be %g\n", ii, rh_in[ii], rh[ii]);
}
if (nc_close(ncid)) ERR;
/* Rename the var. This will remove dimscale-only dataset
* TAL. LAT will become a dimscale. RH will point to LAT. */
if (nc_rename_var(ncid, varid, TAL)) ERR;
if (nc_enddef(ncid)) ERR;
/* if (check_file(ncid, LAT, RH, TAL)) ERR; */
if (nc_close(ncid)) ERR;
if (formats[format] == NC_FORMAT_NETCDF4) {
printf("*** Test renaming attribute in sub-group for %s...\n",
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
/* if (check_file(ncid, LAT, RH, TAL)) ERR; */
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
fprintf(stderr,"*** Test renaming just coordinate variable for %s...",
fmt_names[format]);
{
if (create_test_file(file_names[format], formats[format])) ERR;
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
if (nc_inq_dimid(ncid, ODIM_NAME, &dimid)) ERR;
if (nc_inq_varid(ncid, OVAR_NAME, &varid)) ERR;
if (nc_inq_varid(ncid, OVAR2_NAME, &var2id)) ERR;
if (nc_redef(ncid)) ERR; /* omitting this and nc_enddef call eliminates bug */
/* if (nc_rename_dim(ncid, dimid, NDIM_NAME)) ERR; */
if (nc_rename_var(ncid, varid, NVAR_NAME)) ERR;
if (nc_enddef(ncid)) ERR;
if (nc_get_var_int(ncid, varid, lats_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (lats_in[ii] != lats[ii])
fprintf(stderr, "\tlats_in[%d] is %d, should be %d\n", ii, lats_in[ii], lats[ii]);
}
if (nc_get_var_float(ncid, var2id, rh_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (rh_in[ii] != rh[ii])
fprintf(stderr, "\trh_in[%d] is %g, should be %g\n", ii, rh_in[ii], rh[ii]);
}
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
fprintf(stderr,"*** Test renaming just coordinate dimension for %s...",
fmt_names[format]);
{
if (create_test_file(file_names[format], formats[format])) ERR;
if (nc_open(file_names[format], NC_WRITE, &ncid)) ERR;
if (nc_inq_dimid(ncid, ODIM_NAME, &dimid)) ERR;
if (nc_inq_varid(ncid, OVAR_NAME, &varid)) ERR;
if (nc_inq_varid(ncid, OVAR2_NAME, &var2id)) ERR;
if (nc_redef(ncid)) ERR; /* omitting this and nc_enddef call eliminates bug */
if (nc_rename_dim(ncid, dimid, NDIM_NAME)) ERR;
/* if (nc_rename_var(ncid, varid, NVAR_NAME)) ERR; */
if (nc_enddef(ncid)) ERR;
if (nc_get_var_int(ncid, varid, lats_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (lats_in[ii] != lats[ii])
fprintf(stderr, "\tlats_in[%d] is %d, should be %d\n", ii, lats_in[ii], lats[ii]);
}
if (nc_get_var_float(ncid, var2id, rh_in)) ERR;
for (ii = 0; ii < DIM_LEN; ii++) {
if (rh_in[ii] != rh[ii])
fprintf(stderr, "\trh_in[%d] is %g, should be %g\n", ii, rh_in[ii], rh[ii]);
}
if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;
if (formats[format] == NC_FORMAT_NETCDF4)
{
printf("*** Test renaming attribute in sub-group for %s...",
fmt_names[format]);
{
{
#define DIMNAME "lon"
#define VARNAME "lon"
#define G1_VARNAME "lon"
@ -199,16 +430,16 @@ main(int argc, char **argv)
if (nc_enddef (ncid)) ERR;
/* write variable data */
{
float lon_data[4] = {0, 90, 180, 270};
size_t start[] = {0};
size_t count[] = {4};
if (nc_put_vara(ncid, lon_var, start, count, lon_data)) ERR;
float lon_data[4] = {0, 90, 180, 270};
size_t start[] = {0};
size_t count[] = {4};
if (nc_put_vara(ncid, lon_var, start, count, lon_data)) ERR;
}
{
float g1_lon_data[4] = {0, 90, 180, 270};
size_t start[] = {0};
size_t count[] = {4};
if (nc_put_vara(g1_grp, g1_lon_var, start, count, g1_lon_data)) ERR;
float g1_lon_data[4] = {0, 90, 180, 270};
size_t start[] = {0};
size_t count[] = {4};
if (nc_put_vara(g1_grp, g1_lon_var, start, count, g1_lon_data)) ERR;
}
if (nc_close(ncid)) ERR;
@ -223,17 +454,17 @@ main(int argc, char **argv)
has expected value */
{
if (nc_open(file_names[format], NC_NOWRITE, &ncid)) ERR;
if (nc_inq_grp_ncid(ncid, GRP_NAME, &g1_grp)) ERR;
if (nc_inq_varid(g1_grp, VARNAME, &g1_lon_var)) ERR;
if (nc_get_att_text(g1_grp, g1_lon_var, NEW_NAME, data_in)) ERR;
if (strncmp(CONTENTS, data_in, strlen(CONTENTS))) ERR;
if (nc_close(ncid)) ERR;
if (nc_open(file_names[format], NC_NOWRITE, &ncid)) ERR;
if (nc_inq_grp_ncid(ncid, GRP_NAME, &g1_grp)) ERR;
if (nc_inq_varid(g1_grp, VARNAME, &g1_lon_var)) ERR;
if (nc_get_att_text(g1_grp, g1_lon_var, NEW_NAME, data_in)) ERR;
if (strncmp(CONTENTS, data_in, strlen(CONTENTS))) ERR;
if (nc_close(ncid)) ERR;
}
free(data_in);
}
}
SUMMARIZE_ERR;
}
}
return(0);
} /* next format */
FINAL_RESULTS;
}