1 /*********************************************************************
2 * Copyright 2018, UCAR/Unidata
3 * See netcdf/COPYRIGHT file for copying and redistribuution conditions.
4 *********************************************************************/
5
6
7 #include "dapincludes.h"
8 #include "dapodom.h"
9 #include "dapdump.h"
10 #include "ncd2dispatch.h"
11 #include "ocx.h"
12
13 #define NEWVARM
14
15 /* Define a tracker for memory to support*/
16 /* the concatenation*/
17 struct NCMEMORY {
18 void* memory;
19 char* next; /* where to store the next chunk of data*/
20 };
21
22 /* Forward:*/
23 static NCerror moveto(NCDAPCOMMON*, Getvara*, CDFnode* dataroot, void* memory);
24 static NCerror movetor(NCDAPCOMMON*, OCdatanode currentcontent,
25 NClist* path, int depth,
26 Getvara*, size_t dimindex,
27 struct NCMEMORY*, NClist* segments);
28 static NCerror movetofield(NCDAPCOMMON*, OCdatanode,
29 NClist*, int depth,
30 Getvara*, size_t dimindex,
31 struct NCMEMORY*, NClist* segments);
32
33 static int findfield(CDFnode* node, CDFnode* subnode);
34 static NCerror removepseudodims(DCEprojection* proj);
35
36 static int extract(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, size_t dimindex, OClink, OCdatanode, struct NCMEMORY*);
37 static int extractstring(NCDAPCOMMON*, Getvara*, CDFnode*, DCEsegment*, size_t dimindex, OClink, OCdatanode, struct NCMEMORY*);
38 static void freegetvara(Getvara* vara);
39 static NCerror makegetvar(NCDAPCOMMON*, CDFnode*, void*, nc_type, Getvara**);
40 static NCerror attachsubset(CDFnode* target, CDFnode* pattern);
41
42 /**************************************************/
43 /**
44 1. We build the projection to be sent to the server aka
45 the fetch constraint. We want the server do do as much work
46 as possible, so we send it a url with a fetch constraint
47 that is the merge of the url constraint with the vara
48 constraint.
49
50 The url constraint, if any, is the one that was provided
51 in the url specified in nc_open().
52
53 The vara constraint is the one formed from the arguments
54 (start, count, stride) provided to the call to nc_get_vara().
55
56 There are some exceptions to the formation of the fetch constraint.
57 In all cases, the fetch constraint will use any URL selections,
58 but will use different fetch projections.
59 a. URL is unconstrainable (e.g. file://...):
60 fetchprojection = null => fetch whole dataset
61 b. The target variable (as specified in nc_get_vara())
62 is already in the cache and is whole variable, but note
63 that it might be part of the prefetch mixed in with other prefetched
64 variables.
65 fetchprojection = N.A. since variable is in the cache
66 c. Vara is requesting part of a variable but NCF_WHOLEVAR flag is set.
67 fetchprojection = unsliced vara variable => fetch whole variable
68 d. Vara is requesting part of a variable and NCF_WHOLEVAR flag is not set.
69 fetchprojection = sliced vara variable => fetch part variable
70
71 2. At this point, all or part of the target variable is available in the cache.
72
73 3. We build a projection to walk (guide) the use of the oc
74 data procedures to extract the required data from the cache.
75 For cases a,b,c:
76 walkprojection = merge(urlprojection,varaprojection)
77 For case d:
78 walkprojection = varaprojection without slicing.
79 This means we need only extract the complete contents of the cache.
80 Notice that this will not necessarily be a direct memory to
81 memory copy because the dap encoding still needs to be
82 interpreted. For this case, we derive a walk projection
83 from the vara projection that will properly access the cached data.
84 This walk projection shifts the merged projection so all slices
85 start at 0 and have a stride of 1.
86 */
87
88 NCerror
nc3d_getvarx(int ncid,int varid,const size_t * startp,const size_t * countp,const ptrdiff_t * stridep,void * data,nc_type dsttype0)89 nc3d_getvarx(int ncid, int varid,
90 const size_t *startp,
91 const size_t *countp,
92 const ptrdiff_t* stridep,
93 void *data,
94 nc_type dsttype0)
95 {
96 NCerror ncstat = NC_NOERR;
97 OCerror ocstat = OC_NOERR;
98 int i;
99 NC* drno;
100 NC* substrate;
101 NCDAPCOMMON* dapcomm;
102 CDFnode* cdfvar = NULL; /* cdf node mapping to var*/
103 NClist* varnodes;
104 nc_type dsttype;
105 Getvara* varainfo = NULL;
106 CDFnode* xtarget = NULL; /* target in DATADDS */
107 CDFnode* target = NULL; /* target in constrained DDS */
108 DCEprojection* varaprojection = NULL;
109 NCcachenode* cachenode = NULL;
110 size_t localcount[NC_MAX_VAR_DIMS];
111 NClist* ncdimsall;
112 size_t ncrank;
113 NClist* vars = NULL;
114 DCEconstraint* fetchconstraint = NULL;
115 DCEprojection* fetchprojection = NULL;
116 DCEprojection* walkprojection = NULL;
117 int state;
118 #define FETCHWHOLE 1 /* fetch whole data set */
119 #define FETCHVAR 2 /* fetch whole variable */
120 #define FETCHPART 4 /* fetch constrained variable */
121 #define CACHED 8 /* whole variable is already in the cache */
122
123 ncstat = NC_check_id(ncid, (NC**)&drno);
124 if(ncstat != NC_NOERR) goto fail;
125 dapcomm = (NCDAPCOMMON*)drno->dispatchdata;
126
127 ncstat = NC_check_id(getnc3id(drno), (NC**)&substrate);
128 if(ncstat != NC_NOERR) goto fail;
129
130 /* Locate var node via varid */
131 varnodes = dapcomm->cdf.ddsroot->tree->varnodes;
132 for(i=0;i<nclistlength(varnodes);i++) {
133 CDFnode* node = (CDFnode*)nclistget(varnodes,i);
134 if(node->array.basevar == NULL
135 && node->nctype == NC_Atomic
136 && node->ncid == varid) {
137 cdfvar = node;
138 break;
139 }
140 }
141
142 ASSERT((cdfvar != NULL));
143
144 /* If the variable is prefetchable, then now
145 is the time to do a lazy prefetch */
146 if(FLAGSET(dapcomm->controls,NCF_PREFETCH)
147 && !FLAGSET(dapcomm->controls,NCF_PREFETCH_EAGER)) {
148 if(dapcomm->cdf.cache != NULL && dapcomm->cdf.cache->prefetch == NULL) {
149 ncstat = prefetchdata(dapcomm);
150 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
151 }
152 }
153
154 /* Get the dimension info */
155 ncdimsall = cdfvar->array.dimsetall;
156 ncrank = nclistlength(ncdimsall);
157
158 #ifdef DEBUG
159 {
160 int i;
161 fprintf(stderr,"getvarx: %s",cdfvar->ncfullname);
162 for(i=0;i<ncrank;i++)
163 fprintf(stderr,"(%ld:%ld:%ld)",
164 (long)startp[i],
165 (long)countp[i],
166 (long)stridep[i]
167 );
168 fprintf(stderr,"\n");
169 }
170 #endif
171
172 /* Fill in missing arguments */
173 if(startp == NULL)
174 startp = NC_coord_zero;
175
176 if(countp == NULL) {
177 /* Accumulate the dimension sizes */
178 for(i=0;i<ncrank;i++) {
179 CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i);
180 localcount[i] = dim->dim.declsize;
181 }
182 countp = localcount;
183 }
184
185 if(stridep == NULL)
186 stridep = NC_stride_one;
187
188 /* Validate the dimension sizes */
189 for(i=0;i<ncrank;i++) {
190 CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i);
191 /* countp and startp are unsigned, so will never be < 0 */
192 if(stridep[i] < 1) {
193 ncstat = NC_EINVALCOORDS;
194 goto fail;
195 }
196 if(startp[i] >= dim->dim.declsize
197 || startp[i]+(stridep[i]*(countp[i]-1)) >= dim->dim.declsize) {
198 ncstat = NC_EINVALCOORDS;
199 goto fail;
200 }
201 }
202
203 #ifdef DEBUG
204 {
205 NClist* dims = cdfvar->array.dimsetall;
206 fprintf(stderr,"getvarx: %s",cdfvar->ncfullname);
207 if(nclistlength(dims) > 0) {int i;
208 for(i=0;i<nclistlength(dims);i++)
209 fprintf(stderr,"(%lu:%lu:%lu)",(unsigned long)startp[i],(unsigned long)countp[i],(unsigned long)stridep[i]);
210 fprintf(stderr," -> ");
211 for(i=0;i<nclistlength(dims);i++)
212 if(stridep[i]==1)
213 fprintf(stderr,"[%lu:%lu]",(unsigned long)startp[i],(unsigned long)((startp[i]+countp[i])-1));
214 else {
215 unsigned long iend = (stridep[i] * countp[i]);
216 iend = (iend + startp[i]);
217 iend = (iend - 1);
218 fprintf(stderr,"[%lu:%lu:%lu]",
219 (unsigned long)startp[i],(unsigned long)stridep[i],iend);
220 }
221 }
222 fprintf(stderr,"\n");
223 }
224 #endif
225
226 dsttype = (dsttype0);
227
228 /* Default to using the inquiry type for this var*/
229 if(dsttype == NC_NAT) dsttype = cdfvar->externaltype;
230
231 /* Validate any implied type conversion*/
232 if(cdfvar->etype != dsttype && dsttype == NC_CHAR) {
233 /* The only disallowed conversion is to/from char and non-byte
234 numeric types*/
235 switch (cdfvar->etype) {
236 case NC_STRING: case NC_URL:
237 case NC_CHAR: case NC_BYTE: case NC_UBYTE:
238 break;
239 default:
240 return THROW(NC_ECHAR);
241 }
242 }
243
244 ncstat = makegetvar(dapcomm,cdfvar,data,dsttype,&varainfo);
245 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
246
247 /* Compile the start/stop/stride info into a projection */
248 ncstat = dapbuildvaraprojection(varainfo->target,
249 startp,countp,stridep,
250 &varaprojection);
251 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
252
253 fetchprojection = NULL;
254 walkprojection = NULL;
255
256 /* Create walkprojection as the merge of the url projections
257 and the vara projection; may change in FETCHPART case below*/
258 ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections,
259 varaprojection,&walkprojection);
260 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
261
262 #ifdef DEBUG
263 fprintf(stderr,"getvarx: walkprojection: |%s|\n",dumpprojection(walkprojection));
264 #endif
265
266 /* define the var list of interest */
267 vars = nclistnew();
268 nclistpush(vars,(void*)varainfo->target);
269
270 state = 0;
271 if(iscached(dapcomm,cdfvar,&cachenode)) { /* ignores non-whole variable cache entries */
272 state = CACHED;
273 ASSERT((cachenode != NULL));
274 #ifdef DEBUG
275 fprintf(stderr,"var is in cache\n");
276 #endif
277 /* If it is cached, then it is a whole variable but may still
278 need to apply constraints during the walk */
279 ASSERT(cachenode->wholevariable); /* by construction */
280 } else if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
281 state = FETCHWHOLE;
282 } else {/* load using constraints */
283 if(FLAGSET(dapcomm->controls,NCF_WHOLEVAR))
284 state = FETCHVAR;
285 else
286 state = FETCHPART;
287 }
288 ASSERT(state != 0);
289
290 switch (state) {
291
292 case FETCHWHOLE: {
293 /* buildcachenode3 will create a new cachenode and
294 will also fetch the whole corresponding datadds.
295 */
296 /* Build the complete constraint to use in the fetch */
297 fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
298 /* Use no projections or selections */
299 fetchconstraint->projections = nclistnew();
300 fetchconstraint->selections = nclistnew();
301 #ifdef DEBUG
302 fprintf(stderr,"getvarx: FETCHWHOLE: fetchconstraint: %s\n",dumpconstraint(fetchconstraint));
303 #endif
304 ncstat = buildcachenode(dapcomm,fetchconstraint,vars,&cachenode,0);
305 fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/
306 if(ncstat != NC_NOERR) {THROWCHK(ncstat); nullfree(varainfo);
307 varainfo=NULL;
308 goto fail;}
309 } break;
310
311 case CACHED: {
312 } break;
313
314 case FETCHVAR: { /* Fetch a complete single variable */
315 /* Create fetch projection as the merge of the url projections
316 and the vara projection */
317 ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections,
318 varaprojection,&fetchprojection);
319 /* elide any sequence and string dimensions (dap servers do not allow such). */
320 ncstat = removepseudodims(fetchprojection);
321 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
322
323 /* Convert to a whole variable projection */
324 dcemakewholeprojection(fetchprojection);
325
326 #ifdef DEBUG
327 fprintf(stderr,"getvarx: FETCHVAR: fetchprojection: |%s|\n",dumpprojection(fetchprojection));
328 #endif
329
330 /* Build the complete constraint to use in the fetch */
331 fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
332 /* merged constraint just uses the url constraint selection */
333 fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections);
334 /* and the created fetch projection */
335 fetchconstraint->projections = nclistnew();
336 nclistpush(fetchconstraint->projections,(void*)fetchprojection);
337 #ifdef DEBUG
338 fprintf(stderr,"getvarx: FETCHVAR: fetchconstraint: %s\n",dumpconstraint(fetchconstraint));
339 #endif
340 /* buildcachenode3 will create a new cachenode and
341 will also fetch the corresponding datadds.
342 */
343 ncstat = buildcachenode(dapcomm,fetchconstraint,vars,&cachenode,0);
344 fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/
345 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
346 } break;
347
348 case FETCHPART: {
349 /* Create fetch projection as the merge of the url projections
350 and the vara projection */
351 ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections,
352 varaprojection,&fetchprojection);
353 /* elide any sequence and string dimensions (dap servers do not allow such). */
354 ncstat = removepseudodims(fetchprojection);
355 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
356
357 /* Shift the varaprojection for simple walk */
358 dcefree((DCEnode*)walkprojection) ; /* reclaim any existing walkprojection */
359 walkprojection = (DCEprojection*)dceclone((DCEnode*)varaprojection);
360 dapshiftprojection(walkprojection);
361
362 #ifdef DEBUG
363 fprintf(stderr,"getvarx: FETCHPART: fetchprojection: |%s|\n",dumpprojection(fetchprojection));
364 #endif
365
366 /* Build the complete constraint to use in the fetch */
367 fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
368 /* merged constraint just uses the url constraint selection */
369 fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections);
370 /* and the created fetch projection */
371 fetchconstraint->projections = nclistnew();
372 nclistpush(fetchconstraint->projections,(void*)fetchprojection);
373 #ifdef DEBUG
374 fprintf(stderr,"getvarx: FETCHPART: fetchconstraint: %s\n",dumpconstraint(fetchconstraint));
375 #endif
376 /* buildcachenode3 will create a new cachenode and
377 will also fetch the corresponding datadds.
378 */
379 ncstat = buildcachenode(dapcomm,fetchconstraint,vars,&cachenode,0);
380
381 fetchconstraint = NULL; /*buildcachenode34 takes control of fetchconstraint.*/
382 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
383 } break;
384
385 default: PANIC1("unknown fetch state: %d\n",state);
386 }
387
388 ASSERT(cachenode != NULL);
389
390 #ifdef DEBUG
391 fprintf(stderr,"cache.datadds=%s\n",dumptree(cachenode->datadds));
392 #endif
393
394 /* attach DATADDS to (constrained) DDS */
395 unattach(dapcomm->cdf.ddsroot);
396 ncstat = attachsubset(cachenode->datadds,dapcomm->cdf.ddsroot);
397 if(ncstat) goto fail;
398
399 /* Fix up varainfo to use the cache */
400 varainfo->cache = cachenode;
401 cachenode = NULL;
402 varainfo->varaprojection = walkprojection;
403 walkprojection = NULL;
404
405 /* Get the var correlate from the datadds */
406 target = varainfo->target;
407 xtarget = target->attachment;
408 if(xtarget == NULL)
409 {THROWCHK(ncstat=NC_ENODATA); goto fail;}
410
411 /* Switch to datadds tree space*/
412 varainfo->target = xtarget;
413 ncstat = moveto(dapcomm,varainfo,varainfo->cache->datadds,data);
414 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
415
416 fail:
417 if(vars != NULL) nclistfree(vars);
418 if(varaprojection != NULL) dcefree((DCEnode*)varaprojection);
419 if(fetchconstraint != NULL) dcefree((DCEnode*)fetchconstraint);
420 if(varainfo != NULL) freegetvara(varainfo);
421 if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
422 return THROW(ncstat);
423 }
424
425 /* Remove any pseudodimensions (sequence and string)*/
426 static NCerror
removepseudodims(DCEprojection * proj)427 removepseudodims(DCEprojection* proj)
428 {
429 int i;
430 #ifdef DEBUG1
431 fprintf(stderr,"removesequencedims.before: %s\n",dumpprojection(proj));
432 #endif
433 for(i=0;i<nclistlength(proj->var->segments);i++) {
434 DCEsegment* seg = (DCEsegment*)nclistget(proj->var->segments,i);
435 CDFnode* cdfnode = (CDFnode*)seg->annotation;
436 if(cdfnode->array.seqdim != NULL)
437 seg->rank = 0;
438 else if(cdfnode->array.stringdim != NULL)
439 seg->rank--;
440 }
441 #ifdef DEBUG1
442 fprintf(stderr,"removepseudodims.after: %s\n",dumpprojection(proj));
443 #endif
444 return NC_NOERR;
445 }
446
447 static NCerror
moveto(NCDAPCOMMON * nccomm,Getvara * xgetvar,CDFnode * xrootnode,void * memory)448 moveto(NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xrootnode, void* memory)
449 {
450 OCerror ocstat = OC_NOERR;
451 NCerror ncstat = NC_NOERR;
452 OClink conn = nccomm->oc.conn;
453 OCdatanode xrootcontent;
454 OCddsnode ocroot;
455 NClist* path = nclistnew();
456 struct NCMEMORY memstate;
457
458 memstate.next = (memstate.memory = memory);
459
460 /* Get the root content*/
461 ocroot = xrootnode->tree->ocroot;
462 ocstat = oc_data_getroot(conn,ocroot,&xrootcontent);
463 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
464
465 /* Remember: xgetvar->target is in DATADDS tree */
466 collectnodepath(xgetvar->target,path,WITHDATASET);
467 ncstat = movetor(nccomm,xrootcontent,
468 path,0,xgetvar,0,&memstate,
469 xgetvar->varaprojection->var->segments);
470 done:
471 nclistfree(path);
472 oc_data_free(conn,xrootcontent);
473 if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
474 return THROW(ncstat);
475 }
476
477 static NCerror
movetor(NCDAPCOMMON * nccomm,OCdatanode currentcontent,NClist * path,int depth,Getvara * xgetvar,size_t dimindex,struct NCMEMORY * memory,NClist * segments)478 movetor(NCDAPCOMMON* nccomm,
479 OCdatanode currentcontent,
480 NClist* path,
481 int depth, /* depth is position in segment list*/
482 Getvara* xgetvar,
483 size_t dimindex, /* dimindex is position in xgetvar->slices*/
484 struct NCMEMORY* memory,
485 NClist* segments)
486 {
487 OCerror ocstat = OC_NOERR;
488 NCerror ncstat = NC_NOERR;
489 OClink conn = nccomm->oc.conn;
490 CDFnode* xnode = (CDFnode*)nclistget(path,depth);
491 OCdatanode reccontent = NULL;
492 OCdatanode dimcontent = NULL;
493 OCdatanode fieldcontent = NULL;
494 Dapodometer* odom = NULL;
495 int hasstringdim = 0;
496 DCEsegment* segment;
497 OCDT mode;
498
499 /* Note that we use depth-1 because the path contains the DATASET
500 but the segment list does not */
501 segment = (DCEsegment*)nclistget(segments,depth-1); /*may be NULL*/
502 if(xnode->etype == NC_STRING || xnode->etype == NC_URL) hasstringdim = 1;
503
504 /* Get the mode */
505 ocstat = oc_data_mode(conn,currentcontent,&mode);
506 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
507
508 #ifdef DEBUG2
509 fprintf(stderr,"moveto: nctype=%d depth=%d dimindex=%d mode=%s",
510 xnode->nctype, depth,dimindex,oc_data_modestring(mode));
511 fprintf(stderr," segment=%s hasstringdim=%d\n",
512 dcetostring((DCEnode*)segment),hasstringdim);
513 #endif
514
515 switch (xnode->nctype) {
516
517 #if 0
518 #define OCDT_FIELD ((OCDT)(1)) /* field of a container */
519 #define OCDT_ELEMENT ((OCDT)(2)) /* element of a structure array */
520 #define OCDT_RECORD ((OCDT)(4)) /* record of a sequence */
521 #define OCDT_ARRAY ((OCDT)(8)) /* is structure array */
522 #define OCDT_SEQUENCE ((OCDT)(16)) /* is sequence */
523 #define OCDT_ATOMIC ((OCDT)(32)) /* is atomic leaf */
524 #endif
525
526 default:
527 goto done;
528
529 case NC_Grid:
530 case NC_Dataset:
531 case NC_Structure:
532 /* Separate out the case where structure is dimensioned */
533 if(oc_data_indexable(conn,currentcontent)) {
534 /* => dimensioned structure */
535 /* The current segment should reflect the
536 proper parts of the nc_get_vara argument
537 */
538 /* Create odometer for this structure's part of the projection */
539 odom = dapodom_fromsegment(segment,0,segment->rank);
540 while(dapodom_more(odom)) {
541 /* Compute which instance to move to*/
542 ocstat = oc_data_ithelement(conn,currentcontent,
543 odom->index,&dimcontent);
544 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
545 ASSERT(oc_data_indexed(conn,dimcontent));
546 ncstat = movetor(nccomm,dimcontent,
547 path,depth,/*keep same depth*/
548 xgetvar,dimindex+segment->rank,
549 memory,segments);
550 dapodom_next(odom);
551 }
552 dapodom_free(odom);
553 odom = NULL;
554 } else {/* scalar instance */
555 ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments);
556 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
557 } break;
558
559 case NC_Sequence:
560 if(fIsSet(mode,OCDT_SEQUENCE)) {
561 ASSERT((xnode->attachment != NULL));
562 ASSERT((segment != NULL));
563 ASSERT((segment->rank == 1));
564 /* Build an odometer for walking the sequence,
565 however, watch out
566 for the case when the user set a limit and that limit
567 is not actually reached in this request.
568 */
569 /* By construction, this sequence represents the first
570 (and only) dimension of this segment */
571 odom = dapodom_fromsegment(segment,0,1);
572 while(dapodom_more(odom)) {
573 size_t recordindex = dapodom_count(odom);
574 ocstat = oc_data_ithrecord(conn,currentcontent,
575 recordindex,&reccontent);
576 if(ocstat != OC_NOERR) {
577 if(ocstat == OC_EINDEX)
578 ocstat = OC_EINVALCOORDS;
579 THROWCHK(ocstat); goto done;
580 }
581 ncstat = movetor(nccomm,reccontent,
582 path,depth,
583 xgetvar,dimindex+1,
584 memory,segments);
585 if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto done;}
586 dapodom_next(odom);
587 }
588 } else if(fIsSet(mode,OCDT_RECORD)) {
589 /* Treat like structure */
590 /* currentcontent points to the record instance */
591 ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments);
592 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
593 }
594 break;
595
596 case NC_Atomic:
597
598 if(hasstringdim)
599 ncstat = extractstring(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory);
600 else
601 ncstat = extract(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory);
602 break;
603
604 }
605
606 done:
607 oc_data_free(conn,dimcontent);
608 oc_data_free(conn,fieldcontent);
609 oc_data_free(conn,reccontent);
610 if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
611 if(odom) dapodom_free(odom);
612 return THROW(ncstat);
613 }
614
615 static NCerror
movetofield(NCDAPCOMMON * nccomm,OCdatanode currentcontent,NClist * path,int depth,Getvara * xgetvar,size_t dimindex,struct NCMEMORY * memory,NClist * segments)616 movetofield(NCDAPCOMMON* nccomm,
617 OCdatanode currentcontent,
618 NClist* path,
619 int depth, /* depth is position in segment list*/
620 Getvara* xgetvar,
621 size_t dimindex, /* dimindex is position in xgetvar->slices*/
622 struct NCMEMORY* memory,
623 NClist* segments)
624 {
625 OCerror ocstat = OC_NOERR;
626 NCerror ncstat = NC_NOERR;
627 size_t fieldindex,gridindex;
628 OClink conn = nccomm->oc.conn;
629 CDFnode* xnode = (CDFnode*)nclistget(path,depth);
630 OCdatanode reccontent = NULL;
631 OCdatanode dimcontent = NULL;
632 OCdatanode fieldcontent = NULL;
633 CDFnode* xnext;
634 int newdepth;
635 int ffield;
636
637 /* currentcontent points to the grid/dataset/structure/record instance */
638 xnext = (CDFnode*)nclistget(path,depth+1);
639 ASSERT((xnext != NULL));
640
641 /* If findfield is less than 0,
642 and passes through this stanza,
643 an undefined value will be passed to
644 oc_data_ithfield. See coverity
645 issue 712596. */
646 ffield = findfield(xnode, xnext);
647 if(ffield < 0) {
648 ncstat = NC_EBADFIELD;
649 goto done;
650 } else {
651 fieldindex = findfield(xnode,xnext);
652 }
653
654 /* If the next node is a nc_virtual node, then
655 we need to effectively
656 ignore it and use the appropriate subnode.
657 If the next node is a re-struct'd node, then
658 use it as is.
659 */
660 if(xnext->nc_virtual) {
661 CDFnode* xgrid = xnext;
662 xnext = (CDFnode*)nclistget(path,depth+2); /* real node */
663 gridindex = fieldindex;
664 fieldindex = findfield(xgrid,xnext);
665 fieldindex += gridindex;
666 newdepth = depth+2;
667 } else {
668 newdepth = depth+1;
669 }
670 /* Move to appropriate field */
671 ocstat = oc_data_ithfield(conn,currentcontent,fieldindex,&fieldcontent);
672 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
673 ncstat = movetor(nccomm,fieldcontent,
674 path,newdepth,xgetvar,dimindex,memory,
675 segments);
676
677 done:
678 oc_data_free(conn,dimcontent);
679 oc_data_free(conn,fieldcontent);
680 oc_data_free(conn,reccontent);
681 if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
682 return THROW(ncstat);
683 }
684
685 #if 0
686
687 /* Determine the index in the odometer at which
688 the odometer will be walking the whole subslice
689 This will allow us to optimize.
690 */
691 static int
692 wholeslicepoint(Dapodometer* odom)
693 {
694 unsigned int i;
695 int point;
696 for(point=-1,i=0;i<odom->rank;i++) {
697 ASSERT((odom->size[i] != 0));
698 if(odom->start[i] != 0 || odom->stride[i] != 1
699 || odom->count[i] != odom->size[i])
700 point = i;
701 }
702 if(point == -1)
703 point = 0; /* wholevariable */
704 else if(point == (odom->rank - 1))
705 point = -1; /* no whole point */
706 else
707 point += 1; /* intermediate point */
708 return point;
709 }
710 #endif
711
712 static int
findfield(CDFnode * node,CDFnode * field)713 findfield(CDFnode* node, CDFnode* field)
714 {
715 size_t i;
716 for(i=0;i<nclistlength(node->subnodes);i++) {
717 CDFnode* test = (CDFnode*) nclistget(node->subnodes,i);
718 if(test == field) return i;
719 }
720 return -1;
721 }
722
723 static int
conversionrequired(nc_type t1,nc_type t2)724 conversionrequired(nc_type t1, nc_type t2)
725 {
726 if(t1 == t2)
727 return 0;
728 if(nctypesizeof(t1) != nctypesizeof(t2))
729 return 1;
730 /* Avoid too many cases by making t1 < t2 */
731 if(t1 > t2) {int tmp = t1; t1 = t2; t2 = tmp;}
732 #undef CASE
733 #define CASE(t1,t2) ((t1)<<5 | (t2))
734 switch (CASE(t1,t2)) {
735 case CASE(NC_BYTE,NC_UBYTE):
736 case CASE(NC_BYTE,NC_CHAR):
737 case CASE(NC_CHAR,NC_UBYTE):
738 case CASE(NC_SHORT,NC_USHORT):
739 case CASE(NC_INT,NC_UINT):
740 case CASE(NC_INT64,NC_UINT64):
741 return 0;
742 default: break;
743 }
744 return 1;
745 }
746
747 /* We are at a primitive variable or scalar that has no string dimensions.
748 Extract the data. (This is way too complicated)
749 */
750 static int
extract(NCDAPCOMMON * nccomm,Getvara * xgetvar,CDFnode * xnode,DCEsegment * segment,size_t dimindex,OClink conn,OCdatanode currentcontent,struct NCMEMORY * memory)751 extract(
752 NCDAPCOMMON* nccomm,
753 Getvara* xgetvar,
754 CDFnode* xnode,
755 DCEsegment* segment,
756 size_t dimindex,/*notused*/
757 OClink conn,
758 OCdatanode currentcontent,
759 struct NCMEMORY* memory
760 )
761 {
762 OCerror ocstat = OC_NOERR;
763 NCerror ncstat = NC_NOERR;
764 size_t count,rank0;
765 Dapodometer* odom = NULL;
766 size_t externtypesize;
767 size_t interntypesize;
768 int requireconversion;
769 char value[16];
770
771 ASSERT((segment != NULL));
772
773 requireconversion = conversionrequired(xgetvar->dsttype,xnode->etype);
774
775 ASSERT(xgetvar->cache != NULL);
776 externtypesize = nctypesizeof(xgetvar->dsttype);
777 interntypesize = nctypesizeof(xnode->etype);
778
779 rank0 = nclistlength(xnode->array.dimset0);
780
781 #ifdef DEBUG2
782 fprintf(stderr,"moveto: primitive: segment=%s",
783 dcetostring((DCEnode*)segment));
784 fprintf(stderr," iswholevariable=%d",xgetvar->cache->wholevariable);
785 fprintf(stderr,"\n");
786 #endif
787
788 if(rank0 == 0) {/* scalar */
789 char* mem = (requireconversion?value:memory->next);
790 ASSERT(externtypesize <= sizeof(value));
791 /* Read the whole scalar directly into memory */
792 ocstat = oc_data_readscalar(conn,currentcontent,externtypesize,mem);
793 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
794 if(requireconversion) {
795 /* convert the value to external type */
796 ncstat = dapconvert(xnode->etype,xgetvar->dsttype,memory->next,value,1);
797 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
798 }
799 memory->next += (externtypesize);
800 } else if(xgetvar->cache->wholevariable) {/* && rank0 > 0 */
801 /* There are multiple cases, assuming no conversion required.
802 1) client is asking for whole variable
803 => start=0, count=totalsize, stride=1
804 => read whole thing at one shot
805 2) client is asking for non-strided subset
806 and edges are maximal
807 => start=x, count=y, stride=1
808 => read whole subset at one shot
809 3) client is asking for strided subset or edges are not maximal
810 => start=x, count=y, stride=s
811 => we have to use odometer on leading prefix.
812 If conversion required, then read one-by-one
813 */
814 int safeindex = dcesafeindex(segment,0,rank0);
815 assert(safeindex >= 0 && safeindex <= rank0);
816
817 if(!requireconversion && safeindex == 0) { /* can read whole thing */
818 size_t internlen;
819 count = dcesegmentsize(segment,0,rank0); /* how many to read */
820 internlen = interntypesize*count;
821 /* Read the whole variable directly into memory.*/
822 ocstat = oc_data_readn(conn,currentcontent,NC_coord_zero,count,internlen,memory->next);
823 /* bump memory pointer */
824 memory->next += internlen;
825 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
826 } else if(!requireconversion && safeindex > 0 && safeindex < rank0) {
827 size_t internlen;
828 /* We need to build an odometer for the unsafe prefix of the slices */
829 odom = dapodom_fromsegment(segment,0,safeindex);
830 count = dcesegmentsize(segment,safeindex,rank0); /* read in count chunks */
831 internlen = interntypesize*count;
832 while(dapodom_more(odom)) {
833 ocstat = oc_data_readn(conn,currentcontent,odom->index,count,internlen,memory->next);
834 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
835 memory->next += internlen;
836 dapodom_next(odom);
837 }
838 dapodom_free(odom);
839 } else {
840 /* Cover following cases, all of which require reading
841 values one-by-one:
842 1. requireconversion
843 2. !requireconversion but safeindex == rank0 =>no safe indices
844 Note that in case 2, we will do a no-op conversion.
845 */
846 odom = dapodom_fromsegment(segment,0,rank0);
847 while(dapodom_more(odom)) {
848 char value[16]; /* Big enough to hold any numeric value */
849 ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value);
850 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
851 ncstat = dapconvert(xnode->etype,xgetvar->dsttype,memory->next,value,1);
852 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
853 memory->next += (externtypesize);
854 dapodom_next(odom);
855 }
856 dapodom_free(odom);
857 }
858 } else { /* !xgetvar->cache->wholevariable && rank0 > 0 */
859 /* This is the case where the constraint was applied by the server,
860 so we just read it in, possibly with conversion
861 */
862 if(requireconversion) {
863 /* read one-by-one */
864 odom = dapodom_fromsegment(segment,0,rank0);
865 while(dapodom_more(odom)) {
866 char value[16]; /* Big enough to hold any numeric value */
867 ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value);
868 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
869 ncstat = dapconvert(xnode->etype,xgetvar->dsttype,memory->next,value,1);
870 if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
871 memory->next += (externtypesize);
872 dapodom_next(odom);
873 }
874 dapodom_free(odom);
875 } else {/* Read straight to memory */
876 size_t internlen;
877 count = dcesegmentsize(segment,0,rank0); /* how many to read */
878 internlen = interntypesize*count;
879 ocstat = oc_data_readn(conn,currentcontent,NC_coord_zero,count,internlen,memory->next);
880 if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
881 }
882 }
883 done:
884 return THROW(ncstat);
885 }
886
887 static NCerror
slicestring(OClink conn,char * stringmem,DCEslice * slice,struct NCMEMORY * memory)888 slicestring(OClink conn, char* stringmem, DCEslice* slice, struct NCMEMORY* memory)
889 {
890 size_t stringlen;
891 unsigned int i;
892 NCerror ncstat = NC_NOERR;
893 char* lastchar;
894 size_t charcount; /* number of characters inserted into memory */
895
896 /* libnc-dap chooses to convert string escapes to the corresponding
897 character; so we do likewise.
898 */
899 dapexpandescapes(stringmem);
900 stringlen = strlen(stringmem);
901
902 #ifdef DEBUG2
903 fprintf(stderr,"moveto: slicestring: string/%lu=%s\n",stringlen,stringmem);
904 fprintf(stderr,"slicestring: %lu string=|%s|\n",stringlen,stringmem);
905 fprintf(stderr,"slicestring: slice=[%lu:%lu:%lu/%lu]\n",
906 slice->first,slice->stride,slice->stop,slice->declsize);
907 #endif
908
909 /* Stride across string; if we go past end of string, then pad*/
910 charcount = 0;
911 for(i=slice->first;i<slice->length;i+=slice->stride) {
912 if(i < stringlen)
913 *memory->next = stringmem[i];
914 else /* i >= stringlen*/
915 *memory->next = NC_FILL_CHAR;
916 memory->next++;
917 charcount++;
918 }
919 lastchar = (memory->next);
920 if(charcount > 0) {
921 lastchar--;
922 }
923
924 return THROW(ncstat);
925 }
926
927 /*
928 Extract data for a netcdf variable that has a string dimension.
929 */
930 static int
extractstring(NCDAPCOMMON * nccomm,Getvara * xgetvar,CDFnode * xnode,DCEsegment * segment,size_t dimindex,OClink conn,OCdatanode currentcontent,struct NCMEMORY * memory)931 extractstring(
932 NCDAPCOMMON* nccomm,
933 Getvara* xgetvar,
934 CDFnode* xnode,
935 DCEsegment* segment,
936 size_t dimindex, /*notused*/
937 OClink conn,
938 OCdatanode currentcontent,
939 struct NCMEMORY* memory
940 )
941 {
942 NCerror ncstat = NC_NOERR;
943 OCerror ocstat = OC_NOERR;
944 int i;
945 size_t rank0;
946 NClist* strings = NULL;
947 Dapodometer* odom = NULL;
948
949 ASSERT(xnode->etype == NC_STRING || xnode->etype == NC_URL);
950
951 /* Compute rank minus string dimension */
952 rank0 = nclistlength(xnode->array.dimset0);
953
954 /* keep whole extracted strings stored in an NClist */
955 strings = nclistnew();
956
957 if(rank0 == 0) {/*=> scalar*/
958 char* value = NULL;
959 ocstat = oc_data_readscalar(conn,currentcontent,sizeof(value),&value);
960 if(ocstat != OC_NOERR) goto done;
961 nclistpush(strings,(void*)value);
962 } else {
963 /* Use the odometer to walk to the appropriate fields*/
964 odom = dapodom_fromsegment(segment,0,rank0);
965 while(dapodom_more(odom)) {
966 char* value = NULL;
967 ocstat = oc_data_readn(conn,currentcontent,odom->index,1,sizeof(value),&value);
968 if(ocstat != OC_NOERR)
969 goto done;
970 nclistpush(strings,(void*)value);
971 dapodom_next(odom);
972 }
973 dapodom_free(odom);
974 odom = NULL;
975 }
976 /* Get each string in turn, slice it by applying the string dimm
977 and store in user supplied memory
978 */
979 for(i=0;i<nclistlength(strings);i++) {
980 char* s = (char*)nclistget(strings,i);
981 slicestring(conn,s,&segment->slices[rank0],memory);
982 free(s);
983 }
984 done:
985 if(strings != NULL) nclistfree(strings);
986 if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
987 return THROW(ncstat);
988 }
989
990 static NCerror
makegetvar(NCDAPCOMMON * nccomm,CDFnode * var,void * data,nc_type dsttype,Getvara ** getvarp)991 makegetvar(NCDAPCOMMON* nccomm, CDFnode* var, void* data, nc_type dsttype, Getvara** getvarp)
992 {
993 NCerror ncstat = NC_NOERR;
994
995 if(getvarp)
996 {
997 Getvara* getvar;
998
999 getvar = (Getvara*)calloc(1,sizeof(Getvara));
1000 MEMCHECK(getvar,NC_ENOMEM);
1001
1002 getvar->target = var;
1003 getvar->memory = data;
1004 getvar->dsttype = dsttype;
1005
1006 *getvarp = getvar;
1007 }
1008 return ncstat;
1009 }
1010
1011 /*
1012 Given DDS node, locate the node
1013 in a DATADDS that matches the DDS node.
1014 Return NULL if no node found
1015 */
1016
1017 void
unattach(CDFnode * root)1018 unattach(CDFnode* root)
1019 {
1020 unsigned int i;
1021 CDFtree* xtree = root->tree;
1022 for(i=0;i<nclistlength(xtree->nodes);i++) {
1023 CDFnode* xnode = (CDFnode*)nclistget(xtree->nodes,i);
1024 /* break bi-directional link */
1025 xnode->attachment = NULL;
1026 }
1027 }
1028
1029 static void
setattach(CDFnode * target,CDFnode * pattern)1030 setattach(CDFnode* target, CDFnode* pattern)
1031 {
1032 target->attachment = pattern;
1033 pattern->attachment = target;
1034 /* Transfer important information */
1035 target->externaltype = pattern->externaltype;
1036 target->maxstringlength = pattern->maxstringlength;
1037 target->sequencelimit = pattern->sequencelimit;
1038 target->ncid = pattern->ncid;
1039 /* also transfer libncdap4 info */
1040 target->typeid = pattern->typeid;
1041 target->typesize = pattern->typesize;
1042 }
1043
1044 static NCerror
attachdims(CDFnode * xnode,CDFnode * pattern)1045 attachdims(CDFnode* xnode, CDFnode* pattern)
1046 {
1047 unsigned int i;
1048 for(i=0;i<nclistlength(xnode->array.dimsetall);i++) {
1049 CDFnode* xdim = (CDFnode*)nclistget(xnode->array.dimsetall,i);
1050 CDFnode* tdim = (CDFnode*)nclistget(pattern->array.dimsetall,i);
1051 setattach(xdim,tdim);
1052 #ifdef DEBUG2
1053 fprintf(stderr,"attachdim: %s->%s\n",xdim->ocname,tdim->ocname);
1054 #endif
1055 }
1056 return NC_NOERR;
1057 }
1058
1059 /*
1060 Match a DATADDS node to a DDS node.
1061 It is assumed that both trees have been re-struct'ed if necessary.
1062 */
1063
1064 static NCerror
attachr(CDFnode * xnode,NClist * patternpath,int depth)1065 attachr(CDFnode* xnode, NClist* patternpath, int depth)
1066 {
1067 unsigned int i,plen,lastnode,gridable;
1068 NCerror ncstat = NC_NOERR;
1069 CDFnode* patternpathnode;
1070 CDFnode* patternpathnext;
1071
1072 plen = nclistlength(patternpath);
1073 if(depth >= plen) {THROWCHK(ncstat=NC_EINVAL); goto done;}
1074
1075 lastnode = (depth == (plen-1));
1076 patternpathnode = (CDFnode*)nclistget(patternpath,depth);
1077 ASSERT((simplenodematch(xnode,patternpathnode)));
1078 setattach(xnode,patternpathnode);
1079 #ifdef DEBUG2
1080 fprintf(stderr,"attachnode: %s->%s\n",xnode->ocname,patternpathnode->ocname);
1081 #endif
1082
1083 if(lastnode) goto done; /* We have the match and are done */
1084
1085 if(nclistlength(xnode->array.dimsetall) > 0) {
1086 attachdims(xnode,patternpathnode);
1087 }
1088
1089 ASSERT((!lastnode));
1090 patternpathnext = (CDFnode*)nclistget(patternpath,depth+1);
1091
1092 gridable = (patternpathnext->nctype == NC_Grid && depth+2 < plen);
1093
1094 /* Try to find an xnode subnode that matches patternpathnext */
1095 for(i=0;i<nclistlength(xnode->subnodes);i++) {
1096 CDFnode* xsubnode = (CDFnode*)nclistget(xnode->subnodes,i);
1097 if(simplenodematch(xsubnode,patternpathnext)) {
1098 ncstat = attachr(xsubnode,patternpath,depth+1);
1099 if(ncstat) goto done;
1100 } else if(gridable && xsubnode->nctype == NC_Atomic) {
1101 /* grids may or may not appear in the datadds;
1102 try to match the xnode subnodes against the parts of the grid
1103 */
1104 CDFnode* patternpathnext2 = (CDFnode*)nclistget(patternpath,depth+2);
1105 if(simplenodematch(xsubnode,patternpathnext2)) {
1106 ncstat = attachr(xsubnode,patternpath,depth+2);
1107 if(ncstat) goto done;
1108 }
1109 }
1110 }
1111 done:
1112 return THROW(ncstat);
1113 }
1114
1115 NCerror
attach(CDFnode * xroot,CDFnode * pattern)1116 attach(CDFnode* xroot, CDFnode* pattern)
1117 {
1118 NCerror ncstat = NC_NOERR;
1119 NClist* patternpath = nclistnew();
1120 CDFnode* ddsroot = pattern->root;
1121
1122 if(xroot->attachment) unattach(xroot);
1123 if(ddsroot != NULL && ddsroot->attachment) unattach(ddsroot);
1124 if(!simplenodematch(xroot,ddsroot))
1125 {THROWCHK(ncstat=NC_EINVAL); goto done;}
1126 collectnodepath(pattern,patternpath,WITHDATASET);
1127 ncstat = attachr(xroot,patternpath,0);
1128 done:
1129 nclistfree(patternpath);
1130 return ncstat;
1131 }
1132
1133 static NCerror
attachsubsetr(CDFnode * target,CDFnode * pattern)1134 attachsubsetr(CDFnode* target, CDFnode* pattern)
1135 {
1136 unsigned int i;
1137 NCerror ncstat = NC_NOERR;
1138 int fieldindex;
1139
1140 #ifdef DEBUG2
1141 fprintf(stderr,"attachsubsetr: attach: target=%s pattern=%s\n",
1142 target->ocname,pattern->ocname);
1143 #endif
1144
1145 ASSERT((nodematch(target,pattern)));
1146 setattach(target,pattern);
1147
1148 /* Try to match target subnodes against pattern subnodes */
1149
1150 fieldindex = 0;
1151 for(fieldindex=0,i=0;i<nclistlength(pattern->subnodes) && fieldindex<nclistlength(target->subnodes);i++) {
1152 CDFnode* patternsubnode = (CDFnode*)nclistget(pattern->subnodes,i);
1153 CDFnode* targetsubnode = (CDFnode*)nclistget(target->subnodes,fieldindex);
1154 if(nodematch(targetsubnode,patternsubnode)) {
1155 #ifdef DEBUG2
1156 fprintf(stderr,"attachsubsetr: match: %s :: %s\n",targetsubnode->ocname,patternsubnode->ocname);
1157 #endif
1158 ncstat = attachsubsetr(targetsubnode,patternsubnode);
1159 if(ncstat) goto done;
1160 fieldindex++;
1161 }
1162 }
1163 done:
1164 return THROW(ncstat);
1165 }
1166
1167
1168 /*
1169 Match nodes in pattern tree to nodes in target tree;
1170 pattern tree is typically a structural superset of target tree.
1171 WARNING: Dimensions are not attached
1172 */
1173
1174 static NCerror
attachsubset(CDFnode * target,CDFnode * pattern)1175 attachsubset(CDFnode* target, CDFnode* pattern)
1176 {
1177 NCerror ncstat = NC_NOERR;
1178
1179 if(pattern == NULL) {THROWCHK(ncstat=NC_NOERR); goto done;}
1180 if(!nodematch(target,pattern)) {THROWCHK(ncstat=NC_EINVAL); goto done;}
1181 #ifdef DEBUG2
1182 fprintf(stderr,"attachsubset: target=%s\n",dumptree(target));
1183 fprintf(stderr,"attachsubset: pattern=%s\n",dumptree(pattern));
1184 #endif
1185 ncstat = attachsubsetr(target,pattern);
1186 done:
1187 return ncstat;
1188 }
1189
1190 static void
freegetvara(Getvara * vara)1191 freegetvara(Getvara* vara)
1192 {
1193 if(vara == NULL) return;
1194 dcefree((DCEnode*)vara->varaprojection);
1195 nullfree(vara);
1196 }
1197
1198 #ifdef EXTERN_UNUSED
1199 int
nc3d_getvarmx(int ncid,int varid,const size_t * start,const size_t * edges,const ptrdiff_t * stride,const ptrdiff_t * map,void * data,nc_type dsttype0)1200 nc3d_getvarmx(int ncid, int varid,
1201 const size_t *start,
1202 const size_t *edges,
1203 const ptrdiff_t* stride,
1204 const ptrdiff_t* map,
1205 void* data,
1206 nc_type dsttype0)
1207 {
1208 NCerror ncstat = NC_NOERR;
1209 int i;
1210 NC* drno;
1211 NC* substrate;
1212 NC3_INFO* substrate3;
1213 NCDAPCOMMON* dapcomm;
1214 NC_var* var;
1215 CDFnode* cdfvar; /* cdf node mapping to var*/
1216 NClist* varnodes;
1217 nc_type dsttype;
1218 size_t externsize;
1219 size_t dimsizes[NC_MAX_VAR_DIMS];
1220 Dapodometer* odom = NULL;
1221 unsigned int ncrank;
1222 NClist* ncdims = NULL;
1223 size_t nelems;
1224 #ifdef NEWVARM
1225 char* localcopy; /* of whole variable */
1226 #endif
1227
1228 ncstat = NC_check_id(ncid, (NC**)&drno);
1229 if(ncstat != NC_NOERR) goto done;
1230 dapcomm = (NCDAPCOMMON*)drno->dispatchdata;
1231
1232 ncstat = NC_check_id(drno->substrate, &substrate);
1233 if(ncstat != NC_NOERR) goto done;
1234 substrate3 = (NC3_INFO*)drno->dispatchdata;
1235
1236 var = NC_lookupvar(substrate3,varid);
1237 if(var == NULL) {ncstat = NC_ENOTVAR; goto done;}
1238
1239 /* Locate var node via varid */
1240 varnodes = dapcomm->cdf.ddsroot->tree->varnodes;
1241 for(i=0;i<nclistlength(varnodes);i++) {
1242 CDFnode* node = (CDFnode*)nclistget(varnodes,i);
1243 if(node->array.basevar == NULL
1244 && node->nctype == NC_Atomic
1245 && node->ncid == varid) {
1246 cdfvar = node;
1247 break;
1248 }
1249 }
1250
1251 ASSERT((cdfvar != NULL));
1252 ASSERT((strcmp(cdfvar->ncfullname,var->name->cp)==0));
1253
1254 if(nclistlength(cdfvar->array.dimsetplus) == 0) {
1255 /* The variable is a scalar; consequently, there is only one
1256 thing to get and only one place to put it. */
1257 /* recurse with additional parameters */
1258 return THROW(nc3d_getvarx(ncid,varid,
1259 NULL,NULL,NULL,
1260 data,dsttype0));
1261 }
1262
1263 dsttype = (dsttype0);
1264
1265 /* Default to using the inquiry type for this var*/
1266 if(dsttype == NC_NAT) dsttype = cdfvar->externaltype;
1267
1268 /* Validate any implied type conversion*/
1269 if(cdfvar->etype != dsttype && dsttype == NC_CHAR) {
1270 /* The only disallowed conversion is to/from char and non-byte
1271 numeric types*/
1272 switch (cdfvar->etype) {
1273 case NC_STRING: case NC_URL:
1274 case NC_CHAR: case NC_BYTE: case NC_UBYTE:
1275 break;
1276 default:
1277 return THROW(NC_ECHAR);
1278 }
1279 }
1280
1281 externsize = nctypesizeof(dsttype);
1282
1283 /* Accumulate the dimension sizes and the total # of elements */
1284 ncdims = cdfvar->array.dimsetall;
1285 ncrank = nclistlength(ncdims);
1286
1287 nelems = 1; /* also Compute the number of elements being retrieved */
1288 for(i=0;i<ncrank;i++) {
1289 CDFnode* dim = (CDFnode*)nclistget(ncdims,i);
1290 dimsizes[i] = dim->dim.declsize;
1291 nelems *= edges[i];
1292 }
1293
1294 /* Originally, this code repeatedly extracted single values
1295 using get_var1. In an attempt to improve performance,
1296 I have converted to reading the whole variable at once
1297 and walking it locally.
1298 */
1299
1300 #ifdef NEWVARM
1301 localcopy = (char*)malloc(nelems*externsize);
1302
1303 /* We need to use the varieties of get_vars in order to
1304 properly do conversion to the external type
1305 */
1306
1307 switch (dsttype) {
1308
1309 case NC_CHAR:
1310 ncstat = nc_get_vars_text(ncid,varid,start, edges, stride,
1311 (char*)localcopy);
1312 break;
1313 case NC_BYTE:
1314 ncstat = nc_get_vars_schar(ncid,varid,start, edges, stride,
1315 (signed char*)localcopy);
1316 break;
1317 case NC_SHORT:
1318 ncstat = nc_get_vars_short(ncid,varid, start, edges, stride,
1319 (short*)localcopy);
1320 break;
1321 case NC_INT:
1322 ncstat = nc_get_vars_int(ncid,varid,start, edges, stride,
1323 (int*)localcopy);
1324 break;
1325 case NC_FLOAT:
1326 ncstat = nc_get_vars_float(ncid,varid,start, edges, stride,
1327 (float*)localcopy);
1328 break;
1329 case NC_DOUBLE:
1330 ncstat = nc_get_vars_double(ncid,varid, start, edges, stride,
1331 (double*)localcopy);
1332 break;
1333 default: break;
1334 }
1335
1336
1337 odom = dapodom_new(ncrank,start,edges,stride,NULL);
1338
1339 /* Walk the local copy */
1340 for(i=0;i<nelems;i++) {
1341 size_t voffset = dapodom_varmcount(odom,map,dimsizes);
1342 void* dataoffset = (void*)(((char*)data) + (externsize*voffset));
1343 char* localpos = (localcopy + externsize*i);
1344 /* extract the indexset'th value from local copy */
1345 memcpy(dataoffset,(void*)localpos,externsize);
1346 /*
1347 fprintf(stderr,"new: %lu -> %lu %f\n",
1348 (unsigned long)(i),
1349 (unsigned long)voffset,
1350 *(float*)localpos);
1351 */
1352 dapodom_next(odom);
1353 }
1354 #else
1355 odom = dapodom_new(ncrank,start,edges,stride,NULL);
1356 while(dapodom_more(odom)) {
1357 size_t* indexset = odom->index;
1358 size_t voffset = dapodom_varmcount(odom,map,dimsizes);
1359 char internalmem[128];
1360 char externalmem[128];
1361 void* dataoffset = (void*)(((char*)data) + (externsize*voffset));
1362
1363 /* get the indexset'th value using variable's internal type */
1364 ncstat = nc_get_var1(ncid,varid,indexset,(void*)&internalmem);
1365 if(ncstat != NC_NOERR) goto done;
1366 /* Convert to external type */
1367 ncstat = dapconvert(cdfvar->etype,dsttype,externalmem,internalmem);
1368 if(ncstat != NC_NOERR) goto done;
1369 memcpy(dataoffset,(void*)externalmem,externsize);
1370 /*
1371 fprintf(stderr,"old: %lu -> %lu %f\n",
1372 (unsigned long)dapodom_count(odom),
1373 (unsigned long)voffset,
1374 *(float*)externalmem);
1375 */
1376 dapodom_next(odom);
1377 }
1378 #endif
1379
1380 done:
1381 return ncstat;
1382 }
1383 #endif /*EXTERN_UNUSED*/
1384