00001
00002
00003 #include <dirent.h>
00004 #include <dlfcn.h>
00005 #include <sys/stat.h>
00006 #include <strings.h>
00007 #include <regex.h>
00008 #include <pwd.h>
00009 #include "drms.h"
00010 #include "drms_priv.h"
00011 #include "xmem.h"
00012 #include "drms_dsdsapi.h"
00013 #include "keymap.h"
00014 #include "fitsexport.h"
00015
00016 #ifndef DEBUG
00017 #undef TIME
00018 #define TIME(code) code
00019 #endif
00020
00021 #define kMAXRSETSPEC (DRMS_MAXSERIESNAMELEN + DRMS_MAXQUERYLEN + 128)
00022
00023 static void *ghDSDS = NULL;
00024 static int gAttemptedDSDS = 0;
00025 static unsigned int gRSChunkSize = 128;
00026
00027
00028 static HContainer_t *gSummcon = NULL;
00029
00030 typedef enum
00031 {
00032
00033 kRSParseState_Begin = 0,
00034
00035 kRSParseState_BeginElem,
00036
00037 kRSParseState_DRMS,
00038
00039 kRSParseState_DRMSFilt,
00040
00041 kRSParseState_DRMSFiltSQL,
00042
00043 kRSParseState_DRMSFiltAllVersSQL,
00044
00045 kRSParseState_DRMSSeglist,
00046
00047 kRSParseState_DSDS,
00048
00049 kRSParseState_VOT,
00050
00051
00052 kRSParseState_DSDSPort,
00053
00054 kRSParseState_AtFile,
00055
00056 kRSParseState_EndAtFile,
00057
00058 kRSParseState_Plainfile,
00059
00060 kRSParseState_EndElem,
00061
00062 kRSParseState_End,
00063
00064 kRSParseState_Success,
00065
00066
00067 kRSParseState_Error,
00068 } RSParseState_t;
00069
00070 #define kDSElemParseWS " \t\b"
00071 #define kDSElemParseDelim ",;\n"
00072 #define kOverviewFits "overview.fits"
00073
00074 #define kQUERYNFUDGE (4);
00075
00076 static void FreeSummaryChkCache()
00077 {
00078 if (gSummcon)
00079 {
00080 hcon_destroy(&gSummcon);
00081 }
00082 }
00083
00084 static void drms_record_summchkcache_term(void *data)
00085 {
00086 FreeSummaryChkCache();
00087 }
00088
00089 static int CopySeriesInfo(DRMS_Record_t *target, DRMS_Record_t *source);
00090 static int CopySegments(DRMS_Record_t *target, DRMS_Record_t *source);
00091 static int CopyLinks(DRMS_Record_t *target, DRMS_Record_t *source);
00092 static int CopyKeywords(DRMS_Record_t *target, DRMS_Record_t *source);
00093 static int CopyPrimaryIndex(DRMS_Record_t *target, DRMS_Record_t *source);
00094 static int ParseRecSetDescInternal(const char *recsetsStr, char **allvers, char ***sets, DRMS_RecordSetType_t **types, char ***snames, char ***filts, char ***segs, int *nsets, DRMS_RecQueryInfo_t *info);
00095 static int ParseRecSetDesc(const char *recsetsStr,
00096 char **allvers,
00097 char ***sets,
00098 DRMS_RecordSetType_t **types,
00099 char ***snames,
00100 char ***filts,
00101 int *nsets,
00102 DRMS_RecQueryInfo_t *info);
00103 static int FreeRecSetDescArr(char **allvers,
00104 char ***sets,
00105 DRMS_RecordSetType_t **types,
00106 char ***snames,
00107 char ***filts,
00108 int nsets);
00109 static int FreeRecSetDescArrInternal(char **allvers, char ***sets, DRMS_RecordSetType_t **types, char ***snames, char ***filts, char *** segs, int nsets);
00110
00111
00112 static int IsValidPlainFileSpec(const char *recSetSpec,
00113 DSDS_KeyList_t ***klarrout,
00114 DRMS_Segment_t **segarrout,
00115 int *nRecsout,
00116 char **pkeysout,
00117 int *status);
00118 static void AddLocalPrimekey(DRMS_Record_t *template, int *status);
00119 static int CreateRecordProtoFromFitsAgg(DRMS_Env_t *env,
00120 DSDS_KeyList_t **keylistarr,
00121 DRMS_Segment_t *segarr,
00122 int nRecs,
00123 char **pkeyarr,
00124 int nPKeys,
00125 Exputl_KeyMapClass_t fitsclass,
00126 DRMS_Record_t **proto,
00127 DRMS_Segment_t **segout,
00128 int *status);
00129 static void AdjustRecordProtoSeriesInfo(DRMS_Env_t *env,
00130 DRMS_Record_t *proto,
00131 const char *seriesName,
00132 unsigned int unitsize);
00133 static void AllocRecordProtoSeg(DRMS_Record_t *template, DRMS_Segment_t *seg, int *status);
00134 static void SetRecordProtoPKeys(DRMS_Record_t *template,
00135 char **pkeyarr,
00136 int nkeys,
00137 int *status);
00138 static DRMS_Record_t *CacheRecordProto(DRMS_Env_t *env,
00139 DRMS_Record_t *proto,
00140 const char *seriesName,
00141 int *status);
00142 static DRMS_RecordSet_t *CreateRecordsFromDSDSKeylist(DRMS_Env_t *env,
00143 int nRecs,
00144 DRMS_Record_t *cached,
00145 DSDS_KeyList_t **klarr,
00146 DRMS_Segment_t *segarr,
00147 int pkeysSpecified,
00148 Exputl_KeyMapClass_t fitsclass,
00149 int *status);
00150 static DRMS_RecordSet_t *OpenPlainFileRecords(DRMS_Env_t *env,
00151 DSDS_KeyList_t ***klarr,
00152 DRMS_Segment_t **segarr,
00153 int nRecs,
00154 char **pkeysout,
00155 int *status);
00156
00157 static char *drms_query_string(DRMS_Env_t *env, const char *seriesname, char *where, const char *pkwhere, const char *npkwhere, int filter, int mixed, DRMS_QueryType_t qtype, void *data, const char *fl, int allvers, HContainer_t *firstlast, HContainer_t *pkwhereNFL, int recnumq, int cursor, long long *limit);
00158
00159 static void RSFree(const void *val);
00160
00161
00162 static char *columnList(DRMS_Record_t *rec, HContainer_t *links, HContainer_t *keys, HContainer_t *segs, int *num_cols);
00163
00164 static size_t partialRecordMemsize(DRMS_Record_t *rec, HContainer_t *links, HContainer_t *keys, HContainer_t *segs);
00165
00166
00167
00168
00169
00170
00171
00172 static int IsValidPlainFileSpec(const char *recSetSpecIn,
00173 DSDS_KeyList_t ***klarrout,
00174 DRMS_Segment_t **segarrout,
00175 int *nRecsout,
00176 char **pkeysout,
00177 int *status)
00178 {
00179 int isLocSpec = 0;
00180 struct stat stBuf;
00181 int lstat = DRMS_SUCCESS;
00182 char *lbrack = NULL;
00183 int keylistSize = sizeof(char) * (strlen(recSetSpecIn) + 1);
00184 char *keylist;
00185 char *recSetSpec = strdup(recSetSpecIn);
00186
00187
00188 if ((lbrack = strchr(recSetSpec, '[')) != NULL)
00189 {
00190 if (strchr(lbrack, ']'))
00191 {
00192 *lbrack = '\0';
00193 keylist = malloc(keylistSize);
00194 snprintf(keylist, keylistSize, "%s", lbrack + 1);
00195 *(strchr(keylist, ']')) = '\0';
00196 *pkeysout = strdup(keylist);
00197 free(keylist);
00198 }
00199 }
00200 else
00201 {
00202 *pkeysout = NULL;
00203 }
00204
00205
00206
00207 if (recSetSpec && !stat(recSetSpec, &stBuf) && klarrout && segarrout)
00208 {
00209 if (S_ISREG(stBuf.st_mode) || S_ISLNK(stBuf.st_mode) || S_ISDIR(stBuf.st_mode))
00210 {
00211
00212
00213 if (!gAttemptedDSDS && !ghDSDS)
00214 {
00215 kDSDS_Stat_t dsdsstat;
00216 ghDSDS = DSDS_GetLibHandle(kLIBDSDS, &dsdsstat);
00217 if (dsdsstat != kDSDS_Stat_Success)
00218 {
00219 lstat = DRMS_ERROR_CANTOPENLIBRARY;
00220 }
00221
00222 gAttemptedDSDS = 1;
00223 }
00224
00225 if (lstat == DRMS_SUCCESS && ghDSDS)
00226 {
00227 DSDS_KeyList_t *kl = NULL;
00228 DRMS_Segment_t *seg = NULL;
00229 int iRec = 0;
00230
00231 pDSDSFn_DSDS_read_fitsheader_t pFn_DSDS_read_fitsheader =
00232 (pDSDSFn_DSDS_read_fitsheader_t)DSDS_GetFPtr(ghDSDS, kDSDS_DSDS_READ_FITSHEADER);
00233 pDSDSFn_DSDS_free_keylist_t pFn_DSDS_free_keylist =
00234 (pDSDSFn_DSDS_free_keylist_t)DSDS_GetFPtr(ghDSDS, kDSDS_DSDS_FREE_KEYLIST);
00235 pDSDSFn_DSDS_steal_seginfo_t pFn_DSDS_steal_seginfo =
00236 (pDSDSFn_DSDS_steal_seginfo_t)DSDS_GetFPtr(ghDSDS, kDSDS_DSDS_STEAL_SEGINFO);
00237 pDSDSFn_DSDS_free_seg_t pFn_DSDS_free_seg =
00238 (pDSDSFn_DSDS_free_seg_t)DSDS_GetFPtr(ghDSDS, kDSDS_DSDS_FREE_SEG);
00239
00240
00241 if (pFn_DSDS_read_fitsheader && pFn_DSDS_free_keylist &&
00242 pFn_DSDS_steal_seginfo && pFn_DSDS_free_seg)
00243 {
00244 kDSDS_Stat_t dsdsStat;
00245 int fitshead = 1;
00246
00247 if (S_ISREG(stBuf.st_mode) || S_ISLNK(stBuf.st_mode))
00248 {
00249 (*pFn_DSDS_read_fitsheader)(recSetSpec, &kl, &seg, kLocalSegName, &dsdsStat);
00250
00251 if (dsdsStat == kDSDS_Stat_Success)
00252 {
00253 if (kl == NULL)
00254 {
00255
00256 fitshead = 0;
00257 }
00258 else
00259 {
00260 *klarrout = (DSDS_KeyList_t **)malloc(sizeof(DSDS_KeyList_t *));
00261 *segarrout = (DRMS_Segment_t *)malloc(sizeof(DRMS_Segment_t));
00262
00263 (*klarrout)[0] = kl;
00264 (*pFn_DSDS_steal_seginfo)(&((*segarrout)[0]), seg);
00265
00266
00267 snprintf((*segarrout)[0].filename,
00268 DRMS_MAXSEGFILENAME,
00269 "%s",
00270 recSetSpec);
00271 (*pFn_DSDS_free_seg)(&seg);
00272 *nRecsout = 1;
00273 }
00274 }
00275 else
00276 {
00277 fitshead = 0;
00278 }
00279 }
00280 else
00281 {
00282 struct dirent **fileList = NULL;
00283 int nFiles = -1;
00284
00285 if ((nFiles = scandir(recSetSpec, &fileList, NULL, NULL)) > 0 &&
00286 fileList != NULL)
00287 {
00288 int fileIndex = 0;
00289 iRec = 0;
00290
00291
00292 *klarrout = (DSDS_KeyList_t **)malloc(sizeof(DSDS_KeyList_t *) * nFiles);
00293 *segarrout = (DRMS_Segment_t *)malloc(sizeof(DRMS_Segment_t) * nFiles);
00294
00295 while (fileIndex < nFiles)
00296 {
00297 struct dirent *entry = fileList[fileIndex];
00298 if (entry != NULL)
00299 {
00300 char *oneFile = entry->d_name;
00301 char dirEntry[PATH_MAX] = {0};
00302 snprintf(dirEntry,
00303 sizeof(dirEntry),
00304 "%s%s%s",
00305 recSetSpec,
00306 recSetSpec[strlen(recSetSpec) - 1] == '/' ? "" : "/",
00307 oneFile);
00308 if (*dirEntry != '\0' && !stat(dirEntry, &stBuf));
00309 {
00310 if (S_ISREG(stBuf.st_mode) || S_ISLNK(stBuf.st_mode))
00311 {
00312 (*pFn_DSDS_read_fitsheader)(dirEntry,
00313 &kl,
00314 &seg,
00315 kLocalSegName,
00316 &dsdsStat);
00317
00318 if (dsdsStat == kDSDS_Stat_Success)
00319 {
00320
00321
00322
00323 if (kl == NULL)
00324 {
00325
00326 fitshead = 0;
00327 break;
00328 }
00329 else
00330 {
00331 (*klarrout)[iRec] = kl;
00332 (*pFn_DSDS_steal_seginfo)(&((*segarrout)[iRec]), seg);
00333
00334
00335 snprintf((*segarrout)[iRec].filename,
00336 DRMS_MAXSEGFILENAME,
00337 "%s",
00338 dirEntry);
00339 (*pFn_DSDS_free_seg)(&seg);
00340 iRec++;
00341 }
00342 }
00343 else
00344 {
00345 fitshead = 0;
00346 break;
00347 }
00348 }
00349 }
00350
00351 free(entry);
00352 }
00353
00354 fileIndex++;
00355 }
00356
00357 if (nRecsout)
00358 {
00359 *nRecsout = iRec;
00360 }
00361
00362 free(fileList);
00363 }
00364 }
00365
00366 isLocSpec = fitshead;
00367 }
00368 }
00369 }
00370 }
00371
00372
00373 if (recSetSpec)
00374 {
00375 free(recSetSpec);
00376 }
00377
00378 if (status)
00379 {
00380 *status = lstat;
00381 }
00382
00383 return isLocSpec;
00384 }
00385
00386 static void AddLocalPrimekey(DRMS_Record_t *template, int *status)
00387 {
00388 int stat = DRMS_SUCCESS;
00389 char drmsKeyName[DRMS_MAXKEYNAMELEN];
00390 DRMS_Keyword_t *tKey = NULL;
00391
00392 snprintf(drmsKeyName, sizeof(drmsKeyName), kLocalPrimekey);
00393
00394
00395 tKey = hcon_allocslot_lower(&(template->keywords), drmsKeyName);
00396 XASSERT(tKey);
00397 memset(tKey, 0, sizeof(DRMS_Keyword_t));
00398 tKey->info = malloc(sizeof(DRMS_KeywordInfo_t));
00399 XASSERT(tKey->info);
00400 memset(tKey->info, 0, sizeof(DRMS_KeywordInfo_t));
00401
00402 if (tKey && tKey->info)
00403 {
00404
00405 tKey->record = template;
00406
00407
00408
00409
00410 snprintf(tKey->info->name,
00411 DRMS_MAXKEYNAMELEN,
00412 "%s",
00413 drmsKeyName);
00414
00415 tKey->info->type = DRMS_TYPE_LONGLONG;
00416 strcpy(tKey->info->format, "%lld");
00417
00418
00419 drms_missing(tKey->info->type, &(tKey->value));
00420 }
00421 else
00422 {
00423 stat = DRMS_ERROR_OUTOFMEMORY;
00424 }
00425
00426 if (status)
00427 {
00428 *status = stat;
00429 }
00430 }
00431
00432 static int IsWS(const char *str)
00433 {
00434 int ret = 1;
00435 char *lasts;
00436 char *buf = strdup(str);
00437
00438 if (strtok_r(buf, " \t\b", &lasts))
00439 {
00440 ret = 0;
00441 }
00442
00443 free(buf);
00444
00445 return ret;
00446 }
00447
00448 static int CreateRecordProtoFromFitsAgg(DRMS_Env_t *env,
00449 DSDS_KeyList_t **keylistarr,
00450 DRMS_Segment_t *segarr,
00451 int nRecs,
00452 char **pkeyarr,
00453 int nPKeys,
00454 Exputl_KeyMapClass_t fitsclass,
00455 DRMS_Record_t **proto,
00456 DRMS_Segment_t **segout,
00457 int *status)
00458 {
00459 DRMS_Record_t *template = NULL;
00460 DRMS_Segment_t *seg = NULL;
00461 int iRec = 0;
00462 int stat = DRMS_SUCCESS;
00463 int pkeysSpecified = (pkeyarr != NULL);
00464
00465 if (stat == DRMS_SUCCESS)
00466 {
00467 template = calloc(1, sizeof(DRMS_Record_t));
00468 XASSERT(template);
00469 template->seriesinfo = calloc(1, sizeof(DRMS_SeriesInfo_t));
00470 XASSERT(template->seriesinfo);
00471 template->seriesinfo->hasshadow = -1;
00472 template->seriesinfo->createshadow = 0;
00473 }
00474
00475 if (template && template->seriesinfo)
00476 {
00477 char drmsKeyName[DRMS_MAXKEYNAMELEN];
00478 DRMS_Keyword_t *sKey = NULL;
00479 DRMS_Keyword_t *tKey = NULL;
00480
00481 template->env = env;
00482 template->init = 1;
00483 template->recnum = 0;
00484 template->sunum = -1;
00485 template->sessionid = 0;
00486 template->sessionns = NULL;
00487 template->su = NULL;
00488
00489
00490 hcon_init(&template->segments, sizeof(DRMS_Segment_t), DRMS_MAXHASHKEYLEN,
00491 (void (*)(const void *)) drms_free_segment_struct,
00492 (void (*)(const void *, const void *)) drms_copy_segment_struct);
00493
00494 hcon_init(&template->links, sizeof(DRMS_Link_t), DRMS_MAXHASHKEYLEN,
00495 (void (*)(const void *)) drms_free_link_struct,
00496 (void (*)(const void *, const void *)) drms_copy_link_struct);
00497
00498 hcon_init(&template->keywords, sizeof(DRMS_Keyword_t), DRMS_MAXHASHKEYLEN,
00499 (void (*)(const void *)) drms_free_keyword_struct,
00500 (void (*)(const void *, const void *)) drms_copy_keyword_struct);
00501
00502
00503
00504 for (iRec = 0; iRec < nRecs; iRec++)
00505 {
00506
00507 DSDS_KeyList_t *kl = keylistarr[iRec];
00508 DRMS_Segment_t *oneSeg = NULL;
00509
00510 if (segarr)
00511 {
00512 oneSeg = &(segarr[iRec]);
00513 }
00514
00515 if (kl)
00516 {
00517 while (kl != NULL && ((sKey = kl->elem) != NULL))
00518 {
00519
00520
00521
00522 if (sKey->info->type == DRMS_TYPE_STRING &&
00523 (sKey->value.string_val == NULL ||
00524 IsWS(sKey->value.string_val)))
00525 {
00526 kl = kl->next;
00527 continue;
00528 }
00529
00530
00531 if (!fitsexport_getmappedintkeyname(sKey->info->name,
00532 exputl_keymap_getclname(fitsclass),
00533 NULL,
00534 drmsKeyName,
00535 sizeof(drmsKeyName)))
00536 {
00537 *drmsKeyName = '\0';
00538 stat = DRMS_ERROR_INVALIDDATA;
00539 break;
00540 }
00541
00542 if (!(tKey = hcon_lookup_lower(&(template->keywords), drmsKeyName)))
00543 {
00544
00545 tKey = hcon_allocslot_lower(&(template->keywords), drmsKeyName);
00546 XASSERT(tKey);
00547 memset(tKey, 0, sizeof(DRMS_Keyword_t));
00548 tKey->info = malloc(sizeof(DRMS_KeywordInfo_t));
00549 XASSERT(tKey->info);
00550 memset(tKey->info, 0, sizeof(DRMS_KeywordInfo_t));
00551
00552 if (tKey && tKey->info)
00553 {
00554
00555 tKey->record = template;
00556
00557
00558 memcpy(tKey->info, sKey->info, sizeof(DRMS_KeywordInfo_t));
00559 snprintf(tKey->info->name,
00560 DRMS_MAXKEYNAMELEN,
00561 "%s",
00562 drmsKeyName);
00563
00564
00565 drms_missing(tKey->info->type, &(tKey->value));
00566 }
00567 else
00568 {
00569 stat = DRMS_ERROR_OUTOFMEMORY;
00570 }
00571 }
00572 else if (sKey->info->type != tKey->info->type &&
00573 tKey->info->type != DRMS_TYPE_STRING)
00574 {
00575
00576
00577
00578
00579
00580 if (sKey->info->type != DRMS_TYPE_STRING ||
00581 (sKey->value.string_val != NULL &&
00582 !IsWS(sKey->value.string_val)))
00583 {
00584 tKey->info->type = DRMS_TYPE_STRING;
00585 tKey->info->format[0] = '%';
00586 tKey->info->format[1] = 's';
00587 tKey->info->format[2] = '\0';
00588
00589
00590 tKey->value.string_val = NULL;
00591 drms_missing(DRMS_TYPE_STRING, &(tKey->value));
00592 }
00593 }
00594
00595 kl = kl->next;
00596 }
00597
00598 if (stat == DRMS_SUCCESS)
00599 {
00600
00601
00602
00603 if (oneSeg && oneSeg->info)
00604 {
00605 if (!seg)
00606 {
00607 seg = oneSeg;
00608 }
00609 else if (!drms_segment_segsmatch(seg, oneSeg))
00610 {
00611 stat = DRMS_ERROR_INVALIDDATA;
00612 }
00613 }
00614 }
00615 }
00616 }
00617
00618
00619
00620 if (fitsclass == kKEYMAPCLASS_LOCAL)
00621 {
00622 if (!pkeysSpecified)
00623 {
00624 AddLocalPrimekey(template, &stat);
00625 }
00626 else
00627 {
00628
00629
00630 int iKey;
00631 for (iKey = 0; iKey < nPKeys && stat == DRMS_SUCCESS; iKey++)
00632 {
00633 if (!hcon_member_lower(&(template->keywords), pkeyarr[iKey]))
00634 {
00635 if (strcasecmp(pkeyarr[iKey], kLocalPrimekey) == 0)
00636 {
00637
00638
00639
00640
00641 AddLocalPrimekey(template, &stat);
00642 }
00643 else
00644 {
00645
00646
00647 stat = DRMS_ERROR_INVALIDDATA;
00648 fprintf(stderr,
00649 "keyword %s doesn't exist in fits file header\n",
00650 pkeyarr[iKey]);
00651 }
00652 }
00653 }
00654 }
00655 }
00656 }
00657
00658 if (status)
00659 {
00660 *status = stat;
00661 }
00662
00663 if (stat == DRMS_SUCCESS)
00664 {
00665 *proto = template;
00666 *segout = seg;
00667 }
00668 else
00669 {
00670 drms_destroy_recproto(&template);
00671 }
00672
00673 return iRec;
00674 }
00675
00676 static void AdjustRecordProtoSeriesInfo(DRMS_Env_t *env,
00677 DRMS_Record_t *proto,
00678 const char *seriesName,
00679 unsigned int unitsize)
00680 {
00681
00682 char *user = getenv("USER");
00683 snprintf(proto->seriesinfo->seriesname,
00684 DRMS_MAXSERIESNAMELEN,
00685 "%s",
00686 seriesName);
00687
00688 strcpy(proto->seriesinfo->author, "unknown");
00689 strcpy(proto->seriesinfo->owner, "unknown");
00690
00691 if (user)
00692 {
00693 if (strlen(user) < DRMS_MAXCOMMENTLEN)
00694 {
00695 strcpy(proto->seriesinfo->author, user);
00696 }
00697
00698 if (strlen(user) < DRMS_MAXOWNERLEN)
00699 {
00700 strcpy(proto->seriesinfo->owner, user);
00701 }
00702 }
00703
00704
00705 if (env->session->db_direct)
00706 {
00707 strcpy(proto->seriesinfo->owner, env->session->db_handle->dbuser);
00708 }
00709
00710 if (unitsize > 0)
00711 {
00712 proto->seriesinfo->unitsize = unitsize;
00713 }
00714 else
00715 {
00716 fprintf(stderr,
00717 "The series unit size must be at least 1, but it is %ud.\n",
00718 unitsize);
00719 }
00720 }
00721
00722 static void AllocRecordProtoSeg(DRMS_Record_t *template, DRMS_Segment_t *seg, int *status)
00723 {
00724 int stat = DRMS_SUCCESS;
00725
00726 if (seg)
00727 {
00728 DRMS_Segment_t *tSeg = NULL;
00729
00730 tSeg = hcon_allocslot_lower(&(template->segments), seg->info->name);
00731 XASSERT(tSeg);
00732 memset(tSeg, 0, sizeof(DRMS_Segment_t));
00733 tSeg->info = malloc(sizeof(DRMS_SegmentInfo_t));
00734 XASSERT(tSeg->info);
00735 memset(tSeg->info, 0, sizeof(DRMS_SegmentInfo_t));
00736
00737 if (tSeg && tSeg->info)
00738 {
00739
00740 tSeg->record = template;
00741
00742
00743 memcpy(tSeg->info, seg->info, sizeof(DRMS_SegmentInfo_t));
00744
00745
00746 memcpy(tSeg->axis, seg->axis, sizeof(int) * DRMS_MAXRANK);
00747 }
00748 else
00749 {
00750 stat = DRMS_ERROR_OUTOFMEMORY;
00751 }
00752 }
00753
00754 if (status)
00755 {
00756 *status = stat;
00757 }
00758 }
00759
00760 static void SetRecordProtoPKeys(DRMS_Record_t *template,
00761 char **pkeyarr,
00762 int nkeys,
00763 int *status)
00764 {
00765 int stat = DRMS_SUCCESS;
00766 DRMS_Keyword_t *pkey = NULL;
00767 int ikey = 0;
00768
00769 for (; ikey < nkeys; ikey++)
00770 {
00771 pkey = hcon_lookup_lower(&(template->keywords), pkeyarr[ikey]);
00772 if (pkey != NULL)
00773 {
00774 template->seriesinfo->pidx_keywords[ikey] = pkey;
00775 drms_keyword_setintprime(pkey);
00776 }
00777 else
00778 {
00779 stat = DRMS_ERROR_INVALIDKEYWORD;
00780 break;
00781 }
00782 }
00783
00784 template->seriesinfo->pidx_num = ikey;
00785
00786 if (status)
00787 {
00788 *status = stat;
00789 }
00790 }
00791
00792 static DRMS_Record_t *CacheRecordProto(DRMS_Env_t *env,
00793 DRMS_Record_t *proto,
00794 const char *seriesName,
00795 int *status)
00796 {
00797 int stat = DRMS_SUCCESS;
00798 DRMS_Record_t *cached = NULL;
00799
00800
00801
00802 if (drms_template_record(env, seriesName, &stat) != NULL)
00803 {
00804 fprintf(stderr,"drms_open_dsdsrecords(): "
00805 "ERROR: Series '%s' already exists.\n", seriesName);
00806 drms_free_template_record_struct(proto);
00807 stat = DRMS_ERROR_INVALIDDATA;
00808 }
00809 else
00810 {
00811 stat = DRMS_SUCCESS;
00812 cached = (DRMS_Record_t *)hcon_allocslot_lower(&(env->series_cache), seriesName);
00813 drms_copy_record_struct(cached, proto);
00814
00815 for (int i = 0; i < cached->seriesinfo->pidx_num; i++)
00816 {
00817 cached->seriesinfo->pidx_keywords[i] =
00818 drms_keyword_lookup(cached,
00819 proto->seriesinfo->pidx_keywords[i]->info->name,
00820 0);
00821 }
00822
00823 drms_free_record_struct(proto);
00824 free(proto);
00825 }
00826
00827 if (status)
00828 {
00829 *status = stat;
00830 }
00831
00832 return cached;
00833 }
00834
00835 static DRMS_RecordSet_t *CreateRecordsFromDSDSKeylist(DRMS_Env_t *env,
00836 int nRecs,
00837 DRMS_Record_t *cached,
00838 DSDS_KeyList_t **klarr,
00839 DRMS_Segment_t *segarr,
00840 int setPrimeKey,
00841 Exputl_KeyMapClass_t fitsclass,
00842 int *status)
00843 {
00844 int stat = DRMS_SUCCESS;
00845 int iRec;
00846 DRMS_RecordSet_t *rset = (DRMS_RecordSet_t *)malloc(sizeof(DRMS_RecordSet_t));
00847 rset->n = nRecs;
00848 rset->records = (DRMS_Record_t **)malloc(sizeof(DRMS_Record_t *) * nRecs);
00849 memset(rset->records, 0, sizeof(DRMS_Record_t *) * nRecs);
00850 rset->ss_n = 0;
00851 rset->ss_queries = NULL;
00852 rset->ss_types = NULL;
00853 rset->ss_starts = NULL;
00854 rset->ss_currentrecs = NULL;
00855 rset->cursor = NULL;
00856 rset->env = env;
00857
00858 int iNewRec = 1;
00859 int primekeyCnt = 0;
00860
00861 DSDS_KeyList_t *kl = NULL;
00862 DRMS_Segment_t *sSeg = NULL;
00863 DRMS_Segment_t *tSeg = NULL;
00864
00865 for (iRec = 0; stat == DRMS_SUCCESS && iRec < nRecs; iRec++)
00866 {
00867 kl = klarr[iRec];
00868 if (segarr)
00869 {
00870 sSeg = &(segarr[iRec]);
00871 }
00872
00873 tSeg = NULL;
00874
00875 if (kl)
00876 {
00877 rset->records[iRec] = drms_alloc_record2(cached, iNewRec, &stat);
00878 if (stat == DRMS_SUCCESS)
00879 {
00880 rset->records[iRec]->sessionid = env->session->sessionid;
00881 rset->records[iRec]->sessionns = strdup(env->session->sessionns);
00882 rset->records[iRec]->lifetime = DRMS_TRANSIENT;
00883 }
00884
00885
00886
00887 DRMS_Keyword_t *sKey = NULL;
00888 char drmsKeyName[DRMS_MAXKEYNAMELEN];
00889 int iKey = 0;
00890
00891 while (stat == DRMS_SUCCESS && kl && ((sKey = kl->elem) != NULL))
00892 {
00893 if (!fitsexport_getmappedintkeyname(sKey->info->name,
00894 exputl_keymap_getclname(fitsclass),
00895 NULL,
00896 drmsKeyName,
00897 sizeof(drmsKeyName)))
00898 {
00899 *drmsKeyName = '\0';
00900 stat = DRMS_ERROR_INVALIDDATA;
00901 break;
00902 }
00903
00904
00905
00906
00907 if (sKey->info->type != DRMS_TYPE_STRING ||
00908 (sKey->value.string_val != NULL &&
00909 !IsWS(sKey->value.string_val)))
00910 {
00911 stat = drms_setkey(rset->records[iRec],
00912 drmsKeyName,
00913 sKey->info->type,
00914 &(sKey->value));
00915
00916 if (stat != DRMS_SUCCESS)
00917 {
00918 fprintf(stderr, "Couldn't set keyword '%s'.\n", drmsKeyName);
00919 }
00920 }
00921
00922 kl = kl->next;
00923 iKey++;
00924 }
00925
00926 if (fitsclass == kKEYMAPCLASS_LOCAL)
00927 {
00928
00929 if (setPrimeKey)
00930 {
00931 stat = drms_setkey_longlong(rset->records[iRec],
00932 kLocalPrimekey,
00933 primekeyCnt);
00934 primekeyCnt++;
00935 }
00936
00937
00938 tSeg = hcon_lookup_lower(&(rset->records[iRec]->segments), kLocalSegName);
00939 }
00940 else if (fitsclass == kKEYMAPCLASS_DSDS)
00941 {
00942 tSeg = drms_segment_lookupnum(rset->records[iRec], 0);
00943 }
00944
00945 if (tSeg != NULL)
00946 {
00947 if (sSeg && sSeg->info)
00948 {
00949
00950
00951
00952
00953 snprintf(tSeg->filename, DRMS_MAXSEGFILENAME, "%s", sSeg->filename);
00954 }
00955 }
00956 else
00957 {
00958
00959 }
00960
00961 rset->records[iRec]->readonly = 1;
00962 iNewRec++;
00963 }
00964 }
00965
00966 if (status)
00967 {
00968 *status = stat;
00969 }
00970
00971 return rset;
00972 }
00973
00974 static DRMS_RecordSet_t *OpenPlainFileRecords(DRMS_Env_t *env,
00975 DSDS_KeyList_t ***klarr,
00976 DRMS_Segment_t **segarr,
00977 int nRecs,
00978 char **pkeys,
00979 int *status)
00980 {
00981 DRMS_RecordSet_t *rset = NULL;
00982 int stat = DRMS_SUCCESS;
00983
00984 if (!gAttemptedDSDS && !ghDSDS)
00985 {
00986 kDSDS_Stat_t dsdsstat;
00987 ghDSDS = DSDS_GetLibHandle(kLIBDSDS, &dsdsstat);
00988 if (dsdsstat != kDSDS_Stat_Success)
00989 {
00990 stat = DRMS_ERROR_CANTOPENLIBRARY;
00991 }
00992
00993 gAttemptedDSDS = 1;
00994 }
00995
00996 if (stat == DRMS_SUCCESS && ghDSDS)
00997 {
00998 pDSDSFn_DSDS_free_keylistarr_t pFn_DSDS_free_keylistarr =
00999 (pDSDSFn_DSDS_free_keylistarr_t)DSDS_GetFPtr(ghDSDS, kDSDS_DSDS_FREE_KEYLISTARR);
01000
01001 if (pFn_DSDS_free_keylistarr)
01002 {
01003 char seriesName[DRMS_MAXSERIESNAMELEN];
01004 int nPkeys = 0;
01005
01006
01007 DRMS_Record_t *proto = NULL;
01008 DRMS_Segment_t *seg = NULL;
01009 DRMS_Record_t *cached = NULL;
01010
01011
01012 Exputl_KeyMapClass_t fitsclass = kKEYMAPCLASS_LOCAL;
01013 char drmsKeyName[DRMS_MAXKEYNAMELEN];
01014 char *pkeyarr[DRMS_MAXPRIMIDX] = {0};
01015 int setPrimeKey = 0;
01016
01017 if (pkeys && *pkeys)
01018 {
01019 char *pkeyname = strtok(*pkeys, ",");
01020 nPkeys = 0;
01021 while(pkeyname != NULL)
01022 {
01023 if (!fitsexport_getmappedintkeyname(pkeyname,
01024 exputl_keymap_getclname(fitsclass),
01025 NULL,
01026 drmsKeyName,
01027 sizeof(drmsKeyName)))
01028 {
01029 *drmsKeyName = '\0';
01030 stat = DRMS_ERROR_INVALIDDATA;
01031 break;
01032 }
01033
01034 if (strcasecmp(drmsKeyName, kLocalPrimekey) == 0)
01035 {
01036 setPrimeKey = 1;
01037 }
01038
01039 pkeyname = strtok(NULL, ",");
01040 pkeyarr[nPkeys] = strdup(drmsKeyName);
01041 nPkeys++;
01042 }
01043 }
01044 else
01045 {
01046 pkeyarr[0] = strdup(kLocalPrimekey);
01047 nPkeys = 1;
01048 setPrimeKey = 1;
01049 }
01050
01051 if (stat == DRMS_SUCCESS)
01052 {
01053 CreateRecordProtoFromFitsAgg(env,
01054 *klarr,
01055 *segarr,
01056 nRecs,
01057 pkeyarr,
01058 nPkeys,
01059 kKEYMAPCLASS_LOCAL,
01060 &proto,
01061 &seg,
01062 &stat);
01063 }
01064
01065 if (stat == DRMS_SUCCESS)
01066 {
01067
01068
01069
01070
01071
01072 long long guid = -1;
01073 const char *dsdsNsPrefix = NULL;
01074
01075
01076
01077
01078 dsdsNsPrefix = DSDS_GetNsPrefix();
01079
01080 #ifdef DRMS_CLIENT
01081 drms_send_commandcode(env->session->sockfd, DRMS_GETTMPGUID);
01082 guid = Readlonglong(env->session->sockfd);
01083 #else
01084
01085 guid = drms_server_gettmpguid(NULL);
01086 #endif
01087
01088 snprintf(seriesName, sizeof(seriesName), "%s.%lld", dsdsNsPrefix, guid);
01089
01090
01091 AdjustRecordProtoSeriesInfo(env, proto, seriesName, 32);
01092
01093
01094 if (seg)
01095 {
01096
01097 AllocRecordProtoSeg(proto, seg, &stat);
01098 }
01099 }
01100
01101 if (stat == DRMS_SUCCESS)
01102 {
01103
01104 SetRecordProtoPKeys(proto, pkeyarr, nPkeys, &stat);
01105 }
01106
01107 if (stat == DRMS_SUCCESS)
01108 {
01109
01110 cached = CacheRecordProto(env, proto, seriesName, &stat);
01111
01112
01113 }
01114
01115
01116 if (stat == DRMS_SUCCESS)
01117 {
01118 rset = CreateRecordsFromDSDSKeylist(env,
01119 nRecs,
01120 cached,
01121 *klarr,
01122 *segarr,
01123 setPrimeKey,
01124 kKEYMAPCLASS_LOCAL,
01125 &stat);
01126 }
01127
01128
01129 (*pFn_DSDS_free_keylistarr)(klarr, nRecs);
01130
01131
01132 if (segarr && *segarr)
01133 {
01134 int i;
01135 for (i = 0; i < nRecs; i++)
01136 {
01137 seg = (*segarr + i);
01138
01139
01140 if (seg->info)
01141 {
01142 free(seg->info);
01143 }
01144 }
01145
01146 free(*segarr);
01147 *segarr = NULL;
01148 }
01149
01150
01151 if (pkeys && *pkeys)
01152 {
01153 free(*pkeys);
01154 *pkeys = NULL;
01155 }
01156
01157 for (nPkeys = 0; nPkeys < DRMS_MAXPRIMIDX; nPkeys++)
01158 if (pkeyarr[nPkeys])
01159 {
01160 free(pkeyarr[nPkeys]);
01161 }
01162 }
01163 }
01164 else
01165 {
01166 fprintf(stdout, "Your JSOC environment does not support DSDS database access.\n");
01167 stat = DRMS_ERROR_NODSDSSUPPORT;
01168 }
01169
01170 if (status)
01171 {
01172 *status = stat;
01173 }
01174
01175
01176
01177 return rset;
01178 }
01179
01180
01181 static void RSFree(const void *val)
01182 {
01183 DRMS_RecordSet_t **realPtr = (DRMS_RecordSet_t **)val;
01184 DRMS_RecordSet_t *theRS = NULL;
01185
01186 if (realPtr)
01187 {
01188 theRS = *realPtr;
01189 if (theRS)
01190 {
01191 drms_close_records(theRS, DRMS_FREE_RECORD);
01192
01193 }
01194 }
01195 }
01196
01197 static int linkListSort(const void *he1, const void *he2)
01198 {
01199 DRMS_Link_t **pl1 = (DRMS_Link_t **)hcon_getval(*((HContainerElement_t **)he1));
01200 DRMS_Link_t **pl2 = (DRMS_Link_t **)hcon_getval(*((HContainerElement_t **)he2));
01201
01202 XASSERT(pl1 && pl2);
01203
01204 DRMS_Link_t *l1 = *pl1;
01205 DRMS_Link_t *l2 = *pl2;
01206
01207 XASSERT(l1 && l2);
01208
01209 return (l1->info->rank < l2->info->rank) ? -1 : (l1->info->rank > l2->info->rank ? 1 : 0);
01210 }
01211
01212 static int keyListSort(const void *he1, const void *he2)
01213 {
01214 DRMS_Keyword_t **pk1 = (DRMS_Keyword_t **)hcon_getval(*((HContainerElement_t **)he1));
01215 DRMS_Keyword_t **pk2 = (DRMS_Keyword_t **)hcon_getval(*((HContainerElement_t **)he2));
01216
01217 XASSERT(pk1 && pk2);
01218
01219 DRMS_Keyword_t *k1 = *pk1;
01220 DRMS_Keyword_t *k2 = *pk2;
01221
01222 XASSERT(k1 && k2);
01223
01224 return (k1->info->rank < k2->info->rank) ? -1 : (k1->info->rank > k2->info->rank ? 1 : 0);
01225 }
01226
01227 static int segListSort(const void *he1, const void *he2)
01228 {
01229 DRMS_Segment_t **ps1 = (DRMS_Segment_t **)hcon_getval(*((HContainerElement_t **)he1));
01230 DRMS_Segment_t **ps2 = (DRMS_Segment_t **)hcon_getval(*((HContainerElement_t **)he2));
01231
01232 XASSERT(ps1 && ps2);
01233
01234 DRMS_Segment_t *s1 = *ps1;
01235 DRMS_Segment_t *s2 = *ps2;
01236
01237 XASSERT(s1 && s2);
01238
01239 return (s1->info->segnum < s2->info->segnum) ? -1 : (s1->info->segnum > s2->info->segnum ? 1 : 0);
01240 }
01241
01242
01243
01244 DRMS_RecordSet_t *drms_open_localrecords(DRMS_Env_t *env, const char *dsRecSet, int *status)
01245 {
01246 DRMS_RecordSet_t *rs = NULL;
01247 int stat = DRMS_SUCCESS;
01248 DSDS_KeyList_t **klarr = NULL;
01249 DRMS_Segment_t *segarr = NULL;
01250 int nRecsLocal = 0;
01251 char *pkeys = NULL;
01252
01253 if (IsValidPlainFileSpec(dsRecSet, &klarr, &segarr, &nRecsLocal, &pkeys, &stat))
01254 {
01255 rs = OpenPlainFileRecords(env, &klarr, &segarr, nRecsLocal, &pkeys, &stat);
01256 }
01257
01258 if (status)
01259 {
01260 *status = stat;
01261 }
01262
01263 return rs;
01264 }
01265
01266
01267 DRMS_RecordSet_t *drms_open_dsdsrecords(DRMS_Env_t *env, const char *dsRecSet, int *status)
01268 {
01269 DRMS_RecordSet_t *rset = NULL;
01270 int stat = DRMS_SUCCESS;
01271
01272 if (!gAttemptedDSDS && !ghDSDS)
01273 {
01274
01275 kDSDS_Stat_t dsdsstat;
01276 ghDSDS = DSDS_GetLibHandle(kLIBDSDS, &dsdsstat);
01277 if (dsdsstat != kDSDS_Stat_Success)
01278 {
01279 stat = DRMS_ERROR_CANTOPENLIBRARY;
01280 }
01281
01282 gAttemptedDSDS = 1;
01283 }
01284
01285 if (stat == DRMS_SUCCESS && ghDSDS)
01286 {
01287 pDSDSFn_DSDS_open_records_t pFn_DSDS_open_records =
01288 (pDSDSFn_DSDS_open_records_t)DSDS_GetFPtr(ghDSDS, kDSDS_DSDS_OPEN_RECORDS);
01289 pDSDSFn_DSDS_free_keylistarr_t pFn_DSDS_free_keylistarr =
01290 (pDSDSFn_DSDS_free_keylistarr_t)DSDS_GetFPtr(ghDSDS, kDSDS_DSDS_FREE_KEYLISTARR);
01291 pDSDSFn_DSDS_free_segarr_t pFn_DSDS_free_segarr =
01292 (pDSDSFn_DSDS_free_segarr_t)DSDS_GetFPtr(ghDSDS, kDSDS_DSDS_FREE_SEGARR);
01293
01294 if (pFn_DSDS_open_records && pFn_DSDS_free_keylistarr && pFn_DSDS_free_segarr)
01295 {
01296 char seriesName[DRMS_MAXSERIESNAMELEN];
01297 DSDS_Handle_t hparams;
01298 DSDS_KeyList_t **keylistarr;
01299 DRMS_Segment_t *segarr;
01300 kDSDS_Stat_t dsdsStat;
01301 long long nRecs = 0;
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313 nRecs = (*pFn_DSDS_open_records)(dsRecSet,
01314 seriesName,
01315 &hparams,
01316 &keylistarr,
01317 &segarr,
01318 &dsdsStat);
01319 if (dsdsStat == kDSDS_Stat_Success)
01320 {
01321
01322 DRMS_Record_t *template = NULL;
01323 DRMS_Segment_t *seg = NULL;
01324 DRMS_Record_t *cached = NULL;
01325
01326 CreateRecordProtoFromFitsAgg(env,
01327 keylistarr,
01328 segarr,
01329 nRecs,
01330 NULL,
01331 0,
01332 kKEYMAPCLASS_DSDS,
01333 &template,
01334 &seg,
01335 &stat);
01336
01337 if (stat == DRMS_SUCCESS)
01338 {
01339
01340 AdjustRecordProtoSeriesInfo(env, template, seriesName, 32);
01341 DSDS_SetDSDSParams(ghDSDS, template->seriesinfo, hparams);
01342
01343
01344 if (seg)
01345 {
01346
01347 AllocRecordProtoSeg(template, seg, &stat);
01348 }
01349 }
01350
01351 if (stat == DRMS_SUCCESS)
01352 {
01353
01354 char *pkeyarr[2] = {kDSDS_SERIES_NUM, kDSDS_RN};
01355 SetRecordProtoPKeys(template, pkeyarr, 2, &stat);
01356 }
01357
01358 if (stat == DRMS_SUCCESS)
01359 {
01360
01361 cached = CacheRecordProto(env, template, seriesName, &stat);
01362 }
01363
01364
01365 rset = CreateRecordsFromDSDSKeylist(env,
01366 nRecs,
01367 cached,
01368 keylistarr,
01369 segarr,
01370 0,
01371 kKEYMAPCLASS_DSDS,
01372 &stat);
01373
01374
01375 (*pFn_DSDS_free_keylistarr)(&keylistarr, nRecs);
01376
01377 if (segarr)
01378 {
01379 (*pFn_DSDS_free_segarr)(&segarr, nRecs);
01380 }
01381 }
01382 else
01383 {
01384 stat = DRMS_ERROR_LIBDSDS;
01385
01386 if (dsdsStat == kDSDS_Stat_DSDSOffline)
01387 {
01388 stat = DRMS_ERROR_DSDSOFFLINE;
01389 }
01390 }
01391 }
01392 }
01393 else
01394 {
01395 fprintf(stdout, "Your JSOC environment does not support DSDS database access.\n");
01396 stat = DRMS_ERROR_NODSDSSUPPORT;
01397 }
01398
01399 if (status)
01400 {
01401 *status = stat;
01402 }
01403
01404
01405
01406 return rset;
01407 }
01408
01409 static void QFree(void *data)
01410 {
01411 char **realdata = (char **)data;
01412 if (realdata)
01413 {
01414 free(*realdata);
01415 }
01416 }
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430 DRMS_RecordSet_t *drms_open_records_internal(DRMS_Env_t *env,
01431 const char *recordsetname,
01432 int retrieverecs,
01433 LinkedList_t **llistout,
01434 char **allversout,
01435 int **hasshadowout,
01436 int nrecslimit,
01437 int *status)
01438 {
01439 DRMS_RecordSet_t *rs = NULL;
01440 DRMS_RecordSet_t *ret = NULL;
01441 int i, filter, mixed;
01442 int recnumq;
01443 HContainer_t *firstlast = NULL;
01444 char *query=0, *seriesname=0;
01445 char *pkwhere = NULL;
01446 char *npkwhere = NULL;
01447 HContainer_t *pkwhereNFL = NULL;
01448 HContainer_t *realSets = NULL;
01449 int nRecs = 0;
01450 int j = 0;
01451 char buf[64];
01452 DSDS_KeyList_t **klarr = NULL;
01453 DRMS_Segment_t *segarr = NULL;
01454 int nRecsLocal = 0;
01455 char *pkeys = NULL;
01456 char *seglist = NULL;
01457 char *actualSet = NULL;
01458 char *psl = NULL;
01459 char *lasts = NULL;
01460 char *ans = NULL;
01461 HContainer_t *goodsegcont = NULL;
01462 DB_Text_Result_t *tres = NULL;
01463 int cursor = 0;
01464
01465 int (*filestat)(const char *, struct stat *buf) = stat;
01466
01467 int stat = DRMS_SUCCESS;
01468
01469
01470 LinkedList_t *llist = NULL;
01471
01472
01473 LinkedList_t *klist = NULL;
01474
01475 cursor = (!retrieverecs);
01476 if (llistout)
01477 {
01478 if (*llistout)
01479 {
01480
01481
01482
01483 klist = *llistout;
01484 }
01485 else
01486 {
01487
01488 llist = list_llcreate(sizeof(char *), QFree);
01489 *llistout = llist;
01490 }
01491 }
01492
01493
01494
01495
01496 char **sets = NULL;
01497 DRMS_RecordSetType_t *settypes = NULL;
01498 char **snames = NULL;
01499 char **filts = NULL;
01500 int *setstarts = NULL;
01501
01502 int nsets = 0;
01503 char *allvers = NULL;
01504
01505
01506 DRMS_RecQueryInfo_t rsinfo;
01507 stat = ParseRecSetDesc(recordsetname, &allvers, &sets, &settypes, &snames, &filts, &nsets, &rsinfo);
01508
01509 if (stat == DRMS_SUCCESS)
01510 {
01511 int iSet;
01512
01513 if (nsets > 0)
01514 {
01515 if (allversout)
01516 {
01517 *allversout = strdup(allvers);
01518 }
01519 }
01520
01521 CHECKNULL_STAT(env,status);
01522
01523 if (nsets > 0)
01524 {
01525 setstarts = (int *)malloc(sizeof(int) * nsets);
01526 }
01527
01528 for (iSet = 0; stat == DRMS_SUCCESS && iSet < nsets; iSet++)
01529 {
01530 char *oneSet = sets[iSet];
01531
01532 if (oneSet && strlen(oneSet) > 0)
01533 {
01534 if (settypes[iSet] == kRecordSetType_PlainFile)
01535 {
01536 char pbuf[DRMS_MAXPATHLEN];
01537 struct stat stBuf;
01538 int foundOV = 0;
01539
01540 #if !defined(DSDS_SUPPORT) || !DSDS_SUPPORT
01541 stat = DRMS_ERROR_NODSDSSUPPORT;
01542 goto failure;
01543 #endif
01544
01545 if (!(*filestat)(oneSet, &stBuf) && S_ISDIR(stBuf.st_mode))
01546 {
01547
01548 snprintf(pbuf, sizeof(pbuf), "%s", oneSet);
01549
01550 if (oneSet[strlen(oneSet) - 1] == '/')
01551 {
01552 snprintf(pbuf, sizeof(pbuf), "%s", oneSet);
01553 }
01554 else
01555 {
01556 snprintf(pbuf, sizeof(pbuf), "%s/", oneSet);
01557 }
01558
01559
01560
01561
01562 struct dirent **fileList = NULL;
01563 int nFiles = -1;
01564
01565 if ((nFiles = scandir(pbuf, &fileList, NULL, NULL)) > 0 &&
01566 fileList != NULL)
01567 {
01568 int fileIndex = 0;
01569
01570 while (fileIndex < nFiles)
01571 {
01572 struct dirent *entry = fileList[fileIndex];
01573 if (entry != NULL)
01574 {
01575 char *oneFile = entry->d_name;
01576 char dirEntry[PATH_MAX] = {0};
01577 snprintf(dirEntry,
01578 sizeof(dirEntry),
01579 "%s%s",
01580 pbuf,
01581 oneFile);
01582 if (*dirEntry != '\0' &&
01583 !(*filestat)(dirEntry, &stBuf) &&
01584 S_ISREG(stBuf.st_mode))
01585 {
01586
01587
01588 if (strstr(dirEntry, kOverviewFits))
01589 {
01590 foundOV = 1;
01591 break;
01592 }
01593 }
01594
01595 free(entry);
01596 }
01597
01598 fileIndex++;
01599 }
01600
01601 free(fileList);
01602 }
01603 }
01604
01605 if (foundOV)
01606 {
01607 rs = drms_open_dsdsrecords(env, pbuf, &stat);
01608 if (stat)
01609 goto failure;
01610 }
01611 else
01612 {
01613 if (IsValidPlainFileSpec(oneSet, &klarr, &segarr, &nRecsLocal, &pkeys, &stat))
01614 {
01615 rs = OpenPlainFileRecords(env, &klarr, &segarr, nRecsLocal, &pkeys, &stat);
01616 if (stat)
01617 goto failure;
01618 }
01619 else
01620 {
01621 fprintf(stderr, "Invalid plain file record-set specification %s.\n", oneSet);
01622 goto failure;
01623 }
01624 }
01625 }
01626 else if (settypes[iSet] == kRecordSetType_DSDS)
01627 {
01628 #if !defined(DSDS_SUPPORT) || !DSDS_SUPPORT
01629 stat = DRMS_ERROR_NODSDSSUPPORT;
01630 goto failure;
01631 #endif
01632
01633 rs = drms_open_dsdsrecords(env, oneSet, &stat);
01634 if (stat)
01635 {
01636 if (stat == DRMS_ERROR_DSDSOFFLINE)
01637 {
01638 fprintf(stderr,
01639 "Series '{%s}' data files are offline.\nBring them online with \"peq -A \'%s\'\".\n",
01640 oneSet,
01641 oneSet);
01642 }
01643 goto failure;
01644 }
01645 }
01646 else if (settypes[iSet] == kRecordSetType_VOT)
01647 {
01648
01649 fprintf(stderr, "VOT record-set specification not implemented.\n");
01650 }
01651 else if (settypes[iSet] == kRecordSetType_DSDSPort)
01652 {
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665 #if !defined(DSDS_SUPPORT) || !DSDS_SUPPORT
01666 stat = DRMS_ERROR_NODSDSSUPPORT;
01667 goto failure;
01668 #endif
01669
01670 rs = drms_open_dsdsrecords(env, oneSet, &stat);
01671 if (stat)
01672 {
01673 if (stat == DRMS_ERROR_DSDSOFFLINE)
01674 {
01675 fprintf(stderr,
01676 "Series '{%s}' data files are offline.\nBring them online with \"peq -A \'%s\'\".\n",
01677 oneSet,
01678 oneSet);
01679 }
01680 goto failure;
01681 }
01682
01683 }
01684 else if (settypes[iSet] == kRecordSetType_DRMS)
01685 {
01686 HContainer_t *unsorted = NULL;
01687 DRMS_Keyword_t *keyword = NULL;
01688 int iKey;
01689 DRMS_Keyword_t *pkey = NULL;
01690
01691 if (klist)
01692 {
01693
01694
01695
01696
01697
01698
01699
01700 DRMS_Record_t *recTempl = NULL;
01701 ListNode_t *ln = NULL;
01702
01703 recTempl = drms_template_record(env, snames[iSet], &stat);
01704
01705 if (!recTempl)
01706 {
01707 goto failure;
01708 }
01709
01710
01711
01712
01713
01714
01715 for (iKey = 0; iKey < recTempl->seriesinfo->pidx_num; iKey++)
01716 {
01717 if (!unsorted)
01718 {
01719
01720 unsorted = hcon_create(sizeof(DRMS_Keyword_t *), DRMS_MAXKEYNAMELEN, NULL, NULL, NULL, NULL, 0);
01721 }
01722
01723 if (!unsorted)
01724 {
01725 goto failure;
01726 }
01727
01728 pkey = recTempl->seriesinfo->pidx_keywords[iKey];
01729 hcon_insert_lower(unsorted, pkey->info->name, &pkey);
01730
01731 if (drms_keyword_isindex(pkey))
01732 {
01733
01734 pkey = drms_keyword_slotfromindex(pkey);
01735 hcon_insert_lower(unsorted, pkey->info->name, &pkey);
01736 }
01737 }
01738
01739 list_llreset(klist);
01740 while ((ln = (ListNode_t *)(list_llnext(klist))) != NULL)
01741 {
01742 keyword = drms_keyword_lookup(recTempl, (char *)(ln->data), 0);
01743
01744 if (!keyword)
01745 {
01746 continue;
01747 }
01748
01749 if (!hcon_member_lower(unsorted, keyword->info->name))
01750 {
01751 if (!unsorted)
01752 {
01753
01754 unsorted = hcon_create(sizeof(DRMS_Keyword_t *), DRMS_MAXKEYNAMELEN, NULL, NULL, NULL, NULL, 0);
01755 }
01756
01757 if (!unsorted)
01758 {
01759 goto failure;
01760 }
01761
01762 hcon_insert_lower(unsorted, keyword->info->name, &keyword);
01763 }
01764 }
01765 }
01766
01767
01768
01769
01770 actualSet = strdup(oneSet);
01771 if (actualSet)
01772 {
01773 psl = strchr(actualSet, '{');
01774 if (psl)
01775 {
01776 seglist = strdup(psl);
01777 *psl = '\0';
01778 }
01779
01780 TIME(stat = drms_recordset_query(env,
01781 actualSet,
01782 &query,
01783 &pkwhere,
01784 &npkwhere,
01785 &seriesname,
01786 &filter,
01787 &mixed,
01788 NULL,
01789 &firstlast,
01790 &pkwhereNFL,
01791 &recnumq));
01792
01793 if (actualSet)
01794 {
01795 free(actualSet);
01796 actualSet = NULL;
01797 }
01798 }
01799 else
01800 goto failure;
01801
01802 if (stat)
01803 goto failure;
01804
01805 #ifdef DEBUG
01806 printf("seriesname = %s\n",seriesname);
01807 printf("query = %s\n",query);
01808 #else
01809 if (env->verbose)
01810 {
01811 printf("seriesname = %s\n",seriesname);
01812 printf("where clause = %s\n",query);
01813 }
01814 #endif
01815
01816 if (seglist)
01817 {
01818 char aseg[DRMS_MAXSEGNAMELEN];
01819 goodsegcont = hcon_create(DRMS_MAXSEGNAMELEN,
01820 DRMS_MAXSEGNAMELEN,
01821 NULL,
01822 NULL,
01823 NULL,
01824 NULL,
01825 0);
01826
01827 ans = strtok_r(seglist, " ,;:{}", &lasts);
01828
01829 do
01830 {
01831
01832 snprintf(aseg, sizeof(aseg), "%s", ans);
01833 hcon_insert_lower(goodsegcont, aseg, aseg);
01834 }
01835 while ((ans = strtok_r(NULL, " ,;:{}", &lasts)) != NULL);
01836
01837 free(seglist);
01838 seglist = NULL;
01839 }
01840
01841 if (retrieverecs)
01842 {
01843 XASSERT(allvers[iSet] != '\0');
01844 TIME(rs = drms_retrieve_records(env,
01845 seriesname,
01846 query,
01847 pkwhere,
01848 npkwhere,
01849 filter,
01850 mixed,
01851 goodsegcont,
01852 allvers[iSet] == 'y',
01853 nrecslimit,
01854 firstlast,
01855 pkwhereNFL,
01856 recnumq,
01857 1,
01858 NULL,
01859 unsorted,
01860 NULL,
01861 &stat));
01862
01863 }
01864 else
01865 {
01866
01867
01868
01869 rs = (DRMS_RecordSet_t *)malloc(sizeof(DRMS_RecordSet_t));
01870 memset(rs, 0, sizeof(DRMS_RecordSet_t));
01871
01872
01873
01874
01875
01876 rs->records = NULL;
01877 rs->n = -1;
01878
01879
01880 rs->ss_n = 0;
01881 rs->ss_queries = NULL;
01882 rs->ss_types = NULL;
01883 rs->ss_starts = NULL;
01884 rs->ss_currentrecs = NULL;
01885 rs->cursor = NULL;
01886 rs->env = env;
01887 }
01888
01889 if (llist)
01890 {
01891
01892 long long limit = 0;
01893 char *selquery = drms_query_string(env,
01894 seriesname,
01895 query,
01896 pkwhere,
01897 npkwhere,
01898 filter,
01899 mixed,
01900 DRMS_QUERY_ALL,
01901 NULL,
01902 NULL,
01903 allvers[iSet] == 'y',
01904 firstlast,
01905 pkwhereNFL,
01906 recnumq,
01907 cursor,
01908 &limit);
01909 list_llinserttail(llist, &selquery);
01910 }
01911
01912 if (goodsegcont)
01913 {
01914 hcon_destroy(&goodsegcont);
01915 }
01916
01917 #ifdef DEBUG
01918 printf("rs=%p, env=%p, seriesname=%s, filter=%d, stat=%d\n query=%s\n",rs,env,seriesname,filter,stat,query);
01919 #endif
01920 if (stat)
01921 goto failure;
01922
01923
01924
01925 if (hasshadowout)
01926 {
01927 DRMS_Record_t *template = drms_template_record(env, seriesname, &stat);
01928
01929 if (!*hasshadowout)
01930 {
01931 *hasshadowout = malloc(sizeof(int) * nsets);
01932 }
01933
01934 if (!*hasshadowout)
01935 {
01936 goto failure;
01937 }
01938
01939 (*hasshadowout)[iSet] = template->seriesinfo->hasshadow;
01940 }
01941
01942 free(query);
01943 query = NULL;
01944 if (pkwhere) free(pkwhere);
01945 pkwhere = NULL;
01946 if (npkwhere) free(npkwhere);
01947 npkwhere = NULL;
01948 if (pkwhereNFL) hcon_destroy(&pkwhereNFL);
01949 free(seriesname);
01950 seriesname = NULL;
01951
01952
01953 for (i=0; i<rs->n; i++)
01954 {
01955 if (rs->records[i])
01956 {
01957 rs->records[i]->lifetime = DRMS_PERMANENT;
01958 }
01959 }
01960 }
01961 else
01962 {
01963 fprintf(stderr, "Unexpected record-set specification %s.\n", oneSet);
01964 }
01965
01966 if (stat)
01967 {
01968 goto failure;
01969 }
01970
01971 if (nsets == 1)
01972 {
01973
01974 ret = rs;
01975 }
01976 else
01977 {
01978
01979
01980 if (!realSets)
01981 {
01982 realSets = hcon_create(sizeof(DRMS_RecordSet_t *),
01983 64,
01984 NULL,
01985 NULL,
01986 NULL,
01987 NULL,
01988 0);
01989 }
01990
01991
01992 snprintf(buf, sizeof(buf), "%d", iSet);
01993 hcon_insert(realSets, buf, &rs);
01994
01995
01996 if (rs->n > 0)
01997 {
01998 nRecs += rs->n;
01999 }
02000 }
02001
02002 rs = NULL;
02003 }
02004 }
02005
02006
02007 if (!ret)
02008 {
02009 ret = (DRMS_RecordSet_t *)malloc(sizeof(DRMS_RecordSet_t));
02010 if (ret)
02011 {
02012 ret->n = 0;
02013 ret->records = NULL;
02014 ret->ss_n = 0;
02015 ret->ss_queries = NULL;
02016 ret->ss_types = NULL;
02017 ret->ss_starts = NULL;
02018 ret->ss_currentrecs = NULL;
02019 ret->cursor = NULL;
02020 ret->env = env;
02021 }
02022 }
02023
02024 if (ret)
02025 {
02026 if (nsets > 1)
02027 {
02028 if (realSets && realSets->num_total > 0)
02029 {
02030
02031
02032
02033 if (nRecs > 0)
02034 {
02035 ret->records = (DRMS_Record_t **)malloc(sizeof(DRMS_Record_t *) * nRecs);
02036 ret->n = nRecs;
02037
02038
02039 j = 0;
02040 DRMS_RecordSet_t **prs = NULL;
02041 DRMS_RecordSet_t *oners = NULL;
02042
02043 for (iSet = 0; iSet < nsets; iSet++)
02044 {
02045 snprintf(buf, sizeof(buf), "%d", iSet);
02046 if ((prs = hcon_lookup(realSets, buf)) != NULL)
02047 {
02048 oners = *prs;
02049 if (oners)
02050 {
02051 if (oners->n > 0)
02052 {
02053
02054 setstarts[iSet] = j;
02055 }
02056 else
02057 {
02058 setstarts[iSet] = -1;
02059 }
02060
02061
02062 for (i = 0; i < oners->n; i++)
02063 {
02064 ret->records[j] = oners->records[i];
02065 j++;
02066 }
02067 }
02068
02069
02070 free(oners->records);
02071 free(oners);
02072 oners = NULL;
02073 }
02074 else
02075 {
02076 stat = DRMS_ERROR_INVALIDDATA;
02077 goto failure;
02078 }
02079 }
02080 }
02081 else
02082 {
02083
02084 for (iSet = 0; iSet < nsets; iSet++)
02085 {
02086 setstarts[iSet] = -1;
02087 }
02088
02089 ret->n = -1;
02090
02091
02092 }
02093 }
02094 }
02095 else if (nsets > 0)
02096 {
02097
02098 if (ret->n > 0)
02099 {
02100 setstarts[0] = 0;
02101 }
02102 else
02103 {
02104
02105
02106
02107
02108
02109 setstarts[0] = -1;
02110 }
02111 }
02112
02113
02114 ret->ss_n = nsets;
02115 ret->cursor = NULL;
02116
02117 if (nsets > 0)
02118 {
02119
02120
02121 ret->ss_starts = setstarts;
02122 setstarts = NULL;
02123 ret->ss_currentrecs = (int *)malloc(sizeof(int) * nsets);
02124
02125
02126 ret->ss_queries = (char **)malloc(sizeof(char *) * nsets);
02127 ret->ss_types = (DRMS_RecordSetType_t *)malloc(sizeof(DRMS_RecordSetType_t) * nsets);
02128 if (ret->ss_currentrecs && ret->ss_queries && ret->ss_types)
02129 {
02130 for (iSet = 0; iSet < nsets; iSet++)
02131 {
02132 ret->ss_queries[iSet] = strdup(sets[iSet]);
02133 ret->ss_types[iSet] = settypes[iSet];
02134 ret->ss_currentrecs[iSet] = -1;
02135 }
02136 }
02137 else
02138 {
02139 stat = DRMS_ERROR_OUTOFMEMORY;
02140 goto failure;
02141 }
02142 }
02143 }
02144 else
02145 {
02146 stat = DRMS_ERROR_OUTOFMEMORY;
02147 goto failure;
02148 }
02149
02150 if (realSets)
02151 {
02152 hcon_destroy(&realSets);
02153 }
02154
02155 if (setstarts)
02156 {
02157 free(setstarts);
02158 }
02159
02160 FreeRecSetDescArr(&allvers, &sets, &settypes, &snames, &filts, nsets);
02161
02162 if (firstlast)
02163 {
02164 hcon_destroy(&firstlast);
02165 }
02166
02167 if (status)
02168 *status = stat;
02169
02170 return ret;
02171 }
02172
02173 failure:
02174 if (query)
02175 {
02176 free(query);
02177 }
02178
02179 if (pkwhere)
02180 {
02181 free(pkwhere);
02182 }
02183
02184 if (npkwhere)
02185 {
02186 free(npkwhere);
02187 }
02188
02189 if (pkwhereNFL)
02190 {
02191 hcon_destroy(&pkwhereNFL);
02192 }
02193
02194 if (seriesname)
02195 {
02196 free(seriesname);
02197 }
02198
02199 if (setstarts)
02200 {
02201 free(setstarts);
02202 }
02203 if (actualSet)
02204 {
02205 free(actualSet);
02206 }
02207
02208 if (seglist)
02209 {
02210 free(seglist);
02211 }
02212
02213 FreeRecSetDescArr(&allvers, &sets, &settypes, &snames, &filts, nsets);
02214
02215 if (firstlast)
02216 {
02217 hcon_destroy(&firstlast);
02218 }
02219
02220 if (rs)
02221 {
02222 RSFree(&rs);
02223 }
02224
02225 if (ret)
02226 {
02227 RSFree(&ret);
02228 }
02229
02230 if (realSets)
02231 {
02232 hcon_map(realSets, RSFree);
02233 hcon_destroy(&realSets);
02234 }
02235
02236 if (tres)
02237 {
02238 db_free_text_result(tres);
02239 }
02240
02241 if (status)
02242 *status = stat;
02243 return NULL;
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262 }
02263
02264 DRMS_RecordSet_t *drms_open_records(DRMS_Env_t *env, const char *recordsetname,
02265 int *status)
02266 {
02267 char *allvers = NULL;
02268 DRMS_RecordSet_t *ret = NULL;
02269
02270 ret = drms_open_records_internal(env, recordsetname, 1, NULL, &allvers, NULL, 0, status);
02271 if (allvers)
02272 {
02273 free(allvers);
02274 }
02275
02276 return ret;
02277 }
02278
02279 DRMS_RecordSet_t *drms_open_nrecords(DRMS_Env_t *env,
02280 const char *recordsetname,
02281 int n,
02282 int *status)
02283 {
02284 DRMS_RecordSet_t *rs = NULL;
02285 DRMS_Record_t **recs = NULL;
02286 int statint = DRMS_SUCCESS;
02287 int iset;
02288 int irec;
02289 int nrecs = 0;
02290 DRMS_Record_t *rec = NULL;
02291 int *hasshadow = NULL;
02292
02293 rs = drms_open_records_internal(env, recordsetname, 1, NULL, NULL, &hasshadow, n, &statint);
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304 if (statint == DRMS_SUCCESS && rs && rs->n > 0 && n < 0)
02305 {
02306 for (iset = 0; iset < rs->ss_n && statint == DRMS_SUCCESS; iset++)
02307 {
02308 if (hasshadow[iset] == 1)
02309 {
02310 continue;
02311 }
02312 else
02313 {
02314
02315
02316 {
02317 nrecs = drms_recordset_getssnrecs(rs, iset, &statint);
02318
02319 if (statint != DRMS_SUCCESS)
02320 {
02321 break;
02322 }
02323
02324 recs = (DRMS_Record_t **)malloc(sizeof(DRMS_Record_t *) * nrecs);
02325 if (recs)
02326 {
02327 memset(recs, 0, sizeof(DRMS_Record_t *) * nrecs);
02328
02329 for (irec = 0; irec < nrecs; irec++)
02330 {
02331 rec = rs->records[(rs->ss_starts)[iset] + irec];
02332 recs[nrecs - irec - 1] = rec;
02333 }
02334 }
02335 else
02336 {
02337 statint = DRMS_ERROR_OUTOFMEMORY;
02338 break;
02339 }
02340 }
02341
02342 if (statint == DRMS_SUCCESS)
02343 {
02344
02345 memcpy(rs->records, recs, sizeof(DRMS_Record_t *) * nrecs);
02346 }
02347
02348 if (recs)
02349 {
02350 free(recs);
02351 }
02352 }
02353 }
02354 }
02355
02356 if (hasshadow)
02357 {
02358 free(hasshadow);
02359 hasshadow = NULL;
02360 }
02361
02362 if (status)
02363 {
02364 *status = statint;
02365 }
02366
02367 return rs;
02368 }
02369
02370
02371
02372
02373
02374
02375
02376
02377
02378
02379 DRMS_RecordSet_t *drms_open_recordswithkeys(DRMS_Env_t *env, const char *specification, const char *keylist, int *status)
02380 {
02381 char *allvers = NULL;
02382 DRMS_RecordSet_t *ret = NULL;
02383
02384 if (keylist)
02385 {
02386
02387
02388
02389
02390 char *akey = NULL;
02391 char *lkey = NULL;
02392 char key[DRMS_MAXKEYNAMELEN];
02393 LinkedList_t *list = NULL;
02394
02395 list = list_llcreate(DRMS_MAXKEYNAMELEN, NULL);
02396
02397 if (list)
02398 {
02399
02400 char *keylistDupe = strdup(keylist);
02401
02402 if (keylistDupe)
02403 {
02404
02405 for (akey = strtok_r(keylistDupe, ",", &lkey); akey; akey = strtok_r(NULL, ",", &lkey))
02406 {
02407
02408
02409 snprintf(key, sizeof(key), "%s", akey);
02410 list_llinserttail(list, key);
02411 }
02412
02413 ret = drms_open_records_internal(env, specification, 1, &list, &allvers, NULL, 0, status);
02414
02415 list_llfree(&list);
02416
02417 free(keylistDupe);
02418 keylistDupe = NULL;
02419 }
02420 else
02421 {
02422 fprintf(stderr, "Out of memory in drms_open_recordswithkeys().\n");
02423
02424 if (status)
02425 {
02426 *status = DRMS_ERROR_OUTOFMEMORY;
02427 }
02428 }
02429 }
02430 else
02431 {
02432 fprintf(stderr, "Out of memory in drms_open_recordswithkeys().\n");
02433
02434 if (status)
02435 {
02436 *status = DRMS_ERROR_OUTOFMEMORY;
02437 }
02438 }
02439 }
02440 else
02441 {
02442 ret = drms_open_records_internal(env, specification, 1, NULL, &allvers, NULL, 0, status);
02443 }
02444
02445 if (allvers)
02446 {
02447 free(allvers);
02448 }
02449
02450 return ret;
02451 }
02452
02453
02454 DRMS_RecordSet_t *drms_create_records(DRMS_Env_t *env, int n, const char *series,
02455 DRMS_RecLifetime_t lifetime, int *status)
02456 {
02457 DRMS_Record_t *template;
02458
02459
02460 if ((template = drms_template_record(env, series, status)) == NULL)
02461 return NULL;
02462 return drms_create_records_fromtemplate(env, n, template, lifetime, status);
02463 }
02464
02465 static void CountNonLinkedSegs(const void *value, void *data)
02466 {
02467 int *count = (int *)data;
02468 DRMS_Segment_t *seg = (DRMS_Segment_t *)value;
02469
02470 if (seg && count)
02471 {
02472 if (!seg->info->islink)
02473 {
02474 (*count)++;
02475 }
02476 }
02477 }
02478
02479
02480 DRMS_RecordSet_t *drms_create_records_fromtemplate(DRMS_Env_t *env, int n,
02481 DRMS_Record_t *template,
02482 DRMS_RecLifetime_t lifetime,
02483 int *status)
02484 {
02485 int i=0, stat;
02486 DRMS_RecordSet_t *rs=NULL;
02487 long long *recnum=NULL;
02488 HIterator_t hit;
02489 DRMS_StorageUnit_t **su;
02490 DRMS_Segment_t *seg;
02491 int *slotnum;
02492 char filename[DRMS_MAXPATHLEN];
02493 char *series;
02494 int createslotdirs = 1;
02495
02496 CHECKNULL_STAT(env,status);
02497 CHECKNULL_STAT(template,status);
02498
02499
02500
02501 stat = drms_makewritable(env);
02502
02503 if (stat != DRMS_SUCCESS)
02504 {
02505 if (status)
02506 {
02507 *status = stat;
02508 }
02509
02510 return NULL;
02511 }
02512
02513 int summaryexists = -1;
02514 int canupdatesummaries = -1;
02515
02516 int nnonlinkedsegs = 0;
02517
02518
02519 if (!gSummcon)
02520 {
02521 gSummcon = hcon_create(sizeof(char), DRMS_MAXSERIESNAMELEN, NULL, NULL, NULL, NULL, 0);
02522
02523 if (!gSummcon)
02524 {
02525 stat = DRMS_ERROR_OUTOFMEMORY;
02526 goto failure;
02527 }
02528
02529 BASE_Cleanup_t cu;
02530 cu.item = NULL;
02531 cu.free = drms_record_summchkcache_term;
02532 base_cleanup_register("summarytablechkcache", &cu);
02533 }
02534
02535 if (gSummcon)
02536 {
02537 char *disp = (char *)hcon_lookup_lower(gSummcon, template->seriesinfo->seriesname);
02538 if (disp)
02539 {
02540
02541 if (*disp == 'y')
02542 {
02543
02544 summaryexists = 1;
02545 }
02546 else
02547 {
02548
02549 summaryexists = 0;
02550 }
02551 }
02552 else
02553 {
02554
02555 summaryexists = drms_series_summaryexists(env, template->seriesinfo->seriesname, &stat);
02556
02557 if (stat == DRMS_SUCCESS)
02558 {
02559 char res;
02560
02561 if (summaryexists)
02562 {
02563 res = 'y';
02564
02565
02566
02567 canupdatesummaries = drms_series_canupdatesummaries(env, template->seriesinfo->seriesname, &stat);
02568 }
02569 else
02570 {
02571 res = 'n';
02572 }
02573
02574
02575 hcon_insert(gSummcon, template->seriesinfo->seriesname, &res);
02576 }
02577
02578 if (stat == DRMS_SUCCESS)
02579 {
02580 if (summaryexists && !canupdatesummaries)
02581 {
02582 fprintf(stderr, "You must update your DRMS libraries before you can add records to series '%s'.\n", template->seriesinfo->seriesname);
02583 stat = DRMS_ERROR_CANTCREATERECORD;
02584 goto failure;
02585 }
02586 }
02587 else
02588 {
02589 goto failure;
02590 }
02591 }
02592 }
02593
02594
02595 if (n<1)
02596 {
02597 if (status)
02598 *status = DRMS_ERROR_BADRECORDCOUNT;
02599 return NULL;
02600 }
02601
02602
02603 rs = malloc(sizeof(DRMS_RecordSet_t));
02604 XASSERT(rs);
02605 rs->records = malloc(n*sizeof(DRMS_Record_t *));
02606 XASSERT(rs->records);
02607 memset(rs->records, 0, sizeof(DRMS_Record_t *) * n);
02608 rs->n = n;
02609 rs->ss_n = 0;
02610 rs->ss_queries = NULL;
02611 rs->ss_types = NULL;
02612 rs->ss_starts = NULL;
02613 rs->env = env;
02614
02615
02616 rs->ss_currentrecs = (int *)malloc(sizeof(int));
02617 *rs->ss_currentrecs = -1;
02618 rs->cursor = NULL;
02619 rs->env = env;
02620
02621 series = template->seriesinfo->seriesname;
02622
02623
02624 if ((recnum = drms_alloc_recnum(env, series, lifetime, n)) == NULL)
02625 {
02626 stat = DRMS_ERROR_BADSEQUENCE;
02627 goto failure;
02628 }
02629
02630
02631
02632 for (i=0; i<n; i++)
02633 {
02634 if ((
02635 rs->records[i] = drms_alloc_record2(template, recnum[i], &stat)
02636 ) == NULL)
02637 goto failure;
02638
02639 rs->records[i]->readonly = 0;
02640 rs->records[i]->sessionid = env->session->sessionid;
02641 rs->records[i]->sessionns = strdup(env->session->sessionns);
02642 rs->records[i]->lifetime = lifetime;
02643 }
02644
02645
02646
02647
02648 hcon_map_ext(&template->segments, CountNonLinkedSegs, &nnonlinkedsegs);
02649
02650
02651 if (nnonlinkedsegs > 0)
02652 {
02653 su = malloc(n*sizeof(DRMS_StorageUnit_t *));
02654 XASSERT(su);
02655 slotnum = malloc(n*sizeof(int));
02656 XASSERT(slotnum);
02657
02658
02659
02660 HIterator_t *seghit = hiter_create(&(template->segments));
02661 if (seghit)
02662 {
02663 createslotdirs = 0;
02664 while((seg = (DRMS_Segment_t *)hiter_getnext(seghit)))
02665 {
02666 if (seg->info->protocol != DRMS_TAS)
02667 {
02668 createslotdirs = 1;
02669 }
02670 }
02671 hiter_destroy(&seghit);
02672 }
02673
02674 if ((stat = drms_newslots(env, n, series, recnum, lifetime, slotnum, su, createslotdirs)))
02675 goto failure;
02676
02677 for (i=0; i<n; i++)
02678 {
02679 rs->records[i]->slotnum = slotnum[i];
02680 rs->records[i]->su = su[i];
02681 su[i]->refcount++;
02682 #ifdef DEBUG
02683 printf("record[%d]->su = %p\n",i,su[i]);
02684 #endif
02685 rs->records[i]->sunum = rs->records[i]->su->sunum;
02686 if (slotnum[i]==0)
02687 {
02688
02689
02690 hiter_new(&hit, &rs->records[i]->segments);
02691 while( (seg = (DRMS_Segment_t *)hiter_getnext(&hit)) )
02692 {
02693 if (seg->info->protocol == DRMS_TAS)
02694 {
02695 drms_segment_filename(seg, filename);
02696
02697
02698
02699
02700
02701
02702
02703
02704 *(seg->filename) = '\0';
02705
02706
02707
02708
02709 seg->axis[seg->info->naxis] = rs->records[i]->seriesinfo->unitsize;
02710 seg->blocksize[seg->info->naxis] = 1;
02711 #ifdef DEBUG
02712 printf("creating new tasfile '%s'\n",filename);
02713 #endif
02714
02715 drms_fitstas_create(env,
02716 filename,
02717 seg->cparms,
02718 seg->info->type,
02719 seg->info->naxis+1,
02720 seg->axis,
02721 seg->bzero,
02722 seg->bscale);
02723
02724 seg->axis[seg->info->naxis] = 0;
02725 seg->blocksize[seg->info->naxis] = 0;
02726
02727
02728
02729 char fbuf[PATH_MAX];
02730 FILE *virginPtr = NULL;
02731
02732 snprintf(fbuf, sizeof(fbuf), "%s.virgin", filename);
02733 virginPtr = fopen(fbuf, "w");
02734 if (!virginPtr)
02735 {
02736 stat = DRMS_ERROR_FILECREATE;
02737 goto failure;
02738 }
02739
02740 fclose(virginPtr);
02741 virginPtr = NULL;
02742 }
02743 }
02744
02745 hiter_free(&hit);
02746 }
02747 }
02748 free(su);
02749 free(slotnum);
02750 }
02751 else
02752 for (i=0; i<n; i++)
02753 rs->records[i]->su = NULL;
02754
02755
02756 if (status)
02757 *status = 0;
02758 free(recnum);
02759 return rs;
02760
02761 failure:
02762 if (rs)
02763 drms_close_records(rs, DRMS_FREE_RECORD);
02764 if (recnum)
02765 free(recnum);
02766 if (status)
02767 *status = stat;
02768 return NULL;
02769 }
02770
02771
02772
02773
02774
02775
02776
02777
02778
02779 DRMS_RecordSet_t *drms_create_recprotos(DRMS_RecordSet_t *recset, int *status)
02780 {
02781 DRMS_RecordSet_t *detached;
02782 DRMS_Record_t *recSource = NULL;
02783 DRMS_Record_t *recTarget = NULL;
02784
02785 int nRecs = recset->n;
02786
02787 detached = malloc(sizeof(DRMS_RecordSet_t));
02788 XASSERT(detached);
02789 detached->records = malloc(nRecs * sizeof(DRMS_Record_t *));
02790 XASSERT(detached->records);
02791
02792 if (detached && detached->records)
02793 {
02794 *status = DRMS_SUCCESS;
02795 detached->n = nRecs;
02796 detached->ss_n = 0;
02797 detached->ss_queries = NULL;
02798 detached->ss_types = NULL;
02799 detached->ss_starts = NULL;
02800 detached->ss_currentrecs = NULL;
02801 detached->cursor = NULL;
02802 detached->env = NULL;
02803 }
02804 else
02805 {
02806 *status = DRMS_ERROR_OUTOFMEMORY;
02807 }
02808
02809 int idx = 0;
02810 for (; *status == DRMS_SUCCESS && idx < nRecs; idx++)
02811 {
02812 recSource = recset->records[idx];
02813 recTarget = drms_create_recproto(recSource, status);
02814
02815 if (*status == DRMS_SUCCESS)
02816 {
02817
02818 detached->records[idx] = recTarget;
02819 }
02820 }
02821
02822 return detached;
02823 }
02824
02825 void drms_destroy_recprotos (DRMS_RecordSet_t **protos) {
02826 if (protos && *protos) {
02827 int idx, nRecs = (*protos)->n;
02828 for (idx = 0; idx < nRecs; idx++)
02829 drms_destroy_recproto ((DRMS_Record_t **)((*protos)->records)[idx]);
02830 }
02831 }
02832
02833 DRMS_Record_t *drms_create_recproto(DRMS_Record_t *recSource, int *status)
02834 {
02835 DRMS_Record_t *detached = NULL;
02836 DRMS_Record_t *recTarget = NULL;
02837
02838 recTarget = calloc(1, sizeof(DRMS_Record_t));
02839 XASSERT(recTarget);
02840 recTarget->seriesinfo = calloc(1, sizeof(DRMS_SeriesInfo_t));
02841 XASSERT(recTarget->seriesinfo);
02842 recTarget->seriesinfo->hasshadow = -1;
02843 recTarget->seriesinfo->createshadow = 0;
02844
02845 if (recTarget && recTarget->seriesinfo)
02846 {
02847 recTarget->env = recSource->env;
02848 recTarget->init = 1;
02849 recTarget->recnum = 0;
02850 recTarget->sunum = -1;
02851 recTarget->sessionid = 0;
02852 recTarget->sessionns = NULL;
02853 recTarget->su = NULL;
02854
02855
02856 hcon_init(&recTarget->segments, sizeof(DRMS_Segment_t), DRMS_MAXHASHKEYLEN,
02857 (void (*)(const void *)) drms_free_segment_struct,
02858 (void (*)(const void *, const void *)) drms_copy_segment_struct);
02859
02860 hcon_init(&recTarget->links, sizeof(DRMS_Link_t), DRMS_MAXHASHKEYLEN,
02861 (void (*)(const void *)) drms_free_link_struct,
02862 (void (*)(const void *, const void *)) drms_copy_link_struct);
02863
02864 hcon_init(&recTarget->keywords, sizeof(DRMS_Keyword_t), DRMS_MAXHASHKEYLEN,
02865 (void (*)(const void *)) drms_free_keyword_struct,
02866 (void (*)(const void *, const void *)) drms_copy_keyword_struct);
02867
02868 if (*status == DRMS_SUCCESS)
02869 {
02870 if ((*status = CopySeriesInfo(recTarget, recSource)) != DRMS_SUCCESS)
02871 {
02872 fprintf(stderr,"Failed to create series info.\n");
02873 }
02874 }
02875
02876 if (*status == DRMS_SUCCESS)
02877 {
02878 if ((*status = CopySegments(recTarget, recSource)) != DRMS_SUCCESS)
02879 {
02880 fprintf(stderr,"Failed to copy segments.\n");
02881 }
02882 }
02883
02884 if (*status == DRMS_SUCCESS)
02885 {
02886 if ((*status = CopyLinks(recTarget, recSource)) != DRMS_SUCCESS)
02887 {
02888 fprintf(stderr,"Failed to copy links.\n");
02889 }
02890 }
02891
02892 if (*status == DRMS_SUCCESS)
02893 {
02894 if ((*status = CopyKeywords(recTarget, recSource)) != DRMS_SUCCESS)
02895 {
02896 fprintf(stderr,"Failed to copy keywords.\n");
02897 }
02898
02899
02900 for (int i = 0; i < recTarget->seriesinfo->pidx_num; i++)
02901 {
02902 recTarget->seriesinfo->pidx_keywords[i] =
02903 drms_keyword_lookup(recTarget, recSource->seriesinfo->pidx_keywords[i]->info->name, 0);
02904 }
02905
02906 for (int i = 0; i < recTarget->seriesinfo->dbidx_num; i++)
02907 {
02908 recTarget->seriesinfo->dbidx_keywords[i] =
02909 drms_keyword_lookup(recTarget, recSource->seriesinfo->dbidx_keywords[i]->info->name, 0);
02910 }
02911 }
02912
02913 if (*status == DRMS_SUCCESS)
02914 {
02915 if ((*status = CopyPrimaryIndex(recTarget, recSource)) != DRMS_SUCCESS)
02916 {
02917 fprintf(stderr,"Failed to copy primary index.\n");
02918 }
02919 }
02920
02921 if (*status != DRMS_SUCCESS)
02922 {
02923 hcon_free(&recTarget->segments);
02924 hcon_free(&recTarget->links);
02925 hcon_free(&recTarget->keywords);
02926 free(recTarget);
02927 }
02928 else
02929 {
02930 detached = recTarget;
02931 }
02932 }
02933 else
02934 {
02935 *status = DRMS_ERROR_OUTOFMEMORY;
02936 }
02937
02938 return detached;
02939 }
02940
02941 void drms_destroy_recproto(DRMS_Record_t **proto)
02942 {
02943
02944 if (proto)
02945 {
02946 DRMS_Record_t *prototype = *proto;
02947 char *series = prototype->seriesinfo->seriesname;
02948 DRMS_Env_t *env = prototype->env;
02949
02950
02951 DRMS_Record_t *rec = hcon_lookup_lower(&(env->series_cache), series);
02952 int deep = 1;
02953
02954 if (rec)
02955 {
02956 if (rec->seriesinfo == prototype->seriesinfo)
02957 {
02958
02959 deep = 0;
02960 }
02961 }
02962
02963 if (deep)
02964 {
02965 drms_free_template_record_struct(prototype);
02966 }
02967 else
02968 {
02969 drms_free_record_struct(prototype);
02970 }
02971
02972 free(prototype);
02973
02974 *proto = NULL;
02975 }
02976 }
02977
02978
02979
02980
02981
02982
02983 static DRMS_RecordSet_t *drms_clone_records_internal(DRMS_RecordSet_t *rs_in,
02984 DRMS_RecLifetime_t lifetime,
02985 DRMS_CloneAction_t mode,
02986 int gotosums,
02987 int *status)
02988 {
02989 int i, stat=0, first, last, n, n_total;
02990 DRMS_RecordSet_t *rs_out=NULL;
02991 DRMS_Record_t *rec_in, *rec_out;
02992 long long *recnum=NULL;
02993 HIterator_t hit_in,hit_out;
02994 DRMS_StorageUnit_t **su;
02995 DRMS_Segment_t *seg_in, *seg_out;
02996 int *slotnum;
02997 char dir_in[DRMS_MAXPATHLEN], dir_out[DRMS_MAXPATHLEN];
02998 char command[2*DRMS_MAXPATHLEN+20], filename[DRMS_MAXPATHLEN];
02999 char *series;
03000 DRMS_Env_t *env;
03001 DRMS_Array_t *arr;
03002 int createslotdirs = 1;
03003 HIterator_t *seghit = NULL;
03004 DRMS_Record_t *therec = NULL;
03005
03006 CHECKNULL_STAT(rs_in,status);
03007 n_total = rs_in->n;
03008 if (n_total<1)
03009 {
03010 if (status)
03011 *status = DRMS_ERROR_BADRECORDCOUNT;
03012 return NULL;
03013 }
03014 CHECKNULL_STAT(rs_in->records,status);
03015 CHECKNULL_STAT(rs_in->records[0],status);
03016 env = rs_in->records[0]->env;
03017
03018
03019
03020 stat = drms_makewritable(env);
03021
03022 if (stat != DRMS_SUCCESS)
03023 {
03024 if (status)
03025 {
03026 *status = stat;
03027 }
03028
03029 return NULL;
03030 }
03031
03032
03033 rs_out = malloc(sizeof(DRMS_RecordSet_t));
03034 XASSERT(rs_out);
03035 rs_out->records = malloc(n_total*sizeof(DRMS_Record_t *));
03036 XASSERT(rs_out->records);
03037 rs_out->n = n_total;
03038 rs_out->ss_n = 0;
03039 rs_out->ss_queries = NULL;
03040 rs_out->ss_types = NULL;
03041 rs_out->ss_starts = NULL;
03042 rs_out->ss_currentrecs = NULL;
03043 rs_out->cursor = NULL;
03044 rs_out->env = env;
03045
03046
03047 first = 0;
03048 while(first<n_total)
03049 {
03050 series = rs_in->records[first]->seriesinfo->seriesname;
03051 last = first+1;
03052 while(last<n_total &&
03053 !strcmp(series, rs_in->records[last]->seriesinfo->seriesname))
03054 ++last;
03055 n = last-first;
03056
03057
03058 if ((recnum = drms_alloc_recnum(env, series, lifetime, n)) == NULL)
03059 {
03060 stat = DRMS_ERROR_BADSEQUENCE;
03061 goto failure;
03062 }
03063
03064
03065
03066 for (i=0; i<n; i++)
03067 {
03068 rs_out->records[first+i] = drms_alloc_record2(rs_in->records[first+i],
03069 recnum[i], &stat);
03070 if (rs_out->records[first+i] == NULL) {
03071 stat = 1;
03072 goto failure;
03073 }
03074
03075 rs_out->records[first+i]->readonly = 0;
03076 rs_out->records[first+i]->sessionid = env->session->sessionid;
03077 rs_out->records[first+i]->sessionns = strdup(env->session->sessionns);
03078 rs_out->records[first+i]->lifetime = lifetime;
03079 }
03080
03081
03082
03083 if ( drms_record_num_nonlink_segments(rs_out->records[first]) )
03084 {
03085 switch(mode)
03086 {
03087 case DRMS_SHARE_SEGMENTS:
03088
03089
03090
03091
03092 for (i=0; i<n; i++)
03093 {
03094 therec = rs_in->records[first+i];
03095
03096 if (gotosums)
03097 {
03098
03099
03100 drms_record_directory(therec, dir_in, 1);
03101 }
03102 else
03103 {
03104
03105
03106 if (therec->sunum != -1LL && therec->su == NULL)
03107 {
03108
03109 if ((therec->su = drms_getunit_nosums(therec->env, therec->seriesinfo->seriesname,
03110 therec->sunum, &stat)) == NULL)
03111 {
03112 if (stat)
03113 {
03114 fprintf (stderr, "ERROR in drms_clone_records_internal: stat = %d\n", stat);
03115 goto failure;
03116 }
03117 }
03118 else
03119 {
03120 therec->su->refcount++;
03121 }
03122 }
03123 }
03124
03125 if (therec->su)
03126 {
03127 rs_out->records[first+i]->su = therec->su;
03128 rs_out->records[first+i]->su->refcount++;
03129 }
03130 }
03131 break;
03132 case DRMS_COPY_SEGMENTS:
03133 su = malloc(n*sizeof(DRMS_StorageUnit_t *));
03134 XASSERT(su);
03135 slotnum = malloc(n*sizeof(int));
03136 XASSERT(slotnum);
03137
03138
03139
03140 seghit = hiter_create(&((rs_out->records[0])->segments));
03141 if (seghit)
03142 {
03143 createslotdirs = 0;
03144 while((seg_out = (DRMS_Segment_t *)hiter_getnext(seghit)))
03145 {
03146 if (seg_out->info->protocol != DRMS_TAS)
03147 {
03148 createslotdirs = 1;
03149 }
03150 }
03151 hiter_destroy(&seghit);
03152 }
03153
03154
03155
03156
03157
03158
03159
03160 if (gotosums)
03161 {
03162 if ((stat = drms_newslots(env, n, series, recnum, lifetime, slotnum, su, createslotdirs)))
03163 {
03164 stat = 1;
03165 goto failure;
03166 }
03167 }
03168 else
03169 {
03170 if ((stat = drms_newslots_nosums(env, n, series, recnum, lifetime, slotnum, su, createslotdirs)))
03171 {
03172 if (stat == DRMS_ERROR_NEEDSUMS)
03173 {
03174
03175
03176 fprintf(stderr, "Cannot obtain new slot dirs without making a SUMS request.\n");
03177 }
03178 stat = 1;
03179 goto failure;
03180 }
03181 }
03182
03183
03184
03185 for (i=0; i<n; i++)
03186 {
03187 rec_in = rs_in->records[first+i];
03188 rec_out = rs_out->records[first+i];
03189
03190 rec_out->slotnum = slotnum[i];
03191 rec_out->su = su[i];
03192 su[i]->refcount++;
03193 rec_out->sunum = su[i]->sunum;
03194
03195
03196 if (gotosums)
03197 {
03198 drms_record_directory(rec_in, dir_in, 1);
03199 drms_record_directory(rec_out, dir_out, 1);
03200 }
03201 else
03202 {
03203 if (drms_record_directory_nosums(rec_in, dir_in, sizeof(dir_in)) == DRMS_ERROR_NEEDSUMS ||
03204 drms_record_directory_nosums(rec_out, dir_out, sizeof(dir_out)) == DRMS_ERROR_NEEDSUMS)
03205 {
03206 fprintf(stderr, "Cannot obtain the input/output record directory without making a SUMS request.\n");
03207 stat = 1;
03208 goto failure;
03209 }
03210 }
03211
03212 if (*dir_in == '\0' || *dir_out == '\0')
03213 {
03214 fprintf(stderr, "Unable to obtain the input/output directory.\n");
03215 stat = 1;
03216 goto failure;
03217 }
03218
03219 DIR *dp;
03220 struct dirent *dirp;
03221 if ((dp = opendir(dir_in)) == NULL) {
03222 fprintf(stderr, "Can't open %s\n", dir_in);
03223 stat = 1;
03224 goto failure;
03225 }
03226 while ((dirp = readdir(dp)) != NULL) {
03227 if (!strcmp(dirp->d_name, ".") ||
03228 !strcmp(dirp->d_name, ".."))
03229 continue;
03230 sprintf(command,"cp -rf %s/* %s", dir_in, dir_out);
03231 #ifdef DEBUG
03232 printf("executing %s\n",command);
03233 #endif
03234 if(system(command))
03235 {
03236 fprintf(stderr, "ERROR: system command to copy record directory"
03237 " failed.\n");
03238 stat = 1;
03239 goto failure;
03240 }
03241 break;
03242 }
03243 closedir(dp);
03244
03245 hiter_new_sort(&hit_in, &rec_in->segments, drms_segment_ranksort);
03246 hiter_new_sort(&hit_out, &rec_out->segments, drms_segment_ranksort);
03247 while ((seg_in = (DRMS_Segment_t *)hiter_getnext(&hit_in)) &&
03248 (seg_out = (DRMS_Segment_t *)hiter_getnext(&hit_out)))
03249 {
03250 if (seg_out->info->protocol == DRMS_TAS)
03251 {
03252 if (slotnum[i]==0)
03253 {
03254
03255
03256
03257
03258
03259
03260
03261 drms_segment_filename(seg_out, filename);
03262 seg_out->axis[seg_out->info->naxis] = rec_out->seriesinfo->unitsize;
03263 seg_out->blocksize[seg_out->info->naxis] = 1;
03264
03265 drms_fitstas_create(env,
03266 filename,
03267 seg_out->cparms,
03268 seg_out->info->type,
03269 seg_out->info->naxis+1,
03270 seg_out->axis,
03271 seg_out->bzero,
03272 seg_out->bscale);
03273
03274 seg_out->axis[seg_out->info->naxis] = 0;
03275 seg_out->blocksize[seg_out->info->naxis] = 0;
03276 }
03277
03278
03279
03280
03281
03282 if ((arr = drms_segment_read(seg_in,DRMS_TYPE_RAW,&stat))==NULL)
03283 {
03284 fprintf(stderr,"ERROR at %s, line %d: failed to read "
03285 "segment '%s' of record %s:#%lld\n",__FILE__,__LINE__,
03286 seg_in->info->name, rec_in->seriesinfo->seriesname,
03287 rec_in->recnum);
03288 stat = 1;
03289 goto failure;
03290 }
03291
03292
03293
03294
03295
03296 if (drms_segment_write(seg_out, arr, 0))
03297 {
03298 fprintf(stderr,"ERROR at %s, line %d: failed to write "
03299 "segment '%s' of record %s:#%lld\n",__FILE__,__LINE__,
03300 seg_out->info->name, rec_out->seriesinfo->seriesname,
03301 rec_out->recnum);
03302 stat = 1;
03303 goto failure;
03304 }
03305 drms_free_array(arr);
03306 }
03307 }
03308
03309 hiter_free(&hit_out);
03310 hiter_free(&hit_in);
03311 }
03312 free(su);
03313 free(slotnum);
03314
03315 break;
03316 }
03317 }
03318 else
03319 for (i=0; i<n; i++)
03320 rs_out->records[first+i]->su = NULL;
03321 first = last;
03322 }
03323
03324
03325 if (status)
03326 *status = 0;
03327 free(recnum);
03328 return rs_out;
03329
03330 failure:
03331 fprintf(stderr,"FAILURE in clone_records.\n");
03332 drms_close_records(rs_out, DRMS_FREE_RECORD);
03333 if (recnum)
03334 free(recnum);
03335 if (status)
03336 *status = stat;
03337 return NULL;
03338 }
03339
03340 DRMS_RecordSet_t *drms_clone_records(DRMS_RecordSet_t *rs_in,
03341 DRMS_RecLifetime_t lifetime,
03342 DRMS_CloneAction_t mode, int *status)
03343 {
03344
03345 return drms_clone_records_internal(rs_in, lifetime, mode, 1, status);
03346 }
03347
03348 DRMS_RecordSet_t *drms_clone_records_nosums(DRMS_RecordSet_t *rs_in,
03349 DRMS_RecLifetime_t lifetime,
03350 DRMS_CloneAction_t mode,
03351 int *status)
03352 {
03353
03354
03355 return drms_clone_records_internal(rs_in, lifetime, mode, 0, status);
03356 }
03357
03358
03359
03360 int drms_close_records(DRMS_RecordSet_t *rs, int action)
03361 {
03362 int i, status=0;
03363 DRMS_Record_t *rec = NULL;
03364 DRMS_Segment_t *seg = NULL;
03365 HIterator_t hit;
03366 char filename[DRMS_MAXPATHLEN] = {0};
03367
03368 CHECKNULL(rs);
03369
03370 status = 0;
03371 switch(action)
03372 {
03373 case DRMS_FREE_RECORD:
03374 for (i=0; i<rs->n; i++)
03375 {
03376 rec = rs->records[i];
03377
03378 if (rec)
03379 {
03380
03381
03382
03383 hiter_new_sort(&hit, &(rec->segments), drms_segment_ranksort);
03384
03385 while ((seg = hiter_getnext(&hit)) != NULL)
03386 {
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409 *filename = '\0';
03410
03411 if (rec->sunum != -1LL && seg->info->protocol != DRMS_DSDS && seg->info->protocol != DRMS_LOCAL)
03412 {
03413
03414 if (rec->suinfo && *rec->suinfo->online_loc)
03415 {
03416 if (*seg->filename)
03417 {
03418 if (seg->info->protocol == DRMS_TAS)
03419 {
03420 CHECKSNPRINTF(snprintf(filename, DRMS_MAXPATHLEN, "%s/%s", rec->suinfo->online_loc, seg->filename), DRMS_MAXPATHLEN);
03421 }
03422 else
03423 {
03424 CHECKSNPRINTF(snprintf(filename, DRMS_MAXPATHLEN, "%s/" DRMS_SLOTDIR_FORMAT "/%s", rec->suinfo->online_loc, rec->slotnum, seg->filename), DRMS_MAXPATHLEN);
03425 }
03426 }
03427 else
03428 {
03429 if (seg->info->protocol == DRMS_TAS)
03430 {
03431 CHECKSNPRINTF(snprintf(filename, DRMS_MAXPATHLEN, "%s/%s.tas", rec->suinfo->online_loc, seg->info->name), DRMS_MAXPATHLEN);
03432 }
03433 else
03434 {
03435 CHECKSNPRINTF(snprintf(filename, DRMS_MAXPATHLEN, "%s/" DRMS_SLOTDIR_FORMAT "/%s%s", rec->suinfo->online_loc, rec->slotnum, seg->info->name, drms_prot2ext(seg->info->protocol)), DRMS_MAXPATHLEN);
03436 }
03437 }
03438
03439 }
03440
03441
03442 if (*filename == '\0')
03443 {
03444 if (rec->su != NULL)
03445 {
03446 if (*seg->filename)
03447 {
03448
03449
03450
03451 drms_segment_filename(seg, filename);
03452 }
03453 }
03454 }
03455
03456
03457 if (*filename == '\0')
03458 {
03459 rec->su = drms_su_lookup(rec->env, rec->seriesinfo->seriesname, rec->sunum, NULL);
03460 if (rec->su)
03461 {
03462 rec->su->refcount++;
03463 if (*seg->filename)
03464 {
03465 drms_segment_filename(seg, filename);
03466 }
03467 }
03468 }
03469 }
03470
03471 if (*filename)
03472 {
03473 drms_fitsrw_close(rec->env->verbose, filename);
03474 }
03475 }
03476 }
03477
03478
03479
03480
03481
03482
03483
03484
03485 if (rec && !rec->readonly && rec->su && rec->su->refcount==1)
03486 {
03487 if ((status = drms_freeslot(rec->env, rec->seriesinfo->seriesname,
03488 rec->su->sunum, rec->slotnum)))
03489 {
03490 fprintf(stderr,"ERROR in drms_close_record: drms_freeslot failed with "
03491 "error code %d\n", status);
03492 break;
03493 }
03494 }
03495 }
03496 break;
03497 case DRMS_INSERT_RECORD:
03498 for (i=0; i<rs->n; i++)
03499 {
03500 rec = rs->records[i];
03501
03502 if (rec)
03503 {
03504
03505
03506
03507 hiter_new_sort(&hit, &(rec->segments), drms_segment_ranksort);
03508
03509 while ((seg = hiter_getnext(&hit)) != NULL)
03510 {
03511
03512
03513
03514
03515
03516
03517
03518
03519
03520
03521
03522
03523
03524
03525
03526
03527
03528
03529
03530
03531
03532
03533 *filename = '\0';
03534
03535 if (rec->sunum != -1LL && seg->info->protocol != DRMS_DSDS && seg->info->protocol != DRMS_LOCAL)
03536 {
03537
03538 if (rec->suinfo && *rec->suinfo->online_loc)
03539 {
03540 if (*seg->filename)
03541 {
03542 if (seg->info->protocol == DRMS_TAS)
03543 {
03544 CHECKSNPRINTF(snprintf(filename, DRMS_MAXPATHLEN, "%s/%s", rec->suinfo->online_loc, seg->filename), DRMS_MAXPATHLEN);
03545 }
03546 else
03547 {
03548 CHECKSNPRINTF(snprintf(filename, DRMS_MAXPATHLEN, "%s/" DRMS_SLOTDIR_FORMAT "/%s", rec->suinfo->online_loc, rec->slotnum, seg->filename), DRMS_MAXPATHLEN);
03549 }
03550 }
03551 else
03552 {
03553 if (seg->info->protocol == DRMS_TAS)
03554 {
03555 CHECKSNPRINTF(snprintf(filename, DRMS_MAXPATHLEN, "%s/%s.tas", rec->suinfo->online_loc, seg->info->name), DRMS_MAXPATHLEN);
03556 }
03557 else
03558 {
03559 CHECKSNPRINTF(snprintf(filename, DRMS_MAXPATHLEN, "%s/" DRMS_SLOTDIR_FORMAT "/%s%s", rec->suinfo->online_loc, rec->slotnum, seg->info->name, drms_prot2ext(seg->info->protocol)), DRMS_MAXPATHLEN);
03560 }
03561 }
03562
03563 }
03564
03565
03566 if (*filename == '\0')
03567 {
03568 if (rec->su != NULL)
03569 {
03570 if (*seg->filename)
03571 {
03572 drms_segment_filename(seg, filename);
03573 }
03574 }
03575 }
03576
03577
03578 if (*filename == '\0')
03579 {
03580 rec->su = drms_su_lookup(rec->env, rec->seriesinfo->seriesname, rec->sunum, NULL);
03581 if (rec->su)
03582 {
03583 rec->su->refcount++;
03584 if (*seg->filename)
03585 {
03586 drms_segment_filename(seg, filename);
03587 }
03588 }
03589 }
03590 }
03591
03592 if (*filename)
03593 {
03594 drms_fitsrw_close(rec->env->verbose, filename);
03595 }
03596 }
03597 }
03598
03599 if (rs->records[i]->readonly)
03600 {
03601 fprintf(stderr,"ERROR in drms_close_record: trying to commit a "
03602 "read-only record.\n");
03603 status = DRMS_ERROR_COMMITREADONLY;
03604 break;
03605 }
03606 }
03607 if (!status)
03608 {
03609 #ifdef DEBUG
03610 printf("Inserting records...\n");
03611 #endif
03612 if ((status = drms_insert_records(rs)))
03613 {
03614 fprintf(stderr,"ERROR in drms_close_record: Could not insert record "
03615 "in the database.\ndrms_insert_records failed with error "
03616 "code %d\n",status);
03617 }
03618 }
03619 break;
03620 default:
03621 fprintf(stderr,"ERROR in drms_close_record: Action flag (%d) "
03622 "is invalid.\n",action);
03623 status = DRMS_ERROR_INVALIDACTION;
03624 }
03625
03626 if (rs->cursor && rs->cursor->currentrec >= 0)
03627 {
03628 rs->cursor->currentchunk = -1;
03629 rs->cursor->currentrec = -1;
03630 rs->cursor->lastrec = -1;
03631 }
03632
03633
03634 int ssstatus;
03635 int iset;
03636 int ssn;
03637
03638 pDSDSFn_DSDS_free_handle_t pFn_DSDS_free_handle = (pDSDSFn_DSDS_free_handle_t)DSDS_GetFPtr(ghDSDS, kDSDS_DSDS_FREE_HANDLE);
03639
03640 for (iset = 0, ssstatus = DRMS_SUCCESS; ssstatus == DRMS_SUCCESS && pFn_DSDS_free_handle && iset < rs->ss_n; iset++)
03641 {
03642 ssn = drms_recordset_getssnrecs(rs, iset, &ssstatus);
03643
03644 if (ssstatus == DRMS_SUCCESS)
03645 {
03646
03647
03648
03649 if (ssn > 0 && (rs->ss_types[iset] == kRecordSetType_DSDS || rs->ss_types[iset] == kRecordSetType_PlainFile))
03650 {
03651 char *dsdsParams = NULL;
03652 DRMS_Record_t *dsdsRec = NULL;
03653 DRMS_SeriesInfo_t *si = NULL;
03654 DSDS_pHandle_t pHandle = NULL;
03655
03656 dsdsRec = rs->records[(rs->ss_starts)[iset]];
03657 si = dsdsRec->seriesinfo;
03658
03659
03660 dsdsParams = (char *)malloc(sizeof(char) * kDSDS_MaxHandle);
03661 if (!dsdsParams)
03662 {
03663 status = DRMS_ERROR_OUTOFMEMORY;
03664 break;
03665 }
03666
03667 pHandle = (DSDS_pHandle_t)(&dsdsParams);
03668 DSDS_GetDSDSParams(si, dsdsParams);
03669
03670
03671 (*pFn_DSDS_free_handle)(pHandle);
03672 }
03673 }
03674 }
03675
03676 drms_free_records(rs);
03677 return status;
03678 }
03679
03680 static void FreeSumsInfo(const void *value)
03681 {
03682 SUM_info_t *tofree = *((SUM_info_t **)value);
03683 if (tofree)
03684 {
03685 free(tofree);
03686 }
03687 }
03688
03689 static int SumsInfoSort(const void *he1, const void *he2)
03690 {
03691 SUM_info_t **pi1 = (SUM_info_t **)hcon_getval(*((HContainerElement_t **)he1));
03692 SUM_info_t **pi2 = (SUM_info_t **)hcon_getval(*((HContainerElement_t **)he2));
03693
03694 XASSERT(pi1 && pi2);
03695
03696
03697
03698
03699 SUM_info_t *i1 = *pi1;
03700 SUM_info_t *i2 = *pi2;
03701 int cval;
03702
03703
03704 int i1invalid = (*i1->online_loc == '\0');
03705 int i2invalid = (*i2->online_loc == '\0');
03706 int i1offline = (!i1invalid &&
03707 strcasecmp(i1->archive_status, "Y") == 0 &&
03708 strcasecmp(i1->online_status, "N") == 0 &&
03709 *i1->arch_tape != '\0' &&
03710 strcasecmp(i1->arch_tape, "N/A") != 0);
03711 int i2offline = (!i2invalid &&
03712 strcasecmp(i2->archive_status, "Y") == 0 &&
03713 strcasecmp(i2->online_status, "N") == 0 &&
03714 *i2->arch_tape != '\0' &&
03715 strcasecmp(i2->arch_tape, "N/A") != 0);
03716
03717
03718
03719
03720 if (i1offline && i2offline)
03721 {
03722
03723 cval = strcmp(i1->arch_tape, i2->arch_tape);
03724
03725 if (cval != 0)
03726 {
03727 return cval;
03728 }
03729 else
03730 {
03731
03732 return (i1->arch_tape_fn < i2->arch_tape_fn) ? -1 : (i1->arch_tape_fn > i2->arch_tape_fn ? 1 : 0);
03733 }
03734 }
03735 else if (i2offline)
03736 {
03737
03738 return -1;
03739 }
03740 else if (i1offline)
03741 {
03742
03743 return 1;
03744 }
03745 else
03746 {
03747
03748 return (i1->sunum < i2->sunum) ? -1 : 1;
03749 }
03750 }
03751
03752 static void SuInfoCopyMap(const void *key, const void *value, const void *data)
03753 {
03754 HContainer_t *dst = (HContainer_t *)(data);
03755 HContainerElement_t *elem = (HContainerElement_t *)value;
03756 SUM_info_t *src = NULL;
03757 SUM_info_t *dup = NULL;
03758
03759
03760 if (elem->val && *((SUM_info_t **)elem->val))
03761 {
03762 src = *((SUM_info_t **)elem->val);
03763 dup = malloc(sizeof(SUM_info_t));
03764 *dup = *src;
03765 hcon_insert(dst, key, &dup);
03766 }
03767 }
03768
03769 static int insertIntoSunumList(DRMS_Env_t *env, DRMS_RecordSet_t *rs, HContainer_t **suinfoauth, int sortalso, long long *sunumreqinfo, char **seriesreqinfo, int *cntreqinfo, DRMS_SuAndSeries_t *sunum, int *cnt, HContainer_t **suinfo)
03770 {
03771 DRMS_Record_t *rec = NULL;
03772 int drmsStatus = DRMS_SUCCESS;
03773 DRMS_RecChunking_t cstat = kRecChunking_None;
03774 int newchunk;
03775 SUM_info_t **ponesuinfo = NULL;
03776 char key[128];
03777 SUM_info_t *dup = NULL;
03778 SUM_info_t *dummy = NULL;
03779 int currRec;
03780 int rv = 0;
03781
03782 dummy = (SUM_info_t *)NULL;
03783
03784
03785 currRec = drms_recordset_fetchnext_getcurrent(rs);
03786 drms_recordset_fetchnext_setcurrent(rs, -1);
03787 while ((rec = drms_recordset_fetchnext(env, rs, &drmsStatus, &cstat, &newchunk)) != NULL)
03788 {
03789
03790 if (rec->sunum != -1LL && rec->su == NULL)
03791 {
03792 if (!*suinfoauth)
03793 {
03794
03795
03796
03797
03798
03799
03800
03801
03802 *suinfoauth = (HContainer_t *)hcon_create(sizeof(SUM_info_t *), 128, FreeSumsInfo, NULL, NULL, NULL, 0);
03803 if (!(*suinfoauth))
03804 {
03805 rv = 1;
03806 break;
03807 }
03808 }
03809
03810 snprintf(key, sizeof(key), "%lld", rec->sunum);
03811
03812 if (sortalso)
03813 {
03814
03815 if (!hcon_member(*suinfoauth, key))
03816 {
03817 if (!rec->suinfo)
03818 {
03819 if (*suinfo && (ponesuinfo = (SUM_info_t **)hcon_lookup(*suinfo, key)) && *ponesuinfo)
03820 {
03821
03822 dup = (SUM_info_t *)malloc(sizeof(SUM_info_t));
03823 if (!dup)
03824 {
03825 rv = 1;
03826 break;
03827 }
03828
03829 *dup = **ponesuinfo;
03830
03831
03832
03833 snprintf(dup->owning_series,
03834 sizeof(dup->owning_series),
03835 "%s",
03836 rec->seriesinfo->seriesname);
03837 hcon_insert(*suinfoauth, key, &dup);
03838 }
03839 else
03840 {
03841
03842
03843
03844
03845 sunumreqinfo[*cntreqinfo] = rec->sunum;
03846 seriesreqinfo[*cntreqinfo] = rec->seriesinfo->seriesname;
03847 (*cntreqinfo)++;
03848
03849
03850
03851
03852
03853 hcon_insert(*suinfoauth, key, &dummy);
03854 }
03855 }
03856 else
03857 {
03858
03859
03860 dup = (SUM_info_t *)malloc(sizeof(SUM_info_t));
03861 if (!dup)
03862 {
03863 rv = 1;
03864 break;
03865 }
03866
03867 *dup = *rec->suinfo;
03868
03869
03870
03871 snprintf(dup->owning_series,
03872 sizeof(dup->owning_series),
03873 "%s",
03874 rec->seriesinfo->seriesname);
03875 hcon_insert(*suinfoauth, key, &dup);
03876 }
03877 }
03878 }
03879 else
03880 {
03881
03882 if (!hcon_member(*suinfoauth, key))
03883 {
03884 sunum[*cnt].sunum = rec->sunum;
03885 sunum[*cnt].series = rec->seriesinfo->seriesname;
03886 (*cnt)++;
03887
03888
03889 hcon_insert(*suinfoauth, key, &dummy);
03890 }
03891 }
03892 }
03893 }
03894
03895 drms_recordset_fetchnext_setcurrent(rs, currRec);
03896
03897 return rv;
03898 }
03899
03900
03901 static int setSU(DRMS_Env_t *env, DRMS_RecordSet_t *rs, int sortalso, HContainer_t *suinfoauth)
03902 {
03903 int drmsStatus = DRMS_SUCCESS;
03904 DRMS_RecChunking_t cstat = kRecChunking_None;
03905 int newchunk;
03906 DRMS_Record_t *rec = NULL;
03907 HContainer_t *scon = NULL;
03908 char key[128];
03909 SUM_info_t **ponesuinfo = NULL;
03910 int currRec;
03911 int rv = 0;
03912
03913
03914 currRec = drms_recordset_fetchnext_getcurrent(rs);
03915 drms_recordset_fetchnext_setcurrent(rs, -1);
03916 while ((rec = drms_recordset_fetchnext(env, rs, &drmsStatus, &cstat, &newchunk)) != NULL)
03917 {
03918 rec->su = drms_su_lookup(rec->env, rec->seriesinfo->seriesname, rec->sunum, &scon);
03919
03920
03921 if (rec->su)
03922 {
03923
03924
03925 rec->su->refcount++;
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935 if (sortalso && !rec->suinfo)
03936 {
03937
03938
03939
03940 snprintf(key, sizeof(key), "%llu", (unsigned long long)rec->sunum);
03941 if ((ponesuinfo = (SUM_info_t **)hcon_lookup(suinfoauth, key)) != NULL)
03942 {
03943
03944
03945
03946 rec->suinfo = (SUM_info_t *)malloc(sizeof(SUM_info_t));
03947
03948 if (!rec->suinfo)
03949 {
03950 rv = 1;
03951 break;
03952 }
03953
03954 if (*ponesuinfo)
03955 {
03956 *(rec->suinfo) = **ponesuinfo;
03957 }
03958 else
03959 {
03960 memset(rec->suinfo, 0, sizeof(SUM_info_t));
03961 }
03962 }
03963 else
03964 {
03965 fprintf(stderr, "Missing DRMS storage unit during initialization.\n");
03966 rv = 1;
03967 break;
03968 }
03969 }
03970 }
03971 }
03972
03973 drms_recordset_fetchnext_setcurrent(rs, currRec);
03974
03975 return rv;
03976 }
03977
03978
03979
03980
03981
03982
03983
03984
03985
03986
03987
03988
03989
03990
03991 static int drms_stage_records_internal(DRMS_RecordSet_t *rs, int retrieve, int dontwait, HContainer_t **suinfo)
03992 {
03993
03994 if (!rs) {
03995 return DRMS_SUCCESS;
03996 }
03997
03998 int status = 0;
03999 int bail = 0;
04000 DRMS_SuAndSeries_t *sunum = NULL;
04001 int cnt;
04002 int sortalso = 0;
04003 SUM_info_t **ponesuinfo = NULL;
04004 char key[128];
04005 HContainer_t *suinfoauth = NULL;
04006 long long *sunumreqinfo = NULL;
04007 char **seriesreqinfo = NULL;
04008 int cntreqinfo;
04009 SUM_info_t **infostructs = NULL;
04010 int iinfo;
04011 DRMS_Env_t *env = NULL;
04012
04013 sortalso = (suinfo != NULL);
04014
04015
04016 dontwait = 0;
04017
04018
04019
04020
04021
04022
04023
04024
04025 if (rs->cursor)
04026 {
04027 rs->cursor->staging_needed = sortalso ? 2: 1;
04028 rs->cursor->retrieve = retrieve;
04029 rs->cursor->dontwait = dontwait;
04030 if (sortalso)
04031 {
04032
04033
04034
04035
04036
04037
04038
04039
04040
04041
04042
04043
04044
04045 if (*suinfo && hcon_size(*suinfo) > 0)
04046 {
04047 if (!rs->cursor->suinfo)
04048 {
04049 rs->cursor->suinfo = hcon_create(sizeof(SUM_info_t *), 128, FreeSumsInfo, NULL, NULL, NULL, 0);
04050 }
04051
04052
04053
04054
04055 hash_map_data(&((*suinfo)->hash), SuInfoCopyMap, rs->cursor->suinfo);
04056 }
04057 }
04058 return(DRMS_SUCCESS);
04059 }
04060
04061 if (rs->n >= 1)
04062 {
04063 DRMS_RecordSet_t *linkedrecs = NULL;
04064 DRMS_RecordSet_t *mergedrecs = NULL;
04065 DRMS_RecordSet_t *workingRS = NULL;
04066 DRMS_RecordSet_t *workingRSDupeFree = NULL;
04067 HContainer_t *mapRec = NULL;
04068 char hashkey[DRMS_MAXHASHKEYLEN];
04069 int iRec;
04070 int nSUNUMs;
04071 int currRec;
04072 DRMS_Record_t *rec = NULL;
04073 int drmsStatus = DRMS_SUCCESS;
04074 DRMS_RecChunking_t cstat = kRecChunking_None;
04075 int newchunk;
04076 HIterator_t *hitSeg = NULL;
04077 DRMS_Segment_t *seg = NULL;
04078 int fetchLinks = 0;
04079
04080 env = rs->records[0]->env;
04081
04082
04083
04084
04085
04086 workingRS = rs;
04087 while (1)
04088 {
04089 linkedrecs = drms_record_retrievelinks(env, workingRS, &status);
04090
04091 if (workingRS != rs)
04092 {
04093 for (iRec = 0; iRec < workingRS->n; iRec++)
04094 {
04095 workingRS->records[iRec] = NULL;
04096 }
04097
04098 drms_close_records(workingRS, DRMS_FREE_RECORD);
04099 workingRS = NULL;
04100 workingRSDupeFree = NULL;
04101 }
04102
04103 if (linkedrecs && linkedrecs->n > 0)
04104 {
04105 if (!mapRec)
04106 {
04107 mapRec = hcon_create(sizeof(DRMS_Record_t *), DRMS_MAXHASHKEYLEN, NULL, NULL, NULL, NULL, 0);
04108 if (!mapRec)
04109 {
04110 status = DRMS_ERROR_OUTOFMEMORY;
04111 break;
04112 }
04113 }
04114
04115 if (!workingRSDupeFree)
04116 {
04117 workingRSDupeFree = calloc(1, sizeof(DRMS_RecordSet_t));
04118
04119 if (!workingRSDupeFree)
04120 {
04121 status = DRMS_ERROR_OUTOFMEMORY;
04122 break;
04123 }
04124
04125
04126 workingRSDupeFree->ss_currentrecs = (int *)malloc(sizeof(int));
04127
04128 if (!workingRSDupeFree->ss_currentrecs)
04129 {
04130 status = DRMS_ERROR_OUTOFMEMORY;
04131 break;
04132 }
04133 }
04134
04135 if (!mergedrecs)
04136 {
04137 mergedrecs = calloc(1, sizeof(DRMS_RecordSet_t));
04138
04139 if (!mergedrecs)
04140 {
04141 status = DRMS_ERROR_OUTOFMEMORY;
04142 break;
04143 }
04144 }
04145
04146 for (iRec = 0; iRec < linkedrecs->n; iRec++)
04147 {
04148
04149
04150
04151
04152 drms_make_hashkey(hashkey, linkedrecs->records[iRec]->seriesinfo->seriesname, linkedrecs->records[iRec]->recnum);
04153
04154 if (!hcon_member_lower(mapRec, hashkey))
04155 {
04156 drms_merge_record(mergedrecs, linkedrecs->records[iRec]);
04157 hcon_insert_lower(mapRec, hashkey, &(linkedrecs->records[iRec]));
04158 drms_merge_record(workingRSDupeFree, linkedrecs->records[iRec]);
04159 }
04160
04161
04162
04163
04164 linkedrecs->records[iRec] = NULL;
04165 }
04166
04167 workingRS = workingRSDupeFree;
04168 }
04169 else
04170 {
04171 if (linkedrecs)
04172 {
04173 drms_close_records(linkedrecs, DRMS_FREE_RECORD);
04174 linkedrecs = NULL;
04175 }
04176
04177 break;
04178 }
04179 }
04180
04181 if (mapRec)
04182 {
04183 hcon_destroy(&mapRec);
04184 }
04185
04186 linkedrecs = mergedrecs;
04187
04188 if (linkedrecs)
04189 {
04190 linkedrecs->ss_currentrecs = (int *)malloc(sizeof(int));
04191
04192
04193 if (linkedrecs->ss_currentrecs)
04194 {
04195 *linkedrecs->ss_currentrecs = -1;
04196 }
04197 else
04198 {
04199 status = DRMS_ERROR_OUTOFMEMORY;
04200 }
04201 }
04202
04203 if (status != DRMS_SUCCESS)
04204 {
04205 bail = 1;
04206 }
04207
04208
04209
04210 currRec = drms_recordset_fetchnext_getcurrent(rs);
04211 drms_recordset_fetchnext_setcurrent(rs, -1);
04212
04213 while ((rec = drms_recordset_fetchnext(env, rs, &drmsStatus, &cstat, &newchunk)) != NULL && !fetchLinks)
04214 {
04215 hitSeg = hiter_create(&rec->segments);
04216 if (!hitSeg)
04217 {
04218 bail = 1;
04219 status = DRMS_ERROR_OUTOFMEMORY;
04220 break;
04221 }
04222
04223 while ((seg = (DRMS_Segment_t *)hiter_getnext(hitSeg)) != NULL)
04224 {
04225 if (seg->info->islink)
04226 {
04227 fetchLinks = 1;
04228 break;
04229 }
04230 }
04231
04232 hiter_destroy(&hitSeg);
04233 hitSeg = NULL;
04234 }
04235
04236 drms_recordset_fetchnext_setcurrent(rs, currRec);
04237
04238
04239 if (!bail)
04240 {
04241 nSUNUMs = rs->n;
04242 if (linkedrecs && fetchLinks)
04243 {
04244 nSUNUMs += linkedrecs->n;
04245 }
04246
04247
04248 if (!sortalso)
04249 {
04250 sunum = (DRMS_SuAndSeries_t *)malloc(nSUNUMs * sizeof(DRMS_SuAndSeries_t));
04251 XASSERT(sunum);
04252 if (!sunum)
04253 {
04254 bail = 1;
04255 status = DRMS_ERROR_OUTOFMEMORY;
04256 }
04257
04258 cnt = 0;
04259 }
04260 }
04261
04262 if (!bail)
04263 {
04264
04265 sunumreqinfo = (long long *)malloc(nSUNUMs * sizeof(long long));
04266 XASSERT(sunumreqinfo);
04267 if (!sunumreqinfo)
04268 {
04269 bail = 1;
04270 status = DRMS_ERROR_OUTOFMEMORY;
04271 }
04272 else
04273 {
04274 seriesreqinfo = (char **)malloc(nSUNUMs * sizeof(char *));
04275 XASSERT(seriesreqinfo);
04276
04277 if (!seriesreqinfo)
04278 {
04279 bail = 1;
04280 status = DRMS_ERROR_OUTOFMEMORY;
04281 }
04282 else
04283 {
04284 cntreqinfo = 0;
04285 }
04286 }
04287 }
04288
04289 if (!bail)
04290 {
04291
04292
04293
04294 if (insertIntoSunumList(env, rs, &suinfoauth, sortalso, sunumreqinfo, seriesreqinfo, &cntreqinfo, sunum, &cnt, suinfo))
04295 {
04296 bail = 1;
04297 }
04298 else
04299 {
04300 if (linkedrecs && fetchLinks)
04301 {
04302 if (insertIntoSunumList(env, linkedrecs, &suinfoauth, sortalso, sunumreqinfo, seriesreqinfo, &cntreqinfo, sunum, &cnt, suinfo))
04303 {
04304 bail = 1;
04305 }
04306 }
04307 }
04308 }
04309
04310 if (!bail && suinfoauth && hcon_size(suinfoauth) > 0)
04311 {
04312 if (sortalso)
04313 {
04314 if (cntreqinfo > 0)
04315 {
04316
04317
04318 infostructs = (SUM_info_t **)malloc(sizeof(SUM_info_t *) * cntreqinfo);
04319 if (!infostructs)
04320 {
04321 bail = 1;
04322 status = DRMS_ERROR_OUTOFMEMORY;
04323 }
04324 else
04325 {
04326 memset(infostructs, 0, sizeof(SUM_info_t *) * cntreqinfo);
04327 }
04328
04329 if (!bail)
04330 {
04331
04332
04333 status = drms_getsuinfo(env, sunumreqinfo, cntreqinfo, infostructs);
04334
04335 if (status != DRMS_SUCCESS)
04336 {
04337 fprintf(stderr, "drms_stage_records_internal(): failure calling drms_getsuinfo(), error code %d.\n", status);
04338 bail = 1;
04339 }
04340 else
04341 {
04342
04343 for (iinfo = 0 ; iinfo < cntreqinfo; iinfo++)
04344 {
04345 snprintf(key, sizeof(key), "%llu", (unsigned long long)infostructs[iinfo]->sunum);
04346
04347
04348
04349
04350
04351 snprintf(infostructs[iinfo]->owning_series,
04352 sizeof(infostructs[iinfo]->owning_series),
04353 "%s",
04354 seriesreqinfo[iinfo]);
04355
04356
04357 hcon_remove(suinfoauth, key);
04358 hcon_insert(suinfoauth, key, &(infostructs[iinfo]));
04359 }
04360 }
04361 }
04362 }
04363
04364 if (!bail)
04365 {
04366
04367
04368 HIterator_t hit;
04369 hiter_new_sort(&hit, suinfoauth, SumsInfoSort);
04370 cnt = 0;
04371 sunum = malloc(hcon_size(suinfoauth) * sizeof(DRMS_SuAndSeries_t));
04372 XASSERT(sunum);
04373
04374 if (!sunum)
04375 {
04376 bail = 1;
04377 status = DRMS_ERROR_OUTOFMEMORY;
04378 }
04379 else
04380 {
04381 if (env->verbose)
04382 {
04383 fprintf(stdout, "Sorted (by tapeid/filename) SUNUMs (sunum, tapeid, filenum):\n");
04384 }
04385
04386 while ((ponesuinfo = hiter_getnext(&hit)) != NULL)
04387 {
04388 if (env->verbose)
04389 {
04390 fprintf(stdout,
04391 "%llu\t%s\t%d\n",
04392 (unsigned long long)(*ponesuinfo)->sunum,
04393 (*ponesuinfo)->arch_tape,
04394 (*ponesuinfo)->arch_tape_fn);
04395 }
04396
04397 sunum[cnt].sunum = (*ponesuinfo)->sunum;
04398 sunum[cnt].series = (*ponesuinfo)->owning_series;
04399 cnt++;
04400 }
04401 }
04402 }
04403 }
04404
04405
04406
04407
04408
04409 if (!bail)
04410 {
04411 status = drms_getunits_ex(env, cnt, sunum, retrieve, dontwait);
04412 if (status)
04413 {
04414 bail = 1;
04415 }
04416 }
04417
04418 if (!bail)
04419 {
04420 if (!dontwait)
04421 {
04422 if (setSU(env, rs, sortalso, suinfoauth))
04423 {
04424 bail = 1;
04425 }
04426 else
04427 {
04428 if (linkedrecs && fetchLinks)
04429 {
04430 if (setSU(env, linkedrecs, sortalso, suinfoauth))
04431 {
04432 bail = 1;
04433 }
04434 }
04435 }
04436 }
04437 }
04438 }
04439
04440 if (linkedrecs)
04441 {
04442
04443
04444
04445
04446
04447
04448 if (linkedrecs->ss_currentrecs)
04449 {
04450 free(linkedrecs->ss_currentrecs);
04451 }
04452
04453
04454 if (linkedrecs->records)
04455 {
04456 free(linkedrecs->records);
04457 linkedrecs->records = NULL;
04458 }
04459
04460 free(linkedrecs);
04461 }
04462
04463 if (infostructs)
04464 {
04465 free(infostructs);
04466 infostructs = NULL;
04467 }
04468
04469 if (suinfoauth)
04470 {
04471 hcon_destroy(&suinfoauth);
04472 }
04473
04474 if (seriesreqinfo)
04475 {
04476 free(seriesreqinfo);
04477 seriesreqinfo = NULL;
04478 }
04479
04480 if (sunumreqinfo)
04481 {
04482 free(sunumreqinfo);
04483 sunumreqinfo = NULL;
04484 }
04485
04486 if (sunum)
04487 {
04488 free(sunum);
04489 sunum = NULL;
04490 }
04491 }
04492
04493 return status;
04494 }
04495
04496 int drms_stage_records(DRMS_RecordSet_t *rs, int retrieve, int dontwait)
04497 {
04498
04499 dontwait = 0;
04500
04501 return drms_stage_records_internal(rs, retrieve, dontwait, NULL);
04502 }
04503
04504 int drms_sortandstage_records(DRMS_RecordSet_t *rs, int retrieve, int dontwait, HContainer_t **suinfo)
04505 {
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522
04523
04524 dontwait = 0;
04525
04526 return drms_stage_records_internal(rs, retrieve, dontwait, suinfo);
04527 }
04528
04529 static int InsertRec(HContainer_t **allRecs, DRMS_Record_t *rec, int *nsunums)
04530 {
04531 char hashkey[DRMS_MAXHASHKEYLEN];
04532 int istat = 0;
04533
04534 if (allRecs)
04535 {
04536 drms_make_hashkey(hashkey, rec->seriesinfo->seriesname, rec->recnum);
04537
04538 if (!*allRecs)
04539 {
04540 *allRecs = hcon_create(sizeof(DRMS_Record_t *),
04541 DRMS_MAXHASHKEYLEN,
04542 NULL,
04543 NULL,
04544 NULL,
04545 NULL,
04546 0);
04547 }
04548
04549 if (*allRecs)
04550 {
04551 if (!hcon_member_lower(*allRecs, hashkey))
04552 {
04553 (*nsunums)++;
04554 hcon_insert_lower(*allRecs, hashkey, &rec);
04555 }
04556 }
04557 else
04558 {
04559 fprintf(stderr, "Out of memory in InsertRec().\n");
04560 istat = 1;
04561 }
04562 }
04563 else
04564 {
04565 istat = 1;
04566 }
04567
04568 return istat;
04569 }
04570
04571 static int RecnumSort(const void *he1, const void *he2)
04572 {
04573 DRMS_Record_t **pr1 = (DRMS_Record_t **)hcon_getval(*((HContainerElement_t **)he1));
04574 DRMS_Record_t **pr2 = (DRMS_Record_t **)hcon_getval(*((HContainerElement_t **)he2));
04575 DRMS_Record_t *r1 = NULL;
04576 DRMS_Record_t *r2 = NULL;
04577
04578 XASSERT(pr1 && pr2);
04579
04580 r1 = *pr1;
04581 r2 = *pr2;
04582
04583 return (r1->recnum < r2->recnum) ? -1 : (r1->recnum > r2->recnum ? 1 : 0);
04584 }
04585
04586
04587 static HContainer_t *FindAllRecsWithSUs(DRMS_Record_t **recs, int nRecs, int *nAllRecs, int *status)
04588 {
04589 int nsunums = 0;
04590 HContainer_t *allRecs = NULL;
04591 DRMS_Segment_t *seg = NULL;
04592 int iRec;
04593 HIterator_t *lastseg = NULL;
04594 DRMS_Segment_t *tSeg = NULL;
04595 DRMS_Record_t *tRec = NULL;
04596 int istat = DRMS_SUCCESS;
04597
04598 for (iRec = 0; iRec < nRecs && istat == DRMS_SUCCESS; iRec++)
04599 {
04600 while ((seg = drms_record_nextseg(recs[iRec], &lastseg, 0)))
04601 {
04602 if (seg->info->islink)
04603 {
04604
04605 tSeg = drms_segment_lookup(recs[iRec], seg->info->name);
04606
04607 if (!tSeg)
04608 {
04609
04610
04611 continue;
04612 }
04613
04614 tRec = tSeg->record;
04615
04616
04617 if (InsertRec(&allRecs, tRec, &nsunums))
04618 {
04619 istat = DRMS_ERROR_INVALIDDATA;
04620 break;
04621 }
04622 }
04623 }
04624
04625 if (lastseg)
04626 {
04627 hiter_destroy(&lastseg);
04628 }
04629
04630
04631 if (recs[iRec]->sunum != -1)
04632 {
04633 if (InsertRec(&allRecs, recs[iRec], &nsunums))
04634 {
04635 istat = DRMS_ERROR_INVALIDDATA;
04636 }
04637 }
04638 }
04639
04640
04641 if (!allRecs)
04642 {
04643
04644 allRecs = hcon_create(sizeof(DRMS_Record_t *), DRMS_MAXHASHKEYLEN, NULL, NULL, NULL, NULL, 0);
04645 if (!allRecs)
04646 {
04647 fprintf(stderr, "Out of memory in InsertRec().\n");
04648 istat = DRMS_ERROR_OUTOFMEMORY;
04649 }
04650 }
04651
04652 if (status)
04653 {
04654 *status = istat;
04655 }
04656
04657 if (nAllRecs)
04658 {
04659 *nAllRecs = nsunums;
04660 }
04661
04662 return allRecs;
04663 }
04664
04665
04666
04667 int drms_record_getinfo(DRMS_RecordSet_t *rs)
04668 {
04669 int status = DRMS_SUCCESS;
04670
04671 DRMS_Record_t *rec = NULL;
04672 DRMS_Record_t **prec = NULL;
04673 int nSets = rs->ss_n;
04674 int nRecs = 0;
04675 int nAllRecs;
04676
04677
04678
04679 int iSet;
04680 int iRec;
04681 int bail = 0;
04682 long long *sunums = NULL;
04683 DRMS_Env_t *env = NULL;
04684 SUM_info_t **infostructs = NULL;
04685 HContainer_t *allRecs = NULL;
04686 HIterator_t hit;
04687
04688 if (rs->cursor)
04689 {
04690
04691 rs->cursor->infoneeded = 1;
04692 return(DRMS_SUCCESS);
04693 }
04694
04695 if (rs->n >= 1)
04696 {
04697 for (iSet = 0; !bail && iSet < nSets; iSet++)
04698 {
04699 nRecs = drms_recordset_getssnrecs(rs, iSet, &status);
04700
04701 if (status == DRMS_SUCCESS)
04702 {
04703
04704 allRecs = FindAllRecsWithSUs(&(rs->records[(rs->ss_starts)[iSet]]),
04705 nRecs,
04706 &nAllRecs,
04707 &status);
04708 }
04709
04710 if (status != DRMS_SUCCESS)
04711 {
04712 bail = 1;
04713 break;
04714 }
04715
04716 if (hcon_size(allRecs) > 0)
04717 {
04718
04719 infostructs = (SUM_info_t **)malloc(sizeof(SUM_info_t *) * nAllRecs);
04720 sunums = (long long *)malloc(sizeof(long long) * nAllRecs);
04721
04722
04723 hiter_new_sort(&hit, allRecs, RecnumSort);
04724 iRec = 0;
04725 while ((prec = (DRMS_Record_t **)hiter_getnext(&hit)) != NULL)
04726 {
04727 rec = *prec;
04728
04729 if (!env)
04730 {
04731 env = rec->env;
04732 }
04733 sunums[iRec++] = rec->sunum;
04734 }
04735
04736 hiter_free(&hit);
04737
04738
04739
04740 status = drms_getsuinfo(env, sunums, nAllRecs, infostructs);
04741
04742 if (sunums)
04743 {
04744 free(sunums);
04745 sunums = NULL;
04746 }
04747
04748 if (status != DRMS_SUCCESS)
04749 {
04750 fprintf(stderr, "drms_record_getinfo(): failure calling drms_getsuinfo(), error code %d.\n", status);
04751 bail = 1;
04752 }
04753
04754
04755
04756 if (!bail)
04757 {
04758 hiter_new_sort(&hit, allRecs, RecnumSort);
04759 iRec = 0;
04760 while ((prec = (DRMS_Record_t **)hiter_getnext(&hit)) != NULL)
04761 {
04762 rec = *prec;
04763
04764 if (rec->suinfo)
04765 {
04766
04767 free(rec->suinfo);
04768 }
04769
04770 if (rec->sunum != infostructs[iRec]->sunum)
04771 {
04772 fprintf(stderr, "Infostruct sunum does not match the record's sunum.\n");
04773 status = DRMS_ERROR_INVALIDRECORD;
04774 break;
04775 }
04776
04777 rec->suinfo = infostructs[iRec++];
04778 rec->suinfo->next = NULL;
04779 }
04780
04781 hiter_free(&hit);
04782 }
04783 }
04784
04785 if (allRecs)
04786 {
04787 hcon_destroy(&allRecs);
04788 }
04789
04790 if (infostructs)
04791 {
04792 free(infostructs);
04793 infostructs = NULL;
04794 }
04795
04796 if (sunums)
04797 {
04798 free(sunums);
04799 sunums = NULL;
04800 }
04801
04802 }
04803 }
04804
04805 return status;
04806 }
04807
04808 typedef HContainer_t * Tracker_t;
04809
04810 static void TrackerMakeRecHash(DRMS_Record_t *rec, char *buf, size_t sz)
04811 {
04812 snprintf(buf, sz, "%08p", rec);
04813 }
04814
04815 static Tracker_t *TrackerGetDelRecTracker(int *wascreated)
04816 {
04817 static Tracker_t tracker = NULL;
04818
04819 if (!wascreated)
04820 {
04821 return NULL;
04822 }
04823
04824 if (!tracker)
04825 {
04826 tracker = hcon_create(sizeof(char), DRMS_MAXHASHKEYLEN, NULL, NULL, NULL, NULL, 0);
04827 *wascreated = 1;
04828 }
04829 else
04830 {
04831 *wascreated = 0;
04832 }
04833
04834 return &tracker;
04835 }
04836
04837
04838 static void TrackerFreeTracker(Tracker_t *tracker)
04839 {
04840 if (tracker)
04841 {
04842
04843 hcon_destroy(tracker);
04844 }
04845 }
04846
04847 static int TrackerRecDeleted(Tracker_t tracker, DRMS_Record_t *rec)
04848 {
04849 char hashkey[DRMS_MAXHASHKEYLEN];
04850
04851 if (tracker)
04852 {
04853 TrackerMakeRecHash(rec, hashkey, sizeof(hashkey));
04854 return (hcon_member(tracker, hashkey));
04855 }
04856 else
04857 {
04858 return 0;
04859 }
04860 }
04861
04862 static void TrackerInsertRec(Tracker_t tracker, DRMS_Record_t *rec)
04863 {
04864 char hashkey[DRMS_MAXHASHKEYLEN];
04865 char yes = 'y';
04866
04867 if (tracker)
04868 {
04869 TrackerMakeRecHash(rec, hashkey, sizeof(hashkey));
04870 hcon_insert(tracker, hashkey, &yes);
04871 }
04872 }
04873
04874
04875
04876
04877 static int IsCachedRecord(DRMS_Env_t *env, DRMS_Record_t *rec)
04878 {
04879 int ans = 0;
04880 int drmsstat;
04881
04882 if (env && rec && rec->seriesinfo && rec->seriesinfo->seriesname && drms_series_exists(env, rec->seriesinfo->seriesname, &drmsstat))
04883 {
04884 char hashkey[DRMS_MAXHASHKEYLEN];
04885
04886 drms_make_hashkey(hashkey, rec->seriesinfo->seriesname, rec->recnum);
04887 ans = (hcon_lookup(&env->record_cache, hashkey) != NULL);
04888 }
04889
04890 return ans;
04891 }
04892
04893
04894
04895
04896 void drms_free_records(DRMS_RecordSet_t *rs)
04897 {
04898 int i;
04899 Tracker_t tracker = NULL;
04900 Tracker_t *trackerRef = NULL;
04901 HIterator_t *hit = NULL;
04902 DRMS_Link_t *link = NULL;
04903 DRMS_Record_t *lrec = NULL;
04904 char hashkey[DRMS_MAXHASHKEYLEN];
04905 DRMS_Env_t *env = NULL;
04906 DRMS_RecordSet_t *rslink = NULL;
04907 DRMS_Record_t *delrec = NULL;
04908 int wascreated = 0;
04909 int wascreatedEver = 0;
04910
04911 if (!rs)
04912 return;
04913
04914 if (!rs->cursor)
04915 {
04916 for (i=0; i<rs->n; i++)
04917 if (IsCachedRecord(rs->env, rs->records[i]))
04918 {
04919
04920
04921
04922
04923
04924
04925
04926
04927
04928
04929
04930
04931
04932
04933
04934
04935
04936
04937
04938
04939
04940
04941
04942
04943
04944
04945
04946
04947 trackerRef = TrackerGetDelRecTracker(&wascreated);
04948 tracker = *trackerRef;
04949
04950 if (!tracker)
04951 {
04952 fprintf(stderr, "WARNING: Couldn't obtain record tracker; not freeing records.\n");
04953 break;
04954 }
04955
04956 if (wascreated)
04957 {
04958 wascreatedEver = 1;
04959 }
04960
04961 if (TrackerRecDeleted(tracker, rs->records[i]))
04962 {
04963 continue;
04964 }
04965
04966 env = rs->records[i]->env;
04967
04968
04969
04970
04971
04972
04973 if (rs->records[i]->readonly == 1)
04974 {
04975 hit = hiter_create(&rs->records[i]->links);
04976
04977 }
04978
04979 if (hit)
04980 {
04981
04982 while ((link = (DRMS_Link_t *)hiter_getnext(hit)) != NULL)
04983 {
04984 if (link->recnum >= 0)
04985 {
04986
04987
04988
04989 drms_make_hashkey(hashkey, link->info->target_series, link->recnum);
04990 lrec = hcon_lookup(&env->record_cache, hashkey);
04991
04992
04993
04994 if (lrec && lrec->readonly && link->wasFollowed)
04995 {
04996
04997
04998
04999
05000 rslink = malloc(sizeof(DRMS_RecordSet_t));
05001
05002 if (!rslink)
05003 {
05004
05005 break;
05006 }
05007
05008 rslink->n = 1;
05009 rslink->records = malloc(sizeof(DRMS_Record_t *));
05010 rslink->records[0] = lrec;
05011 rslink->ss_n = 0;
05012 rslink->ss_queries = NULL;
05013 rslink->ss_types = NULL;
05014 rslink->ss_starts = NULL;
05015 rslink->ss_currentrecs = NULL;
05016 rslink->cursor = NULL;
05017 rslink->env = env;
05018
05019 delrec = lrec;
05020 drms_free_records(rslink);
05021 rslink = NULL;
05022 }
05023 }
05024 }
05025
05026 hiter_destroy(&hit);
05027 }
05028
05029
05030
05031 delrec = rs->records[i];
05032 drms_free_record(rs->records[i]);
05033 rs->records[i] = NULL;
05034 TrackerInsertRec(tracker, delrec);
05035 }
05036
05037 if (rs->n>0 && rs->records)
05038 {
05039
05040
05041 free(rs->records);
05042 }
05043 }
05044 else
05045 {
05046
05047 if (rs->records)
05048 {
05049 for (i=0; i < rs->cursor->chunksize; i++)
05050 {
05051 if (IsCachedRecord(rs->env, rs->records[i]))
05052 {
05053
05054
05055
05056
05057
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067
05068
05069
05070
05071
05072
05073
05074
05075
05076
05077
05078
05079
05080
05081 trackerRef = TrackerGetDelRecTracker(&wascreated);
05082 tracker = *trackerRef;
05083
05084 if (!tracker)
05085 {
05086 fprintf(stderr, "WARNING: Couldn't obtain record tracker; not freeing records.\n");
05087 break;
05088 }
05089
05090 if (wascreated)
05091 {
05092 wascreatedEver = 1;
05093 }
05094
05095 if (TrackerRecDeleted(tracker, rs->records[i]))
05096 {
05097 continue;
05098 }
05099
05100 env = rs->records[i]->env;
05101
05102
05103
05104
05105
05106
05107 if (rs->records[i]->readonly == 1)
05108 {
05109 hit = hiter_create(&rs->records[i]->links);
05110
05111 }
05112
05113 if (hit)
05114 {
05115
05116 while ((link = (DRMS_Link_t *)hiter_getnext(hit)) != NULL)
05117 {
05118 if (link->recnum >= 0)
05119 {
05120
05121
05122
05123 drms_make_hashkey(hashkey, link->info->target_series, link->recnum);
05124 lrec = hcon_lookup(&env->record_cache, hashkey);
05125
05126
05127
05128 if (lrec && lrec->readonly && link->wasFollowed)
05129 {
05130
05131
05132
05133
05134 rslink = malloc(sizeof(DRMS_RecordSet_t));
05135
05136 if (!rslink)
05137 {
05138
05139 break;
05140 }
05141
05142 rslink->n = 1;
05143 rslink->records = malloc(sizeof(DRMS_Record_t *));
05144 rslink->records[0] = lrec;
05145 rslink->ss_n = 0;
05146 rslink->ss_queries = NULL;
05147 rslink->ss_types = NULL;
05148 rslink->ss_starts = NULL;
05149 rslink->ss_currentrecs = NULL;
05150 rslink->cursor = NULL;
05151 rslink->env = env;
05152
05153 delrec = lrec;
05154 drms_free_records(rslink);
05155 rslink = NULL;
05156 }
05157 }
05158 }
05159
05160 hiter_destroy(&hit);
05161 }
05162
05163
05164 delrec = rs->records[i];
05165 drms_free_record(rs->records[i]);
05166 rs->records[i] = NULL;
05167 TrackerInsertRec(tracker, delrec);
05168 }
05169 }
05170
05171 if (rs->cursor->chunksize > 0)
05172 {
05173 free(rs->records);
05174 }
05175 }
05176 }
05177
05178 rs->n = 0;
05179
05180
05181 if (rs->ss_queries)
05182 {
05183 int iSet;
05184 for (iSet = 0; iSet < rs->ss_n; iSet++)
05185 {
05186 if (rs->ss_queries[iSet])
05187 {
05188 free(rs->ss_queries[iSet]);
05189 }
05190 }
05191 free(rs->ss_queries);
05192 rs->ss_queries = NULL;
05193 }
05194
05195 if (rs->ss_types)
05196 {
05197 free(rs->ss_types);
05198 rs->ss_types = NULL;
05199 }
05200 if (rs->ss_starts)
05201 {
05202 free(rs->ss_starts);
05203 rs->ss_starts = NULL;
05204 }
05205 if (rs->ss_currentrecs)
05206 {
05207 free(rs->ss_currentrecs);
05208 rs->ss_currentrecs = NULL;
05209 }
05210 if (rs->cursor)
05211 {
05212 drms_free_cursor(&(rs->cursor));
05213 }
05214
05215
05216
05217 rs->ss_n = 0;
05218
05219 free(rs);
05220
05221
05222 if (tracker && wascreatedEver)
05223 {
05224 TrackerFreeTracker(trackerRef);
05225 }
05226 }
05227
05228
05229
05230
05231
05232
05233
05234 DRMS_Record_t *drms_create_record(DRMS_Env_t *env, char *series,
05235 DRMS_RecLifetime_t lifetime, int *status)
05236 {
05237 DRMS_RecordSet_t *rs;
05238 DRMS_Record_t *rec;
05239
05240 rs = drms_create_records(env, 1, series, lifetime, status);
05241 if (rs && (rs->n==1))
05242 {
05243 rec = rs->records[0];
05244 free(rs->records);
05245
05246
05247 if (rs->ss_currentrecs)
05248 {
05249 free(rs->ss_currentrecs);
05250 rs->ss_currentrecs = NULL;
05251 }
05252
05253 free(rs);
05254
05255 return rec;
05256 }
05257 else
05258 return NULL;
05259 }
05260
05261
05262
05263
05264
05265
05266
05267
05268
05269 DRMS_Record_t *drms_clone_record(DRMS_Record_t *oldrec,
05270 DRMS_RecLifetime_t lifetime,
05271 DRMS_CloneAction_t mode, int *status)
05272 {
05273 DRMS_RecordSet_t rs_old,*rs;
05274 DRMS_Record_t *rec;
05275
05276 rs_old.n = 1;
05277 rs_old.records = alloca(sizeof(DRMS_Record_t *));
05278 rs_old.records[0] = oldrec;
05279 rs_old.ss_n = 0;
05280 rs_old.ss_queries = NULL;
05281 rs_old.ss_types = NULL;
05282 rs_old.ss_starts = NULL;
05283 rs_old.ss_currentrecs = NULL;
05284 rs_old.cursor = NULL;
05285 rs_old.env = oldrec->env;
05286
05287 rs = drms_clone_records(&rs_old, lifetime, mode, status);
05288 if (rs && (rs->n==1))
05289 {
05290 rec = rs->records[0];
05291 free(rs->records);
05292 free(rs);
05293 return rec;
05294 }
05295 else
05296 return NULL;
05297 }
05298
05299
05300
05301
05302
05303
05304
05305
05306
05307
05308
05309
05310
05311
05312
05313
05314 int drms_close_record(DRMS_Record_t *rec, int action)
05315 {
05316 DRMS_RecordSet_t *rs_old = malloc(sizeof(DRMS_RecordSet_t));
05317
05318 rs_old->n = 1;
05319 rs_old->records = malloc(sizeof(DRMS_Record_t *));
05320 rs_old->records[0] = rec;
05321 rs_old->ss_n = 0;
05322 rs_old->ss_queries = NULL;
05323 rs_old->ss_types = NULL;
05324 rs_old->ss_starts = NULL;
05325 rs_old->ss_currentrecs = NULL;
05326 rs_old->cursor = NULL;
05327 rs_old->env = rec->env;
05328
05329
05330
05331
05332
05333
05334
05335
05336 return drms_close_records(rs_old, action);
05337 }
05338
05339
05340
05341 int drms_closeall_records(DRMS_Env_t *env, int action)
05342 {
05343 HIterator_t hit;
05344 DRMS_Record_t *rec;
05345 int status;
05346
05347 CHECKNULL(env);
05348 status = 0;
05349 hiter_new(&hit, &env->record_cache);
05350 while( (rec = (DRMS_Record_t *)hiter_getnext(&hit)) )
05351 {
05352 if (action == DRMS_INSERT_RECORD && !rec->readonly)
05353 status = drms_close_record(rec, action);
05354 else
05355 drms_free_record(rec);
05356 if (status)
05357 break;
05358 }
05359
05360 hiter_free(&hit);
05361
05362 return status;
05363 }
05364
05365
05366
05367
05368
05369
05370 void drms_free_record(DRMS_Record_t *rec)
05371 {
05372 char hashkey[DRMS_MAXHASHKEYLEN];
05373 XASSERT(rec);
05374 #ifdef DEBUG
05375 printf("freeing '%s':%lld\n", rec->seriesinfo->seriesname, rec->recnum);
05376 #endif
05377 if (rec->seriesinfo) {
05378 drms_make_hashkey(hashkey, rec->seriesinfo->seriesname, rec->recnum);
05379
05380
05381
05382
05383 --rec->refcount;
05384
05385 if (rec->refcount == 0)
05386 {
05387 hcon_remove(&rec->env->record_cache, hashkey);
05388 }
05389 }
05390 }
05391
05392
05393
05394
05395
05396
05397
05398
05399
05400
05401
05402
05403
05404
05405
05406
05407
05408
05409 DRMS_Record_t *drms_retrieve_record(DRMS_Env_t *env, const char *seriesname,
05410 long long recnum,
05411 HContainer_t *goodsegcont,
05412 int *status)
05413 {
05414 int stat;
05415 DRMS_Record_t *rec;
05416 char hashkey[DRMS_MAXHASHKEYLEN];
05417 HIterator_t *hit = NULL;
05418 const char *hkey = NULL;
05419
05420 CHECKNULL_STAT(env,status);
05421
05422 #ifdef DEBUG
05423 printf("[Trying to retrieve dataset (series=%s, recnum=%lld).\n",seriesname, recnum);
05424 #endif
05425 drms_make_hashkey(hashkey, seriesname, recnum);
05426
05427 if ( (rec = hcon_lookup(&env->record_cache, hashkey)) == NULL )
05428 {
05429
05430 if ((rec = drms_alloc_record(env, seriesname, recnum, &stat)) == NULL)
05431 {
05432 if (status)
05433 *status = stat;
05434 return NULL;
05435 }
05436
05437 #ifdef DEBUG
05438 printf("Allocated the following template for dataset (%s,%lld):\n",
05439 seriesname, recnum);
05440 drms_print_record(rec);
05441 #endif
05442
05443
05444 if ((stat = drms_populate_record(env, rec, recnum)))
05445 {
05446 if (status)
05447 *status = stat;
05448 goto bailout;
05449 }
05450
05451
05452 if (goodsegcont)
05453 {
05454 hit = hiter_create(&(rec->segments));
05455 if (hit)
05456 {
05457 while (hiter_extgetnext(hit, &hkey) != NULL)
05458 {
05459 if (!hcon_lookup(goodsegcont, hkey))
05460 {
05461 hcon_remove(&(rec->segments), hkey);
05462 }
05463 }
05464
05465 hiter_destroy(&hit);
05466 }
05467 }
05468
05469
05470 rec->readonly = 1;
05471
05472 if (status)
05473 *status = DRMS_SUCCESS;
05474 return rec;
05475 }
05476 else
05477 {
05478 #ifdef DEBUG
05479 printf("Found dataset in cache.\n");
05480 #endif
05481
05482
05483 ++rec->refcount;
05484
05485 if (status)
05486 *status = DRMS_SUCCESS;
05487 return rec;
05488 }
05489
05490 bailout:
05491 drms_free_record(rec);
05492 return NULL;
05493 }
05494
05495
05496
05497
05498
05499
05500
05501
05502
05503 static int ParseAndExecTempTableSQL(DRMS_Session_t *session, char **pquery)
05504 {
05505 int istat = DRMS_SUCCESS;
05506 char *query = NULL;
05507 char *pNextStatement = NULL;
05508 int rsp = 0;
05509 int tempTab = 0;
05510
05511 if (pquery && *pquery)
05512 {
05513 query = *pquery;
05514
05515 if ((pNextStatement = strstr(query, ";\n")) != NULL)
05516 {
05517 *pNextStatement = '\0';
05518 *pquery = strdup(pNextStatement + 2);
05519
05520 if (*pquery)
05521 {
05522 tempTab = 1;
05523 }
05524 else
05525 {
05526 istat = DRMS_ERROR_OUTOFMEMORY;
05527 }
05528 }
05529 else
05530 {
05531
05532
05533
05534 rsp = drms_series_hastemptab(query);
05535
05536 if (rsp == -1)
05537 {
05538 istat = DRMS_ERROR_BADDBQUERY;
05539 }
05540 else
05541 {
05542 tempTab = rsp;
05543 }
05544
05545
05546 *pquery = strdup(query);
05547 }
05548
05549 if (istat == DRMS_SUCCESS && tempTab == 1)
05550 {
05551
05552 if (drms_dms(session, NULL, query))
05553 {
05554 istat = DRMS_ERROR_QUERYFAILED;
05555 }
05556 }
05557
05558 free(query);
05559 }
05560
05561 return istat;
05562 }
05563
05564
05565
05566
05567
05568
05569
05570
05571
05572
05573
05574
05575
05576
05577
05578
05579
05580
05581
05582 static DRMS_RecordSet_t *drms_retrieve_records_internal(DRMS_Env_t *env,
05583 const char *seriesname,
05584 char *where,
05585 const char *pkwhere,
05586 const char *npkwhere,
05587 int filter, int mixed,
05588 HContainer_t *goodsegcont,
05589 const char *qoverride,
05590 int allvers,
05591 int nrecs,
05592 HContainer_t *firstlast,
05593 HContainer_t *pkwhereNFL,
05594 int recnumq,
05595 int cursor,
05596 HContainer_t *links,
05597 HContainer_t *keys,
05598 HContainer_t *segs,
05599 int *status)
05600 {
05601 int i,throttled;
05602 int stat = 0;
05603 long long recnum;
05604 DRMS_RecordSet_t *rs;
05605 DB_Binary_Result_t *qres;
05606 DRMS_Record_t *template;
05607 char hashkey[DRMS_MAXHASHKEYLEN];
05608 char *series_lower;
05609 long long limit = 0;
05610 HIterator_t hit;
05611 const char *hkey = NULL;
05612 char *tmpquery = NULL;
05613 long long recsize = 0;
05614
05615 CHECKNULL_STAT(env,status);
05616
05617 if ((template = drms_template_record(env,seriesname,status)) == NULL)
05618 return NULL;
05619 drms_link_getpidx(template);
05620
05621 series_lower = strdup(seriesname);
05622 strtolower(series_lower);
05623
05624 char *query = NULL;
05625
05626 if (qoverride)
05627 {
05628 query = strdup(qoverride);
05629
05630 if (keys && hcon_size(keys) > 0)
05631 {
05632 recsize = partialRecordMemsize(template, NULL, keys, NULL);
05633 }
05634 else
05635 {
05636 recsize = drms_record_memsize(template);
05637 }
05638
05639 limit = (long long)((0.4e6 * env->query_mem) / recsize);
05640 }
05641 else
05642 {
05643 query = drms_query_string(env, seriesname, where, pkwhere, npkwhere, filter, mixed, keys && hcon_size(keys) > 0 ? DRMS_QUERY_PARTIAL : (nrecs == 0 ? DRMS_QUERY_ALL : DRMS_QUERY_N), &nrecs, (char *)keys , allvers, firstlast, pkwhereNFL, recnumq, cursor, &limit);
05644 }
05645
05646 if (env->verbose)
05647 {
05648 fprintf(stdout, "drms_retrieve_records_internal() limit %lld.\n", limit);
05649 }
05650
05651 #ifdef DEBUG
05652 printf("ENTER drms_retrieve_records, env=%p, status=%p\n",env,status);
05653 #endif
05654
05655 #ifdef DEBUG
05656 printf("query = '%s'\n",query);
05657 printf("\nMemory used = %Zu\n\n",xmem_recenthighwater());
05658 #endif
05659
05660
05661
05662
05663
05664 if (ParseAndExecTempTableSQL(env->session, &query))
05665 {
05666 stat = DRMS_ERROR_QUERYFAILED;
05667 fprintf(stderr, "Failed in drms_retrieve_records, query = '%s'\n",query);
05668 goto bailout1;
05669 }
05670
05671 TIME(qres = drms_query_bin(env->session, query));
05672 if (qres == NULL)
05673 {
05674 stat = DRMS_ERROR_QUERYFAILED;
05675 fprintf(stderr, "Failed in drms_retrieve_records, query = '%s'\n",query);
05676 goto bailout1;
05677 }
05678 #ifdef DEBUG
05679 db_print_binary_result(qres);
05680 printf("\nMemory used after query = %Zu\n\n",xmem_recenthighwater());
05681 printf("number of record returned = %d\n",qres->num_rows);
05682 #endif
05683 throttled = (qres->num_rows == limit);
05684
05685
05686
05687 rs = malloc(sizeof(DRMS_RecordSet_t));
05688 XASSERT(rs);
05689 if (qres->num_rows<1)
05690 {
05691 rs->n = 0;
05692 rs->records = NULL;
05693 }
05694 else
05695 {
05696
05697 #ifdef DEBUG
05698 PushTimer();
05699 #endif
05700 rs->n = qres->num_rows;
05701 rs->records=malloc(rs->n*sizeof(DRMS_Record_t*));
05702 XASSERT(rs->records);
05703 for (i=0; i<rs->n; i++)
05704 {
05705 #ifdef DEBUG
05706 printf("Memory used = %Zu\n",xmem_recenthighwater());
05707 #endif
05708 recnum = db_binary_field_getlonglong(qres, i, 0);
05709 drms_make_hashkey(hashkey, seriesname, recnum);
05710
05711
05712
05713 if ((links && hcon_size(links) > 0) || (keys && hcon_size(keys) > 0) || (segs && hcon_size(segs) > 0))
05714 {
05715 DRMS_Link_t *link = NULL;
05716 DRMS_Link_t **plink = NULL;
05717 DRMS_Keyword_t *key = NULL;
05718 DRMS_Keyword_t **pkey = NULL;
05719 DRMS_Segment_t *seg = NULL;
05720 DRMS_Segment_t **pseg = NULL;
05721
05722
05723 rs->records[i] = calloc(1, sizeof(DRMS_Record_t));
05724
05725
05726 rs->records[i]->env = template->env;
05727 rs->records[i]->sunum = -1;
05728 rs->records[i]->init = template->init;
05729 rs->records[i]->readonly = template->readonly;
05730 rs->records[i]->lifetime = template->lifetime;
05731 rs->records[i]->su = template->su;
05732 rs->records[i]->slotnum = template->slotnum;
05733 rs->records[i]->sessionid = template->sessionid;
05734 rs->records[i]->sessionns = template->sessionns;
05735 rs->records[i]->seriesinfo = template->seriesinfo;
05736
05737
05738 hcon_init(&rs->records[i]->links, sizeof(DRMS_Link_t), DRMS_MAXHASHKEYLEN, (void (*)(const void *))drms_free_link_struct, (void (*)(const void *, const void *))drms_copy_link_struct);
05739 hcon_init(&rs->records[i]->keywords, sizeof(DRMS_Keyword_t), DRMS_MAXHASHKEYLEN, (void (*)(const void *))drms_free_keyword_struct, (void (*)(const void *, const void *))drms_copy_keyword_struct);
05740 hcon_init(&rs->records[i]->segments, sizeof(DRMS_Segment_t), DRMS_MAXHASHKEYLEN, (void (*)(const void *))drms_free_segment_struct, (void (*)(const void *, const void *))drms_copy_segment_struct);
05741
05742 const char *keyVal = NULL;
05743 const char *strVal = NULL;
05744
05745
05746 if (!links)
05747 {
05748
05749 hcon_copy(&(rs->records[i]->links), &template->links);
05750 }
05751 else if (hcon_size(links) > 0)
05752 {
05753 hiter_new_sort(&hit, links, linkListSort);
05754 while((plink = (DRMS_Link_t **)hiter_extgetnext(&hit, &keyVal)) != NULL)
05755 {
05756 link = *plink;
05757
05758
05759 hcon_insert(&(rs->records[i]->links), keyVal, link);
05760 }
05761 hiter_free(&hit);
05762 }
05763
05764
05765 hiter_new(&hit, &(rs->records[i]->links));
05766 while((link = (DRMS_Link_t *)hiter_getnext(&hit)) != NULL)
05767 {
05768 link->record = rs->records[i];
05769 }
05770 hiter_free(&hit);
05771
05772
05773
05774
05775 if (!keys)
05776 {
05777
05778 hcon_copy(&(rs->records[i]->keywords), &template->keywords);
05779 }
05780 else if (hcon_size(keys) > 0)
05781 {
05782 hiter_new_sort(&hit, keys, keyListSort);
05783 while((pkey = (DRMS_Keyword_t **)hiter_extgetnext(&hit, &keyVal)) != NULL)
05784 {
05785 key = *pkey;
05786
05787
05788 hcon_insert(&(rs->records[i]->keywords), keyVal, key);
05789
05790 if (key->info->type == DRMS_TYPE_STRING)
05791 {
05792
05793 strVal = key->value.string_val;
05794 key = hcon_lookup_lower(&(rs->records[i]->keywords), keyVal);
05795 XASSERT(key);
05796 key->value.string_val = strdup(strVal);
05797 }
05798 }
05799 hiter_free(&hit);
05800 }
05801
05802
05803 hiter_new(&hit, &(rs->records[i]->keywords));
05804 while((key = (DRMS_Keyword_t *)hiter_getnext(&hit)) != NULL)
05805 {
05806 key->record = rs->records[i];
05807 }
05808 hiter_free(&hit);
05809
05810
05811 if (!segs)
05812 {
05813
05814 hcon_copy(&(rs->records[i]->segments), &template->segments);
05815 }
05816 else if (hcon_size(segs) > 0)
05817 {
05818 hiter_new_sort(&hit, segs, segListSort);
05819 while((pseg = (DRMS_Segment_t **)hiter_extgetnext(&hit, &keyVal)) != NULL)
05820 {
05821 seg = *pseg;
05822
05823
05824 hcon_insert(&(rs->records[i]->segments), keyVal, seg);
05825 }
05826 hiter_free(&hit);
05827 }
05828
05829
05830 hiter_new(&hit, &(rs->records[i]->segments));
05831 while((seg = (DRMS_Segment_t *)hiter_getnext(&hit)) != NULL)
05832 {
05833 seg->record = rs->records[i];
05834 }
05835 hiter_free(&hit);
05836
05837
05838 if (rs->records[i])
05839 {
05840 rs->records[i]->refcount = 1;
05841 }
05842
05843
05844 drms_link_getpidx(rs->records[i]);
05845
05846
05847 rs->records[i]->recnum = recnum;
05848
05849
05850
05851 rs->records[i]->suinfo = NULL;
05852 }
05853 else
05854 {
05855 if ((rs->records[i] = hcon_lookup(&env->record_cache, hashkey)) == NULL)
05856 {
05857
05858 rs->records[i] = hcon_allocslot(&env->record_cache, hashkey);
05859
05860
05861 drms_copy_record_struct(rs->records[i], template);
05862
05863
05864 if (rs->records[i])
05865 {
05866 rs->records[i]->refcount = 1;
05867 }
05868
05869
05870 drms_link_getpidx(rs->records[i]);
05871
05872 rs->records[i]->recnum = recnum;
05873
05874
05875
05876 rs->records[i]->suinfo = NULL;
05877 }
05878 else
05879 {
05880
05881
05882
05883 if (rs->records[i])
05884 {
05885 ++rs->records[i]->refcount;
05886 }
05887
05888 free(rs->records[i]->sessionns);
05889 }
05890 }
05891 rs->records[i]->readonly = 1;
05892 }
05893
05894
05895
05896 #ifdef DEBUG
05897 printf("Time to allocate record structures = %f\n",PopTimer());
05898 printf("\nMemory used before populate= %Zu\n\n",xmem_recenthighwater());
05899 #endif
05900 TIME(if ((stat = drms_populate_records(env, rs, qres)))
05901 {
05902 goto bailout;
05903 } );
05904 #ifdef DEBUG
05905 printf("\nMemory used after populate= %Zu\n\n",xmem_recenthighwater());
05906 #endif
05907 }
05908
05909 if (goodsegcont && rs->n > 0)
05910 {
05911 const char **keynames = NULL;
05912 int nsegs = 0;
05913 int iseg;
05914
05915 for (i=0; i < rs->n; i++)
05916 {
05917
05918 nsegs = hcon_size(&(rs->records[i]->segments));
05919
05920 if (nsegs > 0)
05921 {
05922 keynames = (const char **)malloc(sizeof(const char *) * nsegs);
05923
05924 if (keynames)
05925 {
05926 HIterator_t *hit = NULL;
05927 hit = hiter_create(&(rs->records[i]->segments));
05928 if (hit)
05929 {
05930 iseg = 0;
05931 while (hiter_extgetnext(hit, &hkey) != NULL)
05932 {
05933
05934
05935 if (!hcon_lookup(goodsegcont, hkey))
05936 {
05937 keynames[iseg] = hkey;
05938 iseg++;
05939 }
05940 }
05941
05942 nsegs = iseg;
05943 hiter_destroy(&hit);
05944 }
05945 }
05946
05947 for (iseg = 0; iseg < nsegs; iseg++)
05948 {
05949 hkey = keynames[iseg];
05950 hcon_remove(&(rs->records[i]->segments), hkey);
05951 }
05952
05953 if (keynames)
05954 {
05955 free(keynames);
05956 keynames = NULL;
05957 }
05958 }
05959 }
05960 }
05961
05962
05963 rs->ss_n = 0;
05964 rs->ss_queries = NULL;
05965 rs->ss_types = NULL;
05966 rs->ss_starts = NULL;
05967 rs->ss_currentrecs = NULL;
05968 rs->cursor = NULL;
05969 rs->env = env;
05970
05971 db_free_binary_result(qres);
05972 free(query);
05973 free(series_lower);
05974 if (status)
05975 {
05976 if (!throttled)
05977 *status = DRMS_SUCCESS;
05978 else {
05979 fprintf(stderr, "Query truncated\n");
05980 *status = DRMS_QUERY_TRUNCATED;
05981 }
05982 }
05983 return rs;
05984 bailout:
05985 db_free_binary_result(qres);
05986 for (i=0;i<rs->n;i++)
05987 drms_free_records(rs);
05988 free(rs);
05989 bailout1:
05990 if (tmpquery)
05991 {
05992 free(tmpquery);
05993 }
05994
05995 free(series_lower);
05996 free(query);
05997 if (status)
05998 *status = stat;
05999 return NULL;
06000 }
06001
06002 DRMS_RecordSet_t *drms_retrieve_records(DRMS_Env_t *env,
06003 const char *seriesname,
06004 char *where,
06005 const char *pkwhere,
06006 const char *npkwhere,
06007 int filter, int mixed,
06008 HContainer_t *goodsegcont,
06009 int allvers,
06010 int nrecs,
06011 HContainer_t *firstlast,
06012 HContainer_t *pkwhereNFL,
06013 int recnumq,
06014 int cursor,
06015 HContainer_t *links,
06016 HContainer_t *keys,
06017 HContainer_t *segs,
06018 int *status)
06019 {
06020 return drms_retrieve_records_internal(env,
06021 seriesname,
06022 where,
06023 pkwhere,
06024 npkwhere,
06025 filter,
06026 mixed,
06027 goodsegcont,
06028 NULL,
06029 allvers,
06030 nrecs,
06031 firstlast,
06032 pkwhereNFL,
06033 recnumq,
06034 cursor,
06035 NULL,
06036 keys,
06037 NULL,
06038 status);
06039 }
06040
06041
06042 static DRMS_RecordSet_t *drms_retrieve_records_prepared_query(DRMS_Env_t *env, const char *seriesName, DRMS_Record_t *templRec, const char *prepared, HContainer_t *goodsegcont, unsigned int nElems, int nArgs, DB_Type_t *intype, void **argin, int *status)
06043 {
06044 DB_Binary_Result_t *bres = NULL;
06045 DB_Binary_Result_t **pBres = NULL;
06046 DRMS_RecordSet_t *rv = NULL;
06047 DRMS_RecordSet_t *rvMerge = NULL;
06048 int iBres;
06049 long long recnum = -1;
06050 char hashkey[DRMS_MAXHASHKEYLEN];
06051 int iRec;
06052 int istat = DRMS_SUCCESS;
06053
06054 if (env && seriesName && templRec && prepared && nArgs > 0 && intype && argin)
06055 {
06056
06057 pBres = drms_query_bin_ntuple(env->session, prepared, nElems, nArgs, intype, argin);
06058 if (pBres)
06059 {
06060 for (iBres = 0; iBres < nElems; iBres++)
06061 {
06062 bres = pBres[iBres];
06063
06064 if (bres)
06065 {
06066
06067
06068 drms_link_getpidx(templRec);
06069
06070 rv = calloc(1, sizeof(DRMS_RecordSet_t));
06071 XASSERT(rv);
06072 if (rv)
06073 {
06074 if (bres->num_rows < 1)
06075 {
06076 rv->n = 0;
06077 rv->records = NULL;
06078 }
06079 else
06080 {
06081 rv->n = bres->num_rows;
06082 rv->records = malloc(rv->n * sizeof(DRMS_Record_t *));
06083 XASSERT(rv->records);
06084 if (rv->records)
06085 {
06086 for (iRec = 0; iRec < rv->n; iRec++)
06087 {
06088 recnum = db_binary_field_getlonglong(bres, iRec, 0);
06089 drms_make_hashkey(hashkey, seriesName, recnum);
06090
06091 if ((rv->records[iRec] = hcon_lookup(&env->record_cache, hashkey)) == NULL)
06092 {
06093
06094 rv->records[iRec] = hcon_allocslot(&env->record_cache, hashkey);
06095
06096
06097 drms_copy_record_struct(rv->records[iRec], templRec);
06098
06099
06100 if (rv->records[iRec])
06101 {
06102 rv->records[iRec]->refcount = 1;
06103 }
06104
06105
06106 drms_link_getpidx(rv->records[iRec]);
06107
06108
06109 rv->records[iRec]->recnum = recnum;
06110
06111
06112
06113 rv->records[iRec]->suinfo = NULL;
06114 }
06115 else
06116 {
06117
06118 ++rv->records[iRec]->refcount;
06119 free(rv->records[iRec]->sessionns);
06120 }
06121
06122 rv->records[iRec]->readonly = 1;
06123 }
06124 }
06125 else
06126 {
06127 istat = DRMS_ERROR_OUTOFMEMORY;
06128 }
06129
06130 istat = drms_populate_records(env, rv, bres);
06131
06132
06133 if (!rvMerge)
06134 {
06135 rvMerge = calloc(1, sizeof(DRMS_RecordSet_t));
06136
06137 if (!rvMerge)
06138 {
06139 istat = DRMS_ERROR_OUTOFMEMORY;
06140 break;
06141 }
06142 }
06143
06144 for (iRec = 0; iRec < rv->n; iRec++)
06145 {
06146 drms_merge_record(rvMerge, rv->records[iRec]);
06147 rv->records[iRec] = NULL;
06148 }
06149
06150 }
06151
06152 drms_close_records(rv, DRMS_FREE_RECORD);
06153 }
06154 else
06155 {
06156 istat = DRMS_ERROR_OUTOFMEMORY;
06157 }
06158
06159 db_free_binary_result(bres);
06160 pBres[iBres] = NULL;
06161
06162
06163
06164 }
06165 else
06166 {
06167 istat = DRMS_ERROR_QUERYFAILED;
06168 fprintf(stderr, "Bad element (index = %d) returned from db query in drms_retrieve_records_prepared_query(): '%s'\n", iBres, prepared);
06169 }
06170 }
06171 db_free_binary_result_tuple(&pBres, nElems);
06172 }
06173 else
06174 {
06175 istat = DRMS_ERROR_QUERYFAILED;
06176 fprintf(stderr, "Bad db query in drms_retrieve_records_prepared_query(): '%s'\n", prepared);
06177 }
06178
06179 if (istat == DRMS_SUCCESS)
06180 {
06181 rv = rvMerge;
06182
06183 if (goodsegcont && rv && rv->n > 0)
06184 {
06185 const char **keynames = NULL;
06186 int nsegs = 0;
06187 HIterator_t *hit = NULL;
06188 int iseg;
06189 const char *hkey = NULL;
06190
06191 for (iRec = 0; iRec < rv->n; iRec++)
06192 {
06193
06194 nsegs = hcon_size(&(rv->records[iRec]->segments));
06195
06196 if (nsegs > 0)
06197 {
06198 keynames = (const char **)malloc(sizeof(const char *) * nsegs);
06199
06200 if (keynames)
06201 {
06202 hit = hiter_create(&(rv->records[iRec]->segments));
06203 if (hit)
06204 {
06205 iseg = 0;
06206 while (hiter_extgetnext(hit, &hkey) != NULL)
06207 {
06208
06209
06210 if (!hcon_lookup(goodsegcont, hkey))
06211 {
06212 keynames[iseg] = hkey;
06213 iseg++;
06214 }
06215 }
06216
06217 nsegs = iseg;
06218 hiter_destroy(&hit);
06219 }
06220 }
06221 else
06222 {
06223 istat = DRMS_ERROR_OUTOFMEMORY;
06224 break;
06225 }
06226
06227 for (iseg = 0; iseg < nsegs; iseg++)
06228 {
06229 hkey = keynames[iseg];
06230 hcon_remove(&(rv->records[iRec]->segments), hkey);
06231 }
06232
06233 if (keynames)
06234 {
06235 free(keynames);
06236 keynames = NULL;
06237 }
06238 }
06239 }
06240 }
06241 }
06242
06243 if (istat == DRMS_SUCCESS && rv)
06244 {
06245
06246 rv->ss_n = 0;
06247 rv->ss_queries = NULL;
06248 rv->ss_types = NULL;
06249 rv->ss_starts = NULL;
06250 rv->ss_currentrecs = NULL;
06251 rv->cursor = NULL;
06252 rv->env = env;
06253 }
06254 }
06255 else
06256 {
06257 istat = DRMS_ERROR_INVALIDDATA;
06258 }
06259
06260 if (status)
06261 {
06262 *status = istat;
06263 }
06264
06265 return rv;
06266 }
06267
06268 static int getLinkFetchTempTable(char *tabname, size_t size)
06269 {
06270 static unsigned int id = 0;
06271
06272 if (id < 1000000)
06273 {
06274 snprintf(tabname, size, "linkfetchtemp%06u", id);
06275 id++;
06276 return 0;
06277 }
06278
06279 return 1;
06280 }
06281
06282
06283
06284
06285
06286
06287
06288
06289
06290
06291
06292
06293
06294 static DB_Binary_Result_t *dbFetchRecsFromList(DRMS_Env_t *env, const char *oSeriesName, DRMS_Link_t *linkTempl, LinkedList_t *recList, int *status)
06295 {
06296 const int NUM_ARGS = 16;
06297
06298 char tSeriesName[DRMS_MAXSERIESNAMELEN];
06299 ListNode_t *node = NULL;
06300 long long recnum = -1;
06301 char *argin[NUM_ARGS];
06302 int iArg;
06303 int iExe;
06304 int iRec;
06305 db_int8_t dbRecnum;
06306 char nbuf[32];
06307 int nRecs = 0;
06308 int nExe = 0;
06309
06310 char tmpTab[64];
06311 char tmpTab2[64];
06312 size_t stsz;
06313 size_t stsz1;
06314 size_t stsz2;
06315 size_t stsz3;
06316 size_t stsz4;
06317 char *sql = NULL;
06318 char *tPkeyList = NULL;
06319 char *oLinkColList = NULL;
06320 char *tQualPkeyList = NULL;
06321 DB_Type_t intype[NUM_ARGS];
06322 DB_Binary_Result_t *dbres = NULL;
06323
06324 int istat = DRMS_SUCCESS;
06325
06326
06327 snprintf(tSeriesName, sizeof(tSeriesName), "%s", linkTempl->info->target_series);
06328
06329
06330
06331
06332
06333
06334 nRecs = recList->nitems;
06335
06336 if (nRecs > 0)
06337 {
06338 list_llreset(recList);
06339
06340 nExe = nRecs / NUM_ARGS;
06341
06342
06343 if (nExe > 0)
06344 {
06345
06346 for (iArg = 0; iArg < NUM_ARGS; iArg++)
06347 {
06348 argin[iArg] = calloc(nExe, sizeof(db_int8_t));
06349 intype[iArg] = DB_INT8;
06350 }
06351
06352
06353
06354
06355 iArg = 0;
06356 iExe = 0;
06357 iRec = 0;
06358
06359 while (iRec < nExe * NUM_ARGS && (node = list_llnext(recList)) != NULL)
06360 {
06361
06362
06363 if (!node->data)
06364 {
06365 istat = DRMS_ERROR_DATASTRUCT;
06366 break;
06367 }
06368
06369 dbRecnum = *(long long *)node->data;
06370
06371 if (iArg == NUM_ARGS)
06372 {
06373 iArg = 0;
06374 iExe++;
06375 }
06376
06377 memcpy(argin[iArg] + iExe * db_sizeof(intype[iArg]), &dbRecnum, db_sizeof(intype[iArg]));
06378 iArg++;
06379 iRec++;
06380 }
06381 }
06382
06383 if (istat == DRMS_SUCCESS)
06384 {
06385
06386
06387
06388 if (getLinkFetchTempTable(tmpTab, sizeof(tmpTab)) == 0 && getLinkFetchTempTable(tmpTab2, sizeof(tmpTab2)) == 0)
06389 {
06390 stsz = 128;
06391 sql = calloc(stsz, sizeof(char));
06392 if (sql)
06393 {
06394 int ipkey;
06395 char *collist = NULL;
06396 char *tpkey = NULL;
06397
06398 stsz1 = 2048;
06399 collist = calloc(stsz1, sizeof(char));
06400
06401
06402 stsz2 = 1024;
06403 tPkeyList = calloc(stsz2, sizeof(char));
06404
06405
06406 stsz3 = 1024;
06407 oLinkColList = calloc(stsz3, sizeof(char));
06408
06409
06410
06411 stsz4 = 1024;
06412 tQualPkeyList = calloc(stsz4, sizeof(char));
06413
06414 if (collist && tPkeyList && oLinkColList && tQualPkeyList)
06415 {
06416 for (ipkey = 0; ipkey < linkTempl->info->pidx_num; ipkey++)
06417 {
06418 tpkey = strdup(linkTempl->info->pidx_name[ipkey]);
06419 if (!tpkey)
06420 {
06421 istat = DRMS_ERROR_OUTOFMEMORY;
06422 break;
06423 }
06424
06425 strtolower(tpkey);
06426
06427 collist = base_strcatalloc(collist, tpkey, &stsz1);
06428 collist = base_strcatalloc(collist, " ", &stsz1);
06429
06430 tPkeyList = base_strcatalloc(tPkeyList, tpkey, &stsz2);
06431
06432 oLinkColList = base_strcatalloc(oLinkColList, "ln_", &stsz3);
06433 oLinkColList = base_strcatalloc(oLinkColList, linkTempl->info->name, &stsz3);
06434 oLinkColList = base_strcatalloc(oLinkColList, "_", &stsz3);
06435 oLinkColList = base_strcatalloc(oLinkColList, tpkey, &stsz3);
06436
06437 tQualPkeyList = base_strcatalloc(tQualPkeyList, "TARGET.", &stsz4);
06438 tQualPkeyList = base_strcatalloc(tQualPkeyList, tpkey, &stsz4);
06439
06440 collist = base_strcatalloc(collist, db_type_string(drms2dbtype(linkTempl->info->pidx_type[ipkey])), &stsz1);
06441
06442 if (ipkey < linkTempl->info->pidx_num - 1)
06443 {
06444 collist = base_strcatalloc(collist, ", ", &stsz1);
06445 tPkeyList = base_strcatalloc(tPkeyList, ", ", &stsz2);
06446 oLinkColList = base_strcatalloc(oLinkColList, ", ", &stsz3);
06447 tQualPkeyList = base_strcatalloc(tQualPkeyList, ", ", &stsz4);
06448 }
06449
06450 free(tpkey);
06451 tpkey = NULL;
06452 }
06453
06454 if (istat == DRMS_SUCCESS)
06455 {
06456 sql = base_strcatalloc(sql, "CREATE TEMPORARY TABLE ", &stsz);
06457 sql = base_strcatalloc(sql, tmpTab, &stsz);
06458 sql = base_strcatalloc(sql, " (recnum bigint not null, ", &stsz);
06459 sql = base_strcatalloc(sql, collist, &stsz);
06460 sql = base_strcatalloc(sql, ")", &stsz);
06461
06462 if (drms_dms(env->session, NULL, sql))
06463 {
06464 istat = DRMS_ERROR_QUERYFAILED;
06465 }
06466 }
06467
06468 free(collist);
06469 collist = NULL;
06470 }
06471 else
06472 {
06473 istat = DRMS_ERROR_OUTOFMEMORY;
06474 }
06475
06476 free(sql);
06477 sql = NULL;
06478 }
06479 else
06480 {
06481 istat = DRMS_ERROR_OUTOFMEMORY;
06482 }
06483 }
06484 else
06485 {
06486 istat = DRMS_ERROR_OVERFLOW;
06487 }
06488 }
06489
06490 if (istat == DRMS_SUCCESS)
06491 {
06492 char *oTable = NULL;
06493
06494 stsz = 512;
06495 sql = calloc(stsz, sizeof(char));
06496 if (sql)
06497 {
06498 oTable = strdup(oSeriesName);
06499 if (!oTable)
06500 {
06501 istat = DRMS_ERROR_OUTOFMEMORY;
06502 }
06503 else
06504 {
06505 strtolower(oTable);
06506
06507 if (nExe > 0)
06508 {
06509 sql = base_strcatalloc(sql, "INSERT INTO ", &stsz);
06510 sql = base_strcatalloc(sql, tmpTab, &stsz);
06511 sql = base_strcatalloc(sql, " (recnum, ", &stsz);
06512 sql = base_strcatalloc(sql, tPkeyList, &stsz);
06513 sql = base_strcatalloc(sql, ") SELECT recnum, ", &stsz);
06514 sql = base_strcatalloc(sql, oLinkColList, &stsz);
06515 sql = base_strcatalloc(sql, " FROM ", &stsz);
06516 sql = base_strcatalloc(sql, oTable, &stsz);
06517
06518
06519 sql = base_strcatalloc(sql, " WHERE recnum IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", &stsz);
06520
06521 if (drms_dms_array(env->session, NULL, sql, nExe, NUM_ARGS, intype, (void **)argin))
06522 {
06523 istat = DRMS_ERROR_BADDBQUERY;
06524 }
06525
06526 for (iArg = 0; iArg < NUM_ARGS; iArg++)
06527 {
06528 if (argin[iArg])
06529 {
06530 free(argin[iArg]);
06531 argin[iArg] = NULL;
06532 }
06533 }
06534 }
06535
06536 free(sql);
06537 sql = NULL;
06538
06539 if (istat == DRMS_SUCCESS)
06540 {
06541 if (nRecs % NUM_ARGS != 0)
06542 {
06543
06544
06545 stsz = 512;
06546 sql = calloc(stsz, sizeof(char));
06547 if (sql)
06548 {
06549 sql = base_strcatalloc(sql, "INSERT INTO ", &stsz);
06550 sql = base_strcatalloc(sql, tmpTab, &stsz);
06551 sql = base_strcatalloc(sql, " (recnum, ", &stsz);
06552 sql = base_strcatalloc(sql, tPkeyList, &stsz);
06553 sql = base_strcatalloc(sql, ") SELECT recnum, ", &stsz);
06554 sql = base_strcatalloc(sql, oLinkColList, &stsz);
06555 sql = base_strcatalloc(sql, " FROM ", &stsz);
06556 sql = base_strcatalloc(sql, oTable, &stsz);
06557
06558
06559 sql = base_strcatalloc(sql, " WHERE recnum IN (", &stsz);
06560
06561 iRec = 0;
06562 while ((node = list_llnext(recList)) != NULL)
06563 {
06564 if (!node->data)
06565 {
06566 istat = DRMS_ERROR_DATASTRUCT;
06567 break;
06568 }
06569
06570 recnum = *(long long *)node->data;
06571 snprintf(nbuf, sizeof(nbuf), "%lld", recnum);
06572 sql = base_strcatalloc(sql, nbuf, &stsz);
06573 if (iRec < nRecs % NUM_ARGS - 1)
06574 {
06575 sql = base_strcatalloc(sql, ", ", &stsz);
06576 }
06577
06578 iRec++;
06579 }
06580
06581 sql = base_strcatalloc(sql, ")", &stsz);
06582
06583 if (drms_dms(env->session, NULL, sql))
06584 {
06585 istat = DRMS_ERROR_QUERYFAILED;
06586 }
06587
06588 free(sql);
06589 sql = NULL;
06590 }
06591 else
06592 {
06593 istat = DRMS_ERROR_OUTOFMEMORY;
06594 }
06595 }
06596 }
06597
06598 free(oTable);
06599 oTable = NULL;
06600 }
06601 }
06602 else
06603 {
06604 istat = DRMS_ERROR_OUTOFMEMORY;
06605 }
06606 }
06607
06608 if (istat == DRMS_SUCCESS)
06609 {
06610
06611
06612
06613
06614
06615 stsz = 256;
06616 sql = calloc(stsz, sizeof(char));
06617 if (sql)
06618 {
06619
06620
06621
06622
06623
06624 sql = base_strcatalloc(sql, "SELECT ORIG.recnum AS orecnum, TARGET.recnum AS trecnum, ", &stsz);
06625 sql = base_strcatalloc(sql, tQualPkeyList, &stsz);
06626 sql = base_strcatalloc(sql, " INTO TEMPORARY TABLE ", &stsz);
06627 sql = base_strcatalloc(sql, tmpTab2, &stsz);
06628 sql = base_strcatalloc(sql, " FROM ", &stsz);
06629 sql = base_strcatalloc(sql, tmpTab, &stsz);
06630 sql = base_strcatalloc(sql, " AS ORIG INNER JOIN ", &stsz);
06631 sql = base_strcatalloc(sql, tSeriesName, &stsz);
06632 sql = base_strcatalloc(sql, " AS TARGET USING (", &stsz);
06633 sql = base_strcatalloc(sql, tPkeyList, &stsz);
06634 sql = base_strcatalloc(sql, ");", &stsz);
06635
06636
06637
06638
06639 if (drms_dms(env->session, NULL, sql))
06640 {
06641 istat = DRMS_ERROR_QUERYFAILED;
06642 }
06643
06644 free(sql);
06645 sql = NULL;
06646 }
06647 else
06648 {
06649 istat = DRMS_ERROR_OUTOFMEMORY;
06650 }
06651
06652 if (istat == DRMS_SUCCESS)
06653 {
06654 stsz = 256;
06655 sql = calloc(stsz, sizeof(char));
06656 if (sql)
06657 {
06658 sql = base_strcatalloc(sql,"SELECT orecnum, trecnum FROM ", &stsz);
06659 sql = base_strcatalloc(sql, tmpTab2, &stsz);
06660 sql = base_strcatalloc(sql, " WHERE trecnum IN (SELECT max(trecnum) FROM ", &stsz);
06661 sql = base_strcatalloc(sql, tmpTab2, &stsz);
06662 sql = base_strcatalloc(sql, " GROUP BY ", &stsz);
06663 sql = base_strcatalloc(sql, tPkeyList, &stsz);
06664 sql = base_strcatalloc(sql, ")", &stsz);
06665
06666 dbres = drms_query_bin(env->session, sql);
06667
06668 if (dbres == NULL)
06669 {
06670 istat = DRMS_ERROR_QUERYFAILED;
06671 }
06672
06673 free(sql);
06674 sql = NULL;
06675 }
06676 else
06677 {
06678 istat = DRMS_ERROR_OUTOFMEMORY;
06679 }
06680 }
06681 }
06682
06683 }
06684
06685 if (tQualPkeyList)
06686 {
06687 free(tQualPkeyList);
06688 tQualPkeyList = NULL;
06689 }
06690
06691 if (oLinkColList)
06692 {
06693 free(oLinkColList);
06694 oLinkColList = NULL;
06695 }
06696
06697 if (tPkeyList)
06698 {
06699 free(tPkeyList);
06700 tPkeyList = NULL;
06701 }
06702
06703 if (status)
06704 {
06705 *status = istat;
06706 }
06707
06708 return dbres;
06709 }
06710
06711
06712
06713
06714
06715
06716
06717
06718
06719
06720
06721
06722
06723
06724
06725 static int processFetchedRecs(DB_Binary_Result_t *dbres, const char *oSeries, DRMS_Link_t *linkTempl, HContainer_t *mapRec, LinkedList_t *recList)
06726 {
06727 int iRow;
06728 long long oRecnum;
06729 long long tRecnum;
06730 char hashkey[DRMS_MAXHASHKEYLEN];
06731 void *lookup;
06732 DRMS_Record_t *rec = NULL;
06733 DRMS_Link_t *link = NULL;
06734 int istat = DRMS_SUCCESS;
06735
06736 if (dbres && dbres->num_cols == 2 && oSeries && linkTempl && mapRec)
06737 {
06738
06739
06740
06741
06742 for (iRow = 0; iRow < dbres->num_rows; iRow++)
06743 {
06744 oRecnum = db_binary_field_getlonglong(dbres, iRow, 0);
06745 tRecnum = db_binary_field_getlonglong(dbres, iRow, 1);
06746
06747
06748 lookup = NULL;
06749 drms_make_hashkey(hashkey, oSeries, oRecnum);
06750 lookup = hcon_lookup_lower(mapRec, hashkey);
06751 if (!lookup)
06752 {
06753 istat = DRMS_ERROR_UNKNOWNRECORD;
06754 break;
06755 }
06756
06757 rec = *((DRMS_Record_t **)lookup);
06758
06759
06760 if ((link = hcon_lookup_lower(&rec->links, linkTempl->info->name)) == NULL)
06761 {
06762 istat = DRMS_ERROR_UNKNOWNLINK;
06763 break;
06764 }
06765
06766
06767 link->recnum = tRecnum;
06768
06769 list_llinserttail(recList, &link->recnum);
06770 }
06771 }
06772 else
06773 {
06774 istat = DRMS_ERROR_INVALIDDATA;
06775 }
06776
06777 return istat;
06778 }
06779
06780 int mergePreparedResults(DRMS_RecordSet_t **rvMerge, DRMS_RecordSet_t *rv)
06781 {
06782 int istat = DRMS_SUCCESS;
06783 int iRec;
06784
06785 if (rvMerge && rv)
06786 {
06787 if (!*rvMerge)
06788 {
06789
06790
06791 *rvMerge = calloc(1, sizeof(DRMS_RecordSet_t));
06792 }
06793
06794 if (*rvMerge)
06795 {
06796 for (iRec = 0; iRec < rv->n; iRec++)
06797 {
06798 drms_merge_record(*rvMerge, rv->records[iRec]);
06799 rv->records[iRec] = NULL;
06800 }
06801
06802 drms_close_records(rv, DRMS_FREE_RECORD);
06803 }
06804 else
06805 {
06806 istat = DRMS_ERROR_OUTOFMEMORY;
06807 }
06808 }
06809 else
06810 {
06811 istat = DRMS_ERROR_INVALIDDATA;
06812 }
06813
06814 return istat;
06815 }
06816
06817
06818 DRMS_RecordSet_t *callRetrieveRecsPreparedQuery(DRMS_Env_t *env, HContainer_t *mapTseriesReclist, int *status)
06819 {
06820
06821
06822
06823
06824
06825 const int NUM_ARGS = 16;
06826
06827 DRMS_RecordSet_t *rv = NULL;
06828 DRMS_RecordSet_t *rvSupp = NULL;
06829 DRMS_RecordSet_t *rvMerge = NULL;
06830 size_t stsz;
06831 char *sql = NULL;
06832 HIterator_t *iterTseries = NULL;
06833 void *iterGet = NULL;
06834 const char *seriesGet = NULL;
06835 LinkedList_t *recList = NULL;
06836 DRMS_Record_t *templRec = NULL;
06837 char *colList = NULL;
06838 int nExe = 0;
06839 int iArg;
06840 int iExe;
06841 int iRec;
06842 char *argin[NUM_ARGS];
06843 DB_Type_t intype[NUM_ARGS];
06844 ListNode_t *node = NULL;
06845 long long recnum;
06846 char nbuf[32];
06847 int istat = DRMS_SUCCESS;
06848
06849 iterTseries = hiter_create(mapTseriesReclist);
06850
06851 if (iterTseries)
06852 {
06853
06854 while ((iterGet = hiter_extgetnext(iterTseries, &seriesGet)) != NULL)
06855 {
06856 rv = NULL;
06857 rvSupp = NULL;
06858 recList = *(LinkedList_t **)iterGet;
06859
06860 if (!recList)
06861 {
06862 istat = DRMS_ERROR_INVALIDDATA;
06863 break;
06864 }
06865
06866 templRec = drms_template_record(env, seriesGet, &istat);
06867
06868 if (istat != DRMS_SUCCESS)
06869 {
06870 break;
06871 }
06872
06873
06874
06875
06876 drms_link_getpidx(templRec);
06877 colList = drms_field_list(templRec, NULL);
06878
06879 if (!colList)
06880 {
06881 istat = DRMS_ERROR_OUTOFMEMORY;
06882 break;
06883 }
06884
06885 if (recList->nitems <= 0)
06886 {
06887
06888 free(colList);
06889 continue;
06890 }
06891
06892 list_llreset(recList);
06893
06894 nExe = recList->nitems / NUM_ARGS;
06895
06896 if (nExe > 0)
06897 {
06898 stsz = 512;
06899 sql = calloc(stsz, sizeof(char));
06900 if (sql)
06901 {
06902
06903 sql = base_strcatalloc(sql, "SELECT ", &stsz);
06904 sql = base_strcatalloc(sql, colList, &stsz);
06905 sql = base_strcatalloc(sql, " FROM ", &stsz);
06906 sql = base_strcatalloc(sql, seriesGet, &stsz);
06907
06908 sql = base_strcatalloc(sql, " WHERE recnum IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", &stsz);
06909
06910
06911 for (iArg = 0; iArg < NUM_ARGS; iArg++)
06912 {
06913 argin[iArg] = calloc(nExe, sizeof(db_int8_t));
06914 intype[iArg] = DB_INT8;
06915 }
06916
06917
06918
06919
06920 iArg = 0;
06921 iExe = 0;
06922 iRec = 0;
06923
06924 while (iRec < nExe * NUM_ARGS && (node = list_llnext(recList)) != NULL)
06925 {
06926 if (!node->data)
06927 {
06928 istat = DRMS_ERROR_DATASTRUCT;
06929 break;
06930 }
06931
06932 recnum = *(long long *)node->data;
06933
06934 if (iArg == NUM_ARGS)
06935 {
06936 iArg = 0;
06937 iExe++;
06938 }
06939
06940 memcpy(argin[iArg] + iExe * db_sizeof(intype[iArg]), &recnum, db_sizeof(intype[iArg]));
06941 iArg++;
06942 iRec++;
06943 }
06944
06945 if (istat == DRMS_SUCCESS)
06946 {
06947 rv = drms_retrieve_records_prepared_query(env, seriesGet, templRec, sql, NULL, (unsigned int)nExe, NUM_ARGS, intype, (void **)argin, &istat);
06948
06949 if (rv)
06950 {
06951 istat = mergePreparedResults(&rvMerge, rv);
06952 if (istat != DRMS_SUCCESS)
06953 {
06954 break;
06955 }
06956 }
06957 }
06958
06959 for (iArg = 0; iArg < NUM_ARGS; iArg++)
06960 {
06961 if (argin[iArg])
06962 {
06963 free(argin[iArg]);
06964 argin[iArg] = NULL;
06965 }
06966 }
06967
06968 free(sql);
06969 sql = NULL;
06970 }
06971 else
06972 {
06973 istat = DRMS_ERROR_OUTOFMEMORY;
06974 }
06975 }
06976
06977 if (istat == DRMS_SUCCESS)
06978 {
06979 if (recList->nitems % NUM_ARGS != 0)
06980 {
06981
06982
06983 stsz = 512;
06984 sql = calloc(stsz, sizeof(char));
06985 if (sql)
06986 {
06987 sql = base_strcatalloc(sql, "SELECT ", &stsz);
06988 sql = base_strcatalloc(sql, colList, &stsz);
06989 sql = base_strcatalloc(sql, " FROM ", &stsz);
06990 sql = base_strcatalloc(sql, seriesGet, &stsz);
06991 sql = base_strcatalloc(sql, " WHERE recnum IN (", &stsz);
06992
06993 iRec = 0;
06994 while ((node = list_llnext(recList)) != NULL)
06995 {
06996 if (!node->data)
06997 {
06998 istat = DRMS_ERROR_DATASTRUCT;
06999 break;
07000 }
07001
07002 recnum = *(long long *)node->data;
07003 snprintf(nbuf, sizeof(nbuf), "%lld", recnum);
07004 sql = base_strcatalloc(sql, nbuf, &stsz);
07005 if (iRec < recList->nitems % NUM_ARGS - 1)
07006 {
07007 sql = base_strcatalloc(sql, ", ", &stsz);
07008 }
07009
07010 iRec++;
07011 }
07012
07013 if (istat == DRMS_SUCCESS)
07014 {
07015 sql = base_strcatalloc(sql, ")", &stsz);
07016
07017 rvSupp = drms_retrieve_records_internal(env, seriesGet, NULL, NULL, NULL, 0, 0, NULL, sql, 0, 0, NULL, NULL, 0, 0, NULL, NULL, NULL, &istat);
07018
07019 if (rvSupp)
07020 {
07021 istat = mergePreparedResults(&rvMerge, rvSupp);
07022 if (istat != DRMS_SUCCESS)
07023 {
07024 break;
07025 }
07026 }
07027 }
07028
07029 free(sql);
07030 sql = NULL;
07031 }
07032 else
07033 {
07034 istat = DRMS_ERROR_OUTOFMEMORY;
07035 }
07036 }
07037 }
07038
07039 if (colList)
07040 {
07041 free(colList);
07042 colList = NULL;
07043 }
07044 }
07045
07046 hiter_destroy(&iterTseries);
07047 }
07048 else
07049 {
07050 istat = DRMS_ERROR_OUTOFMEMORY;
07051 }
07052
07053 if (istat == DRMS_SUCCESS && rvMerge)
07054 {
07055 rvMerge->ss_currentrecs = (int *)malloc(sizeof(int));
07056
07057
07058
07059
07060
07061 if (rvMerge->ss_currentrecs)
07062 {
07063 *rvMerge->ss_currentrecs = -1;
07064 }
07065 else
07066 {
07067 istat = DRMS_ERROR_OUTOFMEMORY;
07068 }
07069 }
07070
07071 if (status)
07072 {
07073 *status = istat;
07074 }
07075
07076 return rvMerge;
07077 }
07078
07079
07080
07081 DRMS_RecordSet_t *drms_record_retrievelinks(DRMS_Env_t *env, DRMS_RecordSet_t *recordset, int *status)
07082 {
07083 DRMS_RecordSet_t *rvMerge = NULL;
07084 DRMS_RecordSet_t *rv = NULL;
07085 DRMS_Record_t *linkedRec = NULL;
07086 HContainer_t *mapRec = NULL;
07087 HContainer_t *mapOseriesTseriesCont = NULL;
07088 HContainer_t *mapLinkList = NULL;
07089
07090 HContainer_t *mapTseriesReclist = NULL;
07091 HContainer_t **pMapLinkList = NULL;
07092 LinkedList_t *recListO = NULL;
07093 LinkedList_t *recListT = NULL;
07094 LinkedList_t **pRecList = NULL;
07095 const char *oSeries = NULL;
07096 long long oRecnum;
07097 long long tRecnum;
07098 char hashkey[DRMS_MAXHASHKEYLEN];
07099 DRMS_Record_t *rec = NULL;
07100 DRMS_RecChunking_t cstat = kRecChunking_None;
07101 int newchunk = 0;
07102 DRMS_Link_t *link = NULL;
07103 HIterator_t *last = NULL;
07104 int currRec;
07105 int istat = DRMS_SUCCESS;
07106
07107 mapRec = hcon_create(sizeof(DRMS_Record_t *), DRMS_MAXHASHKEYLEN, NULL, NULL, NULL, NULL, 0);
07108
07109 if (!mapRec)
07110 {
07111 istat = DRMS_ERROR_OUTOFMEMORY;
07112 }
07113
07114 if (istat == DRMS_SUCCESS)
07115 {
07116
07117 currRec = drms_recordset_fetchnext_getcurrent(recordset);
07118 drms_recordset_fetchnext_setcurrent(recordset, -1);
07119 while ((rec = drms_recordset_fetchnext(env, recordset, &istat, &cstat, &newchunk)) != NULL && istat == DRMS_SUCCESS)
07120 {
07121 oSeries = rec->seriesinfo->seriesname;
07122 oRecnum = rec->recnum;
07123
07124 drms_make_hashkey(hashkey, oSeries, oRecnum);
07125
07126 if (hcon_member_lower(mapRec, hashkey))
07127 {
07128 fprintf(stderr, "Unexpected duplicate record in drms_record_retrievelinks().\n");
07129 istat = DRMS_ERROR_INVALIDDATA;
07130 break;
07131 }
07132
07133 hcon_insert_lower(mapRec, hashkey, &rec);
07134
07135 last = NULL;
07136
07137
07138
07139 while ((link = drms_record_nextlink(rec, &last)))
07140 {
07141
07142
07143
07144 if (link->wasFollowed)
07145 {
07146
07147 linkedRec = drms_link_follow(rec, link->info->name, &istat);
07148
07149 if (istat != DRMS_SUCCESS)
07150 {
07151 break;
07152 }
07153
07154 if (!rvMerge)
07155 {
07156
07157
07158 rvMerge = calloc(1, sizeof(DRMS_RecordSet_t));
07159
07160 if (!rvMerge)
07161 {
07162 istat = DRMS_ERROR_OUTOFMEMORY;
07163 break;
07164 }
07165
07166 }
07167
07168 drms_merge_record(rvMerge, linkedRec);
07169 linkedRec = NULL;
07170
07171 continue;
07172 }
07173
07174 if (link->info->type == DYNAMIC_LINK)
07175 {
07176 if (link->isset)
07177 {
07178
07179
07180
07181
07182
07183
07184
07185
07186 if (!mapOseriesTseriesCont)
07187 {
07188
07189 mapOseriesTseriesCont = hcon_create(sizeof(HContainer_t *), DRMS_MAXSERIESNAMELEN, (void (*)(const void *value))hcon_destroy, NULL, NULL, NULL, 0);
07190
07191 if (!mapOseriesTseriesCont)
07192 {
07193 istat = DRMS_ERROR_OUTOFMEMORY;
07194 break;
07195 }
07196 }
07197
07198 pMapLinkList = hcon_lookup_lower(mapOseriesTseriesCont, oSeries);
07199
07200 if (!pMapLinkList)
07201 {
07202
07203 mapLinkList = hcon_create(sizeof(LinkedList_t *), DRMS_MAXLINKNAMELEN, (void (*)(const void *value))list_llfree, NULL, NULL, NULL, 0);
07204 if (!mapLinkList)
07205 {
07206 istat = DRMS_ERROR_OUTOFMEMORY;
07207 break;
07208 }
07209
07210
07211 hcon_insert_lower(mapOseriesTseriesCont, oSeries, &mapLinkList);
07212 }
07213 else
07214 {
07215 mapLinkList = *pMapLinkList;
07216 }
07217
07218 pRecList = hcon_lookup_lower(mapLinkList, link->info->name);
07219
07220 if (!pRecList)
07221 {
07222 recListO = list_llcreate(sizeof(long long), NULL);
07223 if (!recListO)
07224 {
07225 istat = DRMS_ERROR_OUTOFMEMORY;
07226 break;
07227 }
07228
07229
07230 list_llinserttail(recListO, &oRecnum);
07231 hcon_insert_lower(mapLinkList, link->info->name, &recListO);
07232 }
07233 else
07234 {
07235 recListO = *pRecList;
07236 list_llinserttail(recListO, &oRecnum);
07237 }
07238
07239
07240
07241
07242
07243
07244 }
07245 }
07246 else
07247 {
07248
07249 if (link->recnum != -1)
07250 {
07251
07252 tRecnum = link->recnum;
07253
07254
07255
07256
07257
07258
07259
07260
07261
07262
07263
07264
07265
07266
07267
07268 if (!mapTseriesReclist)
07269 {
07270 mapTseriesReclist = hcon_create(sizeof(LinkedList_t *), DRMS_MAXSERIESNAMELEN, (void (*)(const void *value))list_llfree, NULL, NULL, NULL, 0);
07271 if (!mapTseriesReclist)
07272 {
07273 istat = DRMS_ERROR_OUTOFMEMORY;
07274 break;
07275 }
07276 }
07277
07278 if ((pRecList = hcon_lookup_lower(mapTseriesReclist, link->info->target_series)) != NULL)
07279 {
07280
07281 recListT = *pRecList;
07282 }
07283 else
07284 {
07285
07286 recListT = list_llcreate(sizeof(long long), NULL);
07287 if (!recListT)
07288 {
07289 istat = DRMS_ERROR_OUTOFMEMORY;
07290 break;
07291 }
07292
07293 hcon_insert_lower(mapTseriesReclist, link->info->target_series, &recListT);
07294 }
07295
07296 list_llinserttail(recListT, &tRecnum);
07297 }
07298 }
07299
07300
07301
07302
07303
07304
07305
07306
07307
07308 if ((link->info->type == STATIC_LINK && link->recnum !=- 1) || (link->info->type == DYNAMIC_LINK && link->isset))
07309 {
07310
07311 link->wasFollowed = 1;
07312 }
07313
07314 }
07315
07316 if (last)
07317 {
07318 hiter_destroy(&last);
07319 }
07320 }
07321
07322 drms_recordset_fetchnext_setcurrent(recordset, currRec);
07323
07324 if (istat == DRMS_SUCCESS)
07325 {
07326
07327 HIterator_t *iterOseries = NULL;
07328 HIterator_t *iterLink = NULL;
07329 const char *oSeriesGet = NULL;
07330 const char *linkGet = NULL;
07331 void *iterGet = NULL;
07332 DRMS_Record_t *templRec = NULL;
07333 DB_Binary_Result_t *dbres = NULL;
07334
07335
07336
07337
07338
07339
07340
07341
07342
07343
07344
07345
07346
07347
07348 if (mapOseriesTseriesCont)
07349 {
07350 iterOseries = hiter_create(mapOseriesTseriesCont);
07351 if (iterOseries)
07352 {
07353 while ((iterGet = hiter_extgetnext(iterOseries, &oSeriesGet)) != NULL)
07354 {
07355 mapLinkList = *(HContainer_t **)iterGet;
07356
07357 if (mapLinkList == NULL)
07358 {
07359 istat = DRMS_ERROR_CANTCREATEHCON;
07360 break;
07361 }
07362
07363 templRec = drms_template_record(env, oSeriesGet, &istat);
07364
07365 if (templRec == NULL)
07366 {
07367 istat = DRMS_ERROR_UNKNOWNSERIES;
07368 break;
07369 }
07370
07371 iterLink = hiter_create(mapLinkList);
07372
07373 if (iterLink)
07374 {
07375 while ((iterGet = hiter_extgetnext(iterLink, &linkGet)) != NULL)
07376 {
07377
07378
07379
07380 recListO = *((LinkedList_t **)iterGet);
07381
07382 if ((link = hcon_lookup_lower(&templRec->links, linkGet)) == NULL)
07383 {
07384 istat = DRMS_ERROR_UNKNOWNLINK;
07385 break;
07386 }
07387
07388
07389
07390
07391
07392
07393
07394
07395
07396
07397
07398
07399
07400
07401
07402
07403
07404
07405 if ((dbres = dbFetchRecsFromList(env, oSeriesGet, link, recListO, NULL)) == NULL)
07406 {
07407 istat = DRMS_ERROR_BADDBQUERY;
07408 break;
07409 }
07410
07411 if (!mapTseriesReclist)
07412 {
07413 mapTseriesReclist = hcon_create(sizeof(LinkedList_t *), DRMS_MAXSERIESNAMELEN, (void (*)(const void *value))list_llfree, NULL, NULL, NULL, 0);
07414 if (!mapTseriesReclist)
07415 {
07416 istat = DRMS_ERROR_OUTOFMEMORY;
07417 break;
07418 }
07419 }
07420
07421
07422
07423 if ((pRecList = hcon_lookup_lower(mapTseriesReclist, link->info->target_series)) != NULL)
07424 {
07425
07426 recListT = *pRecList;
07427 }
07428 else
07429 {
07430 recListT = list_llcreate(sizeof(long long), NULL);
07431 if (!recListT)
07432 {
07433 istat = DRMS_ERROR_OUTOFMEMORY;
07434 break;
07435 }
07436
07437 hcon_insert_lower(mapTseriesReclist, link->info->target_series, &recListT);
07438 }
07439
07440
07441
07442 istat = processFetchedRecs(dbres, oSeriesGet, link, mapRec, recListT);
07443 if (istat != DRMS_SUCCESS)
07444 {
07445 db_free_binary_result(dbres);
07446 break;
07447 }
07448
07449
07450 db_free_binary_result(dbres);
07451 }
07452
07453 hiter_destroy(&iterLink);
07454 iterLink = NULL;
07455 }
07456 }
07457
07458 hiter_destroy(&iterOseries);
07459 iterOseries = NULL;
07460 }
07461 else
07462 {
07463 istat = DRMS_ERROR_OUTOFMEMORY;
07464 }
07465
07466 hcon_destroy(&mapOseriesTseriesCont);
07467 }
07468
07469 if (istat == DRMS_SUCCESS)
07470 {
07471
07472
07473
07474 if (mapTseriesReclist)
07475 {
07476 rv = callRetrieveRecsPreparedQuery(env, mapTseriesReclist, &istat);
07477 if (rv)
07478 {
07479 istat = mergePreparedResults(&rvMerge, rv);
07480 }
07481 }
07482 }
07483
07484 if (mapTseriesReclist)
07485 {
07486 hcon_destroy(&mapTseriesReclist);
07487 }
07488 }
07489
07490 hcon_destroy(&mapRec);
07491 }
07492
07493 if (istat == DRMS_SUCCESS && rvMerge)
07494 {
07495 rvMerge->ss_currentrecs = (int *)malloc(sizeof(int));
07496
07497
07498
07499
07500
07501 if (rvMerge->ss_currentrecs)
07502 {
07503 *rvMerge->ss_currentrecs = -1;
07504 }
07505 else
07506 {
07507 istat = DRMS_ERROR_OUTOFMEMORY;
07508 }
07509 }
07510
07511 if (status)
07512 {
07513 *status = istat;
07514 }
07515
07516 return rvMerge;
07517 }
07518
07519 char *drms_query_string(DRMS_Env_t *env,
07520 const char *seriesname,
07521 char *where,
07522 const char *pkwhere,
07523 const char *npkwhere,
07524 int filter,
07525 int mixed,
07526 DRMS_QueryType_t qtype,
07527 void *data,
07528 const char *fl,
07529 int allvers,
07530 HContainer_t *firstlast,
07531 HContainer_t *pkwhereNFL,
07532 int recnumq,
07533 int cursor,
07534 long long *limit)
07535 {
07536 DRMS_Record_t *template;
07537 char *field_list = NULL;
07538 char *query = NULL;
07539 char *series_lower;
07540 long long recsize;
07541 char *pidx_names = NULL;
07542 char *pidx_names_desc = NULL;
07543 char *pidx_names_n = NULL;
07544 char *pidx_names_bare = NULL;
07545 char *pidx_names_desc_bare = NULL;
07546 char *limitedtable = NULL;
07547 char *p;
07548 int nrecs = 0;
07549 int unique = 0;
07550
07551 int status = 0;
07552
07553 char *rquery = NULL;
07554 int shadowexists = 0;
07555 int hasfirstlast = 0;
07556
07557 XASSERT(limit);
07558 CHECKNULL_STAT(env,&status);
07559
07560 if ((template = drms_template_record(env,seriesname,&status)) == NULL)
07561 return NULL;
07562 drms_link_getpidx(template);
07563
07564
07565 hasfirstlast = (hcon_size(firstlast) > 0);
07566
07567 switch (qtype) {
07568 case DRMS_QUERY_COUNT:
07569 {
07570 if (!allvers)
07571 {
07572
07573
07574
07575 if (!pkwhere || !*pkwhere)
07576 {
07577
07578 if (!npkwhere || !*npkwhere)
07579 {
07580
07581
07582
07583
07584 shadowexists = drms_series_shadowexists(env, seriesname, &status);
07585
07586 if (status == DRMS_SUCCESS)
07587 {
07588 if (!shadowexists && env->createshadows)
07589 {
07590
07591 if (drms_series_createshadow(env, seriesname, NULL))
07592 {
07593 goto bailout;
07594 }
07595 else
07596 {
07597 shadowexists = 1;
07598 }
07599 }
07600
07601 if (shadowexists && !recnumq)
07602 {
07603 rquery = drms_series_nrecords_querystringA(seriesname, &status);
07604 if (status == DRMS_SUCCESS)
07605 {
07606 if (env->verbose)
07607 {
07608 printf("query (the big enchilada): %s\n", rquery);
07609 }
07610
07611 return rquery;
07612 }
07613 else
07614 {
07615 goto bailout;
07616 }
07617 }
07618 }
07619 }
07620 else
07621 {
07622
07623
07624
07625
07626
07627
07628
07629 shadowexists = drms_series_shadowexists(env, seriesname, &status);
07630
07631 if (status == DRMS_SUCCESS)
07632 {
07633 if (shadowexists && !recnumq)
07634 {
07635 rquery = drms_series_nrecords_querystringB(seriesname, npkwhere, &status);
07636 if (status == DRMS_SUCCESS)
07637 {
07638 if (env->verbose)
07639 {
07640 printf("query (the big enchilada): %s\n", rquery);
07641 }
07642
07643 return rquery;
07644 }
07645 else
07646 {
07647 goto bailout;
07648 }
07649 }
07650 else
07651 {
07652
07653 }
07654 }
07655 else
07656 {
07657 goto bailout;
07658 }
07659 }
07660 }
07661 else
07662 {
07663
07664
07665
07666
07667
07668
07669
07670
07671
07672
07673
07674 if (!npkwhere || !*npkwhere)
07675 {
07676
07677
07678
07679
07680 shadowexists = drms_series_shadowexists(env, seriesname, &status);
07681
07682 if (status == DRMS_SUCCESS)
07683 {
07684 if (shadowexists && !recnumq)
07685 {
07686 if (hasfirstlast)
07687 {
07688 rquery = drms_series_nrecords_querystringFL(env, seriesname, npkwhere, pkwhereNFL, firstlast, &status);
07689 }
07690 else
07691 {
07692 rquery = drms_series_nrecords_querystringC(seriesname, pkwhere, &status);
07693 }
07694
07695 if (status == DRMS_SUCCESS)
07696 {
07697 if (env->verbose)
07698 {
07699 printf("query (the big enchilada): %s\n", rquery);
07700 }
07701
07702 return rquery;
07703 }
07704 else
07705 {
07706 goto bailout;
07707 }
07708 }
07709 else
07710 {
07711
07712 }
07713 }
07714 else
07715 {
07716 goto bailout;
07717 }
07718 }
07719 else
07720 {
07721
07722
07723
07724
07725 shadowexists = drms_series_shadowexists(env, seriesname, &status);
07726
07727 if (status == DRMS_SUCCESS)
07728 {
07729 if (shadowexists && !recnumq)
07730 {
07731 if (hasfirstlast)
07732 {
07733 rquery = drms_series_nrecords_querystringFL(env, seriesname, npkwhere, pkwhereNFL, firstlast, &status);
07734 }
07735 else
07736 {
07737 rquery = drms_series_nrecords_querystringD(seriesname, pkwhere, npkwhere, &status);
07738 }
07739
07740 if (status == DRMS_SUCCESS)
07741 {
07742 if (env->verbose)
07743 {
07744 printf("query (the big enchilada): %s\n", rquery);
07745 }
07746
07747 return rquery;
07748 }
07749 else
07750 {
07751 goto bailout;
07752 }
07753 }
07754 else
07755 {
07756
07757 }
07758 }
07759 }
07760 }
07761 }
07762
07763 field_list = strdup("count(recnum)");
07764 }
07765 break;
07766 case DRMS_QUERY_PARTIAL:
07767
07768 case DRMS_QUERY_FL:
07769
07770 case DRMS_QUERY_ALL:
07771 if (qtype == DRMS_QUERY_PARTIAL)
07772 {
07773
07774
07775
07776
07777 if (fl)
07778 {
07779 HContainer_t *keys = (HContainer_t *)fl;
07780
07781 recsize = partialRecordMemsize(template, NULL, keys, NULL);
07782 if (!recsize)
07783 {
07784 goto bailout;
07785 }
07786
07787 field_list = columnList(template, NULL, keys, NULL, NULL);
07788 }
07789 else
07790 {
07791
07792 field_list = drms_field_list(template, NULL);
07793 recsize = partialRecordMemsize(template, NULL, NULL, NULL);
07794 }
07795 }
07796 else if (qtype == DRMS_QUERY_FL)
07797 {
07798 field_list = strdup(fl);
07799 recsize = drms_keylist_memsize(template, field_list);
07800 if (!recsize) {
07801 goto bailout;
07802 }
07803
07804 unique = *(int *)(data);
07805 }
07806 else
07807 {
07808 field_list = drms_field_list(template, NULL);
07809 recsize = drms_record_memsize(template);
07810 }
07811
07812 {
07813 *limit = (long long)((1.1e6*env->query_mem)/recsize);
07814
07815 if (!allvers)
07816 {
07817 shadowexists = drms_series_shadowexists(env, seriesname, &status);
07818
07819 if (status != DRMS_SUCCESS)
07820 {
07821 goto bailout;
07822 }
07823
07824 if (!pkwhere || !*pkwhere)
07825 {
07826
07827 if (!npkwhere || !*npkwhere)
07828 {
07829
07830
07831
07832
07833
07834 if (!shadowexists && env->createshadows)
07835 {
07836
07837 if (drms_series_createshadow(env, seriesname, NULL))
07838 {
07839 goto bailout;
07840 }
07841 else
07842 {
07843 shadowexists = 1;
07844 }
07845 }
07846
07847 if (shadowexists && !recnumq)
07848 {
07849
07850 rquery = drms_series_all_querystringA(env, seriesname, field_list, *limit, cursor, &status);
07851 if (status == DRMS_SUCCESS)
07852 {
07853 if (env->verbose)
07854 {
07855 printf("query (the big enchilada): %s\n", rquery);
07856 }
07857
07858 free(field_list);
07859 return rquery;
07860 }
07861 else
07862 {
07863 goto bailout;
07864 }
07865 }
07866 }
07867 else
07868 {
07869
07870
07871
07872 if (!shadowexists && env->createshadows)
07873 {
07874
07875 if (drms_series_createshadow(env, seriesname, NULL))
07876 {
07877 goto bailout;
07878 }
07879 else
07880 {
07881 shadowexists = 1;
07882 }
07883 }
07884
07885 if (shadowexists && !recnumq)
07886 {
07887
07888 rquery = drms_series_all_querystringB(env, seriesname, npkwhere, field_list, *limit, cursor, &status);
07889 if (status == DRMS_SUCCESS)
07890 {
07891 if (env->verbose)
07892 {
07893 printf("query (the big enchilada): %s\n", rquery);
07894 }
07895
07896 free(field_list);
07897 return rquery;
07898 }
07899 else
07900 {
07901 goto bailout;
07902 }
07903 }
07904 }
07905 }
07906 else
07907 {
07908
07909 if (!npkwhere || !*npkwhere)
07910 {
07911
07912
07913
07914
07915
07916
07917 if (shadowexists && !recnumq)
07918 {
07919
07920 if (hasfirstlast)
07921 {
07922 rquery = drms_series_all_querystringFL(env, seriesname, npkwhere, pkwhereNFL, field_list, *limit, firstlast, &status);
07923 }
07924 else
07925 {
07926 rquery = drms_series_all_querystringC(env, seriesname, pkwhere, field_list, *limit, cursor, &status);
07927 }
07928
07929 if (status == DRMS_SUCCESS)
07930 {
07931 if (env->verbose)
07932 {
07933 printf("query (the big enchilada): %s\n", rquery);
07934 }
07935
07936 free(field_list);
07937 return rquery;
07938 }
07939 else
07940 {
07941 goto bailout;
07942 }
07943 }
07944 }
07945 else
07946 {
07947
07948 if (shadowexists && !recnumq)
07949 {
07950
07951 if (hasfirstlast)
07952 {
07953 rquery = drms_series_all_querystringFL(env, seriesname, npkwhere, pkwhereNFL, field_list, *limit, firstlast, &status);
07954 }
07955 else
07956 {
07957 rquery = drms_series_all_querystringD(env, seriesname, pkwhere, npkwhere, field_list, *limit, cursor, &status);
07958 }
07959
07960 if (status == DRMS_SUCCESS)
07961 {
07962 if (env->verbose)
07963 {
07964 printf("query (the big enchilada): %s\n", rquery);
07965 }
07966
07967 free(field_list);
07968 return rquery;
07969 }
07970 else
07971 {
07972 goto bailout;
07973 }
07974 }
07975 }
07976 }
07977 }
07978 }
07979 break;
07980 case DRMS_QUERY_N:
07981 {
07982 field_list = drms_field_list(template, NULL);
07983 recsize = drms_record_memsize(template);
07984 *limit = (long long)((1.1e6*env->query_mem)/recsize);
07985 nrecs = *(int *)(data);
07986
07987 if (!allvers)
07988 {
07989 shadowexists = drms_series_shadowexists(env, seriesname, &status);
07990
07991 if (status != DRMS_SUCCESS)
07992 {
07993 goto bailout;
07994 }
07995
07996 if (!pkwhere || !*pkwhere)
07997 {
07998
07999 if (!npkwhere || !*npkwhere)
08000 {
08001
08002 if (!shadowexists && env->createshadows)
08003 {
08004
08005 if (drms_series_createshadow(env, seriesname, NULL))
08006 {
08007 goto bailout;
08008 }
08009 else
08010 {
08011 shadowexists = 1;
08012 }
08013 }
08014
08015 if (shadowexists && !recnumq)
08016 {
08017
08018 rquery = drms_series_n_querystringA(env, seriesname, field_list, nrecs, *limit, &status);
08019 if (status == DRMS_SUCCESS)
08020 {
08021 if (env->verbose)
08022 {
08023 printf("query (the big enchilada): %s\n", rquery);
08024 }
08025
08026 free(field_list);
08027 return rquery;
08028 }
08029 else
08030 {
08031 goto bailout;
08032 }
08033 }
08034 }
08035 else
08036 {
08037
08038 if (!shadowexists && env->createshadows)
08039 {
08040
08041 if (drms_series_createshadow(env, seriesname, NULL))
08042 {
08043 goto bailout;
08044 }
08045 else
08046 {
08047 shadowexists = 1;
08048 }
08049 }
08050
08051 if (shadowexists && !recnumq)
08052 {
08053
08054 rquery = drms_series_n_querystringB(env, seriesname, npkwhere, field_list, nrecs, *limit, &status);
08055 if (status == DRMS_SUCCESS)
08056 {
08057 if (env->verbose)
08058 {
08059 printf("query (the big enchilada): %s\n", rquery);
08060 }
08061
08062 free(field_list);
08063 return rquery;
08064 }
08065 else
08066 {
08067 goto bailout;
08068 }
08069 }
08070 }
08071 }
08072 else
08073 {
08074
08075 if (!npkwhere || !*npkwhere)
08076 {
08077
08078 if (shadowexists && !recnumq)
08079 {
08080
08081
08082 if (hasfirstlast)
08083 {
08084 rquery = drms_series_n_querystringFL(env, seriesname, npkwhere, pkwhereNFL, field_list, nrecs, *limit, firstlast, &status);
08085 }
08086 else
08087 {
08088
08089 rquery = drms_series_n_querystringC(env, seriesname, pkwhere, field_list, nrecs, *limit, &status);
08090 }
08091
08092 if (status == DRMS_SUCCESS)
08093 {
08094 if (env->verbose)
08095 {
08096 printf("query (the big enchilada): %s\n", rquery);
08097 }
08098
08099 free(field_list);
08100 return rquery;
08101 }
08102 else
08103 {
08104 goto bailout;
08105 }
08106 }
08107 }
08108 else
08109 {
08110
08111 if (shadowexists && !recnumq)
08112 {
08113
08114
08115 if (hasfirstlast)
08116 {
08117 rquery = drms_series_n_querystringFL(env, seriesname, npkwhere, pkwhereNFL, field_list, nrecs, *limit, firstlast, &status);
08118 }
08119 else
08120 {
08121 rquery = drms_series_n_querystringD(env, seriesname, pkwhere, npkwhere, field_list, nrecs, *limit, &status);
08122 }
08123
08124 if (status == DRMS_SUCCESS)
08125 {
08126 if (env->verbose)
08127 {
08128 printf("query (the big enchilada): %s\n", rquery);
08129 }
08130
08131 free(field_list);
08132 return rquery;
08133 }
08134 else
08135 {
08136 goto bailout;
08137 }
08138 }
08139 }
08140 }
08141 }
08142 }
08143 break;
08144 default:
08145 printf("Unknown query type: %d\n", (int)qtype);
08146 return NULL;
08147 }
08148
08149 size_t cmdSz;
08150 char numBuf[64];
08151
08152 #ifdef DEBUG
08153 printf("limit = (%f / %lld) = %lld\n",1.1e6*env->query_mem, recsize, *limit);
08154 #endif
08155 series_lower = strdup(seriesname);
08156 strtolower(series_lower);
08157
08158 if (template->seriesinfo->pidx_num>0) {
08159
08160 size_t namesSz = 1024;
08161 pidx_names = calloc(1, namesSz);
08162 XASSERT(pidx_names);
08163
08164
08165 size_t namesDescSz = 1024;
08166 pidx_names_desc = calloc(1, namesDescSz);
08167 XASSERT(pidx_names_desc);
08168
08169
08170 size_t namesNSz = 1024;
08171 pidx_names_n = calloc(1, namesNSz);
08172 XASSERT(pidx_names_n);
08173
08174
08175 size_t namesBareSz = 1024;
08176 pidx_names_bare = calloc(1, namesBareSz);
08177 XASSERT(pidx_names_bare);
08178
08179
08180 size_t namesDescBareSz = 1024;
08181 pidx_names_desc_bare = calloc(1, namesDescBareSz);
08182 XASSERT(pidx_names_desc_bare);
08183
08184
08185 pidx_names = base_strcatalloc(pidx_names, series_lower, &namesSz); XASSERT(pidx_names);
08186 pidx_names = base_strcatalloc(pidx_names, ".", &namesSz); XASSERT(pidx_names);
08187 pidx_names = base_strcatalloc(pidx_names, template->seriesinfo->pidx_keywords[0]->info->name, &namesSz); XASSERT(pidx_names);
08188
08189
08190 pidx_names_desc = base_strcatalloc(pidx_names_desc, series_lower, &namesDescSz); XASSERT(pidx_names_desc);
08191 pidx_names_desc = base_strcatalloc(pidx_names_desc, ".", &namesDescSz); XASSERT(pidx_names_desc);
08192 pidx_names_desc = base_strcatalloc(pidx_names_desc, template->seriesinfo->pidx_keywords[0]->info->name, &namesDescSz); XASSERT(pidx_names_desc);
08193 pidx_names_desc = base_strcatalloc(pidx_names_desc, " DESC", &namesDescSz); XASSERT(pidx_names_desc);
08194
08195
08196
08197
08198
08199
08200 pidx_names_n = base_strcatalloc(pidx_names_n, "limited.", &namesNSz); XASSERT(pidx_names_n);
08201 pidx_names_n = base_strcatalloc(pidx_names_n, template->seriesinfo->pidx_keywords[0]->info->name, &namesNSz); XASSERT(pidx_names_n);
08202
08203
08204
08205
08206
08207 pidx_names_bare = base_strcatalloc(pidx_names_bare, template->seriesinfo->pidx_keywords[0]->info->name, &namesBareSz); XASSERT(pidx_names_bare);
08208
08209
08210
08211
08212
08213 pidx_names_desc_bare = base_strcatalloc(pidx_names_desc_bare, template->seriesinfo->pidx_keywords[0]->info->name, &namesDescBareSz); XASSERT(pidx_names_desc_bare);
08214 pidx_names_desc_bare = base_strcatalloc(pidx_names_desc_bare, " DESC", &namesDescBareSz); XASSERT(pidx_names_desc_bare);
08215
08216
08217 for (int i = 1; i < template->seriesinfo->pidx_num; i++)
08218 {
08219
08220 pidx_names = base_strcatalloc(pidx_names, ", ", &namesSz); XASSERT(pidx_names);
08221 pidx_names = base_strcatalloc(pidx_names, series_lower, &namesSz); XASSERT(pidx_names);
08222 pidx_names = base_strcatalloc(pidx_names, ".", &namesSz); XASSERT(pidx_names);
08223 pidx_names = base_strcatalloc(pidx_names, template->seriesinfo->pidx_keywords[i]->info->name, &namesSz); XASSERT(pidx_names);
08224
08225
08226 pidx_names_desc = base_strcatalloc(pidx_names_desc, ", ", &namesDescSz); XASSERT(pidx_names_desc);
08227 pidx_names_desc = base_strcatalloc(pidx_names_desc, series_lower, &namesDescSz); XASSERT(pidx_names_desc);
08228 pidx_names_desc = base_strcatalloc(pidx_names_desc, ".", &namesDescSz); XASSERT(pidx_names_desc);
08229 pidx_names_desc = base_strcatalloc(pidx_names_desc, template->seriesinfo->pidx_keywords[i]->info->name, &namesDescSz); XASSERT(pidx_names_desc);
08230 pidx_names_desc = base_strcatalloc(pidx_names_desc, " DESC", &namesDescSz); XASSERT(pidx_names_desc);
08231
08232
08233
08234
08235
08236 pidx_names_n = base_strcatalloc(pidx_names_n, ", limited.", &namesNSz); XASSERT(pidx_names_n);
08237 pidx_names_n = base_strcatalloc(pidx_names_n, template->seriesinfo->pidx_keywords[i]->info->name, &namesNSz); XASSERT(pidx_names_n);
08238
08239
08240
08241
08242
08243 pidx_names_bare = base_strcatalloc(pidx_names_bare, ", ", &namesBareSz); XASSERT(pidx_names_bare);
08244 pidx_names_bare = base_strcatalloc(pidx_names_bare, template->seriesinfo->pidx_keywords[i]->info->name, &namesBareSz); XASSERT(pidx_names_bare);
08245
08246
08247
08248
08249
08250 pidx_names_desc_bare = base_strcatalloc(pidx_names_desc_bare, ", ", &namesDescBareSz); XASSERT(pidx_names_desc_bare);
08251 pidx_names_desc_bare = base_strcatalloc(pidx_names_desc_bare, template->seriesinfo->pidx_keywords[i]->info->name, &namesDescBareSz); XASSERT(pidx_names_desc_bare);
08252 pidx_names_desc_bare = base_strcatalloc(pidx_names_desc_bare, " DESC", &namesDescBareSz); XASSERT(pidx_names_desc_bare);
08253 }
08254
08255 if (qtype == DRMS_QUERY_N)
08256 {
08257 int fudge = kQUERYNFUDGE;
08258 cmdSz = 1024;
08259 limitedtable = calloc(1, cmdSz);
08260 XASSERT(limitedtable);
08261
08262
08263
08264
08265
08266
08267
08268
08269 limitedtable = base_strcatalloc(limitedtable, "select recnum,", &cmdSz); XASSERT(limitedtable);
08270 limitedtable = base_strcatalloc(limitedtable, pidx_names_bare, &cmdSz); XASSERT(limitedtable);
08271 limitedtable = base_strcatalloc(limitedtable, " from ", &cmdSz); XASSERT(limitedtable);
08272 limitedtable = base_strcatalloc(limitedtable, series_lower, &cmdSz); XASSERT(limitedtable);
08273 limitedtable = base_strcatalloc(limitedtable, " where 1=1", &cmdSz); XASSERT(limitedtable);
08274
08275 if (where && *where)
08276 {
08277
08278 limitedtable = base_strcatalloc(limitedtable, " and ", &cmdSz); XASSERT(limitedtable);
08279 limitedtable = base_strcatalloc(limitedtable, where, &cmdSz); XASSERT(limitedtable);
08280 }
08281
08282
08283
08284
08285
08286 limitedtable = base_strcatalloc(limitedtable, " order by ", &cmdSz); XASSERT(limitedtable);
08287 limitedtable = base_strcatalloc(limitedtable, nrecs > 0 ? pidx_names_bare : pidx_names_desc_bare, &cmdSz); XASSERT(limitedtable);
08288 limitedtable = base_strcatalloc(limitedtable, " limit ", &cmdSz); XASSERT(limitedtable);
08289
08290 snprintf(numBuf, sizeof(numBuf), "%d", abs(nrecs) * fudge);
08291 limitedtable = base_strcatalloc(limitedtable, numBuf, &cmdSz); XASSERT(limitedtable);
08292 }
08293 }
08294
08295
08296
08297
08298 cmdSz = strlen(field_list)+DRMS_MAXQUERYLEN;
08299 query = calloc(1, cmdSz);
08300 XASSERT(query);
08301
08302
08303
08304
08305
08306
08307 if (filter && template->seriesinfo->pidx_num>0 && !allvers) {
08308 if (mixed) {
08309
08310
08311
08312 if (qtype != DRMS_QUERY_N)
08313 {
08314
08315 query = base_strcatalloc(query, "select ", &cmdSz); XASSERT(query);
08316 query = base_strcatalloc(query, field_list, &cmdSz); XASSERT(query);
08317 query = base_strcatalloc(query, " from ", &cmdSz); XASSERT(query);
08318 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08319 query = base_strcatalloc(query, ", (select q2.max1 as max from (select max(recnum) as max1, min(q1.max) as max2 from ", &cmdSz); XASSERT(query);
08320 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08321 query = base_strcatalloc(query, ", (select ", &cmdSz); XASSERT(query);
08322 query = base_strcatalloc(query, pidx_names, &cmdSz); XASSERT(query);
08323 query = base_strcatalloc(query, ", max(recnum) from ", &cmdSz); XASSERT(query);
08324 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08325 query = base_strcatalloc(query, " where ", &cmdSz); XASSERT(query);
08326 query = base_strcatalloc(query, where, &cmdSz); XASSERT(query);
08327 query = base_strcatalloc(query, " group by ", &cmdSz); XASSERT(query);
08328 query = base_strcatalloc(query, pidx_names, &cmdSz); XASSERT(query);
08329 query = base_strcatalloc(query, ") as q1 where ", &cmdSz); XASSERT(query);
08330 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08331 query = base_strcatalloc(query, ".", &cmdSz); XASSERT(query);
08332 query = base_strcatalloc(query, template->seriesinfo->pidx_keywords[0]->info->name, &cmdSz); XASSERT(query);
08333 query = base_strcatalloc(query, " = q1.", &cmdSz); XASSERT(query);
08334 query = base_strcatalloc(query, template->seriesinfo->pidx_keywords[0]->info->name, &cmdSz); XASSERT(query);
08335
08336 for (int i = 1; i < template->seriesinfo->pidx_num; i++)
08337 {
08338
08339 query = base_strcatalloc(query, " and ", &cmdSz); XASSERT(query);
08340 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08341 query = base_strcatalloc(query, ".", &cmdSz); XASSERT(query);
08342 query = base_strcatalloc(query, template->seriesinfo->pidx_keywords[i]->info->name, &cmdSz); XASSERT(query);
08343 query = base_strcatalloc(query, " = q1.", &cmdSz); XASSERT(query);
08344 query = base_strcatalloc(query, template->seriesinfo->pidx_keywords[i]->info->name, &cmdSz); XASSERT(query);
08345 }
08346
08347
08348 query = base_strcatalloc(query, " group by ", &cmdSz); XASSERT(query);
08349 query = base_strcatalloc(query, pidx_names, &cmdSz); XASSERT(query);
08350 query = base_strcatalloc(query, ") as q2 where max1 = max2) as q3 where ", &cmdSz); XASSERT(query);
08351 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08352 query = base_strcatalloc(query, ".recnum = q3.max", &cmdSz); XASSERT(query);
08353 }
08354 else
08355 {
08356
08357
08358
08359
08360
08361
08362
08363
08364
08365
08366
08367
08368
08369
08370 query = base_strcatalloc(query, "select ", &cmdSz); XASSERT(query);
08371 query = base_strcatalloc(query, field_list, &cmdSz); XASSERT(query);
08372 query = base_strcatalloc(query, " from ", &cmdSz); XASSERT(query);
08373 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08374 query = base_strcatalloc(query, ", (select q2.max1 as max from (select max(recnum) as max1, min(q1.max) as max2 from ", &cmdSz); XASSERT(query);
08375 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08376 query = base_strcatalloc(query, ", (select ", &cmdSz); XASSERT(query);
08377 query = base_strcatalloc(query, pidx_names_n, &cmdSz); XASSERT(query);
08378 query = base_strcatalloc(query, ", max(recnum) from (", &cmdSz); XASSERT(query);
08379 query = base_strcatalloc(query, limitedtable, &cmdSz); XASSERT(query);
08380 query = base_strcatalloc(query, ") as limited group by ", &cmdSz); XASSERT(query);
08381 query = base_strcatalloc(query, pidx_names_n, &cmdSz); XASSERT(query);
08382 query = base_strcatalloc(query, ") as q1 where ", &cmdSz); XASSERT(query);
08383 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08384 query = base_strcatalloc(query, ".", &cmdSz); XASSERT(query);
08385 query = base_strcatalloc(query, template->seriesinfo->pidx_keywords[0]->info->name, &cmdSz); XASSERT(query);
08386 query = base_strcatalloc(query, " = q1.", &cmdSz); XASSERT(query);
08387 query = base_strcatalloc(query, template->seriesinfo->pidx_keywords[0]->info->name, &cmdSz); XASSERT(query);
08388
08389 for (int i = 1; i < template->seriesinfo->pidx_num; i++)
08390 {
08391
08392
08393
08394
08395
08396
08397
08398 query = base_strcatalloc(query, " and ", &cmdSz); XASSERT(query);
08399 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08400 query = base_strcatalloc(query, ".", &cmdSz); XASSERT(query);
08401 query = base_strcatalloc(query, template->seriesinfo->pidx_keywords[i]->info->name, &cmdSz); XASSERT(query);
08402 query = base_strcatalloc(query, " = q1.", &cmdSz); XASSERT(query);
08403 query = base_strcatalloc(query, template->seriesinfo->pidx_keywords[i]->info->name, &cmdSz); XASSERT(query);
08404 }
08405
08406
08407
08408
08409
08410
08411 query = base_strcatalloc(query, " group by ", &cmdSz); XASSERT(query);
08412 query = base_strcatalloc(query, pidx_names, &cmdSz); XASSERT(query);
08413 query = base_strcatalloc(query, ") as q2 where max1 = max2) as q3 where ", &cmdSz); XASSERT(query);
08414 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08415 query = base_strcatalloc(query, ".recnum = q3.max", &cmdSz); XASSERT(query);
08416 }
08417 }
08418 else
08419 {
08420
08421
08422
08423 if (qtype != DRMS_QUERY_N)
08424 {
08425
08426
08427 query = base_strcatalloc(query, "select ", &cmdSz); XASSERT(query);
08428 query = base_strcatalloc(query, field_list, &cmdSz); XASSERT(query);
08429 query = base_strcatalloc(query, " from ", &cmdSz); XASSERT(query);
08430 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08431 query = base_strcatalloc(query, " where recnum in (select max(recnum) from ", &cmdSz); XASSERT(query);
08432 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08433 query = base_strcatalloc(query, " where 1=1 ", &cmdSz); XASSERT(query);
08434
08435 if (where && *where)
08436 {
08437
08438 query = base_strcatalloc(query, " and ", &cmdSz); XASSERT(query);
08439 query = base_strcatalloc(query, where, &cmdSz); XASSERT(query);
08440 }
08441
08442
08443 query = base_strcatalloc(query, " group by ", &cmdSz); XASSERT(query);
08444 query = base_strcatalloc(query, pidx_names, &cmdSz); XASSERT(query);
08445 query = base_strcatalloc(query, " )", &cmdSz); XASSERT(query);
08446 }
08447 else
08448 {
08449
08450
08451
08452
08453
08454
08455
08456
08457
08458 query = base_strcatalloc(query, "select ", &cmdSz); XASSERT(query);
08459 query = base_strcatalloc(query, field_list, &cmdSz); XASSERT(query);
08460 query = base_strcatalloc(query, " from ", &cmdSz); XASSERT(query);
08461 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08462 query = base_strcatalloc(query, " where recnum in (select max(recnum) from (", &cmdSz); XASSERT(query);
08463 query = base_strcatalloc(query, limitedtable, &cmdSz); XASSERT(query);
08464 query = base_strcatalloc(query, ") as limited group by ", &cmdSz); XASSERT(query);
08465 query = base_strcatalloc(query, pidx_names_n, &cmdSz); XASSERT(query);
08466 query = base_strcatalloc(query, ")", &cmdSz); XASSERT(query);
08467 }
08468 }
08469 } else {
08470
08471
08472 query = base_strcatalloc(query, "select ", &cmdSz); XASSERT(query);
08473 query = base_strcatalloc(query, field_list, &cmdSz); XASSERT(query);
08474 query = base_strcatalloc(query, " from ", &cmdSz); XASSERT(query);
08475 query = base_strcatalloc(query, series_lower, &cmdSz); XASSERT(query);
08476 query = base_strcatalloc(query, " where 1 = 1", &cmdSz); XASSERT(query);
08477
08478 if (where && *where) {
08479
08480 query = base_strcatalloc(query, " and ", &cmdSz); XASSERT(query);
08481 query = base_strcatalloc(query, where, &cmdSz); XASSERT(query);
08482
08483 }
08484 }
08485 if (qtype != DRMS_QUERY_COUNT)
08486 {
08487 long long actualLimit = *limit;
08488
08489 if (qtype == DRMS_QUERY_N)
08490 {
08491 if (template->seriesinfo->pidx_num > 0)
08492 {
08493
08494 query = base_strcatalloc(query, " order by ", &cmdSz); XASSERT(query);
08495 query = base_strcatalloc(query, nrecs > 0 ? pidx_names : pidx_names_desc, &cmdSz); XASSERT(query);
08496 }
08497
08498 if (abs(nrecs) < *limit)
08499 {
08500 actualLimit = abs(nrecs);
08501 }
08502
08503
08504 snprintf(numBuf, sizeof(numBuf), "%lld", actualLimit);
08505 query = base_strcatalloc(query, " limit ", &cmdSz); XASSERT(query);
08506 query = base_strcatalloc(query, numBuf, &cmdSz); XASSERT(query);
08507 }
08508 else
08509 {
08510 if (template->seriesinfo->pidx_num > 0) {
08511
08512 query = base_strcatalloc(query, " order by ", &cmdSz); XASSERT(query);
08513 query = base_strcatalloc(query, pidx_names, &cmdSz); XASSERT(query);
08514 }
08515
08516 snprintf(numBuf, sizeof(numBuf), "%lld", actualLimit);
08517 query = base_strcatalloc(query, " limit ", &cmdSz); XASSERT(query);
08518 query = base_strcatalloc(query, numBuf, &cmdSz); XASSERT(query);
08519 }
08520 }
08521
08522 if (qtype == DRMS_QUERY_FL && unique)
08523 {
08524 size_t qsize = strlen(query) * 2;
08525 char *modquery = NULL;
08526 modquery = calloc(1, qsize);
08527 XASSERT(modquery);
08528
08529
08530
08531
08532
08533
08534
08535
08536
08537 modquery = base_strcatalloc(modquery, "select ", &qsize); XASSERT(modquery);
08538 modquery = base_strcatalloc(modquery, field_list, &qsize); XASSERT(modquery);
08539 modquery = base_strcatalloc(modquery, " from (", &qsize); XASSERT(modquery);
08540 modquery = base_strcatalloc(modquery, query, &qsize); XASSERT(modquery);
08541 modquery = base_strcatalloc(modquery, ") as subfoo group by ", &qsize); XASSERT(modquery);
08542 modquery = base_strcatalloc(modquery, field_list, &qsize); XASSERT(modquery);
08543 modquery = base_strcatalloc(modquery, " order by ", &qsize); XASSERT(modquery);
08544 modquery = base_strcatalloc(modquery, field_list, &qsize); XASSERT(modquery);
08545
08546 if (query)
08547 {
08548 free(query);
08549 }
08550
08551 query = modquery;
08552 }
08553
08554 free(series_lower);
08555 bailout:
08556 free(field_list);
08557
08558 if (pidx_names)
08559 {
08560 free(pidx_names);
08561 pidx_names = NULL;
08562 }
08563
08564 if (pidx_names_desc)
08565 {
08566 free(pidx_names_desc);
08567 pidx_names_desc = NULL;
08568 }
08569
08570 if (pidx_names_n)
08571 {
08572 free(pidx_names_n);
08573 pidx_names_n = NULL;
08574 }
08575
08576 if (pidx_names_bare)
08577 {
08578 free(pidx_names_bare);
08579 pidx_names_bare = NULL;
08580 }
08581
08582 if (pidx_names_desc_bare)
08583 {
08584 free(pidx_names_desc_bare);
08585 pidx_names_desc_bare = NULL;
08586 }
08587
08588 if (limitedtable)
08589 {
08590 free(limitedtable);
08591 limitedtable = NULL;
08592 }
08593
08594 if (env->verbose)
08595 {
08596 printf("query (the big enchilada): %s\n", query);
08597 }
08598
08599 return query;
08600 }
08601
08602
08603
08604
08605
08606
08607 DRMS_Record_t *drms_alloc_record2(DRMS_Record_t *template,
08608 long long recnum, int *status)
08609 {
08610 DRMS_Record_t *rec;
08611 char hashkey[DRMS_MAXHASHKEYLEN];
08612 char *series;
08613 DRMS_Env_t *env;
08614
08615 CHECKNULL_STAT(template,status);
08616 env = template->env;
08617 series = template->seriesinfo->seriesname;
08618
08619
08620 drms_make_hashkey(hashkey, series, recnum);
08621
08622
08623 rec = (DRMS_Record_t *)hcon_allocslot(&env->record_cache, hashkey);
08624
08625 rec->su = NULL;
08626
08627 drms_copy_record_struct(rec, template);
08628
08629
08630 if (rec)
08631 {
08632 rec->refcount = 1;
08633 }
08634
08635
08636 drms_link_getpidx(rec);
08637
08638
08639 rec->recnum = recnum;
08640 if (status)
08641 *status = DRMS_SUCCESS;
08642
08643 return rec;
08644 }
08645
08646
08647
08648
08649 DRMS_Record_t *drms_alloc_record(DRMS_Env_t *env, const char *series,
08650 long long recnum, int *status)
08651 {
08652 DRMS_Record_t *template;
08653
08654 CHECKNULL_STAT(env,status);
08655
08656 if ((template = drms_template_record(env, series,status)) == NULL)
08657 return NULL;
08658 return drms_alloc_record2(template, recnum, status);
08659 }
08660
08661
08662
08663
08664
08665
08666
08667
08668
08669
08670
08671
08672
08673 static DRMS_Record_t *drms_template_record_int(DRMS_Env_t *env,
08674 const char *seriesname,
08675 int jsd,
08676 int *status)
08677 {
08678 int stat;
08679 DB_Binary_Result_t *qres = NULL;
08680 DRMS_Record_t *template;
08681 char *p, *q, query[DRMS_MAXQUERYLEN], buf[DRMS_MAXPRIMIDX*DRMS_MAXKEYNAMELEN];
08682 DRMS_Keyword_t *kw;
08683 int dsdsing = 0;
08684 char *colnames = NULL;
08685
08686 XASSERT(env);
08687 XASSERT(seriesname);
08688
08689 char *lcseries = strdup(seriesname);
08690
08691 stat = DRMS_SUCCESS;
08692
08693 if (!lcseries)
08694 {
08695 stat = DRMS_ERROR_OUTOFMEMORY;
08696 goto bailout;
08697 }
08698
08699 strtolower(lcseries);
08700
08701
08702
08703 DRMS_SeriesVersion_t vers2_0 = {"2.0", ""};
08704 DRMS_SeriesVersion_t vers2_1 = {"2.1", ""};
08705
08706 #ifdef DEBUG
08707 printf("Getting template for series '%s'\n",seriesname);
08708 #endif
08709
08710
08711
08712
08713 const char *dsdsNsPrefix = DSDS_GetNsPrefix();
08714
08715 if (strstr(seriesname, dsdsNsPrefix) == seriesname)
08716 {
08717 dsdsing = 1;
08718 }
08719
08720
08721
08722
08723
08724 if (!jsd || dsdsing)
08725 {
08726
08727
08728 if ( (template = hcon_lookup_lower(&env->series_cache, seriesname)) == NULL )
08729 {
08730
08731 char qry[DRMS_MAXQUERYLEN];
08732 char *nspace = ns(lcseries);
08733 int serr;
08734 DB_Text_Result_t *tqres = NULL;
08735
08736 serr = 0;
08737
08738 if (nspace)
08739 {
08740
08741
08742 snprintf(qry, sizeof(qry), "select name from admin.ns where name = '%s'", nspace);
08743 tqres = drms_query_txt(env->session, qry);
08744 if (tqres == NULL)
08745 {
08746 serr = 1;
08747 }
08748 else if (tqres->num_rows != 1)
08749 {
08750 serr = 1;
08751 db_free_text_result(tqres);
08752 tqres = NULL;
08753 }
08754 else
08755 {
08756 db_free_text_result(tqres);
08757 tqres = NULL;
08758
08759
08760
08761
08762
08763 snprintf(qry, sizeof(qry), "select seriesname from %s.drms_series where lower(seriesname) = '%s'", nspace, lcseries);
08764 free(nspace);
08765
08766 if ((tqres = drms_query_txt(env->session, qry)) != NULL && tqres->num_rows == 1)
08767 {
08768 template =
08769 (DRMS_Record_t *)hcon_allocslot_lower(&env->series_cache, tqres->field[0][0]);
08770 memset(template,0,sizeof(DRMS_Record_t));
08771 template->init = 0;
08772 }
08773 else
08774 {
08775 serr = 1;
08776 }
08777
08778 db_free_text_result(tqres);
08779 tqres = NULL;
08780 }
08781 }
08782
08783 if (serr)
08784 {
08785 if (status)
08786 {
08787 *status = DRMS_ERROR_UNKNOWNSERIES;
08788 }
08789
08790 free(lcseries);
08791 return NULL;
08792 }
08793 }
08794 }
08795 else
08796 {
08797 template = malloc(sizeof(DRMS_Record_t));
08798 memset(template, 0, sizeof(DRMS_Record_t));
08799 }
08800
08801 if (template->init == 0 || (jsd && !dsdsing))
08802 {
08803 #ifdef DEBUG
08804 printf("Building new template for series '%s'\n",seriesname);
08805 #endif
08806
08807
08808
08809
08810
08811 template->env = env;
08812 template->init = 1;
08813 template->recnum = 0;
08814 template->sunum = -1LL;
08815 template->sessionid = 0;
08816 template->sessionns = NULL;
08817 template->su = NULL;
08818 template->seriesinfo = calloc(1, sizeof(DRMS_SeriesInfo_t));
08819 XASSERT(template->seriesinfo);
08820 template->seriesinfo->hasshadow = -1;
08821 template->seriesinfo->createshadow = 0;
08822
08823
08824
08825 char *namespace = ns(seriesname);
08826
08827
08828
08829
08830
08831 sprintf(query, "select seriesname, description, author, owner, "
08832 "unitsize, archive, retention, tapegroup, primary_idx, dbidx, version "
08833 "from %s.%s where lower(seriesname) = '%s'",
08834 namespace, DRMS_MASTER_SERIES_TABLE, lcseries);
08835 free(namespace);
08836 #ifdef DEBUG
08837 printf("query string '%s'\n",query);
08838 #endif
08839
08840 if ((qres = drms_query_bin(env->session, query)) == NULL)
08841 {
08842 printf("Failed to retrieve series information for series %s.\n",
08843 seriesname);
08844 stat = DRMS_ERROR_QUERYFAILED;
08845 goto bailout;
08846 }
08847 if (qres->num_cols != 11 || qres->num_rows != 1)
08848 {
08849 printf("Invalid sized query result for global series information for"
08850 " series %s.\n", seriesname);
08851 db_free_binary_result(qres);
08852 stat = DRMS_ERROR_BADQUERYRESULT;
08853 goto bailout;
08854 }
08855 db_binary_field_getstr(qres, 0, 0, DRMS_MAXSERIESNAMELEN,
08856 template->seriesinfo->seriesname);
08857 db_binary_field_getstr(qres, 0, 1, DRMS_MAXCOMMENTLEN,
08858 template->seriesinfo->description);
08859 db_binary_field_getstr(qres, 0, 2, DRMS_MAXCOMMENTLEN,
08860 template->seriesinfo->author);
08861 db_binary_field_getstr(qres, 0, 3, DRMS_MAXOWNERLEN,
08862 template->seriesinfo->owner);
08863 template->seriesinfo->unitsize = db_binary_field_getint(qres, 0, 4);
08864 template->seriesinfo->archive = db_binary_field_getint(qres, 0, 5);
08865 template->seriesinfo->retention = db_binary_field_getint(qres, 0, 6);
08866 template->seriesinfo->retention_perm = 0;
08867 template->seriesinfo->tapegroup = db_binary_field_getint(qres, 0, 7);
08868
08869
08870 if ( !db_binary_field_is_null(qres, 0, 10) ) {
08871 db_binary_field_getstr(qres, 0, 10, DRMS_MAXSERIESVERSION,
08872 template->seriesinfo->version);
08873 }
08874
08875 char *ns = NULL;
08876 char *table = NULL;
08877 char *oid = NULL;
08878 int err = 0;
08879 char *serieslwr = strdup(template->seriesinfo->seriesname);
08880
08881 strtolower(serieslwr);
08882 get_namespace(serieslwr, &ns, &table);
08883
08884 if (serieslwr)
08885 {
08886 free(serieslwr);
08887 }
08888
08889 err = GetTableOID(env, ns, table, &oid);
08890
08891 if (err == DRMS_ERROR_QUERYFAILED)
08892 {
08893 stat = DRMS_ERROR_QUERYFAILED;
08894 }
08895
08896 if (ns)
08897 {
08898 free(ns);
08899 }
08900
08901 if (table)
08902 {
08903 free(table);
08904 }
08905
08906 if (!err)
08907 {
08908 err = GetColumnNames(env, oid, &colnames);
08909 }
08910
08911 if (oid)
08912 {
08913 free(oid);
08914 }
08915
08916 if (stat)
08917 {
08918 goto bailout;
08919 }
08920
08921
08922 if ((stat=drms_template_segments(template)))
08923 goto bailout;
08924 if ((stat=drms_template_links(template)))
08925 goto bailout;
08926 if ((stat=drms_template_keywords_int(template, !jsd, colnames)))
08927 goto bailout;
08928
08929
08930 if (template->segments.num_total > 0)
08931 {
08932 template->seriesinfo->retention_perm = drms_series_isdbowner(env, template->seriesinfo->seriesname, &stat);
08933
08934 if (stat)
08935 {
08936 goto bailout;
08937 }
08938
08939 template->seriesinfo->retention_perm = (template->seriesinfo->retention_perm || drms_client_isproduser(env, &stat));
08940
08941 if (stat)
08942 {
08943 goto bailout;
08944 }
08945
08946 #ifdef DEBUG
08947 printf("retention_perm=%d\n",template->seriesinfo->retention_perm);
08948 #endif
08949 }
08950
08951
08952 if ( !db_binary_field_is_null(qres, 0, 8) )
08953 {
08954 db_binary_field_getstr(qres, 0, 8, DRMS_MAXPRIMIDX*DRMS_MAXKEYNAMELEN, buf);
08955 p = buf;
08956 #ifdef DEBUG
08957 printf("Primary index string = '%s'\n",p);
08958 #endif
08959 template->seriesinfo->pidx_num = 0;
08960 while(*p)
08961 {
08962 XASSERT(template->seriesinfo->pidx_num < DRMS_MAXPRIMIDX);
08963 while(*p && isspace(*p))
08964 ++p;
08965 q = p;
08966 while(*p && !isspace(*p) && *p!=',')
08967 ++p;
08968 *p++ = 0;
08969
08970 #ifdef DEBUG
08971 printf("adding primary key '%s'\n",q);
08972 #endif
08973 kw = hcon_lookup_lower(&template->keywords,q);
08974 XASSERT(kw);
08975
08976 template->seriesinfo->pidx_keywords[(template->seriesinfo->pidx_num)++] =
08977 kw;
08978
08979
08980
08981
08982
08983
08984
08985 if (!drms_series_isvers(template->seriesinfo, &vers2_1))
08986 {
08987 drms_keyword_setintprime(kw);
08988 if (drms_keyword_isindex(kw))
08989 {
08990 DRMS_Keyword_t *slotkey = drms_keyword_slotfromindex(kw);
08991 drms_keyword_setextprime(slotkey);
08992 }
08993 else
08994 {
08995 drms_keyword_setextprime(kw);
08996 }
08997 }
08998 }
08999 #ifdef DEBUG
09000 { int i;
09001 printf("Primary indices: ");
09002 for (i=0; i<template->seriesinfo->pidx_num; i++)
09003 printf("'%s' ",(template->seriesinfo->pidx_keywords[i])->info->name);
09004 }
09005 printf("\n");
09006 #endif
09007 }
09008 else
09009 template->seriesinfo->pidx_num = 0;
09010
09011
09012 if ( !db_binary_field_is_null(qres, 0, 9) ) {
09013 db_binary_field_getstr(qres, 0, 9, DRMS_MAXDBIDX*DRMS_MAXKEYNAMELEN, buf);
09014 p = buf;
09015 #ifdef DEBUG
09016 printf("DB index string = '%s'\n",p);
09017 #endif
09018 template->seriesinfo->dbidx_num = 0;
09019 while(*p) {
09020 XASSERT(template->seriesinfo->dbidx_num < DRMS_MAXDBIDX);
09021 while(*p && isspace(*p))
09022 ++p;
09023 q = p;
09024 while(*p && !isspace(*p) && *p!=',')
09025 ++p;
09026 *p++ = 0;
09027
09028 #ifdef DEBUG
09029 printf("adding db index '%s'\n",q);
09030 #endif
09031 kw = hcon_lookup_lower(&template->keywords,q);
09032 XASSERT(kw);
09033 template->seriesinfo->dbidx_keywords[(template->seriesinfo->dbidx_num)++] = kw;
09034 }
09035 #ifdef DEBUG
09036 { int i;
09037 printf("DB indices: ");
09038 for (i=0; i<template->seriesinfo->dbidx_num; i++)
09039 printf("'%s' ",(template->seriesinfo->dbidx_keywords[i])->info->name);
09040 }
09041 printf("\n");
09042 #endif
09043 } else {
09044 template->seriesinfo->dbidx_num = 0;
09045 }
09046
09047
09048
09049 if (drms_series_isvers(template->seriesinfo, &vers2_0))
09050 {
09051 HIterator_t *hit = hiter_create(&(template->segments));
09052 if (hit)
09053 {
09054 DRMS_Segment_t *seg = NULL;
09055 while ((seg = hiter_getnext(hit)) != NULL)
09056 {
09057
09058
09059 char kbuf[DRMS_MAXKEYNAMELEN];
09060 snprintf(kbuf, sizeof(kbuf), "cparms_sg%03d", seg->info->segnum);
09061
09062 DRMS_Keyword_t *segkey = hcon_lookup_lower(&(template->keywords), kbuf);
09063 if (segkey)
09064 {
09065 snprintf(seg->cparms, DRMS_MAXCPARMS, "%s", segkey->value.string_val);
09066 }
09067
09068 if (drms_series_isvers(template->seriesinfo, &vers2_1))
09069 {
09070
09071
09072 snprintf(kbuf, sizeof(kbuf), "%s_bzero", seg->info->name);
09073
09074 segkey = hcon_lookup_lower(&(template->keywords), kbuf);
09075 if (segkey)
09076 {
09077 seg->bzero = segkey->value.double_val;
09078 }
09079
09080 snprintf(kbuf, sizeof(kbuf), "%s_bscale", seg->info->name);
09081
09082 segkey = hcon_lookup_lower(&(template->keywords), kbuf);
09083 if (segkey)
09084 {
09085 seg->bscale = segkey->value.double_val;
09086 }
09087 }
09088 }
09089
09090 hiter_destroy(&hit);
09091 }
09092 }
09093
09094 db_free_binary_result(qres);
09095 }
09096
09097 if (colnames)
09098 {
09099 free(colnames);
09100 }
09101
09102 if (status)
09103 *status = DRMS_SUCCESS;
09104 free(lcseries);
09105 return template;
09106
09107 bailout:
09108 if (colnames)
09109 {
09110 free(colnames);
09111 }
09112
09113 if (lcseries)
09114 {
09115 free(lcseries);
09116 }
09117
09118 if (status)
09119 *status = stat;
09120 return NULL;
09121 }
09122
09123 DRMS_Record_t *drms_template_record(DRMS_Env_t *env, const char *seriesname,
09124 int *status)
09125 {
09126 return drms_template_record_int(env, seriesname, 0, status);
09127 }
09128
09129
09130 DRMS_Record_t *drms_create_jsdtemplate_record(DRMS_Env_t *env,
09131 const char *seriesname,
09132 int *status)
09133 {
09134 return drms_template_record_int(env, seriesname, 1, status);
09135 }
09136
09137 void drms_destroy_jsdtemplate_record(DRMS_Record_t **rec)
09138 {
09139
09140
09141
09142 if (rec && *rec)
09143 {
09144 const char *dsdsNsPrefix = DSDS_GetNsPrefix();
09145 const char *seriesname = (*rec)->seriesinfo->seriesname;
09146
09147 if (strstr(seriesname, dsdsNsPrefix) != seriesname)
09148 {
09149 drms_free_template_record_struct(*rec);
09150 }
09151
09152 free(*rec);
09153 *rec = NULL;
09154 }
09155 }
09156
09157
09158 void drms_free_template_record_struct(DRMS_Record_t *rec)
09159 {
09160
09161 XASSERT(rec);
09162 if ( rec->init == 1 )
09163 {
09164 (rec->links).deep_free = (void (*)(const void *)) drms_free_template_link_struct;
09165 hcon_free(&rec->links);
09166
09167 (rec->segments).deep_free = (void (*)(const void *)) drms_free_template_segment_struct;
09168 hcon_free(&rec->segments);
09169
09170 (rec->keywords).deep_free = (void (*)(const void *)) drms_free_template_keyword_struct;
09171 hcon_free(&rec->keywords);
09172
09173 free(rec->seriesinfo);
09174 }
09175 }
09176
09177
09178 void drms_free_record_struct(DRMS_Record_t *rec)
09179 {
09180
09181 XASSERT(rec);
09182 if ( rec->init == 1 )
09183 {
09184 hcon_free(&rec->links);
09185 hcon_free(&rec->segments);
09186 hcon_free(&rec->keywords);
09187 free(rec->sessionns);
09188
09189 if (rec->suinfo)
09190 {
09191 free(rec->suinfo);
09192 rec->suinfo = NULL;
09193 }
09194
09195 if (rec->env && !rec->env->session->db_direct && rec->su)
09196 {
09197 --rec->su->refcount;
09198 if (rec->su->refcount == 0)
09199 {
09200 #ifdef DEBUG
09201 printf("drms_free_record_struct: freeing unit sunum=%lld, sudir='%s'\n",
09202 rec->su->sunum,rec->su->sudir);
09203 #endif
09204 drms_freeunit(rec->env, rec->su);
09205 rec->su = NULL;
09206 }
09207 }
09208 }
09209 }
09210
09211
09212 void drms_copy_record_struct(DRMS_Record_t *dst, DRMS_Record_t *src)
09213 {
09214 HIterator_t hit;
09215 DRMS_Keyword_t *key;
09216 DRMS_Link_t *link;
09217 DRMS_Segment_t *seg;
09218
09219 XASSERT(dst && src);
09220
09221
09222 *dst = *src;
09223
09224 hcon_copy(&dst->keywords, &src->keywords);
09225 hcon_copy(&dst->links, &src->links);
09226 hcon_copy(&dst->segments, &src->segments);
09227
09228
09229 hiter_new(&hit, &dst->links);
09230 while( (link = (DRMS_Link_t *)hiter_getnext(&hit)) )
09231 link->record = dst;
09232 hiter_free(&hit);
09233 hiter_new(&hit, &dst->keywords);
09234 while( (key = (DRMS_Keyword_t *)hiter_getnext(&hit)) )
09235 key->record = dst;
09236 hiter_free(&hit);
09237 hiter_new(&hit, &dst->segments);
09238 while( (seg = (DRMS_Segment_t *)hiter_getnext(&hit)) )
09239 seg->record = dst;
09240 hiter_free(&hit);
09241
09242
09243 }
09244
09245
09246
09247
09248 int drms_populate_record(DRMS_Env_t *env, DRMS_Record_t *rec, long long recnum)
09249 {
09250 int stat;
09251 char *query, *field_list, *seriesname;
09252 DB_Binary_Result_t *qres;
09253 DRMS_RecordSet_t rs;
09254 char *series_lower;
09255
09256 CHECKNULL(rec);
09257 seriesname = rec->seriesinfo->seriesname;
09258 field_list = drms_field_list(rec, NULL);
09259 series_lower = strdup(seriesname);
09260 strtolower(series_lower);
09261
09262
09263 query = malloc(strlen(field_list)+10*DRMS_MAXSERIESNAMELEN);
09264 XASSERT(query);
09265 sprintf(query, "select %s from %s where recnum=%lld",
09266 field_list, series_lower, recnum);
09267
09268 qres = drms_query_bin(env->session, query);
09269 if (qres == NULL)
09270 {
09271 stat = DRMS_ERROR_QUERYFAILED;
09272 goto bailout1;
09273 }
09274 else if (qres->num_rows != 1)
09275 {
09276 stat = DRMS_ERROR_BADQUERYRESULT;
09277 goto bailout2;
09278 }
09279 rs.records=malloc(sizeof(DRMS_Record_t*));
09280 XASSERT(rs.records);
09281 rs.n = 1;
09282 rs.records[0] = rec;
09283 rs.ss_n = 0;
09284 rs.ss_queries = NULL;
09285 rs.ss_types = NULL;
09286 rs.ss_starts = NULL;
09287 rs.ss_currentrecs = NULL;
09288 rs.cursor = NULL;
09289 rs.env = env;
09290
09291 stat = drms_populate_records(env, &rs,qres);
09292 db_free_binary_result(qres);
09293 free(query);
09294 free(field_list);
09295 free(rs.records);
09296 free(series_lower);
09297 return stat;
09298
09299 bailout2:
09300 db_free_binary_result(qres);
09301 bailout1:
09302 free(series_lower);
09303 free(query);
09304 free(field_list);
09305 return 1;
09306 }
09307
09308
09309
09310
09311
09312 int drms_populate_records(DRMS_Env_t *env, DRMS_RecordSet_t *rs, DB_Binary_Result_t *qres) {
09313 int row, col, i;
09314 DRMS_Keyword_t *key;
09315 DRMS_Link_t *link;
09316 DRMS_Segment_t *seg;
09317 DRMS_Record_t *rec;
09318 DB_Type_t column_type;
09319 int segnum;
09320 char *record_value;
09321 HIterator_t *last = NULL;
09322
09323 CHECKNULL(rs);
09324 CHECKNULL(qres);
09325
09326 if (rs->n != qres->num_rows)
09327 return DRMS_ERROR_BADQUERYRESULT;
09328
09329
09330
09331
09332 #ifndef DRMS_CLIENT
09333 drms_lock_server(env);
09334 #endif
09335 for (row=0; row<qres->num_rows; row++) {
09336 rec = rs->records[row];
09337 col = 0;
09338
09339 rec->recnum = db_binary_field_getlonglong(qres, row, col++);
09340
09341 rec->sunum = db_binary_field_getlonglong(qres, row, col++);
09342
09343 rec->slotnum = db_binary_field_getint(qres, row, col++);
09344
09345
09346 rec->sessionid = db_binary_field_getint(qres, row, col++);
09347
09348
09349 rec->sessionns = strdup(db_binary_field_get(qres, row, col++));
09350
09351
09352 if (hcon_size(&rec->links) > 0) {
09353 while ((link = drms_record_nextlink(rec, &last))) {
09354 link->record = rec;
09355 if (link->info->type == STATIC_LINK)
09356 link->recnum = db_binary_field_getlonglong(qres, row, col++);
09357 else {
09358
09359 link->isset = db_binary_field_getint(qres, row, col);
09360 col++;
09361
09362
09363 for (i = 0; i < link->info->pidx_num; i++, col++) {
09364 column_type = db_binary_column_type (qres, col);
09365 record_value = db_binary_field_get (qres, row, col);
09366 drms_copy_db2drms (link->info->pidx_type[i], &link->pidx_value[i],
09367 column_type, record_value);
09368 }
09369 }
09370 }
09371
09372 if (last)
09373 {
09374 hiter_destroy(&last);
09375 }
09376 }
09377
09378
09379 if (hcon_size(&rec->keywords) > 0) {
09380
09381 while ((key = drms_record_nextkey(rec, &last, 0)) ) {
09382 key->record = rec;
09383 if (likely (!key->info->islink && !drms_keyword_isconstant(key))) {
09384
09385
09386 if (!qres->column[col].is_null[row]) {
09387 column_type = db_binary_column_type (qres, col);
09388 record_value = db_binary_field_get (qres, row, col);
09389 drms_copy_db2drms (key->info->type, &key->value,
09390 column_type, record_value);
09391 }
09392 col++;
09393 }
09394 }
09395 if (last)
09396 {
09397 hiter_destroy(&last);
09398 }
09399 }
09400
09401
09402 if (hcon_size(&rec->segments) > 0)
09403 {
09404
09405
09406 DRMS_SeriesVersion_t vers2_0 = {"2.0", ""};
09407 DRMS_SeriesVersion_t vers2_1 = {"2.1", ""};
09408 char kbuf[DRMS_MAXKEYNAMELEN];
09409 DRMS_Keyword_t *segkey = NULL;
09410
09411 while( (seg = drms_record_nextseg(rec, &last, 0)) )
09412 {
09413 segnum = seg->info->segnum;
09414 seg->record = rec;
09415
09416 db_binary_field_getstr(qres, row, col++, DRMS_MAXSEGFILENAME, seg->filename);
09417 if (seg->info->scope==DRMS_VARDIM)
09418 {
09419
09420 for (i=0; i<seg->info->naxis; i++)
09421 seg->axis[i] = db_binary_field_getint(qres, row, col++);
09422 }
09423 if (drms_series_isvers(rec->seriesinfo, &vers2_0))
09424 {
09425
09426
09427
09428 snprintf(kbuf, sizeof(kbuf), "cparms_sg%03d", segnum);
09429
09430 segkey = hcon_lookup_lower(&(rec->keywords), kbuf);
09431 if (segkey)
09432 {
09433 snprintf(seg->cparms, DRMS_MAXCPARMS, "%s", segkey->value.string_val);
09434 }
09435 }
09436
09437 if (drms_series_isvers(rec->seriesinfo, &vers2_1))
09438 {
09439
09440
09441 snprintf(kbuf, sizeof(kbuf), "%s_bzero", seg->info->name);
09442
09443 segkey = hcon_lookup_lower(&(rec->keywords), kbuf);
09444 if (segkey)
09445 {
09446 seg->bzero = segkey->value.double_val;
09447 }
09448
09449 snprintf(kbuf, sizeof(kbuf), "%s_bscale", seg->info->name);
09450
09451 segkey = hcon_lookup_lower(&(rec->keywords), kbuf);
09452 if (segkey)
09453 {
09454 seg->bscale = segkey->value.double_val;
09455 }
09456 }
09457 }
09458
09459 if (last)
09460 {
09461 hiter_destroy(&last);
09462 }
09463 }
09464 }
09465
09466 #ifndef DRMS_CLIENT
09467 drms_unlock_server(env);
09468 #endif
09469
09470 return 0;
09471 }
09472
09473
09474
09475
09476
09477
09478
09479
09480
09481 char *drms_field_list(DRMS_Record_t *rec, int *num_cols)
09482 {
09483 int i,len=0;
09484 char *buf, *p;
09485 DRMS_Link_t *link;
09486 DRMS_Keyword_t *key;
09487 int ncol=0, segnum;
09488 DRMS_Segment_t *seg;
09489 HIterator_t *last = NULL;
09490
09491 XASSERT(rec);
09492
09493
09494 ncol=0;
09495 len = strlen("recnum");
09496 len += strlen("sunum")+2;
09497 len += strlen("slotnum")+2;
09498 len += strlen("sessionid")+2;
09499 len += strlen("sessionns")+2;
09500 ncol += 5;
09501
09502
09503 while( (link = drms_record_nextlink(rec, &last)) )
09504 {
09505 if (link->info->type == STATIC_LINK)
09506 {
09507 len += strlen(link->info->name)+5;
09508 ++ncol;
09509 }
09510 else
09511 {
09512 if (link->info->pidx_num) {
09513 len += strlen(link->info->name) + 11;
09514 ++ncol;
09515 }
09516
09517
09518 for (i=0; i<link->info->pidx_num; i++) {
09519 len += strlen (link->info->name);
09520 len += strlen (link->info->pidx_name[i]) + 6;
09521 ++ncol;
09522 }
09523 }
09524 }
09525
09526 if (last)
09527 {
09528 hiter_destroy(&last);
09529 }
09530
09531
09532 while( (key = drms_record_nextkey(rec, &last, 0)) )
09533 {
09534 if (!key->info->islink && !drms_keyword_isconstant(key))
09535 {
09536 len += strlen(key->info->name)+5;
09537 ++ncol;
09538 }
09539 }
09540
09541 if (last)
09542 {
09543 hiter_destroy(&last);
09544 }
09545
09546
09547 while( (seg = drms_record_nextseg(rec, &last, 0)) )
09548 {
09549
09550 len += 13;
09551 ++ncol;
09552 if (seg->info->scope==DRMS_VARDIM)
09553 {
09554
09555 len += 16*seg->info->naxis;
09556 ncol += seg->info->naxis;
09557 }
09558 }
09559
09560 if (last)
09561 {
09562 hiter_destroy(&last);
09563 }
09564
09565
09566 buf = malloc(len+1);
09567 XASSERT(buf);
09568
09569
09570
09571 p = buf;
09572
09573 p += sprintf(p,"%s","recnum");
09574 p += sprintf(p,", %s","sunum");
09575 p += sprintf(p,", %s","slotnum");
09576 p += sprintf(p,", %s","sessionid");
09577 p += sprintf(p,", %s","sessionns");
09578
09579
09580 while( (link = drms_record_nextlink(rec, &last)) )
09581 {
09582 if (link->info->type == STATIC_LINK)
09583 p += sprintf(p,", ln_%s",link->info->name);
09584 else
09585 {
09586 if (link->info->pidx_num) {
09587 p += sprintf(p,", ln_%s_isset", link->info->name);
09588 }
09589
09590
09591 for (i=0; i<link->info->pidx_num; i++)
09592 p += sprintf(p,", ln_%s_%s",link->info->name, link->info->pidx_name[i]);
09593 }
09594 }
09595
09596 if (last)
09597 {
09598 hiter_destroy(&last);
09599 }
09600
09601
09602 while( (key = drms_record_nextkey(rec, &last, 0)) )
09603 {
09604 if (!key->info->islink && !drms_keyword_isconstant(key))
09605 p += sprintf(p,", %s",key->info->name);
09606 }
09607
09608 if (last)
09609 {
09610 hiter_destroy(&last);
09611 }
09612
09613
09614 while( (seg = drms_record_nextseg(rec, &last, 0)) )
09615 {
09616 segnum = seg->info->segnum;
09617 p += sprintf(p, ", sg_%03d_file", segnum);
09618 if (seg->info->scope==DRMS_VARDIM)
09619 {
09620
09621 for (i=0; i<seg->info->naxis; i++)
09622 p += sprintf(p,", sg_%03d_axis%03d",segnum,i);
09623 }
09624 }
09625
09626 if (last)
09627 {
09628 hiter_destroy(&last);
09629 }
09630
09631 buf[len] = 0;
09632
09633 if (num_cols)
09634 *num_cols = ncol;
09635 #ifdef DEBUG
09636 printf("Constructed field list '%s'\n",buf);
09637 #endif
09638 return buf;
09639 }
09640
09641 char *columnList(DRMS_Record_t *rec, HContainer_t *links, HContainer_t *keys, HContainer_t *segs, int *num_cols)
09642 {
09643 int i;
09644 char *buf = NULL;
09645 char *p = NULL;
09646 DRMS_Link_t **plink = NULL;
09647 DRMS_Link_t *link = NULL;
09648 DRMS_Keyword_t **pkey = NULL;
09649 DRMS_Keyword_t *key = NULL;
09650 int ncol=0;
09651 int segnum;
09652 DRMS_Segment_t **pseg = NULL;
09653 DRMS_Segment_t *seg = NULL;
09654 HIterator_t hit;
09655 char *lower = NULL;
09656 char tail[256];
09657 size_t szBuf;
09658 int err;
09659
09660 XASSERT(rec);
09661
09662 err = 0;
09663 ncol = 0;
09664
09665
09666
09667
09668
09669 szBuf = 256;
09670 buf = calloc(szBuf, sizeof(char));
09671 XASSERT(buf);
09672
09673
09674 buf = base_strcatalloc(buf, "recnum", &szBuf);
09675 ++ncol;
09676 buf = base_strcatalloc(buf, ", sunum", &szBuf);
09677 ++ncol;
09678 buf = base_strcatalloc(buf, ", slotnum", &szBuf);
09679 ++ncol;
09680 buf = base_strcatalloc(buf, ", sessionid", &szBuf);
09681 ++ncol;
09682 buf = base_strcatalloc(buf, ", sessionns", &szBuf);
09683 ++ncol;
09684
09685 if (!err)
09686 {
09687
09688 if (links)
09689 {
09690 hiter_new_sort(&hit, links, linkListSort);
09691 while((plink = (DRMS_Link_t **)hiter_getnext(&hit)) != NULL)
09692 {
09693 link = *plink;
09694
09695 lower = strdup(link->info->name);
09696
09697 if (!lower)
09698 {
09699 err = 1;
09700 fprintf(stderr, "Out of memory in columnList().\n");
09701 break;
09702 }
09703
09704 strtolower(lower);
09705
09706 if (link->info->type == STATIC_LINK)
09707 {
09708 snprintf(tail, sizeof(tail), ", ln_%s", lower);
09709 buf = base_strcatalloc(buf, tail, &szBuf);
09710 ++ncol;
09711 }
09712 else
09713 {
09714 if (link->info->pidx_num)
09715 {
09716 snprintf(tail, sizeof(tail), ", ln_%s_isset", lower);
09717 buf = base_strcatalloc(buf, tail, &szBuf);
09718 ++ncol;
09719 }
09720
09721
09722
09723 for (i=0; i<link->info->pidx_num; i++)
09724 {
09725 snprintf(tail, sizeof(tail), ", ln_%s_%s", lower, link->info->pidx_name[i]);
09726 buf = base_strcatalloc(buf, tail, &szBuf);
09727 ++ncol;
09728 }
09729 }
09730
09731 free(lower);
09732 lower = NULL;
09733 }
09734 hiter_free(&hit);
09735 }
09736 else
09737 {
09738 hiter_new_sort(&hit, &(rec->links), drms_link_ranksort);
09739 while((link = (DRMS_Link_t *)hiter_getnext(&hit)) != NULL)
09740 {
09741 lower = strdup(link->info->name);
09742
09743 if (!lower)
09744 {
09745 err = 1;
09746 fprintf(stderr, "Out of memory in columnList().\n");
09747 break;
09748 }
09749
09750 strtolower(lower);
09751
09752 if (link->info->type == STATIC_LINK)
09753 {
09754 snprintf(tail, sizeof(tail), ", ln_%s", lower);
09755 buf = base_strcatalloc(buf, tail, &szBuf);
09756 ++ncol;
09757 }
09758 else
09759 {
09760 if (link->info->pidx_num)
09761 {
09762 snprintf(tail, sizeof(tail), ", ln_%s_isset", lower);
09763 buf = base_strcatalloc(buf, tail, &szBuf);
09764 ++ncol;
09765 }
09766
09767
09768
09769 for (i=0; i<link->info->pidx_num; i++)
09770 {
09771 snprintf(tail, sizeof(tail), ", ln_%s_%s", lower, link->info->pidx_name[i]);
09772 buf = base_strcatalloc(buf, tail, &szBuf);
09773 ++ncol;
09774 }
09775 }
09776
09777 free(lower);
09778 lower = NULL;
09779 }
09780 hiter_free(&hit);
09781 }
09782 }
09783
09784 if (!err)
09785 {
09786
09787 if (keys)
09788 {
09789 hiter_new_sort(&hit, keys, keyListSort);
09790 while((pkey = (DRMS_Keyword_t **)hiter_getnext(&hit)) != NULL)
09791 {
09792 key = *pkey;
09793
09794 lower = strdup(key->info->name);
09795
09796 if (!lower)
09797 {
09798 err = 1;
09799 fprintf(stderr, "Out of memory in columnList().\n");
09800 break;
09801 }
09802
09803 strtolower(lower);
09804
09805 if (!key->info->islink && !drms_keyword_isconstant(key))
09806 {
09807 snprintf(tail, sizeof(tail), ", %s", lower);
09808 buf = base_strcatalloc(buf, tail, &szBuf);
09809 ++ncol;
09810 }
09811
09812 free(lower);
09813 lower = NULL;
09814 }
09815 hiter_free(&hit);
09816 }
09817 else
09818 {
09819 hiter_new_sort(&hit, &(rec->keywords), drms_keyword_ranksort);
09820 while((key = (DRMS_Keyword_t *)hiter_getnext(&hit)) != NULL)
09821 {
09822 lower = strdup(key->info->name);
09823
09824 if (!lower)
09825 {
09826 err = 1;
09827 fprintf(stderr, "Out of memory in columnList().\n");
09828 break;
09829 }
09830
09831 strtolower(lower);
09832
09833 if (!key->info->islink && !drms_keyword_isconstant(key))
09834 {
09835 snprintf(tail, sizeof(tail), ", %s", lower);
09836 buf = base_strcatalloc(buf, tail, &szBuf);
09837 ++ncol;
09838 }
09839
09840 free(lower);
09841 lower = NULL;
09842 }
09843 hiter_free(&hit);
09844 }
09845 }
09846
09847 if (!err)
09848 {
09849
09850 if (segs)
09851 {
09852 hiter_new_sort(&hit, segs, segListSort);
09853 while((pseg = (DRMS_Segment_t **)hiter_getnext(&hit)) != NULL)
09854 {
09855 seg = *pseg;
09856
09857 lower = strdup(seg->info->name);
09858
09859 if (!lower)
09860 {
09861 err = 1;
09862 fprintf(stderr, "Out of memory in columnList().\n");
09863 break;
09864 }
09865
09866 strtolower(lower);
09867
09868 segnum = seg->info->segnum;
09869
09870 snprintf(tail, sizeof(tail), ", sg_%03d_file", segnum);
09871 buf = base_strcatalloc(buf, tail, &szBuf);
09872 ++ncol;
09873
09874 if (seg->info->scope==DRMS_VARDIM)
09875 {
09876
09877 for (i = 0; i < seg->info->naxis; i++)
09878 {
09879 snprintf(tail, sizeof(tail), ", sg_%03d_axis%03d", segnum, i);
09880 buf = base_strcatalloc(buf, tail, &szBuf);
09881 ++ncol;
09882 }
09883 }
09884 free(lower);
09885 lower = NULL;
09886 }
09887 hiter_free(&hit);
09888 }
09889 else
09890 {
09891 hiter_new_sort(&hit, &(rec->segments), drms_segment_ranksort);
09892 while((seg = (DRMS_Segment_t *)hiter_getnext(&hit)) != NULL)
09893 {
09894 lower = strdup(seg->info->name);
09895
09896 if (!lower)
09897 {
09898 err = 1;
09899 fprintf(stderr, "Out of memory in columnList().\n");
09900 break;
09901 }
09902
09903 strtolower(lower);
09904
09905 segnum = seg->info->segnum;
09906
09907 snprintf(tail, sizeof(tail), ", sg_%03d_file", segnum);
09908 buf = base_strcatalloc(buf, tail, &szBuf);
09909 ++ncol;
09910
09911 if (seg->info->scope==DRMS_VARDIM)
09912 {
09913
09914 for (i = 0; i < seg->info->naxis; i++)
09915 {
09916 snprintf(tail, sizeof(tail), ", sg_%03d_axis%03d", segnum, i);
09917 buf = base_strcatalloc(buf, tail, &szBuf);
09918 ++ncol;
09919 }
09920 }
09921 free(lower);
09922 lower = NULL;
09923 }
09924 hiter_free(&hit);
09925 }
09926 }
09927
09928 if (num_cols)
09929 {
09930 *num_cols = ncol;
09931 }
09932
09933 #ifdef DEBUG
09934 printf("Constructed field list '%s'\n",buf);
09935 #endif
09936
09937 return buf;
09938 }
09939
09940
09941 int drms_insert_records(DRMS_RecordSet_t *recset)
09942 {
09943 DRMS_Env_t *env;
09944 int col,row,i,num_args, num_rows;
09945 char *query, *field_list, *seriesname, *p, *series_lower;
09946 DRMS_Keyword_t *key;
09947 DRMS_Link_t *link;
09948 DRMS_Record_t *rec;
09949 DRMS_Segment_t *seg;
09950 DB_Type_t *intype;
09951 char **argin;
09952 int status;
09953 int *sz;
09954 HIterator_t *last = NULL;
09955
09956 CHECKNULL(recset);
09957
09958
09959 if ((num_rows = recset->n) < 1)
09960 return 0;
09961
09962
09963 rec = recset->records[0];
09964 env = rec->env;
09965 seriesname = rec->seriesinfo->seriesname;
09966 series_lower = strdup(seriesname);
09967 strtolower(series_lower);
09968
09969 field_list = drms_field_list(rec, &num_args);
09970
09971
09972
09973 query = malloc(strlen(field_list)+10*DRMS_MAXSERIESNAMELEN);
09974 XASSERT(query);
09975 p = query;
09976 p += sprintf(p, "%s (%s)", series_lower, field_list);
09977 #ifdef DEBUG
09978 printf("Table and column specifier for bulk insert = '%s'\n",query);
09979 #endif
09980
09981 argin = malloc(num_args*sizeof(void *));
09982 XASSERT(argin);
09983 sz = malloc(num_args*sizeof(int));
09984 XASSERT(sz);
09985 intype = malloc(num_args*sizeof(DB_Type_t));
09986 XASSERT(intype);
09987
09988
09989 col = 0;
09990 intype[col] = drms2dbtype(DRMS_TYPE_LONGLONG);
09991 argin[col] = malloc(num_rows*db_sizeof(intype[col]));
09992 XASSERT(argin[col]);
09993 col++;
09994 intype[col] = drms2dbtype(DRMS_TYPE_LONGLONG);
09995 argin[col] = malloc(num_rows*db_sizeof(intype[col]));
09996 XASSERT(argin[col]);
09997 col++;
09998 intype[col] = drms2dbtype(DRMS_TYPE_INT);
09999 argin[col] = malloc(num_rows*db_sizeof(intype[col]));
10000 XASSERT(argin[col]);
10001 col++;
10002 intype[col] = drms2dbtype(DRMS_TYPE_LONGLONG);
10003 argin[col] = malloc(num_rows*db_sizeof(intype[col]));
10004 XASSERT(argin[col]);
10005 col++;
10006 intype[col] = drms2dbtype(DRMS_TYPE_STRING);
10007 argin[col] = malloc(num_rows*sizeof(char *));
10008 XASSERT(argin[col]);
10009 col++;
10010
10011
10012 while( (link = drms_record_nextlink(rec, &last)) )
10013 {
10014 if (link->info->type == STATIC_LINK)
10015 {
10016 intype[col] = drms2dbtype(DRMS_TYPE_LONGLONG);
10017 argin[col] = malloc(num_rows*db_sizeof(intype[col]));
10018 XASSERT(argin[col]);
10019 col++;
10020 }
10021 else
10022 {
10023 if (link->info->pidx_num) {
10024 intype[col] = drms2dbtype(DRMS_TYPE_INT);
10025 argin[col] = malloc(num_rows*db_sizeof(intype[col]));
10026 XASSERT(argin[col]);
10027 col++;
10028 }
10029
10030
10031 for (i=0; i<link->info->pidx_num; i++)
10032 {
10033 intype[col] = drms2dbtype(link->info->pidx_type[i]);
10034 if (link->info->pidx_type[i] == DRMS_TYPE_STRING )
10035 {
10036 argin[col] = malloc(num_rows*sizeof(char *));
10037 XASSERT(argin[col]);
10038 col++;
10039 }
10040 else
10041 {
10042 argin[col] = malloc(num_rows*db_sizeof(intype[col]));
10043 XASSERT(argin[col]);
10044 col++;
10045 }
10046 }
10047 }
10048 }
10049
10050 if (last)
10051 {
10052 hiter_destroy(&last);
10053 }
10054
10055
10056 while( (key = drms_record_nextkey(rec, &last, 0)) )
10057 {
10058 if (!key->info->islink && !drms_keyword_isconstant(key))
10059 {
10060 intype[col] = drms2dbtype(key->info->type);
10061 if ( key->info->type == DRMS_TYPE_STRING )
10062 {
10063 argin[col] = malloc(num_rows*sizeof(char *));
10064 XASSERT(argin[col]);
10065 col++;
10066 }
10067 else
10068 {
10069 argin[col] = malloc(num_rows*db_sizeof(intype[col]));
10070 XASSERT(argin[col]);
10071 col++;
10072 }
10073 }
10074 }
10075
10076 if (last)
10077 {
10078 hiter_destroy(&last);
10079 }
10080
10081
10082 while( (seg = drms_record_nextseg(rec, &last, 0)) )
10083 {
10084
10085 intype[col] = drms2dbtype(DRMS_TYPE_STRING);
10086 argin[col] = malloc(num_rows*sizeof(char *));
10087 XASSERT(argin[col]);
10088 col++;
10089
10090 if (seg->info->scope==DRMS_VARDIM)
10091 {
10092
10093
10094 for (i=0; i<seg->info->naxis; i++)
10095 {
10096 intype[col] = drms2dbtype(DRMS_TYPE_INT);
10097 argin[col] = malloc(num_rows*db_sizeof(intype[col]));
10098 XASSERT(argin[col]);
10099 col++;
10100 }
10101 }
10102 }
10103
10104 if (last)
10105 {
10106 hiter_destroy(&last);
10107 }
10108
10109 for (col=0; col<num_args; col++)
10110 sz[col] = db_sizeof(intype[col]);
10111
10112
10113
10114 for (row=0; row<num_rows; row++)
10115 {
10116 rec = recset->records[row];
10117 col = 0;
10118 memcpy(argin[col]+row*sz[col], &rec->recnum, sz[col]);
10119 col++;
10120 memcpy(argin[col]+row*sz[col], &rec->sunum, sz[col]);
10121 col++;
10122 memcpy(argin[col]+row*sz[col], &rec->slotnum, sz[col]);
10123 col++;
10124 memcpy(argin[col]+row*sz[col], &rec->sessionid, sz[col]);
10125 col++;
10126 memcpy(argin[col]+row*sz[col], &rec->sessionns, sz[col]);
10127 col++;
10128
10129
10130 while( (link = drms_record_nextlink(rec, &last)) )
10131 {
10132 if (link->info->type == STATIC_LINK)
10133 {
10134 memcpy(argin[col]+row*sz[col], &link->recnum, sz[col]);
10135 col++;
10136 }
10137 else
10138 {
10139 memcpy(argin[col]+row*sz[col], &link->isset, sz[col]);
10140 col++;
10141
10142
10143 for (i=0; i<link->info->pidx_num; i++)
10144 {
10145 if (link->info->pidx_type[i] == DRMS_TYPE_STRING )
10146 {
10147 memcpy(argin[col]+row*sz[col], &link->pidx_value[i].string_val, sz[col]);
10148 col++;
10149 }
10150 else
10151 {
10152 memcpy(argin[col]+row*sz[col],
10153 drms_addr(link->info->pidx_type[i], &link->pidx_value[i]), sz[col]);
10154 col++;
10155 }
10156 }
10157 }
10158 }
10159
10160 if (last)
10161 {
10162 hiter_destroy(&last);
10163 }
10164
10165
10166 while( (key = drms_record_nextkey(rec, &last, 0)) )
10167 {
10168 if (!key->info->islink && !drms_keyword_isconstant(key))
10169 {
10170 if (key->info->type == DRMS_TYPE_STRING )
10171 {
10172 memcpy(argin[col]+row*sz[col], &key->value.string_val, sz[col]);
10173 col++;
10174 }
10175 else
10176 {
10177 memcpy(argin[col]+row*sz[col],
10178 drms_addr(key->info->type, &key->value), sz[col]);
10179 col++;
10180 }
10181 }
10182 }
10183
10184 if (last)
10185 {
10186 hiter_destroy(&last);
10187 }
10188
10189
10190 while( (seg = drms_record_nextseg(rec, &last, 0)) )
10191 {
10192
10193
10194 ((char **)argin[col])[row] = seg->filename;
10195 col++;
10196 if (seg->info->scope==DRMS_VARDIM)
10197 {
10198
10199
10200 for (i=0; i<seg->info->naxis; i++)
10201 {
10202 memcpy(argin[col]+row*sz[col], &seg->axis[i], sz[col]);
10203 col++;
10204 }
10205 }
10206 }
10207
10208 if (last)
10209 {
10210 hiter_destroy(&last);
10211 }
10212 }
10213 #ifdef DEBUG
10214 printf("col = %d, num_args=%d\n",col,num_args);
10215 #endif
10216 XASSERT(col==num_args);
10217 status = drms_bulk_insert_array(env->session, query, num_rows, num_args,
10218 intype, (void **)argin);
10219
10220 for (col=0; col<num_args; col++)
10221 free(argin[col]);
10222 free(argin);
10223 free(intype);
10224 free(query);
10225 free(sz);
10226 free(field_list);
10227 free(series_lower);
10228
10229
10230
10231
10232
10233
10234
10235
10236
10237
10238
10239
10240 #if 0
10241 char **pkeynames = NULL;
10242 int ipk;
10243 int rv;
10244 int irec;
10245 long long *recnums = NULL;
10246
10247 pkeynames = malloc(sizeof(char *) * recset->records[0]->seriesinfo->pidx_num);
10248 recnums = malloc(sizeof(long long) * num_rows);
10249
10250 if (pkeynames && recnums)
10251 {
10252 for (ipk = 0; ipk < recset->records[0]->seriesinfo->pidx_num; ipk++)
10253 {
10254 pkeynames[ipk] = strdup(recset->records[0]->seriesinfo->pidx_keywords[ipk]->info->name);
10255 }
10256
10257 for (irec = 0; irec < num_rows; irec++)
10258 {
10259 recnums[irec] = recset->records[irec]->recnum;
10260 }
10261
10262 rv = drms_series_updatesummaries(env, seriesname, num_rows, recset->records[0]->seriesinfo->pidx_num, pkeynames, recnums, 1);
10263
10264 if (!status)
10265 {
10266
10267
10268 status = rv;
10269 }
10270
10271 for (ipk = 0; ipk < recset->records[0]->seriesinfo->pidx_num; ipk++)
10272 {
10273 if (pkeynames[ipk])
10274 {
10275 free(pkeynames[ipk]);
10276 pkeynames[ipk] = NULL;
10277 }
10278 }
10279
10280 free(pkeynames);
10281 pkeynames = NULL;
10282 free(recnums);
10283 recnums = NULL;
10284 }
10285 else
10286 {
10287 status = DRMS_ERROR_OUTOFMEMORY;
10288 }
10289 #endif
10290
10291 return status;
10292 }
10293
10294
10295
10296
10297
10298
10299
10300
10301
10302
10303
10304 long long drms_record_size(DRMS_Record_t *rec)
10305 {
10306 long long size;
10307 DRMS_Segment_t *seg;
10308 HIterator_t hit;
10309
10310 CHECKNULL(rec);
10311 size = 0;
10312
10313 hiter_new(&hit, &rec->segments);
10314 while( (seg = (DRMS_Segment_t *)hiter_getnext(&hit)) )
10315 {
10316
10317 size += drms_segment_size(seg,NULL);
10318
10319 }
10320 hiter_free(&hit);
10321 return size;
10322 }
10323
10324
10325
10326 void drms_print_record(DRMS_Record_t *rec)
10327 {
10328 drms_fprint_record(stdout, rec);
10329 }
10330
10331
10332
10333 void drms_fprint_record(FILE *keyfile, DRMS_Record_t *rec)
10334 {
10335 int i;
10336 const int fwidth=17;
10337 HIterator_t hit;
10338 DRMS_Link_t *link;
10339 DRMS_Keyword_t *key;
10340 DRMS_Segment_t *seg;
10341
10342 if (rec==NULL)
10343 {
10344 fprintf(stderr,"NULL pointer in drms_print_record.\n");
10345 return;
10346 }
10347 fprintf(keyfile, "================================================================================\n");
10348 fprintf(keyfile, "%-*s:\t%s\n",fwidth,"Series name",rec->seriesinfo->seriesname);
10349 fprintf(keyfile, "%-*s:\t%s\n",fwidth,"Version",rec->seriesinfo->version);
10350 fprintf(keyfile, "%-*s:\t%lld\n",fwidth,"Record #",rec->recnum);
10351 fprintf(keyfile, "%-*s:\t%lld\n",fwidth,"Storage unit #",rec->sunum);
10352 if (rec->su)
10353 {
10354 fprintf(keyfile, "%-*s:\t%s\n",fwidth,"Storage unit dir",rec->su->sudir);
10355 }
10356 fprintf(keyfile, "%-*s:\t%d\n",fwidth,"Storage unit slot #",rec->slotnum);
10357 fprintf(keyfile, "%-*s:\t%lld\n",fwidth,"Session ID",rec->sessionid);
10358 fprintf(keyfile, "%-*s:\t%s\n",fwidth,"Session Namespace",rec->sessionns);
10359 fprintf(keyfile, "%-*s:\t%d\n",fwidth,"Readonly",rec->readonly);
10360 fprintf(keyfile, "%-*s:\t%s\n",fwidth,"Description",rec->seriesinfo->description);
10361 fprintf(keyfile, "%-*s:\t%s\n",fwidth,"Author",rec->seriesinfo->author);
10362 fprintf(keyfile, "%-*s:\t%s\n",fwidth,"Owner",rec->seriesinfo->owner);
10363 fprintf(keyfile, "%-*s:\t%d\n",fwidth,"Unitsize",rec->seriesinfo->unitsize);
10364 fprintf(keyfile, "%-*s:\t%d\n",fwidth,"Archive",rec->seriesinfo->archive);
10365 fprintf(keyfile, "%-*s:\t%d\n",fwidth,"Retention",rec->seriesinfo->retention);
10366 fprintf(keyfile, "%-*s:\t%d\n",fwidth,"Retention_perm",rec->seriesinfo->retention_perm);
10367 fprintf(keyfile, "%-*s:\t%d\n",fwidth,"Tapegroup",rec->seriesinfo->tapegroup);
10368
10369 for (i=0; i<rec->seriesinfo->pidx_num; i++)
10370 fprintf(keyfile, "%-*s %d:\t%s\n",fwidth,"Internal primary index",i,
10371 (rec->seriesinfo->pidx_keywords[i])->info->name);
10372
10373 int npkeys = 0;
10374 char **extpkeys =
10375 drms_series_createpkeyarray(rec->env, rec->seriesinfo->seriesname, &npkeys, NULL);
10376 if (extpkeys && npkeys > 0)
10377 {
10378 for (i=0; i<npkeys; i++)
10379 fprintf(keyfile, "%-*s %d:\t%s\n",fwidth,"External primary index",i,
10380 extpkeys[i]);
10381 }
10382
10383 if (extpkeys)
10384 {
10385 drms_series_destroypkeyarray(&extpkeys, npkeys);
10386 }
10387
10388 for (i=0; i<rec->seriesinfo->dbidx_num; i++)
10389 fprintf(keyfile, "%-*s %d:\t%s\n",fwidth,"DB index",i,
10390 (rec->seriesinfo->dbidx_keywords[i])->info->name);
10391
10392 hiter_new_sort(&hit, &rec->keywords, drms_keyword_ranksort);
10393 while( (key = (DRMS_Keyword_t *)hiter_getnext(&hit)) )
10394 {
10395 fprintf(keyfile, "%-*s '%s':\n",13,"Keyword",key->info->name);
10396 drms_keyword_fprint(keyfile, key);
10397 }
10398
10399 hiter_new_sort(&hit, &rec->links, drms_link_ranksort);
10400 while( (link = (DRMS_Link_t *)hiter_getnext(&hit)) )
10401 {
10402 fprintf(keyfile, "%-*s '%s':\n",13,"Link",link->info->name);
10403 drms_link_fprint(keyfile, link);
10404 }
10405
10406 hiter_new_sort(&hit, &rec->segments, drms_segment_ranksort);
10407 while( (seg = (DRMS_Segment_t *)hiter_getnext(&hit)) )
10408 {
10409 fprintf(keyfile, "%-*s '%s':\n",fwidth,"Segment",seg->info->name);
10410 drms_segment_fprint(keyfile, seg);
10411 }
10412 fprintf(keyfile, "================================================================================\n");
10413 }
10414
10415 int drms_record_numkeywords(DRMS_Record_t *rec)
10416 {
10417 if (rec)
10418 return hcon_size(&rec->keywords);
10419 else
10420 return 0;
10421 }
10422
10423 int drms_record_numlinks(DRMS_Record_t *rec)
10424 {
10425 if (rec)
10426 return hcon_size(&rec->links);
10427 else
10428 return 0;
10429 }
10430
10431 int drms_record_numsegments(DRMS_Record_t *rec)
10432 {
10433 if (rec)
10434 return hcon_size(&rec->segments);
10435 else
10436 return 0;
10437 }
10438
10439 int drms_record_num_nonlink_segments(DRMS_Record_t *rec)
10440 {
10441 HIterator_t hit;
10442 DRMS_Segment_t *seg;
10443 int count = 0;
10444 if (rec) {
10445 hiter_new(&hit, &rec->segments);
10446 while( (seg = (DRMS_Segment_t *)hiter_getnext(&hit)) ) {
10447 if (!seg->info->islink) {
10448 count++;
10449 }
10450 }
10451
10452 hiter_free(&hit);
10453 }
10454 return count;
10455 }
10456
10457
10458
10459
10460 int drms_record_directory (DRMS_Record_t *rec, char *dirname, int retrieve) {
10461 int stat;
10462 if (drms_record_numsegments (rec) <= 0) {
10463 #ifdef DEBUG
10464 fprintf (stderr, "ERROR: Calling drms_record_directory is valid only for "
10465 "records containing data segments.");
10466 #endif
10467 dirname[0] = 0;
10468 return(DRMS_ERROR_NOSEGMENT);
10469 }
10470
10471
10472
10473
10474 if (drms_record_isdsds(rec))
10475 {
10476
10477
10478 fprintf(stderr, "ERROR: Cannot call drms_record_directory() on a record that contains a DRMS_DSDS segment.\n");
10479 return(DRMS_ERROR_NODSDSSUPPORT);
10480 }
10481
10482 if (rec->sunum != -1LL && rec->su == NULL) {
10483 #ifdef DEBUG
10484 printf ("Getting SU for record %s:#%lld, sunum=%lld\n",
10485 rec->seriesinfo->seriesname,rec->recnum, rec->sunum);
10486 #endif
10487 if ((rec->su = drms_getunit (rec->env, rec->seriesinfo->seriesname,
10488 rec->sunum, retrieve, &stat)) == NULL) {
10489 if (stat)
10490 {
10491 fprintf (stderr, "ERROR in drms_record_directory: Cannot retrieve "
10492 "storage unit. stat = %d\n", stat);
10493 return(DRMS_ERROR_SUMGET);
10494 }
10495 dirname[0] = '\0';
10496 return(DRMS_SUCCESS);
10497 }
10498 rec->su->refcount++;
10499 #ifdef DEBUG
10500 printf("Retrieved unit sunum=%lld, sudir=%s\n",
10501 rec->su->sunum, rec->su->sudir);
10502 #endif
10503 }
10504
10505
10506 if (rec->su)
10507 {
10508
10509
10510
10511
10512 DRMS_Segment_t *seg = NULL;
10513 int hasslotdirs = 0;
10514 HIterator_t *seghit = hiter_create(&(rec->segments));
10515 if (seghit)
10516 {
10517 while((seg = (DRMS_Segment_t *)hiter_getnext(seghit)))
10518 {
10519 if (seg->info->protocol != DRMS_TAS)
10520 {
10521 hasslotdirs = 1;
10522 break;
10523 }
10524 }
10525 hiter_destroy(&seghit);
10526 }
10527
10528 if (hasslotdirs)
10529 {
10530 CHECKSNPRINTF(snprintf(dirname, DRMS_MAXPATHLEN, "%s/" DRMS_SLOTDIR_FORMAT,
10531 rec->su->sudir, rec->slotnum), DRMS_MAXPATHLEN);
10532 }
10533 else
10534 {
10535 CHECKSNPRINTF(snprintf(dirname, DRMS_MAXPATHLEN, "%s",
10536 rec->su->sudir), DRMS_MAXPATHLEN);
10537 }
10538 }
10539
10540 return(DRMS_SUCCESS);
10541 }
10542
10543
10544
10545 int drms_record_directory_nosums(DRMS_Record_t *rec, char *dirout, int size)
10546 {
10547 int rv = DRMS_SUCCESS;
10548
10549 if (dirout && size >= 1)
10550 {
10551 if (drms_record_numsegments(rec) <= 0)
10552 {
10553 *dirout = '\0';
10554 rv = DRMS_ERROR_NOSEGMENT;
10555 }
10556 else if (drms_record_isdsds(rec))
10557 {
10558
10559 fprintf(stderr, "ERROR: Cannot call drms_record_directory_nosums() on a record that contains a DRMS_DSDS segment.\n");
10560 *dirout = '\0';
10561 rv = DRMS_ERROR_NODSDSSUPPORT;
10562 }
10563 else
10564 {
10565
10566 if (rec->su && *rec->su->sudir != '\0')
10567 {
10568
10569
10570
10571
10572 DRMS_Segment_t *seg = NULL;
10573 int hasslotdirs = 0;
10574 HIterator_t *seghit = hiter_create(&(rec->segments));
10575
10576 if (seghit)
10577 {
10578 while((seg = (DRMS_Segment_t *)hiter_getnext(seghit)))
10579 {
10580 if (seg->info->protocol != DRMS_TAS)
10581 {
10582 hasslotdirs = 1;
10583 break;
10584 }
10585 }
10586 hiter_destroy(&seghit);
10587 }
10588
10589 if (hasslotdirs)
10590 {
10591 CHECKSNPRINTF(snprintf(dirout, size, "%s/" DRMS_SLOTDIR_FORMAT, rec->su->sudir, rec->slotnum), size);
10592 }
10593 else
10594 {
10595 CHECKSNPRINTF(snprintf(dirout, size, "%s", rec->su->sudir), size);
10596 }
10597 }
10598 else
10599 {
10600 if (rec->sunum != -1LL && rec->su == NULL)
10601 {
10602
10603
10604 rv = DRMS_ERROR_NEEDSUMS;
10605 }
10606
10607 *dirout = '\0';
10608 }
10609 }
10610 }
10611 else
10612 {
10613 rv = DRMS_ERROR_INVALIDDATA;
10614 }
10615
10616 return rv;
10617 }
10618
10619
10620
10621
10622
10623
10624
10625 FILE *drms_record_fopen(DRMS_Record_t *rec, char *filename, const char *mode)
10626 {
10627 int stat;
10628 int newslot = 0;
10629 char path[DRMS_MAXPATHLEN];
10630 FILE *fp;
10631 int createslotdirs = 1;
10632 DRMS_Segment_t *seg = NULL;
10633
10634 if (drms_record_numsegments(rec) < 0)
10635 {
10636 fprintf(stderr,"ERROR: Calling drms_record_fopen is only for records "
10637 "containing data segments.");
10638 return NULL;
10639 }
10640 switch(mode[0])
10641 {
10642 case 'w':
10643 case 'a':
10644 if (rec->su==NULL)
10645 {
10646
10647
10648 HIterator_t *seghit = hiter_create(&(rec->segments));
10649 if (seghit)
10650 {
10651 createslotdirs = 0;
10652 while((seg = (DRMS_Segment_t *)hiter_getnext(seghit)))
10653 {
10654 if (seg->info->protocol != DRMS_TAS)
10655 {
10656 createslotdirs = 1;
10657 }
10658 }
10659 hiter_destroy(&seghit);
10660 }
10661
10662 if ((stat = drms_newslots(rec->env, 1, rec->seriesinfo->seriesname,
10663 &rec->recnum, rec->lifetime, &rec->slotnum,
10664 &rec->su, createslotdirs)))
10665 {
10666 fprintf(stderr,"ERROR in drms_record_fopen: drms_newslot"
10667 " failed with error code %d.\n",stat);
10668 return NULL;
10669 }
10670 rec->sunum = rec->su->sunum;
10671 newslot = 1;
10672 }
10673 break;
10674 case 'r':
10675
10676
10677 if (rec->sunum != -1LL && rec->su==NULL)
10678 {
10679 if ((rec->su = drms_getunit(rec->env, rec->seriesinfo->seriesname,
10680 rec->sunum, 1, &stat)) == NULL)
10681 {
10682 if (stat)
10683 fprintf(stderr,"ERROR in drms_record_fopen: Cannot open file for "
10684 "reading in non-existent storage unit slot. stat = %d\n", stat);
10685 return NULL;
10686 }
10687 rec->su->refcount++;
10688 }
10689 }
10690
10691 CHECKSNPRINTF(snprintf(path,DRMS_MAXPATHLEN, "%s/" DRMS_SLOTDIR_FORMAT "/%s",
10692 rec->su->sudir, rec->slotnum, filename), DRMS_MAXPATHLEN);
10693
10694 if (!(fp = fopen(path, mode)))
10695 {
10696 perror("ERROR in drms_record_fopen: fopen failed with");
10697 if (newslot)
10698 drms_freeslot(rec->env, rec->seriesinfo->seriesname,
10699 rec->su->sunum, rec->slotnum);
10700 }
10701 return fp;
10702 }
10703
10704
10705 long long drms_record_memsize(DRMS_Record_t *rec)
10706 {
10707 return partialRecordMemsize(rec, NULL, NULL, NULL);
10708 }
10709
10710
10711
10712
10713
10714
10715 long long drms_keylist_memsize(DRMS_Record_t *template, const char *keylist)
10716 {
10717 long long size = 0;
10718
10719 char *key = NULL;
10720 char *list = strdup(keylist);
10721
10722
10723 char *src = NULL;
10724 char *dst = NULL;
10725 src = dst = list;
10726
10727 while (*src != '\0')
10728 {
10729 if (*src != ' ')
10730 {
10731 *dst = *src;
10732 dst++;
10733 }
10734 src++;
10735 }
10736 *dst = '\0';
10737
10738 char *p = list;
10739 while (*p != '\0')
10740 {
10741 char *start = p;
10742 int len = 0;
10743
10744 while (*p != ',' && *p != '\0')
10745 {
10746 len++;
10747 p++;
10748 }
10749
10750 key = malloc (len + 1);
10751 snprintf (key, len + 1, "%s", start);
10752
10753 if (strcmp(key, "recnum") == 0 || strcmp(key, "sunum") == 0 || strcmp(key, "slotnum") == 0 || strcmp(key, "sessionid") == 0 || strcmp(key, "sessionns") == 0)
10754 {
10755 size += sizeof(long long);
10756 }
10757 else
10758 {
10759 DRMS_Keyword_t *keyword = drms_keyword_lookup(template, key, 0);
10760
10761 if (keyword)
10762 {
10763 switch(keyword->info->type)
10764 {
10765 case DRMS_TYPE_CHAR:
10766 size += sizeof(char);
10767 break;
10768 case DRMS_TYPE_SHORT:
10769 size += sizeof(short);
10770 break;
10771 case DRMS_TYPE_INT:
10772 size += sizeof(int);
10773 break;
10774 case DRMS_TYPE_LONGLONG:
10775 size += sizeof(long long);
10776 break;
10777 case DRMS_TYPE_FLOAT:
10778 size += sizeof(float);
10779 break;
10780 case DRMS_TYPE_DOUBLE:
10781 size += sizeof(double);
10782 break;
10783 case DRMS_TYPE_TIME:
10784 size += sizeof(double);
10785 break;
10786 case DRMS_TYPE_STRING:
10787 if (keyword->value.string_val)
10788 {
10789 size += strlen(keyword->value.string_val);
10790 }
10791 break;
10792 default:
10793 fprintf(stderr, "ERROR: Unhandled DRMS type %d\n",(int)keyword->info->type);
10794 XASSERT(0);
10795 goto bailout;
10796 }
10797 }
10798 else
10799 {
10800 fprintf(stderr, "Unknown keyword: %s\n", key);
10801 size = 0;
10802 goto bailout;
10803 }
10804 }
10805
10806
10807 if (*p != '\0')
10808 {
10809 p++;
10810 }
10811
10812 if (key)
10813 {
10814 free(key);
10815 key = NULL;
10816 }
10817 }
10818
10819 bailout:
10820 if (key)
10821 {
10822 free(key);
10823 key = NULL;
10824 }
10825
10826 free(list);
10827
10828 return size;
10829 }
10830
10831
10832 size_t partialRecordMemsize(DRMS_Record_t *rec, HContainer_t *links, HContainer_t *keys, HContainer_t *segs)
10833 {
10834
10835 size_t allocSize;
10836 size_t hConElementSize;
10837 HIterator_t hit;
10838 DRMS_Link_t **plink = NULL;
10839 DRMS_Link_t *link = NULL;
10840 DRMS_Keyword_t **pkeyword = NULL;
10841 DRMS_Keyword_t *keyword = NULL;
10842 DRMS_Segment_t **psegment = NULL;
10843 DRMS_Segment_t *segment = NULL;
10844
10845 allocSize = 0;
10846
10847
10848
10849 hConElementSize = sizeof(HContainerElement_t) + sizeof(Entry_t);
10850
10851
10852
10853
10854
10855
10856
10857 allocSize += DRMS_MAXHASHKEYLEN + sizeof(DRMS_Record_t) + hConElementSize + 3 * sizeof(Table_t);
10858
10859
10860
10861 allocSize += sizeof(DRMS_Record_t) + 3 * sizeof(Table_t);
10862
10863
10864 if (links)
10865 {
10866 hiter_new_sort(&hit, links, linkListSort);
10867 while((plink = (DRMS_Link_t **)hiter_getnext(&hit)) != NULL)
10868 {
10869 link = *plink;
10870
10871
10872
10873
10874
10875
10876 allocSize += 2 * (sizeof(DRMS_Link_t) + DRMS_MAXLINKNAMELEN + hConElementSize);
10877 }
10878 hiter_free(&hit);
10879 }
10880 else
10881 {
10882
10883 hiter_new_sort(&hit, &(rec->links), drms_link_ranksort);
10884 while((link = (DRMS_Link_t *)hiter_getnext(&hit)) != NULL)
10885 {
10886
10887
10888
10889
10890
10891
10892 allocSize += 2 * (sizeof(DRMS_Link_t) + DRMS_MAXLINKNAMELEN + hConElementSize);
10893 }
10894 hiter_free(&hit);
10895 }
10896
10897
10898 if (keys)
10899 {
10900 hiter_new_sort(&hit, keys, keyListSort);
10901 while((pkeyword = (DRMS_Keyword_t **)hiter_getnext(&hit)) != NULL)
10902 {
10903 keyword = *pkeyword;
10904
10905
10906
10907 allocSize += 2 * (sizeof(DRMS_Keyword_t) + DRMS_MAXKEYNAMELEN + hConElementSize);
10908
10909 if (!keyword->info->islink && !drms_keyword_isconstant(keyword))
10910 {
10911 if (keyword->info->type == DRMS_TYPE_STRING)
10912 {
10913 if (keyword->value.string_val)
10914 {
10915 allocSize += strlen(keyword->value.string_val);
10916 }
10917 else
10918 {
10919 allocSize += 40;
10920 }
10921 }
10922 }
10923 }
10924 hiter_free(&hit);
10925 }
10926 else
10927 {
10928
10929 hiter_new_sort(&hit, &(rec->keywords), drms_keyword_ranksort);
10930 while((keyword = (DRMS_Keyword_t *)hiter_getnext(&hit)) != NULL)
10931 {
10932
10933
10934 allocSize += 2 * (sizeof(DRMS_Keyword_t) + DRMS_MAXKEYNAMELEN + hConElementSize);
10935
10936 if (!keyword->info->islink && !drms_keyword_isconstant(keyword))
10937 {
10938 if (keyword->info->type == DRMS_TYPE_STRING)
10939 {
10940 if (keyword->value.string_val)
10941 {
10942 allocSize += strlen(keyword->value.string_val);
10943 }
10944 else
10945 {
10946 allocSize += 40;
10947 }
10948 }
10949 }
10950 }
10951 hiter_free(&hit);
10952 }
10953
10954
10955 if (segs)
10956 {
10957 hiter_new_sort(&hit, segs, segListSort);
10958 while((psegment = (DRMS_Segment_t **)hiter_getnext(&hit)) != NULL)
10959 {
10960 segment = *psegment;
10961
10962
10963
10964 allocSize += 2 * (sizeof(DRMS_Segment_t) + DRMS_MAXSEGNAMELEN + hConElementSize);
10965 }
10966 hiter_free(&hit);
10967 }
10968 else
10969 {
10970 hiter_new_sort(&hit, &(rec->segments), drms_segment_ranksort);
10971 while((segment = (DRMS_Segment_t *)hiter_getnext(&hit)) != NULL)
10972 {
10973
10974
10975 allocSize += 2 * (sizeof(DRMS_Segment_t) + DRMS_MAXSEGNAMELEN + hConElementSize);
10976 }
10977 hiter_free(&hit);
10978 }
10979
10980 return allocSize;
10981 }
10982
10983
10984 int CopySeriesInfo(DRMS_Record_t *target, DRMS_Record_t *source)
10985 {
10986 memcpy(target->seriesinfo, source->seriesinfo, sizeof(DRMS_SeriesInfo_t));
10987 memset(target->seriesinfo->pidx_keywords, 0, sizeof(DRMS_Keyword_t *) * DRMS_MAXPRIMIDX);
10988 memset(target->seriesinfo->dbidx_keywords, 0, sizeof(DRMS_Keyword_t *) * DRMS_MAXDBIDX);
10989
10990 return DRMS_SUCCESS;
10991 }
10992
10993 int CopySegments(DRMS_Record_t *target, DRMS_Record_t *source)
10994 {
10995 int status = DRMS_SUCCESS;
10996 drms_create_segment_prototypes(target, source, &status);
10997
10998 return status;
10999 }
11000
11001 int CopyLinks(DRMS_Record_t *target, DRMS_Record_t *source)
11002 {
11003 int status = DRMS_SUCCESS;
11004 drms_create_link_prototypes(target, source, &status);
11005
11006 return status;
11007 }
11008
11009 int CopyKeywords(DRMS_Record_t *target, DRMS_Record_t *source)
11010 {
11011 int status = DRMS_SUCCESS;
11012 drms_create_keyword_prototypes(target, source, &status);
11013
11014 return status;
11015 }
11016
11017
11018
11019 int CopyPrimaryIndex(DRMS_Record_t *target, DRMS_Record_t *source)
11020 {
11021 int status = DRMS_SUCCESS;
11022
11023 if (target != NULL && target->seriesinfo != NULL)
11024 {
11025 target->seriesinfo->pidx_num = source->seriesinfo->pidx_num;
11026
11027 int idx = 0;
11028 for (; status == DRMS_SUCCESS && idx < source->seriesinfo->pidx_num; idx++)
11029 {
11030 char *name = source->seriesinfo->pidx_keywords[idx]->info->name;
11031 DRMS_Keyword_t *key = hcon_lookup_lower(&target->keywords, name);
11032 if (key != NULL)
11033 {
11034 target->seriesinfo->pidx_keywords[idx] = key;
11035 }
11036 else
11037 {
11038 status = DRMS_ERROR_INVALIDKEYWORD;
11039 }
11040 }
11041 }
11042 else
11043 {
11044 status = DRMS_ERROR_INVALIDRECORD;
11045 }
11046
11047 return status;
11048 }
11049
11050 static int DSElem_IsWS(const char **c)
11051 {
11052 const char *pC = *c;
11053 const char *pWS = kDSElemParseWS;
11054
11055 while (*pWS)
11056 {
11057 if (*pC == *pWS)
11058 {
11059 break;
11060 }
11061
11062 pWS++;
11063 }
11064
11065 if (*pWS)
11066 {
11067 return 1;
11068 }
11069
11070 return 0;
11071 }
11072
11073 static int DSElem_IsDelim(const char **c)
11074 {
11075 const char *pDel = kDSElemParseDelim;
11076
11077 while (*pDel)
11078 {
11079 if (**c == *pDel)
11080 {
11081 break;
11082 }
11083
11084 pDel++;
11085 }
11086
11087 if (*pDel)
11088 {
11089 return 1;
11090 }
11091
11092 return 0;
11093 }
11094
11095 static int DSElem_IsComment(const char **c)
11096 {
11097 return (**c == '#');
11098 }
11099
11100
11101
11102 static int DSElem_SkipWS(char **c)
11103 {
11104 if (**c == '\0')
11105 {
11106 return 0;
11107 }
11108 else if (!DSElem_IsWS((const char **)c))
11109 {
11110 return 1;
11111 }
11112 else
11113 {
11114 char *pC = *c;
11115
11116 while (*pC)
11117 {
11118 const char *pWS = kDSElemParseWS;
11119
11120 while (*pWS)
11121 {
11122 if (*pC == *pWS)
11123 {
11124 pC++;
11125 break;
11126 }
11127
11128 pWS++;
11129 }
11130
11131 if (*pWS)
11132 {
11133 *c = pC;
11134 return 1;
11135 }
11136 }
11137
11138 return 0;
11139 }
11140 }
11141
11142 static int DSElem_SkipComment(char **c)
11143 {
11144 char *endc = NULL;
11145
11146 if (**c == '#')
11147 {
11148 endc = strchr((*c + 1), '#');
11149
11150 if (endc)
11151 {
11152 *c = endc + 1;
11153 }
11154 else
11155 {
11156 *c = strchr(*c, '\0');
11157 }
11158
11159 return 1;
11160 }
11161 else
11162 {
11163 return 0;
11164 }
11165 }
11166
11167
11168
11169
11170
11171
11172
11173
11174
11175
11176 int ParseRecSetDescInternal(const char *recsetsStr, char **allvers, char ***sets, DRMS_RecordSetType_t **settypes, char ***snames, char ***filts, char ***segs, int *nsets, DRMS_RecQueryInfo_t *info)
11177 {
11178 int status = DRMS_SUCCESS;
11179 RSParseState_t state = kRSParseState_Begin;
11180 RSParseState_t oldstate;
11181 char *rsstr = strdup(recsetsStr);
11182 char *pc = rsstr;
11183 LinkedList_t *intSets = NULL;
11184 LinkedList_t *intSettypes = NULL;
11185 LinkedList_t *intAllVers = NULL;
11186 LinkedList_t *intSnames = NULL;
11187 LinkedList_t *intFilts = NULL;
11188 LinkedList_t *intSegs = NULL;
11189 char *pset = NULL;
11190 char *sname = NULL;
11191 char *pfiltstr = NULL;
11192 char *filtstr = NULL;
11193 char *psegliststr = NULL;
11194 char *segliststr = NULL;
11195 int currfiltsz;
11196 size_t filtstrsz = 64;
11197 size_t seglistsz;
11198 int count = 0;
11199 char buf[kMAXRSETSPEC] = {0};
11200 char *pcBuf = buf;
11201 LinkedList_t *multiRSQueries = NULL;
11202 LinkedList_t *multiRSTypes = NULL;
11203 LinkedList_t *multiRSAllVers = NULL;
11204 LinkedList_t *multiRSSnames = NULL;
11205 LinkedList_t *multiRSFilts = NULL;
11206 LinkedList_t *multiRSSegs = NULL;
11207 DRMS_RecordSetType_t currSettype;
11208 char currAllVers = 'n';
11209 int countMultiRS = 0;
11210 char *endInput = rsstr + strlen(rsstr);
11211 int nfilter = 0;
11212 int recnumrsseen = 0;
11213 DRMS_RecQueryInfo_t intinfo = 0;
11214
11215
11216 int empty = 0;
11217 char *ptest = NULL;
11218
11219 ptest = rsstr;
11220 empty = (DSElem_SkipWS(&ptest) == 0);
11221
11222 *nsets = 0;
11223
11224 if (rsstr && !empty)
11225 {
11226 while (pc && pc <= endInput && state != kRSParseState_Error)
11227 {
11228 switch (state)
11229 {
11230 case kRSParseState_Begin:
11231 intSets = list_llcreate(sizeof(char *), NULL);
11232 intSettypes = list_llcreate(sizeof(DRMS_RecordSetType_t), NULL);
11233 intAllVers = list_llcreate(sizeof(char), NULL);
11234 intSnames = list_llcreate(sizeof(char *), NULL);
11235 intFilts = list_llcreate(sizeof(char *), NULL);
11236 intSegs = list_llcreate(sizeof(char *), NULL);
11237 if (!intSets || !intSettypes || !intAllVers || !intSnames || !intFilts || !intSegs)
11238 {
11239 state = kRSParseState_Error;
11240 status = DRMS_ERROR_OUTOFMEMORY;
11241 }
11242 else
11243 {
11244 state = kRSParseState_BeginElem;
11245 }
11246 break;
11247 case kRSParseState_BeginElem:
11248
11249 if (pc < endInput)
11250 {
11251 if (DSElem_IsWS((const char **)&pc))
11252 {
11253
11254 pc++;
11255 }
11256 else if (*pc == '[' || *pc == ']' || *pc == ',' ||
11257 *pc == ';' || *pc == '#')
11258 {
11259 state = kRSParseState_Error;
11260 }
11261 else
11262 {
11263 if (*pc == '{')
11264 {
11265 pc++;
11266 if (DSElem_SkipWS(&pc))
11267 {
11268 if (DSDS_IsDSDSSpec(pc))
11269 {
11270 state = kRSParseState_DSDS;
11271 }
11272 else if (strstr(pc, "vot:") == pc)
11273 {
11274 state = kRSParseState_VOT;
11275 }
11276 else if (DSDS_IsDSDSPort(pc))
11277 {
11278 state = kRSParseState_DSDSPort;
11279 }
11280 else
11281 {
11282 fprintf(stderr,
11283 "Unexpected record-set specification within curly brackets.\n" );
11284 state = kRSParseState_Error;
11285 }
11286 }
11287 else
11288 {
11289 state = kRSParseState_Error;
11290 }
11291 }
11292 else if (*pc == '@')
11293 {
11294
11295
11296 state = kRSParseState_AtFile;
11297
11298
11299 intinfo |= kAtFile;
11300 pc++;
11301 }
11302 else if (*pc == '/' || *pc == '.')
11303 {
11304 state = kRSParseState_Plainfile;
11305 }
11306 else
11307 {
11308 state = kRSParseState_DRMS;
11309 }
11310 }
11311
11312 currfiltsz = 0;
11313 }
11314 break;
11315 case kRSParseState_DRMS:
11316
11317
11318 recnumrsseen = 0;
11319 if (pc < endInput)
11320 {
11321 if (*pc == ']')
11322 {
11323
11324 state = kRSParseState_Error;
11325 }
11326 else if (*pc == '[')
11327 {
11328 *pcBuf++ = *pc++;
11329
11330 if (pc < endInput && (*pc == '?' || *pc == '!'))
11331 {
11332 if (*pc == '!')
11333 {
11334 state = kRSParseState_DRMSFiltAllVersSQL;
11335 }
11336 else
11337 {
11338 state = kRSParseState_DRMSFiltSQL;
11339 }
11340
11341 *pcBuf++ = *pc++;
11342 }
11343 else
11344 {
11345 state = kRSParseState_DRMSFilt;
11346 }
11347
11348
11349 intinfo |= kFilters;
11350 }
11351 else if (*pc == '{')
11352 {
11353 *pcBuf++ = *pc++;
11354 state = kRSParseState_DRMSSeglist;
11355 }
11356 else if (DSElem_IsDelim((const char **)&pc))
11357 {
11358
11359 if (sname == NULL)
11360 {
11361 size_t len = strlen(buf);
11362 sname = strdup(buf);
11363 *(sname + len - 1) = '\0';
11364 }
11365
11366 pc++;
11367 state = kRSParseState_EndElem;
11368 }
11369 else if (DSElem_IsComment((const char **)&pc))
11370 {
11371
11372 if (sname == NULL)
11373 {
11374 size_t len = strlen(buf);
11375 sname = strdup(buf);
11376 *(sname + len - 1) = '\0';
11377 }
11378
11379 DSElem_SkipComment(&pc);
11380 state = kRSParseState_EndElem;
11381 }
11382 else if (DSElem_IsWS((const char **)&pc))
11383 {
11384
11385 if (DSElem_SkipWS(&pc))
11386 {
11387 if (*pc == '[')
11388 {
11389 *pcBuf++ = *pc++;
11390
11391 if (pc < endInput && (*pc == '?' || *pc == '!'))
11392 {
11393 if (*pc == '!')
11394 {
11395 state = kRSParseState_DRMSFiltAllVersSQL;
11396 }
11397 else
11398 {
11399 state = kRSParseState_DRMSFiltSQL;
11400 }
11401
11402 *pcBuf++ = *pc++;
11403 }
11404 else
11405 {
11406 state = kRSParseState_DRMSFilt;
11407 }
11408 }
11409 else if (*pc == '{')
11410 {
11411 *pcBuf++ = *pc++;
11412 state = kRSParseState_DRMSSeglist;
11413 }
11414 else if (DSElem_IsDelim((const char **)&pc))
11415 {
11416
11417 if (sname == NULL)
11418 {
11419 size_t len = strlen(buf);
11420 char *pchar = buf;
11421
11422 sname = strdup(buf);
11423 *(sname + len - 1) = '\0';
11424
11425
11426 while (*pchar)
11427 {
11428 if (DSElem_IsWS((const char **)&pchar))
11429 {
11430
11431 *pchar = '\0';
11432 break;
11433 }
11434 }
11435 }
11436
11437 pc++;
11438 state = kRSParseState_EndElem;
11439 }
11440 else if (DSElem_IsComment((const char **)&pc))
11441 {
11442
11443 if (sname == NULL)
11444 {
11445 size_t len = strlen(buf);
11446 char *pchar = buf;
11447
11448 sname = strdup(buf);
11449 *(sname + len - 1) = '\0';
11450
11451
11452 while (*pchar)
11453 {
11454 if (DSElem_IsWS((const char **)&pchar))
11455 {
11456
11457 *pchar = '\0';
11458 break;
11459 }
11460 }
11461 }
11462
11463 DSElem_SkipComment(&pc);
11464 state = kRSParseState_EndElem;
11465 }
11466 else
11467 {
11468 state = kRSParseState_Error;
11469 }
11470 }
11471 else
11472 {
11473
11474 if (sname == NULL)
11475 {
11476 char *pchar = buf;
11477
11478 sname = strdup(buf);
11479
11480
11481 while (*pchar)
11482 {
11483 if (DSElem_IsWS((const char **)&pchar))
11484 {
11485
11486 *pchar = '\0';
11487 break;
11488 }
11489 }
11490 }
11491
11492 state = kRSParseState_EndElem;
11493 }
11494 }
11495 else
11496 {
11497 *pcBuf++ = *pc++;
11498 }
11499 }
11500 else
11501 {
11502 if (sname == NULL)
11503 {
11504 sname = strdup(buf);
11505 }
11506
11507 state = kRSParseState_EndElem;
11508 }
11509
11510 if (state == kRSParseState_EndElem)
11511 {
11512 currSettype = kRecordSetType_DRMS;
11513 }
11514 break;
11515 case kRSParseState_DRMSFilt:
11516
11517 if (pc < endInput)
11518 {
11519 if (sname == NULL)
11520 {
11521
11522
11523 size_t len = strlen(buf);
11524 sname = strdup(buf);
11525 *(sname + len - 1) = '\0';
11526 }
11527
11528 if (pfiltstr == NULL)
11529 {
11530
11531 pfiltstr = pcBuf - 1;
11532 }
11533
11534
11535
11536
11537 if (*pc == ':' && recnumrsseen)
11538 {
11539 state = kRSParseState_Error;
11540 fprintf(stderr, "Only one recnum list filter is allowed.\n");
11541 break;
11542 }
11543 else if (*pc == ':')
11544 {
11545 recnumrsseen = 1;
11546 }
11547
11548
11549
11550 if (*pc == '?')
11551 {
11552 *pcBuf++ = *pc++;
11553 state = kRSParseState_DRMSFiltSQL;
11554 }
11555 else if (*pc == '!')
11556 {
11557 *pcBuf++ = *pc++;
11558 state = kRSParseState_DRMSFiltAllVersSQL;
11559 }
11560 else
11561 {
11562
11563 while (*pc != ']' && state != kRSParseState_Error)
11564 {
11565 DRMS_Type_Value_t val;
11566 memset(&val, 0, sizeof(DRMS_Type_Value_t));
11567 int rlen = drms_sscanf_str(pc, "]", &val);
11568 int ilen = 0;
11569
11570 if (rlen == -1)
11571 {
11572 state = kRSParseState_Error;
11573 fprintf(stderr, "Invalid string in DRMS filter.\n");
11574 }
11575 else
11576 {
11577
11578 DRMS_Value_t dummy = {DRMS_TYPE_STRING, val};
11579 drms_value_free(&dummy);
11580
11581
11582
11583 while (ilen < rlen)
11584 {
11585 *pcBuf++ = *pc++;
11586
11587 if (pc == endInput)
11588 {
11589 state = kRSParseState_Error;
11590 }
11591
11592 ilen++;
11593 }
11594 }
11595 }
11596
11597
11598
11599
11600 if (*pc == ']' && state != kRSParseState_Error)
11601 {
11602 *pcBuf++ = *pc++;
11603
11604
11605 char *tmpbuf = malloc(pcBuf - pfiltstr - currfiltsz + 1);
11606
11607 if (!tmpbuf)
11608 {
11609 status = DRMS_ERROR_OUTOFMEMORY;
11610 state = kRSParseState_Error;
11611 }
11612 else
11613 {
11614
11615
11616
11617
11618 strncpy(tmpbuf, pfiltstr + currfiltsz, pcBuf - pfiltstr - currfiltsz);
11619 tmpbuf[pcBuf - pfiltstr - currfiltsz] = '\0';
11620 currfiltsz = pcBuf - pfiltstr;
11621
11622 if (!filtstr)
11623 {
11624 filtstr = calloc(filtstrsz, 1);
11625 }
11626
11627 if (filtstr)
11628 {
11629
11630 filtstr = base_strcatalloc(filtstr, tmpbuf, &filtstrsz);
11631 }
11632
11633 if (tmpbuf)
11634 {
11635 free(tmpbuf);
11636 }
11637
11638 if (!filtstr)
11639 {
11640 status = DRMS_ERROR_OUTOFMEMORY;
11641 state = kRSParseState_Error;
11642 }
11643 else
11644 {
11645 if (DSElem_SkipWS(&pc))
11646 {
11647 if (*pc == '[')
11648 {
11649 *pcBuf++ = *pc++;
11650
11651 if (pc < endInput && (*pc == '?' || *pc == '!'))
11652 {
11653 if (*pc == '!')
11654 {
11655 state = kRSParseState_DRMSFiltAllVersSQL;
11656 }
11657 else
11658 {
11659 state = kRSParseState_DRMSFiltSQL;
11660 }
11661
11662 *pcBuf++ = *pc++;
11663 }
11664 else
11665 {
11666 state = kRSParseState_DRMSFilt;
11667 }
11668 }
11669 else if (*pc == '{')
11670 {
11671 *pcBuf++ = *pc++;
11672 state = kRSParseState_DRMSSeglist;
11673 }
11674 else if (DSElem_IsDelim((const char **)&pc))
11675 {
11676 pc++;
11677 state = kRSParseState_EndElem;
11678 }
11679 else if (DSElem_IsComment((const char **)&pc))
11680 {
11681 DSElem_SkipComment(&pc);
11682 state = kRSParseState_EndElem;
11683 }
11684 else
11685 {
11686 state = kRSParseState_Error;
11687 }
11688 }
11689 else
11690 {
11691 state= kRSParseState_EndElem;
11692 }
11693 }
11694 }
11695 }
11696 else
11697 {
11698 state = kRSParseState_Error;
11699 }
11700 }
11701 }
11702 else
11703 {
11704
11705 state = kRSParseState_Error;
11706 }
11707
11708 if (state == kRSParseState_EndElem)
11709 {
11710 currSettype = kRecordSetType_DRMS;
11711 }
11712
11713 nfilter++;
11714
11715 break;
11716 case kRSParseState_DRMSFiltAllVersSQL:
11717 currAllVers = 'y';
11718
11719 case kRSParseState_DRMSFiltSQL:
11720 if (pc < endInput)
11721 {
11722 if (sname == NULL)
11723 {
11724
11725
11726 size_t len = strlen(buf);
11727
11728 sname = strdup(buf);
11729 *(sname + len - 2) = '\0';
11730 }
11731
11732 if (pfiltstr == NULL)
11733 {
11734
11735
11736 pfiltstr = pcBuf - 2;
11737 }
11738
11739 if (*pc == '"' || *pc == '\'')
11740 {
11741
11742 DRMS_Type_Value_t val;
11743 memset(&val, 0, sizeof(DRMS_Type_Value_t));
11744 int rlen = drms_sscanf_str(pc, NULL, &val);
11745 int ilen = 0;
11746
11747
11748 DRMS_Value_t dummy = {DRMS_TYPE_STRING, val};
11749 drms_value_free(&dummy);
11750
11751 if (rlen == -1)
11752 {
11753
11754 fprintf(stderr, "Invalid quoted string '%s'.\n", pc);
11755 state = kRSParseState_Error;
11756 }
11757 else
11758 {
11759
11760
11761 while (ilen < rlen)
11762 {
11763 *pcBuf++ = *pc++;
11764 ilen++;
11765 }
11766 }
11767 }
11768
11769 else if (*pc == '$' && *(pc+1) == '(')
11770 {
11771
11772
11773
11774
11775
11776
11777 char *rparen = strchr(pc+2, ')');
11778 char temptime[100];
11779 if (!rparen || rparen - pc > 40)
11780 {
11781 fprintf(stderr,"Time conversion error starting at %s\n",pc+2);
11782 state = kRSParseState_Error;
11783 }
11784 else
11785 {
11786
11787 TIME t;
11788 #ifdef DEBUG
11789 int consumed;
11790 #endif
11791
11792 strncpy(temptime,pc+2,rparen-pc-2);
11793
11794 #ifdef DEBUG
11795 consumed =
11796 #endif
11797 sscan_time_ext(temptime, &t);
11798
11799
11800 if (time_is_invalid(t))
11801 fprintf(stderr,"Warning: invalid time from %s\n",temptime);
11802 #ifdef DEBUG
11803 fprintf(stderr,"XXXXXXX original in drms_record, convert time %s uses %d chars, gives %f\n",temptime, consumed,t);
11804 #endif
11805 pc = rparen + 1;
11806 pcBuf += sprintf(pcBuf, "%16.6f", t);
11807 }
11808 }
11809 else if ((*pc == '?' && state == kRSParseState_DRMSFiltSQL) ||
11810 (*pc == '!' && state == kRSParseState_DRMSFiltAllVersSQL))
11811 {
11812 *pcBuf++ = *pc++;
11813 if ((pc < endInput) && (*pc == ']'))
11814 {
11815 state = kRSParseState_DRMSFilt;
11816 }
11817 }
11818 else
11819 {
11820
11821
11822 *pcBuf++ = *pc++;
11823 }
11824 }
11825 else
11826 {
11827
11828 state = kRSParseState_Error;
11829 }
11830
11831
11832 break;
11833 case kRSParseState_DRMSSeglist:
11834
11835 if (pc < endInput)
11836 {
11837 if (sname == NULL)
11838 {
11839
11840
11841
11842
11843 size_t len = strlen(buf);
11844
11845 sname = strdup(buf);
11846 *(sname + len - 1) = '\0';
11847 }
11848
11849 if (psegliststr == NULL)
11850 {
11851
11852 psegliststr = pcBuf - 1;
11853 }
11854
11855 DSElem_SkipWS(&pc);
11856
11857 while (*pc != '}' && pc < endInput)
11858 {
11859 if (DSElem_IsWS((const char **)&pc))
11860 {
11861 DSElem_SkipWS(&pc);
11862 }
11863 else if (*pc == ',' || *pc == ':' || *pc == ';')
11864 {
11865 DSElem_SkipWS(&pc);
11866 if (*pc == '}')
11867 {
11868 state = kRSParseState_Error;
11869 break;
11870 }
11871
11872 *pcBuf++ = *pc++;
11873 }
11874 else
11875 {
11876 *pcBuf++ = *pc++;
11877 }
11878 }
11879
11880 if (state != kRSParseState_Error && *pc != '}')
11881 {
11882 state = kRSParseState_Error;
11883 }
11884 }
11885 else
11886 {
11887
11888 state = kRSParseState_Error;
11889 }
11890
11891 if (state != kRSParseState_Error)
11892 {
11893
11894 *pcBuf++ = *pc++;
11895
11896
11897 seglistsz = pcBuf - psegliststr + 1;
11898 segliststr = calloc(seglistsz, sizeof(char) + 1);
11899
11900 if (!segliststr)
11901 {
11902 status = DRMS_ERROR_OUTOFMEMORY;
11903 state = kRSParseState_Error;
11904 }
11905 else
11906 {
11907 strncpy(segliststr, psegliststr, seglistsz);
11908 }
11909 }
11910
11911 if (state != kRSParseState_Error)
11912 {
11913 if (DSElem_SkipWS(&pc))
11914 {
11915 if (DSElem_IsDelim((const char **)&pc))
11916 {
11917 pc++;
11918 state = kRSParseState_EndElem;
11919 }
11920 else if (DSElem_IsComment((const char **)&pc))
11921 {
11922 DSElem_SkipComment(&pc);
11923 state = kRSParseState_EndElem;
11924 }
11925 else
11926 {
11927 state = kRSParseState_Error;
11928 }
11929 }
11930 else
11931 {
11932 state = kRSParseState_EndElem;
11933 }
11934 }
11935
11936 if (state == kRSParseState_EndElem)
11937 {
11938 currSettype = kRecordSetType_DRMS;
11939 }
11940 break;
11941 case kRSParseState_DSDS:
11942 case kRSParseState_DSDSPort:
11943
11944 oldstate = state;
11945
11946 if (pc < endInput)
11947 {
11948 if (*pc == '{')
11949 {
11950 state = kRSParseState_Error;
11951 }
11952 else if (DSElem_IsWS((const char **)&pc))
11953 {
11954
11955 pc++;
11956 }
11957 else if (*pc == '}')
11958 {
11959 pc++;
11960
11961 if (pc < endInput)
11962 {
11963 if (DSElem_IsWS((const char **)&pc))
11964 {
11965 if (!DSElem_SkipWS(&pc))
11966 {
11967 state = kRSParseState_EndElem;
11968 }
11969 }
11970
11971 if (state != kRSParseState_EndElem)
11972 {
11973 if (DSElem_IsDelim((const char **)&pc))
11974 {
11975 pc++;
11976 state = kRSParseState_EndElem;
11977 }
11978 else if (DSElem_IsComment((const char **)&pc))
11979 {
11980 DSElem_SkipComment(&pc);
11981 state = kRSParseState_EndElem;
11982 }
11983 else
11984 {
11985
11986
11987 state = kRSParseState_Error;
11988 }
11989 }
11990 }
11991 else
11992 {
11993 state = kRSParseState_EndElem;
11994 }
11995 }
11996 else
11997 {
11998 *pcBuf++ = *pc++;
11999 }
12000 }
12001 else
12002 {
12003 state = kRSParseState_Error;
12004 }
12005
12006 if (state == kRSParseState_EndElem)
12007 {
12008 if (oldstate == kRSParseState_DSDS)
12009 {
12010 currSettype = kRecordSetType_DSDS;
12011 }
12012 else if (oldstate == kRSParseState_DSDSPort)
12013 {
12014 currSettype = kRecordSetType_DSDSPort;
12015 }
12016 else
12017 {
12018 state = kRSParseState_Error;
12019 }
12020 }
12021 break;
12022 case kRSParseState_VOT:
12023
12024 if (pc < endInput)
12025 {
12026 if (*pc == '{')
12027 {
12028 state = kRSParseState_Error;
12029 }
12030 else if (DSElem_IsWS((const char **)&pc))
12031 {
12032
12033 pc++;
12034 }
12035 else if (*pc == '}')
12036 {
12037 pc++;
12038
12039 if (pc < endInput)
12040 {
12041 if (DSElem_IsWS((const char **)&pc))
12042 {
12043 if (!DSElem_SkipWS(&pc))
12044 {
12045 state = kRSParseState_EndElem;
12046 }
12047 }
12048
12049 if (DSElem_IsDelim((const char **)&pc))
12050 {
12051 pc++;
12052 state = kRSParseState_EndElem;
12053 }
12054 else if (DSElem_IsComment((const char **)&pc))
12055 {
12056 DSElem_SkipComment(&pc);
12057 state = kRSParseState_EndElem;
12058 }
12059 else
12060 {
12061
12062
12063 state = kRSParseState_Error;
12064 }
12065 }
12066 else
12067 {
12068 state = kRSParseState_EndElem;
12069 }
12070 }
12071 else
12072 {
12073 *pcBuf++ = *pc++;
12074 }
12075 }
12076 else
12077 {
12078 state = kRSParseState_Error;
12079 }
12080
12081 if (state == kRSParseState_EndElem)
12082 {
12083 currSettype = kRecordSetType_VOT;
12084 }
12085 break;
12086 case kRSParseState_AtFile:
12087 if (pc < endInput)
12088 {
12089 if (DSElem_IsDelim((const char **)&pc))
12090 {
12091 pc++;
12092 state = kRSParseState_EndAtFile;
12093 }
12094 else if (DSElem_IsComment((const char **)&pc))
12095 {
12096 DSElem_SkipComment(&pc);
12097 state = kRSParseState_EndAtFile;
12098 }
12099 else if (DSElem_IsWS((const char **)&pc))
12100 {
12101
12102
12103
12104 if (DSElem_SkipWS(&pc))
12105 {
12106
12107 if (DSElem_IsDelim((const char **)&pc))
12108 {
12109 pc++;
12110 state = kRSParseState_EndAtFile;
12111 }
12112 else if (DSElem_IsComment((const char **)&pc))
12113 {
12114 DSElem_SkipComment(&pc);
12115 state = kRSParseState_EndAtFile;
12116 }
12117 else
12118 {
12119 fprintf(stderr,
12120 "'@' files containing whitespace are not allowed.\n");
12121 state = kRSParseState_Error;
12122 }
12123 }
12124 else
12125 {
12126
12127 state = kRSParseState_EndAtFile;
12128 }
12129 }
12130 else
12131 {
12132 *pcBuf++ = *pc++;
12133 }
12134 }
12135 else
12136 {
12137 state = kRSParseState_EndAtFile;
12138 }
12139 break;
12140 case kRSParseState_EndAtFile:
12141 {
12142 char lineBuf[LINE_MAX];
12143 char *fullline = NULL;
12144 char **queriesAtFile = NULL;
12145 DRMS_RecordSetType_t *typesAtFile = NULL;
12146 char **snamesAtFile = NULL;
12147 char **filtsAtFile = NULL;
12148 char **segsAtFile = NULL;
12149 char *allversAtFile = NULL;
12150 int nsetsAtFile = 0;
12151 int iSet = 0;
12152 struct stat stBuf;
12153 FILE *atfile = NULL;
12154 regex_t regexp;
12155 regmatch_t matches[3];
12156 struct passwd *pwordrec = NULL;
12157 char atfname[PATH_MAX];
12158
12159
12160
12161 if (multiRSQueries)
12162 {
12163 state = kRSParseState_Error;
12164 break;
12165 }
12166 else
12167 {
12168 multiRSQueries = list_llcreate(sizeof(char *), NULL);
12169 multiRSTypes = list_llcreate(sizeof(DRMS_RecordSetType_t), NULL);
12170 multiRSAllVers = list_llcreate(sizeof(char), NULL);
12171 multiRSSnames = list_llcreate(sizeof(char *), NULL);
12172 multiRSFilts = list_llcreate(sizeof(char *), NULL);
12173 multiRSSegs = list_llcreate(sizeof(char *), NULL);
12174
12175
12176 *pcBuf = '\0';
12177
12178
12179
12180
12181 if (regcomp(®exp, "[:space:]*~([^/]+)/(.+)", REG_EXTENDED) != 0)
12182 {
12183 fprintf(stderr, "Invalid regular-expression pattern.\n");
12184 state = kRSParseState_Error;
12185 break;
12186 }
12187 else
12188 {
12189 char *tmpfname = strdup(buf);
12190 char *username = NULL;
12191 char *suffix = NULL;
12192
12193 if (!tmpfname)
12194 {
12195 state = kRSParseState_Error;
12196 fprintf(stderr, "No memory.\n");
12197 break;
12198 }
12199
12200 if (regexec(®exp, buf, (size_t)3, matches, 0) != 0)
12201 {
12202
12203
12204 snprintf(atfname, sizeof(atfname), "%s", tmpfname);
12205 }
12206 else
12207 {
12208 tmpfname[matches[1].rm_eo] = '\0';
12209 username = strdup(tmpfname + matches[1].rm_so);
12210
12211 if (!username)
12212 {
12213 state = kRSParseState_Error;
12214 fprintf(stderr, "No memory.\n");
12215 break;
12216 }
12217
12218 tmpfname[matches[2].rm_eo] = '\0';
12219 suffix = strdup(tmpfname + matches[2].rm_so);
12220
12221 if (!suffix)
12222 {
12223 state = kRSParseState_Error;
12224 fprintf(stderr, "No memory.\n");
12225 break;
12226 }
12227
12228 pwordrec = getpwnam(username);
12229
12230 if (pwordrec)
12231 {
12232 snprintf(atfname, sizeof(atfname), "%s/%s", pwordrec->pw_dir, suffix);
12233 }
12234 }
12235
12236 free(suffix);
12237 free(username);
12238 free(tmpfname);
12239 regfree(®exp);
12240 }
12241
12242 if (buf && stat(atfname, &stBuf) == 0)
12243 {
12244 if (S_ISREG(stBuf.st_mode))
12245 {
12246
12247 if ((atfile = fopen(atfname, "r")) == NULL)
12248 {
12249 fprintf(stderr, "Cannot open @file %s for reading, skipping.\n", atfname);
12250 }
12251 else
12252 {
12253 int len = 0;
12254 while (!(fgets(lineBuf, LINE_MAX, atfile) == NULL))
12255 {
12256
12257 len = strlen(lineBuf);
12258
12259 fullline = strdup(lineBuf);
12260
12261 if (len == LINE_MAX - 1)
12262 {
12263
12264 while (!(fgets(lineBuf, LINE_MAX, atfile) == NULL))
12265 {
12266 fullline = realloc(fullline, strlen(fullline) + strlen(lineBuf) + 1);
12267 snprintf(fullline + strlen(fullline),
12268 strlen(lineBuf) + 1,
12269 "%s",
12270 lineBuf);
12271 if (strlen(lineBuf) > 1 && lineBuf[strlen(lineBuf) - 1] == '\n')
12272 {
12273 break;
12274 }
12275 }
12276 }
12277
12278 len = strlen(fullline);
12279
12280
12281 if (len > 1)
12282 {
12283 DRMS_RecQueryInfo_t infoAtFile;
12284
12285 if (fullline[len - 1] == '\n')
12286 {
12287 fullline[len - 1] = '\0';
12288 }
12289
12290 status = ParseRecSetDescInternal(fullline, &allversAtFile, &queriesAtFile, &typesAtFile, &snamesAtFile, &filtsAtFile, &segsAtFile, &nsetsAtFile, &infoAtFile);
12291
12292 if (status == DRMS_SUCCESS)
12293 {
12294
12295
12296
12297
12298 for (iSet = 0; iSet < nsetsAtFile; iSet++)
12299 {
12300
12301
12302 pset = strdup(queriesAtFile[iSet]);
12303 list_llinserttail(multiRSQueries, &pset);
12304 list_llinserttail(multiRSTypes, &(typesAtFile[iSet]));
12305 list_llinserttail(multiRSAllVers, &(allversAtFile[iSet]));
12306
12307
12308
12309
12310
12311
12312 if (snamesAtFile[iSet])
12313 {
12314 pset = strdup(snamesAtFile[iSet]);
12315 }
12316 else
12317 {
12318 pset = NULL;
12319 }
12320 list_llinserttail(multiRSSnames, &pset);
12321
12322
12323
12324 if (filtsAtFile[iSet])
12325 {
12326 pset = strdup(filtsAtFile[iSet]);
12327 }
12328 else
12329 {
12330 pset = NULL;
12331 }
12332 list_llinserttail(multiRSFilts, &pset);
12333
12334 if (segsAtFile[iSet])
12335 {
12336 pset = strdup(segsAtFile[iSet]);
12337 }
12338 else
12339 {
12340 pset = NULL;
12341 }
12342 list_llinserttail(multiRSSegs, &pset);
12343
12344 countMultiRS++;
12345 }
12346
12347 intinfo |= infoAtFile;
12348 }
12349 else
12350 {
12351 state = kRSParseState_Error;
12352 break;
12353 }
12354
12355 FreeRecSetDescArrInternal(&allversAtFile, &queriesAtFile, &typesAtFile, &snamesAtFile, &filtsAtFile, &segsAtFile, nsetsAtFile);
12356 }
12357
12358 if (fullline)
12359 {
12360 free(fullline);
12361 fullline = NULL;
12362 }
12363 }
12364 }
12365 }
12366 else
12367 {
12368 fprintf(stderr, "@file %s is not a regular file, skipping.\n", atfname);
12369 }
12370 }
12371 else
12372 {
12373 perror(NULL);
12374 fprintf(stderr, "Cannot find @file %s, skipping.\n", atfname);
12375 }
12376 }
12377 }
12378
12379
12380
12381 state = kRSParseState_EndElem;
12382 break;
12383 case kRSParseState_Plainfile:
12384
12385 if (pc < endInput)
12386 {
12387 if (DSElem_IsDelim((const char **)&pc))
12388 {
12389 pc++;
12390 state = kRSParseState_EndElem;
12391 }
12392 else if (DSElem_IsComment((const char **)&pc))
12393 {
12394 DSElem_SkipComment(&pc);
12395 state = kRSParseState_EndElem;
12396 }
12397 else if (DSElem_IsWS((const char **)&pc))
12398 {
12399
12400
12401
12402 if (DSElem_SkipWS(&pc))
12403 {
12404
12405 if (DSElem_IsDelim((const char **)&pc))
12406 {
12407 pc++;
12408 state = kRSParseState_EndElem;
12409 }
12410 else if (DSElem_IsComment((const char **)&pc))
12411 {
12412 DSElem_SkipComment(&pc);
12413 state = kRSParseState_EndElem;
12414 }
12415 else
12416 {
12417 fprintf(stderr,
12418 "'plainfiles' containing whitespace are not allowed.\n");
12419 state = kRSParseState_Error;
12420 }
12421 }
12422 else
12423 {
12424
12425 state = kRSParseState_EndElem;
12426 }
12427 }
12428 else
12429 {
12430 *pcBuf++ = *pc++;
12431 }
12432 }
12433 else
12434 {
12435 state = kRSParseState_EndElem;
12436 }
12437
12438 if (state == kRSParseState_EndElem)
12439 {
12440 currSettype = kRecordSetType_PlainFile;
12441 }
12442 break;
12443 case kRSParseState_EndElem:
12444
12445
12446 *pcBuf = '\0';
12447
12448
12449 if (!multiRSQueries)
12450 {
12451 pset = strdup(buf);
12452 list_llinserttail(intSets, &pset);
12453 list_llinserttail(intSettypes, &currSettype);
12454 list_llinserttail(intAllVers, &currAllVers);
12455 list_llinserttail(intSnames, &sname);
12456 list_llinserttail(intFilts, &filtstr);
12457 list_llinserttail(intSegs, &segliststr);
12458 currAllVers = 'n';
12459 count++;
12460 }
12461 else
12462 {
12463 int iSet;
12464 ListNode_t *node = NULL;
12465
12466 for (iSet = 0; iSet < countMultiRS; iSet++)
12467 {
12468 node = list_llgethead(multiRSQueries);
12469 if (node)
12470 {
12471
12472 list_llinserttail(intSets, node->data);
12473 list_llremove(multiRSQueries, node);
12474 list_llfreenode(&node);
12475 }
12476
12477 node = list_llgethead(multiRSTypes);
12478 if (node)
12479 {
12480 list_llinserttail(intSettypes, node->data);
12481 list_llremove(multiRSTypes, node);
12482 list_llfreenode(&node);
12483 }
12484
12485 node = list_llgethead(multiRSAllVers);
12486 if (node)
12487 {
12488 list_llinserttail(intAllVers, node->data);
12489 list_llremove(multiRSAllVers, node);
12490 list_llfreenode(&node);
12491 }
12492
12493 node = list_llgethead(multiRSSnames);
12494 if (node)
12495 {
12496 list_llinserttail(intSnames, node->data);
12497 list_llremove(multiRSSnames, node);
12498 list_llfreenode(&node);
12499 }
12500
12501 node = list_llgethead(multiRSFilts);
12502 if (node)
12503 {
12504 list_llinserttail(intFilts, node->data);
12505 list_llremove(multiRSFilts, node);
12506 list_llfreenode(&node);
12507 }
12508
12509 node = list_llgethead(multiRSSegs);
12510 if (node)
12511 {
12512 list_llinserttail(intSegs, node->data);
12513 list_llremove(multiRSSegs, node);
12514 list_llfreenode(&node);
12515 }
12516
12517 count++;
12518 }
12519
12520 free(multiRSQueries);
12521 multiRSQueries = NULL;
12522 free(multiRSTypes);
12523 multiRSTypes = NULL;
12524 free(multiRSAllVers);
12525 multiRSAllVers = NULL;
12526 free(multiRSSnames);
12527 multiRSSnames = NULL;
12528 free(multiRSFilts);
12529 multiRSFilts = NULL;
12530 free(multiRSSegs);
12531 multiRSSegs = NULL;
12532 countMultiRS = 0;
12533 }
12534
12535 if (pc < endInput)
12536 {
12537 if (DSElem_SkipWS(&pc))
12538 {
12539 state = kRSParseState_BeginElem;
12540 }
12541 else
12542 {
12543 state = kRSParseState_End;
12544 }
12545 }
12546 else
12547 {
12548 state = kRSParseState_End;
12549 }
12550
12551 pcBuf = buf;
12552 bzero(buf, sizeof(buf));
12553
12554
12555
12556 sname = NULL;
12557
12558
12559 pfiltstr = NULL;
12560 filtstr = NULL;
12561
12562
12563 segliststr = NULL;
12564
12565 break;
12566 case kRSParseState_End:
12567 if (DSElem_SkipWS(&pc))
12568 {
12569
12570 state = kRSParseState_Error;
12571 }
12572 else
12573 {
12574 pc = NULL;
12575 state = kRSParseState_Success;
12576 }
12577 break;
12578 default:
12579 state = kRSParseState_Error;
12580 }
12581 }
12582
12583 free(rsstr);
12584 }
12585
12586 if (status == DRMS_SUCCESS && state == kRSParseState_Success && count > 0)
12587 {
12588 *sets = (char **)malloc(sizeof(char *) * count);
12589 *settypes = (DRMS_RecordSetType_t *)malloc(sizeof(DRMS_RecordSetType_t) * count);
12590 *allvers = (char *)malloc(sizeof(char) * count + 1);
12591 *snames = (char **)malloc(sizeof(char *) * count);
12592 *filts = (char **)malloc(sizeof(char *) * count);
12593 if (segs)
12594 {
12595 *segs = (char **)malloc(sizeof(char *) * count);
12596 }
12597
12598 if (*sets && *settypes && *allvers && *snames && *filts && (!segs || *segs))
12599 {
12600 int iset;
12601 ListNode_t *node = NULL;
12602 *nsets = count;
12603
12604 for (iset = 0; iset < count; iset++)
12605 {
12606 node = list_llgethead(intSets);
12607 if (node)
12608 {
12609
12610 memcpy(&((*sets)[iset]), node->data, sizeof(char *));
12611 list_llremove(intSets, node);
12612 list_llfreenode(&node);
12613 }
12614
12615 node = list_llgethead(intSettypes);
12616 if (node)
12617 {
12618 memcpy(&((*settypes)[iset]), node->data, sizeof(DRMS_RecordSetType_t));
12619 list_llremove(intSettypes, node);
12620 list_llfreenode(&node);
12621 }
12622
12623 node = list_llgethead(intAllVers);
12624 if (node)
12625 {
12626 memcpy(&((*allvers)[iset]), node->data, sizeof(char));
12627 list_llremove(intAllVers, node);
12628 list_llfreenode(&node);
12629 }
12630
12631 node = list_llgethead(intSnames);
12632 if (node)
12633 {
12634 memcpy(&((*snames)[iset]), node->data, sizeof(char *));
12635 list_llremove(intSnames, node);
12636 list_llfreenode(&node);
12637 }
12638
12639 node = list_llgethead(intFilts);
12640 if (node)
12641 {
12642 memcpy(&((*filts)[iset]), node->data, sizeof(char *));
12643 list_llremove(intFilts, node);
12644 list_llfreenode(&node);
12645 }
12646
12647 node = list_llgethead(intSegs);
12648 if (node)
12649 {
12650 if (segs)
12651 {
12652 memcpy(&((*segs)[iset]), node->data, sizeof(char *));
12653 }
12654 list_llremove(intSegs, node);
12655 list_llfreenode(&node);
12656 }
12657 }
12658
12659 (*allvers)[count] = '\0';
12660
12661 if (info)
12662 {
12663 *info = intinfo;
12664 }
12665 }
12666 else
12667 {
12668 status = DRMS_ERROR_OUTOFMEMORY;
12669 }
12670 }
12671
12672 if (status == DRMS_SUCCESS && state != kRSParseState_Success)
12673 {
12674 status = DRMS_ERROR_INVALIDDATA;
12675 }
12676
12677 if (intSets)
12678 {
12679 list_llfree(&intSets);
12680 }
12681
12682 if (intSettypes)
12683 {
12684 list_llfree(&intSettypes);
12685 }
12686
12687 if (intAllVers)
12688 {
12689 list_llfree(&intAllVers);
12690 }
12691
12692 if (intSnames)
12693 {
12694 list_llfree(&intSnames);
12695 }
12696
12697 if (intFilts)
12698 {
12699 list_llfree(&intFilts);
12700 }
12701
12702 if (intSegs)
12703 {
12704 list_llfree(&intSegs);
12705 }
12706
12707 return status;
12708 }
12709
12710 int ParseRecSetDesc(const char *recsetsStr,
12711 char **allvers,
12712 char ***sets,
12713 DRMS_RecordSetType_t **settypes,
12714 char ***snames,
12715 char ***filts,
12716 int *nsets,
12717 DRMS_RecQueryInfo_t *info)
12718 {
12719 return ParseRecSetDescInternal(recsetsStr, allvers, sets, settypes, snames, filts, NULL, nsets, info);
12720 }
12721
12722 int FreeRecSetDescArrInternal(char **allvers, char ***sets, DRMS_RecordSetType_t **types, char ***snames, char ***filts, char ***segs, int nsets)
12723 {
12724 int error = 0;
12725
12726 if (allvers && *allvers)
12727 {
12728 free(*allvers);
12729 allvers = NULL;
12730 }
12731
12732 if (sets)
12733 {
12734 int iSet;
12735 char **setArr = *sets;
12736
12737 if (setArr)
12738 {
12739 for (iSet = 0; iSet < nsets; iSet++)
12740 {
12741 char *oneSet = setArr[iSet];
12742
12743 if (oneSet)
12744 {
12745 free(oneSet);
12746 }
12747 }
12748
12749 free(setArr);
12750 }
12751
12752 *sets = NULL;
12753 }
12754
12755 if (types && *types)
12756 {
12757 free(*types);
12758 types = NULL;
12759 }
12760
12761 if (snames)
12762 {
12763 int iSet;
12764 char **snameArr = *snames;
12765
12766 if (snameArr)
12767 {
12768 for (iSet = 0; iSet < nsets; iSet++)
12769 {
12770 char *oneSname = snameArr[iSet];
12771
12772 if (oneSname)
12773 {
12774 free(oneSname);
12775 }
12776 }
12777
12778 free(snameArr);
12779 }
12780
12781 *snames = NULL;
12782 }
12783
12784 if (filts)
12785 {
12786 int iSet;
12787 char **filtsArr = *filts;
12788
12789 if (filtsArr)
12790 {
12791 for (iSet = 0; iSet < nsets; iSet++)
12792 {
12793 char *oneFilt = filtsArr[iSet];
12794
12795 if (oneFilt)
12796 {
12797 free(oneFilt);
12798 }
12799 }
12800
12801 free(filtsArr);
12802 }
12803
12804 *filts = NULL;
12805 }
12806
12807 if (segs)
12808 {
12809 int iSet;
12810 char **segsArr = *segs;
12811
12812 if (segsArr)
12813 {
12814 for (iSet = 0; iSet < nsets; iSet++)
12815 {
12816 char *oneSeg = segsArr[iSet];
12817
12818 if (oneSeg)
12819 {
12820 free(oneSeg);
12821 }
12822 }
12823
12824 free(segsArr);
12825 }
12826
12827 *segs = NULL;
12828 }
12829
12830 return error;
12831 }
12832
12833 int FreeRecSetDescArr(char **allvers, char ***sets, DRMS_RecordSetType_t **types, char ***snames, char ***filts, int nsets)
12834 {
12835 return FreeRecSetDescArrInternal(allvers, sets, types, snames, filts, NULL, nsets);
12836 }
12837
12838 int drms_recproto_setseriesinfo(DRMS_Record_t *rec,
12839 int *unitSize,
12840 int *bArchive,
12841 int *nDaysRetention,
12842 int *tapeGroup,
12843 const char *description)
12844 {
12845 int status = DRMS_NO_ERROR;
12846
12847 if (rec && rec->seriesinfo)
12848 {
12849 if (unitSize)
12850 {
12851 rec->seriesinfo->unitsize = *unitSize;
12852 }
12853
12854 if (bArchive)
12855 {
12856 rec->seriesinfo->archive = *bArchive;
12857 }
12858
12859 if (nDaysRetention)
12860 {
12861 rec->seriesinfo->retention = *nDaysRetention;
12862 }
12863
12864 if (tapeGroup)
12865 {
12866 rec->seriesinfo->tapegroup = *tapeGroup;
12867 }
12868
12869 if (description && strlen(description) < DRMS_MAXCOMMENTLEN)
12870 {
12871 strcpy(rec->seriesinfo->description, description);
12872 }
12873 }
12874 else
12875 {
12876 status = DRMS_ERROR_INVALIDDATA;
12877 }
12878
12879 return status;
12880 }
12881
12882 static int IsFileOrDir(const char *q)
12883 {
12884 int ret = 0;
12885 char *lbrack = NULL;
12886 char *query = strdup(q);
12887 struct stat stBuf;
12888
12889 if (query)
12890 {
12891 if ((lbrack = strchr(query, '[')) != NULL)
12892 {
12893 *lbrack = '\0';
12894 }
12895
12896 if (!stat(query, &stBuf))
12897 {
12898 if (S_ISREG(stBuf.st_mode) || S_ISLNK(stBuf.st_mode) || S_ISDIR(stBuf.st_mode))
12899 {
12900 ret = 1;
12901 }
12902 }
12903
12904 free(query);
12905 }
12906
12907 return ret;
12908 }
12909
12910 DRMS_RecordSetType_t drms_record_getquerytype(const char *query)
12911 {
12912 DRMS_RecordSetType_t ret;
12913 const char *pQ = (*query == '{') ? query + 1 : query;
12914
12915 if (DSDS_IsDSDSSpec(pQ))
12916 {
12917 ret = kRecordSetType_DSDS;
12918 }
12919 else if (DSDS_IsDSDSPort(query))
12920 {
12921 ret = kRecordSetType_DSDSPort;
12922 }
12923 else if (IsFileOrDir(query))
12924 {
12925 ret = kRecordSetType_PlainFile;
12926 }
12927 else
12928 {
12929 ret = kRecordSetType_DRMS;
12930 }
12931
12932 return ret;
12933 }
12934
12935 char *drms_record_jsoc_version(DRMS_Env_t *env, DRMS_Record_t *rec) {
12936 char *jsocversion = 0;
12937 char query[DRMS_MAXQUERYLEN];
12938 snprintf(query, DRMS_MAXQUERYLEN, "select jsoc_version from %s.drms_session where sessionid = %lld", rec->sessionns, rec->sessionid);
12939 DB_Text_Result_t *qres;
12940 if ((qres = drms_query_txt(env->session, query)) && qres->num_rows>0) {
12941 if (qres->field[0][0][0]) {
12942 jsocversion = malloc(strlen(qres->field[0][0])+1);
12943 XASSERT(jsocversion);
12944 strcpy(jsocversion, qres->field[0][0]);
12945 }
12946 }
12947 db_free_text_result(qres);
12948 return jsocversion;
12949 }
12950
12951 char *drms_recordset_acquireseriesname(const char *query)
12952 {
12953 char *sn = strdup(query);
12954 char *pc = NULL;
12955
12956 if (sn)
12957 {
12958 pc = index(sn, '[');
12959 if (pc)
12960 {
12961 *pc = '\0';
12962 pc = strdup(sn);
12963 free(sn);
12964 sn = pc;
12965 }
12966 }
12967
12968 return sn;
12969 }
12970
12971 int drms_recordset_getssnrecs(DRMS_RecordSet_t *set, unsigned int setnum, int *status)
12972 {
12973 int start = 0;
12974 int end = 0;
12975 int stat = DRMS_SUCCESS;
12976 int res = 0;
12977 int notnegone = 0;
12978
12979 if (setnum >= set->ss_n)
12980 {
12981 stat = DRMS_RANGE;
12982 }
12983 else
12984 {
12985 if (set->ss_starts[setnum] == -1)
12986 {
12987
12988 res = 0;
12989 }
12990 else
12991 {
12992 start = set->ss_starts[setnum];
12993 notnegone = setnum + 1;
12994
12995
12996 while (notnegone < set->ss_n && set->ss_starts[notnegone] == -1)
12997 {
12998 notnegone++;
12999 }
13000
13001 if (notnegone == set->ss_n)
13002 {
13003
13004
13005 end = set->n - 1;
13006 res = end - start + 1;
13007 }
13008 else
13009 {
13010 end = set->ss_starts[notnegone];
13011 res = end - start;
13012 }
13013 }
13014 }
13015
13016 if (status)
13017 {
13018 *status = stat;
13019 }
13020
13021 return res;
13022 }
13023
13024
13025
13026
13027
13028
13029
13030
13031
13032
13033
13034
13035
13036
13037 int drms_merge_record(DRMS_RecordSet_t *rs, DRMS_Record_t *rec)
13038 {
13039 int iset;
13040 int nmerge = 0;
13041 int err = 0;
13042
13043 if (rs && rec)
13044 {
13045 if (rs->ss_n > 0)
13046 {
13047 for (iset = 0; iset < rs->ss_n; iset++)
13048 {
13049 if (rs->ss_queries && rs->ss_queries[iset])
13050 {
13051 free(rs->ss_queries[iset]);
13052 rs->ss_queries[iset] = NULL;
13053 }
13054 }
13055
13056 if (rs->ss_queries)
13057 {
13058 free(rs->ss_queries);
13059 rs->ss_queries = NULL;
13060 }
13061
13062 if (rs->ss_types)
13063 {
13064 free(rs->ss_types);
13065 rs->ss_types = NULL;
13066 }
13067
13068 if (rs->ss_starts)
13069 {
13070 free(rs->ss_starts);
13071 rs->ss_starts = NULL;
13072 }
13073
13074 if (rs->ss_currentrecs)
13075 {
13076 free(rs->ss_currentrecs);
13077 rs->ss_currentrecs = NULL;
13078 }
13079
13080 if (rs->cursor)
13081 {
13082 drms_free_cursor(&(rs->cursor));
13083 }
13084
13085
13086 }
13087
13088 if (rs->records == NULL)
13089 {
13090
13091 rs->records = malloc(sizeof(DRMS_Record_t *) * 32);
13092 rs->n = 0;
13093 rs->ss_n = -32;
13094 }
13095
13096 if (rs->n == abs(rs->ss_n))
13097 {
13098
13099 rs->records = realloc(rs->records, sizeof(DRMS_Record_t *) * abs(rs->ss_n) * 2);
13100 if (rs->records)
13101 {
13102 rs->ss_n = -1 * abs(rs->ss_n) * 2;
13103 }
13104 else
13105 {
13106 err = 1;
13107 }
13108 }
13109
13110 if (!err)
13111 {
13112 rs->records[rs->n] = rec;
13113 rs->n++;
13114 nmerge = 1;
13115 }
13116
13117 }
13118
13119 return nmerge;
13120 }
13121
13122 int drms_recordset_setchunksize(unsigned int size)
13123 {
13124 int status = DRMS_SUCCESS;
13125
13126 if (size > 0 && size <= DRMS_MAXCHUNKSIZE)
13127 {
13128 gRSChunkSize = size;
13129 }
13130 else
13131 {
13132 status = DRMS_ERROR_BADCHUNKSIZE;
13133 fprintf(stderr,
13134 "Invalid chunk size '%u'. Must be > 0 and <= '%d'.\n",
13135 size,
13136 DRMS_MAXCHUNKSIZE);
13137 }
13138
13139 return status;
13140 }
13141
13142 unsigned int drms_recordset_getchunksize()
13143 {
13144
13145 return gRSChunkSize;
13146 }
13147
13148
13149
13150 int drms_open_recordchunk(DRMS_Env_t *env,
13151 DRMS_RecordSet_t *rs,
13152 DRMS_RecSetCursorSeek_t seektype,
13153 long long chunkindex,
13154 int *status)
13155 {
13156 int stat = DRMS_SUCCESS;
13157 int nrecs;
13158
13159 if (rs && rs->cursor)
13160 {
13161 DRMS_RecordSet_t *fetchedrecs = NULL;
13162
13163 switch (seektype)
13164 {
13165 case kRSChunk_Abs:
13166 {
13167
13168 fprintf(stderr, "Cannot manually reposition cursor (yet).\n");
13169 stat = DRMS_ERROR_INVALIDDATA;
13170 }
13171 break;
13172 case kRSChunk_First:
13173 {
13174
13175 if (rs->cursor->currentchunk >= 0)
13176 {
13177 fprintf(stderr, "Cannot manually reposition cursor (yet).\n");
13178 stat = DRMS_ERROR_INVALIDDATA;
13179 break;
13180 }
13181
13182
13183 }
13184 case kRSChunk_Next:
13185 {
13186 if (rs->cursor->currentchunk >= 0)
13187 {
13188
13189 chunkindex = rs->cursor->currentchunk + 1;
13190 }
13191 else
13192 {
13193
13194 chunkindex = 0;
13195 }
13196 }
13197 break;
13198 default:
13199 fprintf(stderr, "Unsupported seek type '%d'.\n", (int)seektype);
13200 stat = DRMS_ERROR_INVALIDDATA;
13201 }
13202
13203 if (stat == DRMS_SUCCESS && chunkindex != rs->cursor->currentchunk)
13204 {
13205
13206
13207
13208
13209
13210 int iset;
13211 char sqlquery[DRMS_MAXQUERYLEN];
13212 char *seriesname = NULL;
13213 char *psl = NULL;
13214 char *seglist = NULL;
13215 char *lasts = NULL;
13216 char *ans = NULL;
13217 HContainer_t *goodsegcont = NULL;
13218
13219 nrecs = 0;
13220
13221
13222
13223 for (iset = 0; iset < rs->ss_n; iset++)
13224 {
13225 goodsegcont = NULL;
13226
13227 if (nrecs == rs->cursor->chunksize)
13228 {
13229
13230 break;
13231 }
13232 else if (nrecs < rs->cursor->chunksize)
13233 {
13234 seriesname = drms_recordset_acquireseriesname(rs->ss_queries[iset]);
13235
13236 if (!seriesname)
13237 {
13238 stat = DRMS_ERROR_OUTOFMEMORY;
13239 break;
13240 }
13241
13242 snprintf(sqlquery,
13243 sizeof(sqlquery),
13244 "FETCH FORWARD %d FROM %s",
13245 rs->cursor->chunksize - nrecs,
13246 rs->cursor->names[iset]);
13247
13248
13249 psl = strchr(rs->ss_queries[iset], '{');
13250 if (psl)
13251 {
13252 seglist = strdup(psl);
13253 if (!seglist)
13254 {
13255 stat = DRMS_ERROR_OUTOFMEMORY;
13256 break;
13257 }
13258 }
13259
13260 if (seglist)
13261 {
13262 char aseg[DRMS_MAXSEGNAMELEN];
13263 goodsegcont = hcon_create(DRMS_MAXSEGNAMELEN,
13264 DRMS_MAXSEGNAMELEN,
13265 NULL,
13266 NULL,
13267 NULL,
13268 NULL,
13269 0);
13270
13271 ans = strtok_r(seglist, " ,;:{}", &lasts);
13272
13273 do
13274 {
13275
13276 snprintf(aseg, sizeof(aseg), "%s", ans);
13277 hcon_insert_lower(goodsegcont, aseg, aseg);
13278 }
13279 while ((ans = strtok_r(NULL, " ,;:{}", &lasts)) != NULL);
13280
13281 free(seglist);
13282 seglist = NULL;
13283 }
13284
13285
13286 fetchedrecs = drms_retrieve_records_internal(env,
13287 seriesname,
13288 NULL,
13289 NULL,
13290 NULL,
13291 0,
13292 0,
13293 goodsegcont,
13294 sqlquery,
13295 rs->cursor->allvers[iset],
13296 0,
13297 NULL,
13298 NULL,
13299 0,
13300 1,
13301 NULL,
13302 NULL,
13303 NULL,
13304 &stat);
13305
13306 if (goodsegcont)
13307 {
13308 hcon_destroy(&goodsegcont);
13309 }
13310
13311 free(seriesname);
13312 seriesname = NULL;
13313
13314 if (stat != DRMS_SUCCESS)
13315 {
13316 fprintf(stderr, "Cursor query '%s' fetch failure", sqlquery);
13317 break;
13318 }
13319
13320 if (fetchedrecs == 0)
13321 {
13322
13323 break;
13324 }
13325
13326
13327
13328
13329
13330
13331 fetchedrecs->ss_starts = (int *)malloc(sizeof(int) * 1);
13332 fetchedrecs->ss_starts[0] = 0;
13333 fetchedrecs->ss_n = 1;
13334
13335
13336
13337 fetchedrecs->ss_currentrecs = (int *)malloc(sizeof(int));
13338
13339 if (fetchedrecs->ss_currentrecs)
13340 {
13341 fetchedrecs->ss_currentrecs[0] = -1;
13342 }
13343 else
13344 {
13345 stat = DRMS_ERROR_OUTOFMEMORY;
13346 }
13347
13348 if (stat == DRMS_SUCCESS)
13349 {
13350
13351 if (rs->cursor->staging_needed)
13352 {
13353 if (rs->cursor->staging_needed == 1)
13354 {
13355
13356 stat = drms_stage_records(fetchedrecs, rs->cursor->retrieve, rs->cursor->dontwait);
13357 }
13358 else if (rs->cursor->staging_needed == 2)
13359 {
13360
13361
13362
13363
13364 stat = drms_sortandstage_records(fetchedrecs, rs->cursor->retrieve, rs->cursor->dontwait, &rs->cursor->suinfo);
13365 }
13366 else
13367 {
13368
13369 }
13370
13371
13372 if (stat != DRMS_SUCCESS && stat != DRMS_REMOTESUMS_TRYLATER && stat != DRMS_ERROR_SUMSTRYLATER)
13373 {
13374 fprintf(stderr, "Cursor query '%s' record staging failure, status=%d.\n", sqlquery, stat);
13375 break;
13376 }
13377 }
13378 }
13379
13380
13381
13382
13383
13384
13385 if (stat == DRMS_SUCCESS)
13386 {
13387 if (rs->cursor->infoneeded)
13388 {
13389 stat = drms_record_getinfo(fetchedrecs);
13390
13391 if (stat != DRMS_SUCCESS)
13392 {
13393 fprintf(stderr, "Failure calling drms_record_getinfo(), status=%d.\n", stat);
13394 break;
13395 }
13396 }
13397 }
13398
13399
13400 int nrecs_thisset;
13401 for (nrecs_thisset = 0; nrecs_thisset < fetchedrecs->n; nrecs_thisset++)
13402 {
13403 rs->records[nrecs] = fetchedrecs->records[nrecs_thisset];
13404 fetchedrecs->records[nrecs_thisset] = NULL;
13405 nrecs++;
13406 }
13407
13408
13409
13410
13411 drms_close_records(fetchedrecs, DRMS_FREE_RECORD);
13412
13413 }
13414 }
13415
13416 if (nrecs > 0)
13417 {
13418 if (nrecs < rs->cursor->chunksize)
13419 {
13420
13421
13422 rs->cursor->lastrec = nrecs - 1;
13423 }
13424
13425
13426
13427
13428 if (stat == DRMS_SUCCESS || stat == DRMS_REMOTESUMS_TRYLATER || stat == DRMS_ERROR_SUMSTRYLATER)
13429 {
13430 rs->cursor->currentchunk = chunkindex;
13431 rs->cursor->currentrec = -1;
13432 }
13433 }
13434 else
13435 {
13436
13437
13438
13439
13440
13441
13442
13443
13444
13445
13446 rs->cursor->currentrec = rs->cursor->chunksize - 1;
13447 rs->cursor->lastrec = rs->cursor->chunksize - 1;
13448 }
13449 }
13450 }
13451 else
13452 {
13453 fprintf(stderr, "Recordset is either NULL, or is not chunked.\n");
13454 stat = DRMS_ERROR_INVALIDDATA;
13455 }
13456
13457 if (status)
13458 {
13459 *status = stat;
13460 }
13461
13462 return nrecs;
13463 }
13464
13465
13466
13467
13468
13469
13470
13471 int drms_close_recordchunk(DRMS_RecordSet_t *rs)
13472 {
13473 int irec;
13474 int status = 0;
13475 DRMS_Record_t *rec;
13476 DRMS_RecordSet_t *rs_new = NULL;
13477
13478 int recstart = 0;
13479 int recend = 0;
13480
13481 if (rs->cursor->currentchunk >= 0)
13482 {
13483
13484 recstart = 0;
13485 recend = recstart + rs->cursor->chunksize - 1;
13486 rs_new = malloc(sizeof(DRMS_RecordSet_t));
13487 memset(rs_new, 0, sizeof(DRMS_RecordSet_t));
13488
13489 for (irec = recstart; irec <= recend; irec++)
13490 {
13491 rec = rs->records[irec];
13492 drms_merge_record(rs_new, rec);
13493 rs->records[irec] = NULL;
13494 }
13495
13496
13497 rs_new->env = rs->env;
13498
13499 drms_close_records(rs_new, DRMS_FREE_RECORD);
13500
13501 rs->cursor->currentchunk = -1;
13502 rs->cursor->currentrec = -1;
13503 rs->cursor->lastrec = -1;
13504 }
13505
13506 return status;
13507 }
13508
13509
13510
13511
13512
13513
13514
13515
13516
13517
13518
13519
13520
13521
13522
13523
13524
13525
13526
13527
13528
13529
13530
13531
13532
13533
13534
13535
13536
13537
13538 DRMS_RecordSet_t *drms_open_recordset(DRMS_Env_t *env,
13539 const char *rsquery,
13540 int *status)
13541 {
13542 DRMS_RecordSet_t *rs = NULL;
13543 long long guid = -1;
13544 int stat = DRMS_SUCCESS;
13545 char *cursorquery = NULL;
13546 char cursorname[DRMS_MAXCURSORNAMELEN];
13547 char *seriesname = NULL;
13548 char *pQuery = NULL;
13549 char *cursorselect = NULL;
13550 char *pLimit = NULL;
13551 int iset;
13552 int querylen;
13553
13554 if (rsquery)
13555 {
13556
13557
13558 LinkedList_t *querylist = NULL;
13559 char *tmp = strdup(rsquery);
13560 char *allvers = NULL;
13561
13562 if (tmp)
13563 {
13564
13565
13566 rs = drms_open_records_internal(env, tmp, 0, &querylist, &allvers, NULL, 0, &stat);
13567 free(tmp);
13568 }
13569 else
13570 {
13571 stat = DRMS_ERROR_OUTOFMEMORY;
13572 }
13573
13574
13575
13576 if (rs && querylist && allvers)
13577 {
13578
13579 rs->cursor = (DRMS_RecSetCursor_t *)malloc(sizeof(DRMS_RecSetCursor_t));
13580 rs->cursor->names = (char **)malloc(sizeof(char *) * rs->ss_n);
13581 memset(rs->cursor->names, 0, sizeof(char *) * rs->ss_n);
13582 rs->cursor->allvers = (int *)malloc(sizeof(int) * rs->ss_n);
13583 memset(rs->cursor->allvers, 0, sizeof(int) * rs->ss_n);
13584
13585 rs->cursor->staging_needed = rs->cursor->retrieve = rs->cursor->dontwait = 0;
13586 rs->cursor->infoneeded = 0;
13587 rs->cursor->suinfo = NULL;
13588
13589 iset = 0;
13590 list_llreset(querylist);
13591 ListNode_t *ln = NULL;
13592
13593 while ((ln = (ListNode_t *)(list_llnext(querylist))) != NULL)
13594 {
13595 pQuery = *((char **)ln->data);
13596
13597 seriesname = drms_recordset_acquireseriesname(rs->ss_queries[iset]);
13598
13599 if (seriesname)
13600 {
13601 char *dot = strchr(seriesname, '.');
13602 if (dot)
13603 {
13604 *dot = '_';
13605 }
13606
13607 #ifdef DRMS_CLIENT
13608 drms_send_commandcode(env->session->sockfd, DRMS_GETTMPGUID);
13609 guid = Readlonglong(env->session->sockfd);
13610 #else
13611
13612 guid = drms_server_gettmpguid(NULL);
13613 #endif
13614
13615 snprintf(cursorname, sizeof(cursorname), "%s_CURSOR%lld", seriesname, guid);
13616
13617
13618
13619
13620
13621
13622
13623
13624
13625
13626
13627
13628
13629 cursorselect = strdup(pQuery);
13630
13631 if (!cursorselect)
13632 {
13633 stat = DRMS_ERROR_OUTOFMEMORY;
13634 }
13635 else
13636 {
13637
13638
13639 if (ParseAndExecTempTableSQL(env->session, &cursorselect))
13640 {
13641 stat = DRMS_ERROR_QUERYFAILED;
13642 }
13643
13644 if (stat == DRMS_SUCCESS)
13645 {
13646 if ((pLimit = strcasestr(cursorselect, " limit")) != NULL)
13647 {
13648 *pLimit = '\0';
13649 }
13650
13651 querylen = sizeof(char) * (strlen(cursorname) + strlen(cursorselect) + 128);
13652 cursorquery = malloc(querylen);
13653
13654 if (!cursorquery)
13655 {
13656 stat = DRMS_ERROR_OUTOFMEMORY;
13657 }
13658 else
13659 {
13660 snprintf(cursorquery,
13661 querylen,
13662 "DECLARE %s NO SCROLL CURSOR FOR (%s) FOR READ ONLY",
13663 cursorname,
13664 cursorselect);
13665
13666
13667 if (env->verbose)
13668 {
13669 fprintf(stdout, "Cursor declaration ==> %s\n", cursorquery);
13670 }
13671
13672 if (drms_dms(env->session, NULL, cursorquery))
13673 {
13674 stat = DRMS_ERROR_QUERYFAILED;
13675 }
13676 else
13677 {
13678 rs->cursor->names[iset] = strdup(cursorname);
13679 }
13680
13681 free(cursorquery);
13682 cursorquery = NULL;
13683 }
13684 }
13685
13686 free(cursorselect);
13687 cursorselect = NULL;
13688 }
13689
13690 free(seriesname);
13691
13692 if (stat != DRMS_SUCCESS)
13693 {
13694 break;
13695 }
13696
13697 XASSERT(allvers[iset] != '\0');
13698 rs->cursor->allvers[iset] = (allvers[iset] == 'y');
13699 }
13700
13701 iset++;
13702 }
13703
13704 rs->cursor->parent = rs;
13705 rs->cursor->env = env;
13706 rs->cursor->chunksize = drms_recordset_getchunksize();
13707 rs->cursor->currentchunk = -1;
13708 rs->cursor->lastrec = -1;
13709 rs->cursor->currentrec = -1;
13710 }
13711 else
13712 {
13713 if (rs)
13714 {
13715 rs->cursor = NULL;
13716 }
13717 }
13718
13719 if (querylist)
13720 {
13721 list_llfree(&querylist);
13722 }
13723
13724 if (allvers)
13725 {
13726 free(allvers);
13727 }
13728 }
13729
13730 if (stat != DRMS_SUCCESS)
13731 {
13732
13733 drms_free_records(rs);
13734 }
13735
13736 if (status)
13737 {
13738 *status = stat;
13739 }
13740
13741 return rs;
13742 }
13743
13744
13745
13746
13747
13748
13749
13750
13751
13752
13753
13754
13755
13756
13757 DRMS_Record_t *drms_recordset_fetchnext(DRMS_Env_t *env,
13758 DRMS_RecordSet_t *rs,
13759 int *drmsstatus,
13760 DRMS_RecChunking_t *chunkstat,
13761 int *newchunk)
13762 {
13763 DRMS_Record_t *ret = NULL;
13764 int stat = DRMS_SUCCESS;
13765 DRMS_RecChunking_t cstat = kRecChunking_None;
13766 int neednewchunk = -1;
13767 int nRecsRetr = -1;
13768
13769 if (newchunk)
13770 {
13771 *newchunk = 0;
13772 }
13773
13774 if (rs && rs->cursor)
13775 {
13776 if (!rs->records)
13777 {
13778 rs->records = (DRMS_Record_t **)calloc(rs->cursor->chunksize, sizeof(DRMS_Record_t *));
13779 }
13780
13781 if (rs->cursor->currentchunk == -1)
13782 {
13783
13784 neednewchunk = (int)kRSChunk_First;
13785 }
13786 else
13787 {
13788
13789 rs->cursor->currentrec++;
13790
13791 if (rs->cursor->currentrec == rs->cursor->chunksize)
13792 {
13793 drms_close_recordchunk(rs);
13794 neednewchunk = (int)kRSChunk_Next;
13795 }
13796 }
13797
13798 if (neednewchunk >= 0)
13799 {
13800 nRecsRetr = drms_open_recordchunk(env, rs, (DRMS_RecSetCursorSeek_t)neednewchunk, 0, &stat);
13801
13802
13803 if (stat != DRMS_SUCCESS && stat != DRMS_REMOTESUMS_TRYLATER && stat != DRMS_ERROR_SUMSTRYLATER)
13804 {
13805 fprintf(stderr, "Error retrieving record chunk '%d'.\n", rs->cursor->currentchunk);
13806 }
13807 else if (nRecsRetr == 0)
13808 {
13809
13810
13811 cstat = kRecChunking_NoMoreRecs;
13812 }
13813 else
13814 {
13815 rs->cursor->currentrec++;
13816 if (newchunk)
13817 {
13818 *newchunk = 1;
13819 }
13820 }
13821 }
13822 else
13823 {
13824
13825
13826
13827
13828 if (rs->cursor->lastrec >= 0 && rs->cursor->currentrec > rs->cursor->lastrec)
13829 {
13830 rs->cursor->currentrec = rs->cursor->lastrec;
13831 cstat = kRecChunking_NoMoreRecs;
13832 }
13833 }
13834
13835
13836
13837
13838
13839 if ((stat == DRMS_SUCCESS || stat == DRMS_REMOTESUMS_TRYLATER || stat == DRMS_ERROR_SUMSTRYLATER) && rs->cursor->currentrec >= 0 && cstat != kRecChunking_NoMoreRecs)
13840 {
13841
13842 ret = rs->records[rs->cursor->currentrec];
13843
13844 if (nRecsRetr == 0 || (rs->cursor->lastrec > 0 && rs->cursor->lastrec == rs->cursor->currentrec))
13845 {
13846
13847
13848 cstat = kRecChunking_LastInRS;
13849 }
13850 else if (rs->cursor->currentrec == rs->cursor->chunksize - 1)
13851 {
13852 cstat = kRecChunking_LastInChunk;
13853 }
13854 }
13855 }
13856 else if (rs)
13857 {
13858
13859 XASSERT(rs->ss_currentrecs);
13860
13861 if (rs->ss_currentrecs)
13862 {
13863
13864
13865
13866
13867 if (*rs->ss_currentrecs == -1)
13868 {
13869 *rs->ss_currentrecs = 0;
13870 }
13871
13872 if (*rs->ss_currentrecs < rs->n)
13873 {
13874 ret = rs->records[*rs->ss_currentrecs];
13875 (*rs->ss_currentrecs)++;
13876 }
13877
13878
13879 }
13880 }
13881 else
13882 {
13883 stat = DRMS_ERROR_INVALIDDATA;
13884 fprintf(stderr, "Error in drms_recordset_fetchnext(): empty recordset set provided.\n");
13885 }
13886
13887 if (drmsstatus)
13888 {
13889 *drmsstatus = stat;
13890 }
13891
13892 if (chunkstat)
13893 {
13894 *chunkstat = cstat;
13895 }
13896
13897 return ret;
13898 }
13899
13900 int drms_recordset_fetchnext_getcurrent(DRMS_RecordSet_t *rset)
13901 {
13902 if (rset && rset->ss_currentrecs)
13903 {
13904 return rset->ss_currentrecs[0];
13905 }
13906
13907 return -1;
13908 }
13909
13910 void drms_recordset_fetchnext_setcurrent(DRMS_RecordSet_t *rset, int current)
13911 {
13912 if (rset && rset->ss_currentrecs)
13913 {
13914 rset->ss_currentrecs[0] = current;
13915 }
13916 }
13917
13918 void drms_free_cursor(DRMS_RecSetCursor_t **cursor)
13919 {
13920 int iname;
13921 char sqlquery[DRMS_MAXQUERYLEN];
13922
13923 if (cursor)
13924 {
13925 if (*cursor)
13926 {
13927 if ((*cursor)->names)
13928 {
13929 for (iname = 0; iname < (*cursor)->parent->ss_n; iname++)
13930 {
13931 if ((*cursor)->names[iname])
13932 {
13933 snprintf(sqlquery, sizeof(sqlquery), "CLOSE %s", (*cursor)->names[iname]);
13934 if (drms_dms((*cursor)->env->session, NULL, sqlquery))
13935 {
13936 fprintf(stderr, "Failed to close cursor '%s'.\n",(*cursor)->names[iname]);
13937 }
13938
13939 free((*cursor)->names[iname]);
13940 (*cursor)->names[iname] = NULL;
13941 }
13942 }
13943
13944 free((*cursor)->names);
13945 (*cursor)->names = NULL;
13946 }
13947
13948 if ((*cursor)->allvers)
13949 {
13950 free((*cursor)->allvers);
13951 (*cursor)->allvers = NULL;
13952 }
13953
13954 if ((*cursor)->suinfo)
13955 {
13956 hcon_destroy(&((*cursor)->suinfo));
13957 }
13958
13959 free(*cursor);
13960 }
13961
13962 *cursor = NULL;
13963 }
13964 }
13965
13966
13967
13968
13969
13970
13971
13972 int drms_count_records(DRMS_Env_t *env, const char *recordsetname, int *status)
13973 {
13974 int stat, filter, mixed;
13975 char *query=NULL, *where=NULL, *seriesname=NULL;
13976 char *pkwhere = NULL;
13977 char *npkwhere = NULL;
13978 HContainer_t *pkwhereNFL = NULL;
13979 int count = 0;
13980 int subcount = 0;
13981 DB_Text_Result_t *tres = NULL;
13982 int allvers = 0;
13983 HContainer_t *firstlast = NULL;
13984 int recnumq;
13985
13986 char *allversA = NULL;
13987
13988
13989 char **sets = NULL;
13990 DRMS_RecordSetType_t *settypes = NULL;
13991 char **snames = NULL;
13992 char **filts = NULL;
13993 int nsets = 0;
13994 DRMS_RecQueryInfo_t rsinfo;
13995 int iSet;
13996 char *actualSet = NULL;
13997 char *psl = NULL;
13998 long long limit = 0;
13999
14000
14001
14002
14003 stat = ParseRecSetDesc(recordsetname, &allversA, &sets, &settypes, &snames, &filts, &nsets, &rsinfo);
14004
14005 if (stat)
14006 {
14007 goto failure;
14008 }
14009
14010 for (iSet = 0; stat == DRMS_SUCCESS && iSet < nsets; iSet++)
14011 {
14012 char *oneSet = sets[iSet];
14013
14014 if (oneSet && strlen(oneSet) > 0)
14015 {
14016 if (settypes[iSet] == kRecordSetType_DRMS)
14017 {
14018
14019
14020
14021 actualSet = strdup(oneSet);
14022 if (actualSet)
14023 {
14024
14025 psl = strchr(actualSet, '{');
14026 if (psl)
14027 {
14028 *psl = '\0';
14029 }
14030
14031 stat = drms_recordset_query(env, actualSet, &where, &pkwhere, &npkwhere, &seriesname, &filter, &mixed, &allvers, &firstlast, &pkwhereNFL, &recnumq);
14032
14033 if (stat)
14034 {
14035 goto failure;
14036 }
14037
14038 query = drms_query_string(env, seriesname, where, pkwhere, npkwhere, filter, mixed, DRMS_QUERY_COUNT, NULL, NULL, allvers, firstlast, pkwhereNFL, recnumq, 0, &limit);
14039
14040 if (!query)
14041 {
14042 stat = DRMS_ERROR_QUERYFAILED;
14043 goto failure;
14044 }
14045
14046 tres = drms_query_txt(env->session, query);
14047
14048 if (!tres)
14049 {
14050 stat = DRMS_ERROR_QUERYFAILED;
14051 goto failure;
14052 }
14053
14054 if (tres && tres->num_rows == 1 && tres->num_cols == 1)
14055 {
14056 subcount = atoi(tres->field[0][0]);
14057 }
14058 else
14059 {
14060 stat = DRMS_ERROR_BADQUERYRESULT;
14061 goto failure;
14062 }
14063
14064 db_free_text_result(tres);
14065 tres = NULL;
14066
14067 count += subcount;
14068
14069 free(where);
14070 where = NULL;
14071
14072 if (firstlast)
14073 {
14074 hcon_destroy(&firstlast);
14075 }
14076
14077 if (pkwhere)
14078 {
14079 free(pkwhere);
14080 pkwhere = NULL;
14081 }
14082 if (npkwhere)
14083 {
14084 free(npkwhere);
14085 npkwhere = NULL;
14086 }
14087 free(seriesname);
14088 seriesname = NULL;
14089 if (pkwhereNFL)
14090 {
14091 hcon_destroy(&pkwhereNFL);
14092 }
14093 free(query);
14094 query = NULL;
14095
14096 if (actualSet)
14097 {
14098 free(actualSet);
14099 actualSet = NULL;
14100 }
14101 }
14102 }
14103 }
14104 else
14105 {
14106 fprintf(stderr, "Unsupported record-set type: %d\n", (int)settypes[iSet]);
14107 }
14108 }
14109
14110 FreeRecSetDescArr(&allversA, &sets, &settypes, &snames, &filts, nsets);
14111
14112 *status = DRMS_SUCCESS;
14113 return(count);
14114
14115 failure:
14116 if (seriesname) free(seriesname);
14117 if (query) free(query);
14118 if (where) free(where);
14119 if (firstlast) hcon_destroy(&firstlast);
14120 if (pkwhere) free(pkwhere);
14121 if (npkwhere) free(npkwhere);
14122 if (pkwhereNFL) hcon_destroy(&pkwhereNFL);
14123 if (tres) db_free_text_result(tres);
14124 FreeRecSetDescArr(&allversA, &sets, &settypes, &snames, &filts, nsets);
14125 *status = stat;
14126 return(0);
14127 }
14128
14129
14130 DRMS_Array_t *drms_record_getvector(DRMS_Env_t *env,
14131 const char *recordsetname,
14132 const char *keylist,
14133 DRMS_Type_t type,
14134 int unique,
14135 int *status)
14136 {
14137 int stat, filter, mixed;
14138 char *query=NULL, *where=NULL, *seriesname=NULL;
14139 char *pkwhere = NULL;
14140 char *npkwhere = NULL;
14141 HContainer_t *pkwhereNFL = NULL;
14142 int count = 0;
14143 int keys = 0;
14144 DB_Binary_Result_t *bres=NULL;
14145 DRMS_Array_t *vectors=NULL;
14146 HContainer_t *firstlast = NULL;
14147 int recnumq;
14148
14149 int iSet;
14150 char *allvers = NULL;
14151
14152
14153 char **sets = NULL;
14154 DRMS_RecordSetType_t *settypes = NULL;
14155 char **snames = NULL;
14156 char **filts = NULL;
14157 int nsets = 0;
14158 DRMS_RecQueryInfo_t rsinfo;
14159 long long limit = 0;
14160
14161
14162
14163
14164 stat = ParseRecSetDesc(recordsetname, &allvers, &sets, &settypes, &snames, &filts, &nsets, &rsinfo);
14165
14166 if (stat)
14167 {
14168 goto failure;
14169 }
14170
14171 for (iSet = 0; stat == DRMS_SUCCESS && iSet < nsets; iSet++)
14172 {
14173 char *oneSet = sets[iSet];
14174
14175 if (oneSet && strlen(oneSet) > 0)
14176 {
14177 if (settypes[iSet] == kRecordSetType_DRMS)
14178 {
14179
14180
14181
14182 stat = drms_recordset_query(env, oneSet, &where, &pkwhere, &npkwhere, &seriesname, &filter, &mixed, NULL, &firstlast, &pkwhereNFL, &recnumq);
14183 if (stat)
14184 {
14185 goto failure;
14186 }
14187
14188 query = drms_query_string(env,
14189 seriesname,
14190 where,
14191 pkwhere,
14192 npkwhere,
14193 filter,
14194 mixed,
14195 DRMS_QUERY_FL,
14196 &unique,
14197 keylist,
14198 allvers[iSet] == 'y',
14199 firstlast,
14200 pkwhereNFL,
14201 recnumq,
14202 0,
14203 &limit);
14204 if (!query)
14205 {
14206 goto failure;
14207 }
14208
14209 if (env->verbose)
14210 {
14211 fprintf(stdout, "drms_record_getvector() limit %lld.\n", limit);
14212 }
14213
14214
14215
14216
14217
14218 if (ParseAndExecTempTableSQL(env->session, &query))
14219 {
14220 stat = DRMS_ERROR_QUERYFAILED;
14221 fprintf(stderr, "Failed in drms_record_getvector, query = '%s'\n",query);
14222 goto failure;
14223 }
14224
14225 bres = drms_query_bin(env->session, query);
14226
14227 if (bres)
14228 {
14229 int col, row;
14230 int dims[2];
14231
14232 if (bres->num_rows == limit)
14233 {
14234 stat = DRMS_QUERY_TRUNCATED;
14235 }
14236
14237 dims[0] = keys = bres->num_cols;
14238 dims[1] = count = bres->num_rows;
14239 vectors = drms_array_create(type, 2, dims, NULL, &stat);
14240 if (stat) goto failure;
14241 drms_array2missing(vectors);
14242 for (col=0; col<keys; col++)
14243 {
14244 DB_Type_t db_type = bres->column[col].type;
14245 for (row=0; row<count; row++)
14246 {
14247 int8_t *val = (int8_t *)(vectors->data) + (count * col + row) * drms_sizeof(type);
14248 char *db_src = bres->column[col].data + row * bres->column[col].size;
14249 if (!bres->column[col].is_null[row])
14250 switch(type)
14251 {
14252 case DRMS_TYPE_CHAR:
14253 *(char *)val = dbtype2char(db_type,db_src);
14254 break;
14255 case DRMS_TYPE_SHORT:
14256 *(short *)val = dbtype2short(db_type,db_src);
14257 break;
14258 case DRMS_TYPE_INT:
14259 *(int *)val = dbtype2longlong(db_type,db_src);
14260 break;
14261 case DRMS_TYPE_LONGLONG:
14262 *(long long *)val = dbtype2longlong(db_type,db_src);
14263 break;
14264 case DRMS_TYPE_FLOAT:
14265 *(float *)val = dbtype2float(db_type,db_src);
14266 break;
14267 case DRMS_TYPE_DOUBLE:
14268 *(double *)val = dbtype2double(db_type,db_src);
14269 break;
14270 case DRMS_TYPE_TIME:
14271 *(TIME *)val = dbtype2double(db_type,db_src);
14272 break;
14273 case DRMS_TYPE_STRING:
14274 if (db_type == DB_STRING || db_type == DB_VARCHAR)
14275 *(char **)val = strdup((char *)db_src);
14276 else
14277 {
14278 int len = db_binary_default_width(db_type);
14279 *(char **)val = (char *)malloc(len);
14280 XASSERT(*(char **)val);
14281 dbtype2str(db_type, db_src, len, *(char **)val);
14282 }
14283 break;
14284 default:
14285 fprintf(stderr, "ERROR: Unhandled DRMS type %d\n",(int)type);
14286 XASSERT(0);
14287 goto failure;
14288 }
14289 }
14290 }
14291 if (seriesname) free(seriesname);
14292 if (query) free(query);
14293 if (where) free(where);
14294 if (pkwhere) free(pkwhere);
14295 if (npkwhere) free(npkwhere);
14296 if (pkwhereNFL) hcon_destroy(&pkwhereNFL);
14297 if (status) *status = DRMS_SUCCESS;
14298
14299 if (firstlast)
14300 {
14301 hcon_destroy(&firstlast);
14302 }
14303
14304 FreeRecSetDescArr(&allvers, &sets, &settypes, &snames, &filts, nsets);
14305
14306 db_free_binary_result(bres);
14307 bres = NULL;
14308
14309 return(vectors);
14310 }
14311 }
14312 }
14313 }
14314
14315 failure:
14316 if (seriesname) free(seriesname);
14317 if (query) free(query);
14318 if (where) free(where);
14319 if (pkwhere) free(pkwhere);
14320 if (npkwhere) free(npkwhere);
14321 if (pkwhereNFL) hcon_destroy(&pkwhereNFL);
14322 if (firstlast)
14323 {
14324 hcon_destroy(&firstlast);
14325 }
14326 FreeRecSetDescArr(&allvers, &sets, &settypes, &snames, &filts, nsets);
14327 if (status) *status = stat;
14328 return(NULL);
14329 }
14330
14331
14332
14333 int drms_record_isdsds(DRMS_Record_t *rec)
14334 {
14335 int isdsds = 0;
14336
14337 DRMS_Segment_t *seg = NULL;
14338 HIterator_t *hit = hiter_create(&rec->segments);
14339
14340 if (hit)
14341 {
14342 while (seg = (DRMS_Segment_t *)hiter_getnext(hit))
14343 {
14344 if (seg->info->protocol == DRMS_DSDS)
14345 {
14346 isdsds = 1;
14347 break;
14348 }
14349 }
14350
14351 hiter_destroy(&hit);
14352 }
14353
14354 return isdsds;
14355 }
14356
14357 int drms_record_islocal(DRMS_Record_t *rec)
14358 {
14359 int islocal = 0;
14360
14361 DRMS_Segment_t *seg = NULL;
14362 HIterator_t *hit = hiter_create(&rec->segments);
14363
14364 if (hit)
14365 {
14366 while (seg = (DRMS_Segment_t *)hiter_getnext(hit))
14367 {
14368 if (seg->info->protocol == DRMS_LOCAL)
14369 {
14370 islocal = 1;
14371 break;
14372 }
14373 }
14374
14375 hiter_destroy(&hit);
14376 }
14377
14378 return islocal;
14379 }
14380
14381 DRMS_Segment_t *drms_record_nextseg(DRMS_Record_t *rec, HIterator_t **last, int followlink)
14382 {
14383 DRMS_Segment_t *seg = NULL;
14384 DRMS_Segment_t *segret = NULL;
14385 HIterator_t *hit = NULL;
14386
14387 if (last)
14388 {
14389 if (*last)
14390 {
14391
14392 hit = *last;
14393 }
14394 else
14395 {
14396 hit = *last = (HIterator_t *)malloc(sizeof(HIterator_t));
14397 if (hit != NULL)
14398 {
14399 hiter_new_sort(hit, &(rec->segments), drms_segment_ranksort);
14400 }
14401 }
14402
14403 seg = hiter_getnext(hit);
14404
14405 if (seg && followlink)
14406 {
14407
14408
14409 segret = drms_segment_lookup(rec, seg->info->name);
14410 }
14411 else
14412 {
14413 segret = seg;
14414 }
14415 }
14416
14417 return segret;
14418 }
14419
14420
14421 DRMS_Segment_t *drms_record_nextseg2(DRMS_Record_t *rec, HIterator_t **last, int followlink, DRMS_Segment_t **orig)
14422 {
14423 DRMS_Segment_t *seg = NULL;
14424 DRMS_Segment_t *segret = NULL;
14425 HIterator_t *hit = NULL;
14426
14427 if (last)
14428 {
14429 if (*last)
14430 {
14431
14432 hit = *last;
14433 }
14434 else
14435 {
14436 hit = *last = (HIterator_t *)malloc(sizeof(HIterator_t));
14437 if (hit != NULL)
14438 {
14439 hiter_new_sort(hit, &(rec->segments), drms_segment_ranksort);
14440 }
14441 }
14442
14443 seg = hiter_getnext(hit);
14444
14445 if (seg && followlink)
14446 {
14447
14448
14449 segret = drms_segment_lookup(rec, seg->info->name);
14450 }
14451 else
14452 {
14453 segret = seg;
14454 }
14455
14456 if (orig)
14457 {
14458 *orig = seg;
14459 }
14460 }
14461
14462 return segret;
14463 }
14464
14465
14466
14467
14468 DRMS_Keyword_t *drms_record_nextkey(DRMS_Record_t *rec, HIterator_t **last, int followlink)
14469 {
14470 DRMS_Keyword_t *key = NULL;
14471 DRMS_Keyword_t *keyret = NULL;
14472 HIterator_t *hit = NULL;
14473
14474 if (last)
14475 {
14476 if (*last)
14477 {
14478
14479 hit = *last;
14480 }
14481 else
14482 {
14483 hit = *last = (HIterator_t *)malloc(sizeof(HIterator_t));
14484 if (hit != NULL)
14485 {
14486 hiter_new_sort(hit, &(rec->keywords), drms_keyword_ranksort);
14487 }
14488 }
14489
14490 key = hiter_getnext(hit);
14491
14492 if (key)
14493 {
14494
14495
14496 keyret = drms_keyword_lookup(rec, key->info->name, followlink);
14497 }
14498 }
14499
14500 return keyret;
14501 }
14502
14503
14504 DRMS_Link_t *drms_record_nextlink(DRMS_Record_t *rec, HIterator_t **last)
14505 {
14506 DRMS_Link_t *lnk = NULL;
14507 HIterator_t *hit = NULL;
14508
14509 if (last)
14510 {
14511 if (*last)
14512 {
14513
14514 hit = *last;
14515 }
14516 else
14517 {
14518 hit = *last = (HIterator_t *)malloc(sizeof(HIterator_t));
14519 if (hit != NULL)
14520 {
14521 hiter_new_sort(hit, &(rec->links), drms_link_ranksort);
14522 }
14523 }
14524
14525 lnk = hiter_getnext(hit);
14526 }
14527
14528 return lnk;
14529 }
14530
14531 int drms_record_parserecsetspec(const char *recsetsStr,
14532 char **allvers,
14533 char ***sets,
14534 DRMS_RecordSetType_t **types,
14535 char ***snames,
14536 char ***filts,
14537 int *nsets,
14538 DRMS_RecQueryInfo_t *info)
14539 {
14540 return ParseRecSetDesc(recsetsStr, allvers, sets, types, snames, filts, nsets, info);
14541 }
14542
14543 int drms_record_parserecsetspec_plussegs(const char *recsetsStr, char **allvers, char ***sets, DRMS_RecordSetType_t **types, char ***snames, char ***filts, char ***segs, int *nsets, DRMS_RecQueryInfo_t *info)
14544 {
14545 return ParseRecSetDescInternal(recsetsStr, allvers, sets, types, snames, filts, segs, nsets, info);
14546 }
14547
14548 int drms_record_freerecsetspecarr(char **allvers,
14549 char ***sets,
14550 DRMS_RecordSetType_t **types,
14551 char ***snames,
14552 char ***filts,
14553 int nsets)
14554 {
14555 return FreeRecSetDescArr(allvers, sets, types, snames, filts, nsets);
14556 }
14557
14558 int drms_record_freerecsetspecarr_plussegs(char **allvers, char ***sets, DRMS_RecordSetType_t **types, char ***snames, char ***filts, char ***segs, int nsets)
14559 {
14560 return FreeRecSetDescArrInternal(allvers, sets, types, snames, filts, segs, nsets);
14561 }