00001
00002
00003 #include "drms.h"
00004 #include "drms_priv.h"
00005 #include "xmem.h"
00006
00007
00008
00009
00010
00011
00012 static int drms_link_resolve(DRMS_Link_t *link);
00013
00014
00015
00016 static int drms_link_resolveall(DRMS_Link_t *link, int *n, long long **recnums);
00017
00018
00019
00020 void drms_free_template_link_struct(DRMS_Link_t *link)
00021 {
00022 if (link->info->type == DYNAMIC_LINK) {
00023 for (int i = 0; i < link->info->pidx_num; i++)
00024 free(link->info->pidx_name[i]);
00025 }
00026 free(link->info);
00027 }
00028
00029
00030 void drms_free_link_struct(DRMS_Link_t *link)
00031 {
00032 int i;
00033
00034
00035 if (link->info->type == DYNAMIC_LINK)
00036 {
00037 for (i=0; i<link->info->pidx_num; i++)
00038 {
00039 if (link->info->pidx_type[i] == DRMS_TYPE_STRING &&
00040 link->pidx_value[i].string_val != NULL)
00041 {
00042 free(link->pidx_value[i].string_val);
00043 }
00044 }
00045 }
00046 }
00047
00048
00049 void drms_copy_link_struct(DRMS_Link_t *dst, DRMS_Link_t *src)
00050 {
00051 int i;
00052
00053
00054 memcpy(dst, src, sizeof(DRMS_Link_t));
00055
00056
00057 if (src->info->type == DYNAMIC_LINK)
00058 {
00059 for (i=0; i<src->info->pidx_num; i++)
00060 {
00061 if (src->info->pidx_type[i] == DRMS_TYPE_STRING &&
00062 src->pidx_value[i].string_val != NULL)
00063 {
00064 copy_string(&dst->pidx_value[i].string_val,
00065 src->pidx_value[i].string_val);
00066 }
00067 }
00068 }
00069 }
00070
00071
00072 HContainer_t *drms_create_link_prototypes(DRMS_Record_t *target,
00073 DRMS_Record_t *source,
00074 int *status)
00075 {
00076 HContainer_t *ret = NULL;
00077 DRMS_Link_t *tLink = NULL;
00078 DRMS_Link_t *sLink = NULL;
00079
00080 XASSERT(target != NULL && target->links.num_total == 0 && source != NULL);
00081
00082 if (target != NULL && target->links.num_total == 0 && source != NULL)
00083 {
00084 *status = DRMS_SUCCESS;
00085 HIterator_t hit;
00086
00087 hiter_new_sort(&hit, &(source->links), drms_link_ranksort);
00088
00089 while ((sLink = hiter_getnext(&hit)) != NULL)
00090 {
00091 if (sLink->info && strlen(sLink->info->name) > 0)
00092 {
00093 tLink = hcon_allocslot_lower(&(target->links), sLink->info->name);
00094 XASSERT(tLink);
00095 memset(tLink, 0, sizeof(DRMS_Link_t));
00096 tLink->info = malloc(sizeof(DRMS_LinkInfo_t));
00097 XASSERT(tLink->info);
00098 memset(tLink->info, 0, sizeof(DRMS_LinkInfo_t));
00099
00100 if (tLink && tLink->info)
00101 {
00102
00103 tLink->record = target;
00104
00105 memcpy(tLink->pidx_value,
00106 sLink->pidx_value,
00107 DRMS_MAXPRIMIDX * sizeof(DRMS_Type_Value_t));
00108
00109
00110 memcpy(tLink->info, sLink->info, sizeof(DRMS_LinkInfo_t));
00111
00112 int idx = 0;
00113 for (; idx < tLink->info->pidx_num; idx++)
00114 {
00115 tLink->info->pidx_name[idx] = strdup(sLink->info->pidx_name[idx]);
00116
00117
00118 if (tLink->info->pidx_type[idx] == DRMS_TYPE_STRING &&
00119 sLink->pidx_value[idx].string_val != NULL)
00120 {
00121 copy_string(&(tLink->pidx_value[idx].string_val),
00122 sLink->pidx_value[idx].string_val);
00123 }
00124 }
00125
00126 tLink->recnum = sLink->recnum;
00127 tLink->isset = sLink->isset;
00128
00129 }
00130 else
00131 {
00132 *status = DRMS_ERROR_OUTOFMEMORY;
00133 }
00134 }
00135 else
00136 {
00137 *status = DRMS_ERROR_INVALIDLINK;
00138 }
00139 }
00140
00141 hiter_free(&hit);
00142
00143 if (*status == DRMS_SUCCESS)
00144 {
00145 ret = &(target->links);
00146 }
00147 }
00148 else
00149 {
00150 *status = DRMS_ERROR_INVALIDRECORD;
00151 }
00152
00153 return ret;
00154 }
00155
00156
00157 int drms_setlink_static(DRMS_Record_t *rec, const char *linkname, long long recnum)
00158 {
00159 DRMS_Link_t *link;
00160
00161 if ( (link = hcon_lookup_lower(&rec->links,linkname)) == NULL )
00162 return DRMS_ERROR_UNKNOWNLINK;
00163
00164 if (link->info->type==STATIC_LINK)
00165 {
00166 link->recnum = recnum;
00167
00168 return DRMS_SUCCESS;
00169 }
00170 else
00171 return DRMS_ERROR_INVALIDLINKTYPE;
00172 }
00173
00174 int drms_setlink_dynamic(DRMS_Record_t *rec, const char *linkname,
00175 DRMS_Type_t *types, DRMS_Type_Value_t *values)
00176 {
00177 int i;
00178 DRMS_Link_t *link;
00179
00180 if ( (link = hcon_lookup_lower(&rec->links,linkname)) == NULL )
00181 return DRMS_ERROR_UNKNOWNLINK;
00182
00183 if (link->info->type==DYNAMIC_LINK)
00184 {
00185 for (i=0; i<link->info->pidx_num; i++)
00186 {
00187 if (types[i] != link->info->pidx_type[i])
00188 return DRMS_ERROR_INVALIDLINKTYPE;
00189 }
00190 for (i=0; i<link->info->pidx_num; i++)
00191 {
00192 drms_copy_drms2drms(types[i], &link->pidx_value[i], &values[i]);
00193 }
00194 link->isset = 1;
00195 return DRMS_SUCCESS;
00196 }
00197 else
00198 return DRMS_ERROR_INVALIDLINKTYPE;
00199 }
00200
00201 int drms_link_set(const char *linkname, DRMS_Record_t *baserec, DRMS_Record_t *supplementingrec)
00202 {
00203 int status;
00204 DRMS_Link_t *link = NULL;
00205
00206 if ((link = hcon_lookup_lower(&baserec->links, linkname)) == NULL)
00207 {
00208 status = DRMS_ERROR_UNKNOWNLINK;
00209 }
00210 else
00211 {
00212 if (link->info->type == DYNAMIC_LINK)
00213 {
00214 DRMS_Type_t pidxtypes[DRMS_MAXPRIMIDX];
00215 DRMS_Type_Value_t pidxvalues[DRMS_MAXPRIMIDX] = {0};
00216 int npidx = supplementingrec->seriesinfo->pidx_num;
00217 int ikey;
00218 DRMS_Keyword_t *pkey;
00219 DRMS_Keyword_t *keyinstance ;
00220
00221 memset(pidxtypes, 0, sizeof(DRMS_Type_t) * DRMS_MAXPRIMIDX);
00222
00223 for (ikey = 0; ikey < npidx; ikey++)
00224 {
00225 pkey = supplementingrec->seriesinfo->pidx_keywords[ikey];
00226 pidxtypes[ikey] = pkey->info->type;
00227
00228
00229
00230 keyinstance = drms_keyword_lookup(supplementingrec, pkey->info->name, 0);
00231
00232 if (!keyinstance)
00233 {
00234 status = DRMS_ERROR_INVALIDKEYWORD;
00235 }
00236
00237 pidxvalues[ikey] = keyinstance->value;
00238 }
00239
00240 status = drms_setlink_dynamic(baserec, linkname, pidxtypes, pidxvalues);
00241 }
00242 else if (link->info->type == STATIC_LINK)
00243 {
00244 status = drms_setlink_static(baserec, linkname, supplementingrec->recnum);
00245 }
00246 else
00247 {
00248 status = DRMS_ERROR_INVALIDDATA;
00249 }
00250 }
00251
00252 return status;
00253 }
00254
00255
00256 DRMS_Record_t *drms_link_follow(DRMS_Record_t *rec, const char *linkname,
00257 int *status)
00258 {
00259 DRMS_Link_t *link = NULL;
00260 char hashkey[DRMS_MAXHASHKEYLEN];
00261 DRMS_Record_t *linkedRec = NULL;
00262
00263 if ( (link = hcon_lookup_lower(&rec->links,linkname)) == NULL )
00264 {
00265 if (status)
00266 *status = DRMS_ERROR_UNKNOWNLINK;
00267 return NULL;
00268 }
00269 if ((link->info->type == STATIC_LINK && link->recnum==-1) ||
00270 (link->info->type == DYNAMIC_LINK && !link->isset))
00271 {
00272 if (status)
00273 *status = DRMS_ERROR_LINKNOTSET;
00274 return NULL;
00275 }
00276 if (drms_link_resolve(link))
00277 {
00278 if (status)
00279 *status = DRMS_ERROR_BADLINK;
00280 return NULL;
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 drms_make_hashkey(hashkey, link->info->target_series, link->recnum);
00303
00304 if ((linkedRec = hcon_lookup(&rec->env->record_cache, hashkey)) != NULL)
00305 {
00306
00307 if (status)
00308 {
00309 *status = DRMS_SUCCESS;
00310 }
00311
00312 if (link->wasFollowed)
00313 {
00314
00315
00316
00317 }
00318 else
00319 {
00320
00321
00322
00323
00324 ++linkedRec->refcount;
00325 link->wasFollowed = 1;
00326 }
00327
00328 return linkedRec;
00329 }
00330 else
00331 {
00332
00333 XASSERT(!link->wasFollowed);
00334
00335 link->wasFollowed = 1;
00336 return drms_retrieve_record(rec->env, link->info->target_series, link->recnum, NULL, status);
00337 }
00338 }
00339
00340
00341 #if 0
00342
00343
00344
00345
00346
00347
00348 DRMS_RecordSet_t *drms_link_followall(DRMS_Record_t *rec, const char *linkname,
00349 int *status)
00350 {
00351 int stat;
00352 DRMS_RecordSet_t *result;
00353 DRMS_Link_t *link;
00354 int i;
00355 long long *recnums;
00356
00357 result = malloc(sizeof(DRMS_RecordSet_t));
00358 XASSERT(result);
00359 if ( (link = hcon_lookup_lower(&rec->links,linkname)) == NULL )
00360 {
00361 stat = DRMS_ERROR_UNKNOWNLINK;
00362 goto bailout;
00363 }
00364 if ((link->info->type == STATIC_LINK && link->recnum==-1) ||
00365 (link->info->type == DYNAMIC_LINK && !link->isset)) {
00366 if (status)
00367 *status = DRMS_ERROR_LINKNOTSET;
00368 return NULL;
00369 }
00370
00371 result->ss_n = 0;
00372 result->ss_queries = NULL;
00373 result->ss_types = NULL;
00374 result->ss_starts = NULL;
00375
00376 if (drms_link_resolveall(link, &result->n, &recnums))
00377 {
00378 if (recnums)
00379 free(recnums);
00380 stat = DRMS_ERROR_BADLINK;
00381 goto bailout;
00382 }
00383 result->records = malloc(result->n*sizeof(DRMS_Record_t *));
00384 XASSERT(result->records);
00385 for (i=0; i<result->n; i++)
00386 {
00387 result->records[i] = drms_retrieve_record(rec->env, link->info->target_series,
00388 recnums[i], NULL, &stat);
00389 if (stat)
00390 {
00391 fprintf(stderr, "ERROR in drms_link_followall: drms_retrieve failed "
00392 "for series='%s', recnum=%lld\n",link->info->target_series,recnums[i]);
00393 result->n = i;
00394 drms_free_records(result);
00395 goto bailout;
00396 }
00397 }
00398 if (recnums)
00399 free(recnums);
00400
00401 return result;
00402
00403 bailout:
00404 free(result);
00405 if (status)
00406 *status = stat;
00407 return NULL;
00408 }
00409 #endif
00410
00411
00412
00413 static int drms_link_resolve(DRMS_Link_t *link)
00414 {
00415 int i, n;
00416 long long maxrecnum, *recnums;
00417
00418
00419
00420 if (link->info->type == STATIC_LINK || link->recnum>=0 )
00421 {
00422 return 0;
00423 }
00424 else
00425 {
00426 if (drms_link_resolveall(link, &n, &recnums))
00427 return 1;
00428
00429
00430 maxrecnum = recnums[0];
00431 for(i=1; i<n; i++)
00432 {
00433 if (recnums[i]>maxrecnum)
00434 maxrecnum = recnums[i];
00435 }
00436 link->recnum = maxrecnum;
00437 free(recnums);
00438 return 0;
00439 }
00440 }
00441
00442
00443
00444 static int drms_link_resolveall(DRMS_Link_t *link, int *n, long long **recnums)
00445 {
00446 char query[DRMS_MAXQUERYLEN+DRMS_MAXPRIMIDX*DRMS_MAXKEYNAMELEN], *p;
00447 DB_Binary_Result_t *qres;
00448 DRMS_Env_t *env;
00449 int i;
00450 void *argin[DRMS_MAXPRIMIDX];
00451 DB_Type_t intype[DRMS_MAXPRIMIDX];
00452 char *table;
00453
00454
00455
00456 if (link->info->type == STATIC_LINK )
00457 {
00458 *n = 1;
00459 *recnums = malloc(*n*sizeof(long long));
00460 XASSERT(*recnums);
00461 (*recnums)[0] = link->recnum;
00462 return 0;
00463 }
00464 else
00465 {
00466 XASSERT(link->info->pidx_num>0);
00467 env = link->record->env;
00468
00469
00470
00471
00472
00473
00474
00475 table = strdup(link->info->target_series);
00476 strtolower(table);
00477 p = query;
00478 p += sprintf(p, "select recnum from %s where ", table);
00479 free(table);
00480 p += sprintf(p, "%s=?", link->info->pidx_name[0]);
00481 for (i=1; i<link->info->pidx_num; i++)
00482 {
00483 p += sprintf(p, " and %s=?", link->info->pidx_name[i]);
00484 }
00485 *p = 0;
00486
00487
00488 for (i=0; i<link->info->pidx_num; i++)
00489 {
00490 intype[i] = drms2dbtype(link->info->pidx_type[i]);
00491 argin[i] = drms_addr(link->info->pidx_type[i], &link->pidx_value[i]);
00492 }
00493
00494 #ifdef DEBUG
00495 printf("query string in drms_link_resolve = '%s'\n",query);
00496 #endif
00497
00498
00499 qres = drms_query_bin_array(env->session, query, link->info->pidx_num,
00500 intype, argin);
00501 if (qres==NULL || qres->num_rows <= 0)
00502 return 1;
00503
00504
00505 *n = qres->num_rows;
00506 *recnums = malloc(*n*sizeof(long long));
00507 XASSERT(*recnums);
00508 for(i=0; i<(int)qres->num_rows; i++)
00509 {
00510 (*recnums)[i] = db_binary_field_getlonglong(qres,i,0);
00511 }
00512 #ifdef DEBUG
00513 printf("Link resolved to series='%s', recnum=%lld\n",link->info->target_series,
00514 link->recnum);
00515 #endif
00516 db_free_binary_result(qres);
00517 return 0;
00518 }
00519 }
00520
00521 void drms_link_print(DRMS_Link_t *link)
00522 {
00523 drms_link_fprint(stdout, link);
00524 }
00525
00526 void drms_link_fprint(FILE *keyfile, DRMS_Link_t *link)
00527 {
00528 const int fieldwidth=13;
00529 int i;
00530
00531 fprintf(keyfile, "\t%-*s:\t'%s'\n", fieldwidth, "Name", link->info->name);
00532 fprintf(keyfile, "\t%-*s:\t'%s'\n", fieldwidth, "Target series", link->info->target_series);
00533 fprintf(keyfile, "\t%-*s:\t%s\n", fieldwidth, "Description", link->info->description);
00534 if (link->info->type == STATIC_LINK)
00535 {
00536 fprintf(keyfile, "\t%-*s:\t%s\n", fieldwidth, "Type", "STATIC_LINK");
00537 }
00538 else
00539 {
00540 fprintf(keyfile, "\t%-*s:\t%s\n", fieldwidth, "Type", "DYNAMIC_LINK");
00541 fprintf(keyfile, "\t%-*s:\t%d\n", fieldwidth, "Pidx_num", link->info->pidx_num);
00542 for(i=0;i<link->info->pidx_num; i++)
00543 {
00544 fprintf(keyfile, "\t%-*s%1d :\t%s\n", fieldwidth-2, "Pidx_name", i,
00545 link->info->pidx_name[i]);
00546 fprintf(keyfile, "\t%-*s%1d :\t%s\n", fieldwidth-2, "Pidx_type", i,
00547 drms_type2str(link->info->pidx_type[i]));
00548 fprintf(keyfile, "\t%-*s%1d :\t", fieldwidth-2, "Pidx_value", i);
00549 drms_fprintfval(keyfile, link->info->pidx_type[i], &link->pidx_value[i]);
00550 fprintf(keyfile, "\n");
00551 }
00552 }
00553 fprintf(keyfile, "\t%-*s:\t%lld\n", fieldwidth, "Recnum", link->recnum);
00554 }
00555
00556
00557
00558
00559
00560
00561
00562 int drms_template_links(DRMS_Record_t *template)
00563 {
00564 int i,j, status = DRMS_NO_ERROR;
00565 DRMS_Env_t *env;
00566 char buf[DRMS_MAXLINKNAMELEN], query[DRMS_MAXQUERYLEN];
00567 DRMS_Link_t *link;
00568 DB_Binary_Result_t *qres;
00569 int rank;
00570
00571 env = template->env;
00572
00573
00574 hcon_init(&template->links, sizeof(DRMS_Link_t), DRMS_MAXHASHKEYLEN,
00575 (void (*)(const void *)) drms_free_link_struct,
00576 (void (*)(const void *, const void *)) drms_copy_link_struct);
00577
00578
00579 char *namespace = ns(template->seriesinfo->seriesname);
00580 char *lcseries = strdup(template->seriesinfo->seriesname);
00581
00582 if (!lcseries)
00583 {
00584 status = DRMS_ERROR_OUTOFMEMORY;
00585 goto bailout;
00586 }
00587
00588 strtolower(lcseries);
00589
00590 sprintf(query, "select linkname, target_seriesname, type, description "
00591 "from %s.%s where lower(seriesname) = '%s' order by linkname",
00592 namespace, DRMS_MASTER_LINK_TABLE, lcseries);
00593 free(lcseries);
00594 free(namespace);
00595 if ((qres = drms_query_bin(env->session, query)) == NULL)
00596 {
00597 printf("Failed to retrieve link definitions for series %s.\n",
00598 template->seriesinfo->seriesname);
00599 return DRMS_ERROR_QUERYFAILED;
00600 }
00601
00602 if (qres->num_rows>0 && qres->num_cols != 4 )
00603 {
00604 status = DRMS_ERROR_BADFIELDCOUNT;
00605 goto bailout;
00606 }
00607
00608 rank = 0;
00609 for (i = 0; i<(int)qres->num_rows; i++)
00610 {
00611
00612 db_binary_field_getstr(qres, i, 0, sizeof(buf), buf);
00613 link = hcon_allocslot_lower(&template->links, buf);
00614 memset(link,0,sizeof(DRMS_Link_t));
00615 link->info = malloc(sizeof(DRMS_LinkInfo_t));
00616 XASSERT(link->info);
00617 memset(link->info,0,sizeof(DRMS_LinkInfo_t));
00618
00619 link->record = template;
00620 strcpy(link->info->name, buf);
00621 db_binary_field_getstr(qres, i, 1, sizeof(link->info->target_series), link->info->target_series);
00622 db_binary_field_getstr(qres, i, 2, sizeof(buf), buf);
00623 if (!strcmp(buf,"static"))
00624 link->info->type = STATIC_LINK;
00625 else if (!strcmp(buf,"dynamic"))
00626 link->info->type = DYNAMIC_LINK;
00627 else
00628 {
00629 fprintf(stderr,"ERROR: '%s' is not a valid link type.\n",buf);
00630 goto bailout;
00631 }
00632 db_binary_field_getstr(qres, i, 3, DRMS_MAXCOMMENTLEN, link->info->description);
00633 #ifdef DEBUG
00634 printf("Link %d: name='%s', target_series='%s', type=%d, description=%s\n",
00635 i, link->name, link->target_series, link->type, link->info->description);
00636 #endif
00637 link->info->pidx_num = -1;
00638
00639
00640
00641
00642 link->info->rank = rank++;
00643
00644 for(j=0; j<DRMS_MAXPRIMIDX; j++)
00645 {
00646 memset(&link->pidx_value[j],0,sizeof(DRMS_Type_Value_t));
00647 }
00648 link->isset = 0;
00649 link->wasFollowed = 0;
00650 link->recnum = -1;
00651 }
00652 db_free_binary_result(qres);
00653 return DRMS_SUCCESS;
00654
00655 bailout:
00656 db_free_binary_result(qres);
00657 return status;
00658 }
00659
00660
00661
00662
00663
00664
00665 int drms_link_getpidx(DRMS_Record_t *rec)
00666 {
00667 int i, status;
00668 DRMS_Keyword_t *key;
00669 DRMS_Record_t *template;
00670 DRMS_Link_t *link;
00671 HIterator_t hit;
00672
00673 status = DRMS_SUCCESS;
00674
00675 hiter_new(&hit, &rec->links);
00676 while( (link = (DRMS_Link_t *)hiter_getnext(&hit)) )
00677 {
00678
00679 if (link->info->type == DYNAMIC_LINK && link->info->pidx_num == -1)
00680 {
00681 template = drms_template_record(link->record->env,
00682 link->info->target_series,&status);
00683 if (template==NULL)
00684 {
00685 fprintf(stderr,"ERROR: Couldn't get template for series '%s'.\n"
00686 "drms_template_record returned status=%d\n",
00687 link->info->target_series, status);
00688 return;
00689 }
00690
00691 link->info->pidx_num = template->seriesinfo->pidx_num;
00692 for (i=0; i<link->info->pidx_num; i++)
00693 {
00694 key = template->seriesinfo->pidx_keywords[i];
00695 link->info->pidx_type[i] = key->info->type;
00696 copy_string(&link->info->pidx_name[i], key->info->name);
00697 }
00698 }
00699 }
00700
00701 hiter_free(&hit);
00702
00703 return status;
00704 }