libdsdb3  3.0
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Groups
ds_dod.c
Go to the documentation of this file.
1 /*******************************************************************************
2 *
3 * COPYRIGHT (C) 2010 Battelle Memorial Institute. All Rights Reserved.
4 *
5 ********************************************************************************
6 *
7 * Author:
8 * name: Brian Ermold
9 * phone: (509) 375-2277
10 * email: brian.ermold@pnl.gov
11 *
12 ********************************************************************************
13 *
14 * REPOSITORY INFORMATION:
15 * $Revision: 17019 $
16 * $Author: ermold $
17 * $Date: 2013-03-05 19:19:42 +0000 (Tue, 05 Mar 2013) $
18 *
19 ********************************************************************************
20 *
21 * NOTE: DOXYGEN is used to generate documentation for this file.
22 *
23 *******************************************************************************/
24 
25 /** @file ds_dod.c
26  * Datastream DOD Functions.
27  */
28 
29 #include "dsdb3.h"
30 #include "dbog_dod.h"
31 
32 /**
33  * @defgroup DSDB_DSDODS Datastream DODs
34  */
35 /*@{*/
36 
37 /*******************************************************************************
38  * Private Functions
39  */
40 /** @privatesection */
41 
42 static int _dsdb_change_dsdod_att_value(
43  CDSGroup *cds,
44  char *var_name,
45  char *att_name,
46  char *att_type,
47  char *att_value,
48  int locker)
49 {
50  void *parent;
51  CDSAtt *att;
52  CDSDataType type;
53  size_t length;
54  size_t nelems;
55  void *value;
56  int free_value;
57 
58  /* Get the CDS attribute */
59 
60  parent = (var_name) ? (void *)cds_get_var(cds, var_name) : (void *)cds;
61 
62  if (!parent) {
63  return(1);
64  }
65 
66  att = cds_get_att(parent, att_name);
67  if (!att) {
68  return(1);
69  }
70 
71  /* Make sure the attribute types match */
72 
73  type = cds_data_type(att_type);
74 
75  if (type != att->type) {
76  return(1);
77  }
78 
79  /* Check if the attribute is locked */
80 
81  if (att->def_lock == locker) {
83  }
84  else if (att->def_lock) {
85  return(1);
86  }
87 
88  /* Create the attribute value */
89 
90  free_value = 0;
91 
92  if (!att_value) {
93  return(1);
94  }
95  else if (type == CDS_CHAR) {
96  value = (void *)att_value;
97  length = strlen(att_value) + 1;
98  }
99  else {
100 
101  value = cds_string_to_array(att_value, type, &nelems, NULL);
102 
103  if (value) {
104  length = (size_t)nelems;
105  free_value = 1;
106  }
107  else if (nelems == 0) {
108  return(1);
109  }
110  else {
111  /* memory allocation error */
112  return(0);
113  }
114  }
115 
116  /* change attribute value */
117 
118  if (!cds_change_att_value(att, type, length, value)) {
119  if (free_value) free(value);
120  return(0);
121  }
122 
123  cds_set_definition_lock(att, locker);
124 
125  if (free_value) free(value);
126 
127  return(1);
128 }
129 
130 /**
131  * Insert a time into an array of time values.
132  *
133  * The time value will be inserted into the array such that the
134  * array maintains a sorted order starting with the earliest time.
135  * The time value will not be added to the array if it matches a
136  * time already defined in the array.
137  *
138  * This function allocates memory for the times array so it must
139  * be freed when it is no longer needed.
140  *
141  * @param times - memory address of the times array pointer
142  * @param ntimes - pointer to the number of time values
143  * @param new_time - time value to add to the array
144  *
145  * @return
146  * - pointer to the times array
147  * - NULL if a memory allocation error occurred
148  */
149 static time_t *_dsdb_insert_time_array_value(
150  time_t **times,
151  int *ntimes,
152  time_t new_time)
153 {
154  time_t *new_times;
155  int insert_index;
156  int i;
157 
158  if (*ntimes <= 0) {
159  *times = NULL;
160  *ntimes = 0;
161  insert_index = 0;
162  }
163  else if (new_time > (*times)[*ntimes - 1]) {
164  insert_index = *ntimes;
165  }
166  else {
167  for (i = 0; new_time > (*times)[i]; i++);
168 
169  if (new_time == (*times)[i]) {
170  return(*times);
171  }
172  else {
173  insert_index = i;
174  }
175  }
176 
177  new_times = (time_t *)realloc(*times, (*ntimes+1) * sizeof(time_t));
178  if (!new_times) {
179  return((time_t *)NULL);
180  }
181 
182  *times = new_times;
183 
184  for (i = (*ntimes); i > insert_index; i--) {
185  (*times)[i] = (*times)[i-1];
186  }
187 
188  *ntimes += 1;
189  (*times)[i] = new_time;
190 
191  return(*times);
192 }
193 
194 /*******************************************************************************
195  * Public Functions
196  */
197 /** @publicsection */
198 
199 /**
200  * Free all memory used by a DSDOD structure.
201  *
202  * @param dsdod - pointer to the DSDOD structure
203  */
204 void dsdb_free_dsdod(DSDOD *dsdod)
205 {
206  int i;
207 
208  if (dsdod) {
209 
210  if (dsdod->cds_group) {
212  cds_delete_group(dsdod->cds_group);
213  }
214 
215  if (dsdod->site) free((void *)dsdod->site);
216  if (dsdod->facility) free((void *)dsdod->facility);
217  if (dsdod->name) free((void *)dsdod->name);
218  if (dsdod->level) free((void *)dsdod->level);
219  if (dsdod->version) free((void *)dsdod->version);
220  if (dsdod->att_times) free((void *)dsdod->att_times);
221 
222  if (dsdod->ndod_times) {
223  for (i = 0; i < dsdod->ndod_times; i++) {
224  free(dsdod->dod_versions[i]);
225  }
226  free(dsdod->dod_times);
227  free(dsdod->dod_versions);
228  }
229 
230  free(dsdod);
231  }
232 }
233 
234 /**
235  * Get the DSDOD for a datastream.
236  *
237  * This function will get the DSDOD for the specified datastream
238  * and data time. It will:
239  *
240  * - create a new DSDOD structure
241  * - get the list of DOD versions used by the specified datastream
242  * - get the list of times when the attribute values change
243  * - get the DOD for the specified data time
244  * - load the site/facility specific attribute values
245  * - load the time varying attribute values for the specified data time
246  *
247  * If the data time is not specified, the current time will be used.
248  * If the data time is less than the time of the earliest DOD version,
249  * the earliest DOD version will be used.
250  *
251  * The memory used by the output structure is dynamically allocated.
252  * It is the responsibility of the calling process to free this memory
253  * when it is no longer needed (see dsdb_free_dsdod()).
254  *
255  * Error messages from this function are sent to the message
256  * handler (see msngr_init_log() and msngr_init_mail()).
257  *
258  * Null results from the database are not reported as errors.
259  * It is the responsibility of the calling process to report
260  * these as errors if necessary.
261  *
262  * @param dsdb - pointer to the open database connection
263  * @param site - site name
264  * @param facility - facility name
265  * @param dsc_name - datastream class name
266  * @param dsc_level - datastream class level
267  *
268  * @param data_time - the time used to determine the DOD version and
269  * set the time varying attribute values. If not
270  * specified the current time will be used.
271  *
272  * @param dsdod - output: pointer to the DSDOD structure
273  *
274  * @return
275  * - 1 if successful
276  * - 0 if the database returned a NULL result
277  * - -1 if an error occurred
278  *
279  * @see dsdb_free_dsdod()
280  */
282  DSDB *dsdb,
283  const char *site,
284  const char *facility,
285  const char *dsc_name,
286  const char *dsc_level,
287  time_t data_time,
288  DSDOD **dsdod)
289 {
290  int status;
291  int nversions;
292 
293  if (!data_time) {
294  data_time = time(NULL);
295  }
296 
297  /* Create a new DSDOD structure */
298 
299  *dsdod = dsdb_new_dsdod(site, facility, dsc_name, dsc_level);
300  if (!*dsdod) {
301  return(-1);
302  }
303 
304  (*dsdod)->data_time = data_time;
305 
306  /* Get the list of DOD versions used by this datastream */
307 
308  nversions = dsdb_get_dsdod_versions(dsdb, *dsdod);
309  if (nversions <= 0) {
310  dsdb_free_dsdod(*dsdod);
311  *dsdod = (DSDOD *)NULL;
312  return(nversions);
313  }
314 
315  /* Get the DOD and datastream attributes */
316 
317  status = dsdb_update_dsdod(dsdb, *dsdod, data_time);
318  if (status <= 0) {
319  dsdb_free_dsdod(*dsdod);
320  *dsdod = (DSDOD *)NULL;
321  return(status);
322  }
323 
324  return(1);
325 }
326 
327 /**
328  * Update a DSDOD for the time of the data being processed.
329  *
330  * This function will use the time of the data being processed
331  * to update the DOD version and/or the time varying attribute
332  * values if they are different from what is currently loaded.
333  *
334  * Error messages from this function are sent to the message
335  * handler (see msngr_init_log() and msngr_init_mail()).
336  *
337  * @param dsdb - pointer to the open database connection
338  * @param dsdod - pointer to the DSDOD structure
339  * @param data_time - the time of the data being processed
340  *
341  * @return
342  * - 1 if the DSDOD was updated or no updates were needed
343  * - 0 if the database returned a NULL result
344  * - -1 if an error occurred
345  */
347  DSDB *dsdb,
348  DSDOD *dsdod,
349  time_t data_time)
350 {
351  const char *dod_version;
352  char *dsdod_version;
353  CDSGroup *cds_group;
354  int natt_times;
355  int status;
356 
357  /* Check if the DOD version needs to be updated */
358 
359  dod_version = dsdb_check_for_dsdod_version_update(dsdod, data_time);
360  if (dod_version) {
361 
362  /* Set DSDOD version */
363 
364  dsdod_version = msngr_copy_string(dod_version);
365 
366  if (!dsdod_version) {
367 
368  ERROR( DSDB_LIB_NAME,
369  "Could not update DSDOD for: %s%s%s.%s\n"
370  " -> memory allocation error\n",
371  dsdod->site, dsdod->name, dsdod->facility, dsdod->level);
372 
373  return(-1);
374  }
375 
376  /* Get the DOD */
377 
378  status = dsdb_get_dod(
379  dsdb, dsdod->name, dsdod->level, dsdod_version, &cds_group);
380 
381  if (status <= 0) {
382  free(dsdod_version);
383  return(status);
384  }
385 
386  /* Update the DSDOD */
387 
388  if (dsdod->version) free(dsdod->version);
389  if (dsdod->cds_group) {
391  cds_delete_group(dsdod->cds_group);
392  }
393 
394  dsdod->data_time = data_time;
395  dsdod->version = dsdod_version;
396  dsdod->cds_group = cds_group;
397 
398  /* Get the site/facility specific attribute values */
399 
400  if (dsdb_get_dsdod_att_values(dsdb, dsdod) < 0) {
401  return(-1);
402  }
403 
404  /* Get the list of times when there are attribute value changes */
405 
406  natt_times = dsdb_get_dsdod_att_times(dsdb, dsdod);
407  if (natt_times < 0) {
408  return(-1);
409  }
410 
411  /* Get the time varying attribute values */
412 
413  if (natt_times > 0) {
414  if (dsdb_get_dsdod_time_att_values(dsdb, dsdod) < 0) {
415  return(-1);
416  }
417  }
418 
419  return(1);
420  }
421 
422  /* Check if the time varying attribute values need to be updated */
423 
424  if (dsdb_check_for_dsdod_time_atts_update(dsdod, data_time)) {
425 
426  dsdod->data_time = data_time;
427 
428  if (dsdb_get_dsdod_time_att_values(dsdb, dsdod) < 0) {
429  return(-1);
430  }
431 
432  return(1);
433  }
434 
435  return(0);
436 }
437 
438 /**
439  * Check for a DSDOD version update.
440  *
441  * This function will check if the DOD version being used by a DSDOD
442  * needs to be updated. The new DOD version will be determined for
443  * the specified data time using the dod_times and dod_versions
444  * listed in the DSDOD (see dsdb_get_dsdod_versions()).
445  *
446  * @param dsdod - pointer to the DSDOD structure
447  * @param data_time - the time of the data being processed
448  *
449  * @return
450  * - the new DOD version if the DSDOD needs to be updated.
451  * - NULL if no update is needed.
452  */
454  DSDOD *dsdod,
455  time_t data_time)
456 {
457  const char *dod_version;
458  int i;
459 
460  if (dsdod->ndod_times == 0) {
461  return((const char *)NULL);
462  }
463 
464  for (i = 0; i < dsdod->ndod_times; i++) {
465  if (data_time < dsdod->dod_times[i]) {
466  break;
467  }
468  }
469 
470  if (i > 0) i--;
471 
472  dod_version = dsdod->dod_versions[i];
473 
474  if (!dsdod->version) {
475  return(dod_version);
476  }
477 
478  if (strcmp(dod_version, dsdod->version) != 0) {
479  return(dod_version);
480  }
481 
482  return((const char *)NULL);
483 }
484 
485 /**
486  * Check for DSDOD time varying attribute value updates.
487  *
488  * This function will check if the time varying attribute values
489  * for a DSDOD need to be updated. This is done by checking for
490  * an attribute change time in the DSDOD att_times array that falls
491  * between the data_time of the DSDOD and the specified data_time.
492  * (see dsdb_get_dsdod_att_times()).
493  *
494  * @param dsdod - pointer to the DSDOD structure
495  * @param data_time - the time of the data being processed
496  *
497  * @return
498  * - 1 if one or more attribute values need to be updated.
499  * - 0 if no update is needed.
500  */
502  DSDOD *dsdod,
503  time_t data_time)
504 {
505  time_t t1;
506  time_t t2;
507  time_t tn;
508  int n;
509 
510  if (dsdod->natt_times == 0) {
511  return(0);
512  }
513 
514  if (dsdod->data_time < data_time) {
515  t1 = dsdod->data_time;
516  t2 = data_time;
517  }
518  else {
519  t1 = data_time;
520  t2 = dsdod->data_time;
521  }
522 
523  for (n = 0; n < dsdod->natt_times; n++) {
524 
525  tn = dsdod->att_times[n];
526 
527  if (t1 < tn && tn <= t2) {
528  break;
529  }
530  }
531 
532  if (n < dsdod->natt_times) {
533  return(1);
534  }
535 
536  return(0);
537 }
538 
539 /**
540  * Create a new DSDOD structure.
541  *
542  * The memory used by the returned structure is dynamically allocated.
543  * It is the responsibility of the calling process to free this memory
544  * when it is no longer needed (see dsdb_free_dsdod()).
545  *
546  * Error messages from this function are sent to the message
547  * handler (see msngr_init_log() and msngr_init_mail()).
548  *
549  * @param site - site name
550  * @param facility - facility name
551  * @param dsc_name - datastream class name
552  * @param dsc_level - datastream class level
553  *
554  * @return
555  * - pointer to the new DSDOD structure
556  * - NULL if a memory allocation error occurred
557  *
558  * @see dsdb_free_dsdod()
559  */
561  const char *site,
562  const char *facility,
563  const char *dsc_name,
564  const char *dsc_level)
565 {
566  DSDOD *dsdod;
567 
568  /* Create the DSDOD structure */
569 
570  dsdod = (DSDOD *)calloc(1, sizeof(DSDOD));
571  if (!dsdod) {
572  goto RETURN_MEM_ERROR;
573  }
574 
575  /* Copy the input arguments into the DSDOD structure */
576 
577  dsdod->site = msngr_copy_string(site);
578  if (!dsdod->site) {
579  goto RETURN_MEM_ERROR;
580  }
581 
582  dsdod->facility = msngr_copy_string(facility);
583  if (!dsdod->facility) {
584  goto RETURN_MEM_ERROR;
585  }
586 
587  dsdod->name = msngr_copy_string(dsc_name);
588  if (!dsdod->name) {
589  goto RETURN_MEM_ERROR;
590  }
591 
592  dsdod->level = msngr_copy_string(dsc_level);
593  if (!dsdod->level) {
594  goto RETURN_MEM_ERROR;
595  }
596 
597  return(dsdod);
598 
599 RETURN_MEM_ERROR:
600 
601  ERROR( DSDB_LIB_NAME,
602  "Could not create new DSDOD structure for: %s%s%s.%s\n"
603  " -> memory allocation error\n",
604  site, dsc_name, facility, dsc_level);
605 
606  if (dsdod) {
607  dsdb_free_dsdod(dsdod);
608  }
609 
610  return((DSDOD *)NULL);
611 }
612 
613 /**
614  * Get the DOD for a datastream class and DOD version.
615  *
616  * This function will set the definition lock value to 1 for all
617  * dimensions and attributes that do not have NULL values. It will
618  * also set the definition lock value to 1 for all variables
619  * (see cds_set_definition_lock()).
620  *
621  * The memory used by the output structure is dynamically allocated.
622  * It is the responsibility of the calling process to free this memory
623  * when it is no longer needed (see cds_delete_group()).
624  *
625  * Error messages from this function are sent to the message
626  * handler (see msngr_init_log() and msngr_init_mail()).
627  *
628  * Null results from the database are not reported as errors.
629  * It is the responsibility of the calling process to report
630  * these as errors if necessary.
631  *
632  * @param dsdb - pointer to the open database connection
633  * @param dsc_name - datastream class name
634  * @param dsc_level - datastream class level
635  * @param dod_version - DOD version
636  * @param cds_group - output: pointer to the CDSGroup containing the DOD
637  *
638  * @return
639  * - 1 if successful
640  * - 0 if the database returned a NULL result
641  * - -1 if an error occurred
642  *
643  * @see cds_delete_group()
644  */
646  DSDB *dsdb,
647  const char *dsc_name,
648  const char *dsc_level,
649  const char *dod_version,
650  CDSGroup **cds_group)
651 {
652  DBStatus status;
653  char cds_name[128];
654  CDSDim *dim;
655  CDSAtt *att;
656  CDSVar *var;
657  DBResult *dims;
658  DBResult *atts;
659  DBResult *vars;
660  int dims_row;
661  int atts_row;
662  int vars_row;
663  int unlimited;
664  char *dim_name;
665  char *att_name;
666  char *var_name;
667  const char *var_dims[8];
668  int nvar_dims;
669  char *strval;
670  size_t nelems;
671  size_t length;
672  CDSDataType type;
673  void *value;
674  int free_value;
675  int set_lock;
676  int dod_not_found;
677 
678  /* Create the CDS Group */
679 
680  sprintf(cds_name, "%s.%s-%s", dsc_name, dsc_level, dod_version);
681 
682  *cds_group = cds_define_group((CDSGroup *)NULL, cds_name);
683  if (!*cds_group) {
684  return(-1);
685  }
686 
687  dod_not_found = 1;
688 
689  /* Get DOD Dimensions */
690 
691  status = dodog_get_dod_dims(dsdb->dbconn,
692  dsc_name, dsc_level, dod_version, &dims);
693 
694  if (status != DB_NO_ERROR) {
695  if (status != DB_NULL_RESULT) {
696  cds_delete_group(*cds_group);
697  *cds_group = (CDSGroup *)NULL;
698  return(-1);
699  }
700  }
701  else {
702 
703  dod_not_found = 0;
704 
705  for (dims_row = 0; dims_row < dims->nrows; dims_row++) {
706 
707  dim_name = DodDimName(dims,dims_row);
708  strval = DodDimLength(dims,dims_row);
709  unlimited = 0;
710  set_lock = 0;
711 
712  if (strval == NULL) {
713  length = 0;
714  }
715  else {
716  length = (size_t)atoi(strval);
717  if (length == 0) {
718  unlimited = 1;
719  }
720  set_lock = 1;
721  }
722 
723  dim = cds_define_dim(*cds_group, dim_name, length, unlimited);
724 
725  if (!dim) {
726  dims->free(dims);
727  cds_delete_group(*cds_group);
728  *cds_group = (CDSGroup *)NULL;
729  return(-1);
730  }
731 
732  if (set_lock) cds_set_definition_lock(dim, 1);
733  }
734 
735  dims->free(dims);
736  }
737 
738  /* Get Global DOD Attributes */
739 
740  status = dodog_get_dod_atts(dsdb->dbconn,
741  dsc_name, dsc_level, dod_version, &atts);
742 
743  if (status != DB_NO_ERROR) {
744  if (status != DB_NULL_RESULT) {
745  cds_delete_group(*cds_group);
746  *cds_group = (CDSGroup *)NULL;
747  return(-1);
748  }
749  }
750  else {
751 
752  dod_not_found = 0;
753 
754  for (atts_row = 0; atts_row < atts->nrows; atts_row++) {
755 
756  att_name = DodAttName(atts,atts_row);
757  strval = DodAttType(atts,atts_row);
758  type = cds_data_type(strval);
759  strval = DodAttValue(atts,atts_row);
760  free_value = 0;
761  set_lock = 0;
762 
763  if (strval == (char *)NULL) {
764  length = 0;
765  value = (void *)NULL;
766  }
767  else if (type == CDS_CHAR) {
768  value = (void *)strval;
769  length = strlen(strval) + 1;
770  set_lock = 1;
771  }
772  else {
773  value = cds_string_to_array(strval, type, &nelems, NULL);
774 
775  if (nelems == (size_t)-1) {
776 
777  ERROR( DSDB_LIB_NAME,
778  "Could not convert string to array: '%s'\n"
779  " -> memory allocation error\n", strval);
780 
781  atts->free(atts);
782  cds_delete_group(*cds_group);
783  *cds_group = (CDSGroup *)NULL;
784  return(-1);
785  }
786 
787  length = nelems;
788  free_value = 1;
789  set_lock = 1;
790  }
791 
792  att = cds_define_att(*cds_group, att_name, type, length, value);
793 
794  if (!att) {
795  if (free_value) free(value);
796  atts->free(atts);
797  cds_delete_group(*cds_group);
798  *cds_group = (CDSGroup *)NULL;
799  return(-1);
800  }
801 
802  if (set_lock) cds_set_definition_lock(att, 1);
803  if (free_value) free(value);
804  }
805 
806  atts->free(atts);
807  }
808 
809  /* Get DOD Variables */
810 
811  status = dodog_get_dod_vars(dsdb->dbconn,
812  dsc_name, dsc_level, dod_version, &vars);
813 
814  if (status != DB_NO_ERROR) {
815  if (status != DB_NULL_RESULT) {
816  cds_delete_group(*cds_group);
817  *cds_group = (CDSGroup *)NULL;
818  return(-1);
819  }
820  }
821  else {
822 
823  dod_not_found = 0;
824 
825  /* Get DOD Variable Dimensions */
826 
827  status = dodog_get_dod_var_dims(dsdb->dbconn,
828  dsc_name, dsc_level, dod_version, "%", &dims);
829 
830  if (status != DB_NO_ERROR) {
831  if (status != DB_NULL_RESULT) {
832  vars->free(vars);
833  cds_delete_group(*cds_group);
834  *cds_group = (CDSGroup *)NULL;
835  return(-1);
836  }
837  }
838 
839  dims_row = 0;
840 
841  /* Get DOD Variable Attributes */
842 
843  status = dodog_get_dod_var_atts(dsdb->dbconn,
844  dsc_name, dsc_level, dod_version, "%", &atts);
845 
846  if (status != DB_NO_ERROR) {
847  if (status != DB_NULL_RESULT) {
848  if (dims) dims->free(dims);
849  vars->free(vars);
850  cds_delete_group(*cds_group);
851  *cds_group = (CDSGroup *)NULL;
852  return(-1);
853  }
854  }
855 
856  atts_row = 0;
857 
858  /* Define Variables */
859 
860  for (vars_row = 0; vars_row < vars->nrows; vars_row++) {
861 
862  var_name = DodVarName(vars,vars_row);
863  strval = DodVarType(vars,vars_row);
864  type = cds_data_type(strval);
865 
866  /* create list of variable dimension names */
867 
868  nvar_dims = 0;
869 
870  for (; dims_row < dims->nrows; dims_row++) {
871 
872  strval = DodVarDimVarName(dims,dims_row);
873 
874  if ((strcmp(var_name, strval) != 0)) {
875  break;
876  }
877 
878  var_dims[nvar_dims++] = DodVarDimName(dims,dims_row);
879  }
880 
881  /* define variable */
882 
883  var = cds_define_var(
884  *cds_group, var_name, type, nvar_dims, var_dims);
885 
886  if (!var) {
887  if (dims) dims->free(dims);
888  if (atts) atts->free(atts);
889  vars->free(vars);
890  cds_delete_group(*cds_group);
891  *cds_group = (CDSGroup *)NULL;
892  return(-1);
893  }
894 
895  /* define variable attributes */
896 
897  for (; atts_row < atts->nrows; atts_row++) {
898 
899  strval = DodVarAttVarName(atts,atts_row);
900 
901  if ((strcmp(var_name, strval) != 0)) {
902  break;
903  }
904 
905  att_name = DodVarAttName(atts,atts_row);
906  strval = DodVarAttType(atts,atts_row);
907  type = cds_data_type(strval);
908  strval = DodVarAttValue(atts,atts_row);
909  free_value = 0;
910  set_lock = 0;
911 
912  if (strval == (char *)NULL) {
913  length = 0;
914  value = (void *)NULL;
915  }
916  else if (type == CDS_CHAR) {
917  value = (void *)strval;
918  length = strlen(strval) + 1;
919  set_lock = 1;
920  }
921  else {
922  value = cds_string_to_array(strval, type, &nelems, NULL);
923 
924  if (nelems == (size_t)-1) {
925 
926  ERROR( DSDB_LIB_NAME,
927  "Could not convert string to array: '%s'\n"
928  " -> memory allocation error\n", strval);
929 
930  if (dims) dims->free(dims);
931  if (atts) atts->free(atts);
932  vars->free(vars);
933  cds_delete_group(*cds_group);
934  *cds_group = (CDSGroup *)NULL;
935  return(-1);
936  }
937 
938  length = (size_t)nelems;
939  free_value = 1;
940  set_lock = 1;
941  }
942 
943  att = cds_define_att(var, att_name, type, length, value);
944 
945  if (!att) {
946  if (dims) dims->free(dims);
947  if (atts) atts->free(atts);
948  if (free_value) free(value);
949  vars->free(vars);
950  cds_delete_group(*cds_group);
951  *cds_group = (CDSGroup *)NULL;
952  return(-1);
953  }
954 
955  if ((strcmp(var_name, "time") == 0) ||
956  (strcmp(var_name, "base_time") == 0) ||
957  (strcmp(var_name, "time_offset") == 0)) {
958 
959  if ((strcmp(att_name, "long_name") == 0) ||
960  (strcmp(att_name, "units") == 0) ||
961  (strcmp(att_name, "string") == 0)) {
962 
963  set_lock = 0;
964  }
965  }
966 
967  if (set_lock) cds_set_definition_lock(att, 1);
968  if (free_value) free(value);
969  }
970 
971  cds_set_definition_lock(var, 1);
972  }
973 
974  if (dims) dims->free(dims);
975  if (atts) atts->free(atts);
976  vars->free(vars);
977  }
978 
979  /* Check if the DOD was found */
980 
981  if (dod_not_found) {
982  cds_delete_group(*cds_group);
983  *cds_group = (CDSGroup *)NULL;
984  return(0);
985  }
986 
987  cds_set_definition_lock(*cds_group, 1);
988 
989  return(1);
990 }
991 
992 /**
993  * Get the list of DOD versions used by a datastream.
994  *
995  * This function will populate the dod_times and dod_versions
996  * members of the specified DSDOD.
997  *
998  * Error messages from this function are sent to the message
999  * handler (see msngr_init_log() and msngr_init_mail()).
1000  *
1001  * Null results from the database are not reported as errors.
1002  * It is the responsibility of the calling process to report
1003  * these as errors if necessary.
1004  *
1005  * @param dsdb - pointer to the open database connection
1006  * @param dsdod - pointer to the DSDOD structure
1007  *
1008  * @return
1009  * - number of DOD versions
1010  * - 0 if the database returned a NULL result
1011  * - -1 if an error occurred
1012  */
1014  DSDB *dsdb,
1015  DSDOD *dsdod)
1016 {
1017  DBStatus status;
1018  int row;
1019  char *dod_version;
1020  time_t dod_time;
1021  char *time_string;
1022 
1023  DBResult *dbres = (DBResult *)NULL;
1024  int ndod_times = 0;
1025  char **dod_versions = (char **)NULL;
1026  time_t *dod_times = (time_t *)NULL;
1027 
1028  /* Get list of DOD times and versions */
1029 
1030  status = dodog_get_ds_dod_versions(dsdb->dbconn,
1031  dsdod->site, dsdod->facility, dsdod->name, dsdod->level, &dbres);
1032 
1033  if (status == DB_NO_ERROR) {
1034 
1035  dod_times = (time_t *)calloc((dbres->nrows + 1), sizeof(time_t));
1036  if (!dod_times) {
1037  goto RETURN_MEM_ERROR;
1038  }
1039 
1040  dod_versions = (char **)calloc((dbres->nrows + 1), sizeof(char *));
1041  if (!dod_versions) {
1042  goto RETURN_MEM_ERROR;
1043  }
1044 
1045  for (row = 0; row < dbres->nrows; row++) {
1046 
1047  dod_version = DsDodVersion(dbres,row);
1048  time_string = DsDodTime(dbres,row);
1049 
1050  dsdb_text_to_time(dsdb, time_string, &dod_time);
1051 
1052  dod_times[row] = dod_time;
1053  dod_versions[row] = msngr_copy_string(dod_version);
1054 
1055  if (!dod_versions[row]) {
1056  goto RETURN_MEM_ERROR;
1057  }
1058 
1059  ndod_times++;
1060  }
1061 
1062  dbres->free(dbres);
1063 
1064  /* Update the time and version lists in the DSDOD */
1065 
1066  if (dsdod->ndod_times) {
1067  for (row = 0; row < dsdod->ndod_times; row++) {
1068  free(dsdod->dod_versions[row]);
1069  }
1070  free(dsdod->dod_times);
1071  free(dsdod->dod_versions);
1072  }
1073 
1074  dsdod->ndod_times = ndod_times;
1075  dsdod->dod_times = dod_times;
1076  dsdod->dod_versions = dod_versions;
1077 
1078  return(ndod_times);
1079  }
1080  else if (status == DB_NULL_RESULT) {
1081  return(0);
1082  }
1083 
1084  return(-1);
1085 
1086 RETURN_MEM_ERROR:
1087 
1088  if (ndod_times) {
1089  for (row = 0; row < ndod_times; row++) {
1090  free(dod_versions[row]);
1091  }
1092  }
1093 
1094  if (dbres) dbres->free(dbres);
1095  if (dod_times) free(dod_times);
1096  if (dod_versions) free(dsdod->dod_versions);
1097 
1098  ERROR( DSDB_LIB_NAME,
1099  "Could not get DSDOD versions for: %s%s%s.%s\n"
1100  " -> memory allocation error\n",
1101  dsdod->site, dsdod->name, dsdod->facility, dsdod->level);
1102 
1103  return(-1);
1104 }
1105 
1106 /**
1107  * Get the list of times when the attribute values change for a DSDOD.
1108  *
1109  * The DOD and site/facility specific attributes must be loaded
1110  * before this function can be called (see dsdb_new_dsdod(),
1111  * dsdb_get_dod() and dsdb_get_dsdod_att_values()).
1112  *
1113  * This function will only load the times for attributes found
1114  * in the DOD that have not been locked or have a definition lock
1115  * value equal to 3 (see dsdb_get_dsdod_time_att_values()).
1116  *
1117  * Error messages from this function are sent to the message
1118  * handler (see msngr_init_log() and msngr_init_mail()).
1119  *
1120  * @param dsdb - pointer to the open database connection
1121  * @param dsdod - pointer to the DSDOD structure
1122  *
1123  * @return
1124  * - number of attribute value change times
1125  * - 0 if the database returned a NULL result
1126  * - -1 if an error occurred
1127  */
1129  DSDB *dsdb,
1130  DSDOD *dsdod)
1131 {
1132  DBStatus status;
1133  DBResult *dbres;
1134  CDSVar *var;
1135  CDSAtt *att;
1136  int row;
1137  char *var_name;
1138  char *att_name;
1139  char *time_string;
1140  time_t secs1970;
1141 
1142  int natt_times = 0;
1143  time_t *att_times = (time_t *)NULL;
1144 
1145  /* Get Global Attribute Times */
1146 
1147  status = dodog_get_ds_att_times(dsdb->dbconn,
1148  dsdod->site, dsdod->facility, dsdod->name, dsdod->level, "%", &dbres);
1149 
1150  if (status != DB_NO_ERROR) {
1151  if (status != DB_NULL_RESULT) {
1152  return(-1);
1153  }
1154  }
1155  else {
1156  for (row = 0; row < dbres->nrows; row++) {
1157 
1158  att_name = DsAttTimeName(dbres,row);
1159 
1160  att = cds_get_att(dsdod->cds_group, att_name);
1161  if (!att) {
1162  continue;
1163  }
1164 
1165  if (att->def_lock && att->def_lock != 3) {
1166  continue;
1167  }
1168 
1169  time_string = DsAttTimeTime(dbres,row);
1170 
1171  dsdb_text_to_time(dsdb, time_string, &secs1970);
1172 
1173  if (!_dsdb_insert_time_array_value(
1174  &att_times, &natt_times, secs1970)) {
1175 
1176  ERROR( DSDB_LIB_NAME,
1177  "Could not get DSDOD attribute change times for: %s%s%s.%s\n"
1178  " -> memory allocation error\n",
1179  dsdod->site, dsdod->name, dsdod->facility, dsdod->level);
1180 
1181  if (att_times) free(att_times);
1182 
1183  dbres->free(dbres);
1184  return(-1);
1185  }
1186  }
1187 
1188  dbres->free(dbres);
1189  }
1190 
1191  /* Get Variable Attribute Times */
1192 
1193  status = dodog_get_ds_var_att_times(dsdb->dbconn,
1194  dsdod->site, dsdod->facility, dsdod->name, dsdod->level,
1195  "%", "%", &dbres);
1196 
1197  if (status != DB_NO_ERROR) {
1198  if (status != DB_NULL_RESULT) {
1199  return(-1);
1200  }
1201  }
1202  else {
1203  for (row = 0; row < dbres->nrows; row++) {
1204 
1205  var_name = DsVarAttTimeVar(dbres,row);
1206  att_name = DsVarAttTimeName(dbres,row);
1207 
1208  var = cds_get_var(dsdod->cds_group, var_name);
1209  if (!var) {
1210  continue;
1211  }
1212 
1213  att = cds_get_att(var, att_name);
1214  if (!att) {
1215  continue;
1216  }
1217 
1218  if (att->def_lock && att->def_lock != 3) {
1219  continue;
1220  }
1221 
1222  time_string = DsVarAttTimeTime(dbres,row);
1223 
1224  dsdb_text_to_time(dsdb, time_string, &secs1970);
1225 
1226  if (!_dsdb_insert_time_array_value(
1227  &att_times, &natt_times, secs1970)) {
1228 
1229  ERROR( DSDB_LIB_NAME,
1230  "Could not get DSDOD attribute change times for: %s%s%s.%s\n"
1231  " -> memory allocation error\n",
1232  dsdod->site, dsdod->name, dsdod->facility, dsdod->level);
1233 
1234  if (att_times) free(att_times);
1235 
1236  dbres->free(dbres);
1237  return(-1);
1238  }
1239  }
1240 
1241  dbres->free(dbres);
1242  }
1243 
1244  /* Update the attribute times list in the DSDOD */
1245 
1246  if (dsdod->att_times) {
1247  free(dsdod->att_times);
1248  }
1249 
1250  dsdod->natt_times = natt_times;
1251  dsdod->att_times = att_times;
1252 
1253  return(dsdod->natt_times);
1254 }
1255 
1256 /**
1257  * Get the site/facility specific attributes for a DSDOD.
1258  *
1259  * The DOD must be loaded before this function can be called
1260  * (see dsdb_new_dsdod() and dsdb_get_dod()).
1261  *
1262  * This function will only update attributes found in the DOD that
1263  * have not been locked or have definition lock values of 2. All
1264  * attributes updated by this function will have their definition
1265  * lock value set to 2 (see cds_set_definition_lock()).
1266  *
1267  * Error messages from this function are sent to the message
1268  * handler (see msngr_init_log() and msngr_init_mail()).
1269  *
1270  * Null results from the database are not reported as errors.
1271  * It is the responsibility of the calling process to report
1272  * these as errors if necessary.
1273  *
1274  * @param dsdb - pointer to the open database connection
1275  * @param dsdod - pointer to the DSDOD structure
1276  *
1277  * @return
1278  * - number of attribute values updated
1279  * - 0 if the database returned a NULL result
1280  * - -1 if an error occurred
1281  */
1283  DSDB *dsdb,
1284  DSDOD *dsdod)
1285 {
1286  DBStatus status;
1287  DBResult *dbres;
1288  int row;
1289  char *var_name;
1290  char *att_name;
1291  char *att_type;
1292  char *att_value;
1293 
1294  int att_count = 0;
1295 
1296  /* Get Global Attributes */
1297 
1298  status = dodog_get_ds_atts(dsdb->dbconn,
1299  dsdod->site, dsdod->facility, dsdod->name, dsdod->level, &dbres);
1300 
1301  if (status != DB_NO_ERROR) {
1302  if (status != DB_NULL_RESULT) {
1303  return(-1);
1304  }
1305  }
1306  else {
1307 
1308  for (row = 0; row < dbres->nrows; row++) {
1309 
1310  att_name = DsAttName(dbres,row);
1311  att_type = DsAttType(dbres,row);
1312  att_value = DsAttValue(dbres,row);
1313 
1314  if (!_dsdb_change_dsdod_att_value(dsdod->cds_group,
1315  NULL, att_name, att_type, att_value, 2)) {
1316 
1317  ERROR( DSDB_LIB_NAME,
1318  "Could not get DSDOD attribute values for: %s%s%s.%s\n"
1319  " -> memory allocation error\n",
1320  dsdod->site, dsdod->name, dsdod->facility, dsdod->level);
1321 
1322  dbres->free(dbres);
1323  return(-1);
1324  }
1325 
1326  att_count++;
1327  }
1328 
1329  dbres->free(dbres);
1330  }
1331 
1332  /* Get Variable Attributes */
1333 
1334  status = dodog_get_ds_var_atts(dsdb->dbconn,
1335  dsdod->site, dsdod->facility, dsdod->name, dsdod->level, "%", &dbres);
1336 
1337  if (status != DB_NO_ERROR) {
1338  if (status != DB_NULL_RESULT) {
1339  return(-1);
1340  }
1341  }
1342  else {
1343 
1344  for (row = 0; row < dbres->nrows; row++) {
1345 
1346  var_name = DsVarAttVar(dbres,row);
1347  att_name = DsVarAttName(dbres,row);
1348  att_type = DsVarAttType(dbres,row);
1349  att_value = DsVarAttValue(dbres,row);
1350 
1351  if (!_dsdb_change_dsdod_att_value(dsdod->cds_group,
1352  var_name, att_name, att_type, att_value, 2)) {
1353 
1354  ERROR( DSDB_LIB_NAME,
1355  "Could not get DSDOD attribute values for: %s%s%s.%s\n"
1356  " -> memory allocation error\n",
1357  dsdod->site, dsdod->name, dsdod->facility, dsdod->level);
1358 
1359  dbres->free(dbres);
1360  return(-1);
1361  }
1362 
1363  att_count++;
1364  }
1365 
1366  dbres->free(dbres);
1367  }
1368 
1369  return(att_count);
1370 }
1371 
1372 /**
1373  * Get the time varying attribute values for a DSDOD.
1374  *
1375  * This function will load the time varying attribute values for
1376  * a DSDOD using the data time specified in the DSDOD structure.
1377  *
1378  * The DOD and site/facility specific attributes must be loaded
1379  * before this function can be called (see dsdb_new_dsdod(),
1380  * dsdb_get_dod() and dsdb_get_dsdod_att_values()).
1381  *
1382  * This function will only update attributes found in the DOD that
1383  * have not been locked or have definition lock values of 3. All
1384  * attributes updated by this function will have their definition
1385  * lock value set to 3 (see cds_set_definition_lock()).
1386  *
1387  * Error messages from this function are sent to the message
1388  * handler (see msngr_init_log() and msngr_init_mail()).
1389  *
1390  * @param dsdb - pointer to the open database connection
1391  * @param dsdod - pointer to the DSDOD structure
1392  *
1393  * @return
1394  * - number of attribute values updated
1395  * - 0 if the database returned a NULL result
1396  * - -1 if an error occurred
1397  */
1399  DSDB *dsdb,
1400  DSDOD *dsdod)
1401 {
1402  DBStatus status;
1403  DBResult *dbres;
1404  int row;
1405  char *var_name;
1406  char *att_name;
1407  char *att_type;
1408  char *att_value;
1409 
1410  int att_count = 0;
1411 
1412  /* Get Datastream Global Time Attributes */
1413 
1414  status = dodog_get_ds_time_atts(dsdb->dbconn,
1415  dsdod->site, dsdod->facility, dsdod->name, dsdod->level,
1416  dsdod->data_time, &dbres);
1417 
1418  if (status != DB_NO_ERROR) {
1419  if (status != DB_NULL_RESULT) {
1420  return(-1);
1421  }
1422  }
1423  else {
1424 
1425  for (row = 0; row < dbres->nrows; row++) {
1426 
1427  att_name = DsTimeAttName(dbres,row);
1428  att_type = DsTimeAttType(dbres,row);
1429  att_value = DsTimeAttValue(dbres,row);
1430 
1431  if (!_dsdb_change_dsdod_att_value(dsdod->cds_group,
1432  NULL, att_name, att_type, att_value, 3)) {
1433 
1434  ERROR( DSDB_LIB_NAME,
1435  "Could not get DSDOD attribute values for: %s%s%s.%s\n"
1436  " -> memory allocation error\n",
1437  dsdod->site, dsdod->name, dsdod->facility, dsdod->level);
1438 
1439  dbres->free(dbres);
1440  return(-1);
1441  }
1442 
1443  att_count++;
1444  }
1445 
1446  dbres->free(dbres);
1447  }
1448 
1449  /* Get Datastream Variable Attributes */
1450 
1451  status = dodog_get_ds_var_time_atts(dsdb->dbconn,
1452  dsdod->site, dsdod->facility, dsdod->name, dsdod->level, "%",
1453  dsdod->data_time, &dbres);
1454 
1455  if (status != DB_NO_ERROR) {
1456  if (status != DB_NULL_RESULT) {
1457  return(-1);
1458  }
1459  }
1460  else {
1461 
1462  for (row = 0; row < dbres->nrows; row++) {
1463 
1464  var_name = DsVarTimeAttVar(dbres,row);
1465  att_name = DsVarTimeAttName(dbres,row);
1466  att_type = DsVarTimeAttType(dbres,row);
1467  att_value = DsVarTimeAttValue(dbres,row);
1468 
1469  if (!_dsdb_change_dsdod_att_value(dsdod->cds_group,
1470  var_name, att_name, att_type, att_value, 3)) {
1471 
1472  ERROR( DSDB_LIB_NAME,
1473  "Could not get DSDOD attribute values for: %s%s%s.%s\n"
1474  " -> memory allocation error\n",
1475  dsdod->site, dsdod->name, dsdod->facility, dsdod->level);
1476 
1477  dbres->free(dbres);
1478  return(-1);
1479  }
1480 
1481  att_count++;
1482  }
1483 
1484  dbres->free(dbres);
1485  }
1486 
1487  return(att_count);
1488 }
1489 
1490 /**
1491  * Get the highest DOD version for a datastream class.
1492  *
1493  * The memory used by the output string is dynamically allocated.
1494  * It is the responsibility of the calling process to free this memory
1495  * when it is no longer needed.
1496  *
1497  * Error messages from this function are sent to the message
1498  * handler (see msngr_init_log() and msngr_init_mail()).
1499  *
1500  * Null results from the database are not reported as errors.
1501  * It is the responsibility of the calling process to report
1502  * these as errors if necessary.
1503  *
1504  * @param dsdb - pointer to the open database connection
1505  * @param dsc_name - datastream class name
1506  * @param dsc_level - datastream class level
1507  * @param dod_version - output: the highest dod version
1508  *
1509  * @return
1510  * - 1 if successful
1511  * - 0 if the database returned a NULL result
1512  * - -1 if an error occurred
1513  */
1515  DSDB *dsdb,
1516  const char *dsc_name,
1517  const char *dsc_level,
1518  char **dod_version)
1519 {
1520  DBStatus status;
1521 
1522  status = dodog_get_highest_dod_version(
1523  dsdb->dbconn, dsc_name, dsc_level, dod_version);
1524 
1525  if (status == DB_NO_ERROR) {
1526  return(1);
1527  }
1528  else if (status == DB_NULL_RESULT) {
1529  return(0);
1530  }
1531 
1532  return(-1);
1533 }
1534 
1535 /*@}*/