1/*
2 * Legal Notice
3 *
4 * This document and associated source code (the "Work") is a part of a
5 * benchmark specification maintained by the TPC.
6 *
7 * The TPC reserves all right, title, and interest to the Work as provided
8 * under U.S. and international laws, including without limitation all patent
9 * and trademark rights therein.
10 *
11 * No Warranty
12 *
13 * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION
14 * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE
15 * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER
16 * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
17 * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES,
18 * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR
19 * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF
20 * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE.
21 * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT,
22 * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT
23 * WITH REGARD TO THE WORK.
24 * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO
25 * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE
26 * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS
27 * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT,
28 * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY,
29 * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT
30 * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD
31 * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * Contributors:
34 * Gradient Systems
35 */
36#include "config.h"
37#include "porting.h"
38#include <stdio.h>
39#include <fcntl.h>
40#include <assert.h>
41#ifdef WIN32
42#include <io.h>
43#include <stdlib.h>
44#include <search.h>
45#else
46#include <sys/types.h>
47#include <sys/stat.h>
48#include <netinet/in.h>
49#endif
50#ifdef NCR
51#include <sys/types.h>
52#endif
53#ifndef USE_STDLIB_H
54#include <malloc.h>
55#endif
56#include "config.h"
57#include "decimal.h"
58#include "date.h"
59#include "dist.h"
60#include "genrand.h"
61#include "error_msg.h"
62#include "r_params.h"
63#include "dcomp.h"
64#ifdef TEST
65option_t options[] = {{"DISTRIBUTIONS", OPT_STR, 2, "read distributions from file <s>", NULL, "tester_dist.idx"}, NULL};
66
67char params[2];
68struct {
69 char *name;
70} tdefs[] = {NULL};
71#endif
72
73/* NOTE: these need to be in sync with a_dist.h */
74#define D_NAME_LEN 20
75#define FL_LOADED 0x01
76static int load_dist(d_idx_t *d);
77
78/*
79 * Routine: di_compare()
80 * Purpose: comparison routine for two d_idx_t entries; used by qsort
81 * Algorithm:
82 * Data Structures:
83 *
84 * Params:
85 * Returns:
86 * Called By:
87 * Calls:
88 * Assumptions:
89 * Side Effects:
90 * TODO: None
91 */
92int di_compare(const void *op1, const void *op2) {
93 d_idx_t *ie1 = (d_idx_t *)op1, *ie2 = (d_idx_t *)op2;
94
95 return (strcasecmp(ie1->name, ie2->name));
96}
97
98/*
99 * Routine: find_dist(char *name)
100 * Purpose: translate from dist_t name to d_idx_t *
101 * Algorithm:
102 * Data Structures:
103 *
104 * Params:
105 * Returns:
106 * Called By:
107 * Calls:
108 * Assumptions:
109 * Side Effects:
110 * TODO: None
111 */
112d_idx_t *find_dist(char *name) {
113 static int index_loaded = 0, entry_count;
114 static d_idx_t *idx = NULL;
115 d_idx_t key, *id = NULL;
116 int i;
117 FILE *ifp;
118 int32_t temp;
119
120 /* load the index if this is the first time through */
121 if (!index_loaded) {
122 /* make sure that this is read one thread at a time */
123 if (!index_loaded) /* make sure no one beat us to it */
124 {
125
126 /* open the dist file */
127 if ((ifp = fopen(get_str("DISTRIBUTIONS"), "rb")) == NULL) {
128 fprintf(stderr, "Error: open of distributions failed: ");
129 perror(get_str("DISTRIBUTIONS"));
130 exit(1);
131 }
132 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
133 fprintf(stderr, "Error: read of index count failed: ");
134 perror(get_str("DISTRIBUTIONS"));
135 exit(2);
136 }
137 entry_count = ntohl(temp);
138 if ((temp = fseek(ifp, -entry_count * IDX_SIZE, SEEK_END)) < 0) {
139 fprintf(stderr, "Error: lseek to index failed: ");
140 fprintf(stderr, "attempting to reach %d\nSystem error: ", (int)(-entry_count * IDX_SIZE));
141 perror(get_str("DISTRIBUTIONS"));
142 exit(3);
143 }
144 idx = (d_idx_t *)malloc(entry_count * sizeof(d_idx_t));
145 MALLOC_CHECK(idx);
146 for (i = 0; i < entry_count; i++) {
147 memset(idx + i, 0, sizeof(d_idx_t));
148 if (fread(idx[i].name, 1, D_NAME_LEN, ifp) < D_NAME_LEN) {
149 fprintf(stderr, "Error: read index failed (1): ");
150 perror(get_str("DISTRIBUTIONS"));
151 exit(2);
152 }
153 idx[i].name[D_NAME_LEN] = '\0';
154 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
155 fprintf(stderr, "Error: read index failed (2): ");
156 perror(get_str("DISTRIBUTIONS"));
157 exit(2);
158 }
159 idx[i].index = ntohl(temp);
160 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
161 fprintf(stderr, "Error: read index failed (4): ");
162 perror(get_str("DISTRIBUTIONS"));
163 exit(2);
164 }
165 idx[i].offset = ntohl(temp);
166 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
167 fprintf(stderr, "Error: read index failed (5): ");
168 perror(get_str("DISTRIBUTIONS"));
169 exit(2);
170 }
171 idx[i].str_space = ntohl(temp);
172 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
173 fprintf(stderr, "Error: read index failed (6): ");
174 perror(get_str("DISTRIBUTIONS"));
175 exit(2);
176 }
177 idx[i].length = ntohl(temp);
178 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
179 fprintf(stderr, "Error: read index failed (7): ");
180 perror(get_str("DISTRIBUTIONS"));
181 exit(2);
182 }
183 idx[i].w_width = ntohl(temp);
184 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
185 fprintf(stderr, "Error: read index failed (8): ");
186 perror(get_str("DISTRIBUTIONS"));
187 exit(2);
188 }
189 idx[i].v_width = ntohl(temp);
190 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
191 fprintf(stderr, "Error: read index failed (9): ");
192 perror(get_str("DISTRIBUTIONS"));
193 exit(2);
194 }
195 idx[i].name_space = ntohl(temp);
196 idx[i].dist = NULL;
197 }
198 qsort((void *)idx, entry_count, sizeof(d_idx_t), di_compare);
199 index_loaded = 1;
200
201 /* make sure that this is read one thread at a time */
202 fclose(ifp);
203 }
204 }
205
206 /* find the distribution, if it exists and move to it */
207 strcpy(key.name, name);
208 id = (d_idx_t *)bsearch((void *)&key, (void *)idx, entry_count, sizeof(d_idx_t), di_compare);
209 if (id != NULL) /* found a valid distribution */
210 if (id->flags != FL_LOADED) /* but it needs to be loaded */
211 load_dist(id);
212
213 return (id);
214}
215
216/*
217 * Routine: load_dist(int fd, dist_t *d)
218 * Purpose: load a particular distribution
219 * Algorithm:
220 * Data Structures:
221 *
222 * Params:
223 * Returns:
224 * Called By:
225 * Calls:
226 * Assumptions:
227 * Side Effects:
228 * TODO: None
229 */
230static int load_dist(d_idx_t *di) {
231 int res = 0, i, j;
232 dist_t *d;
233 int32_t temp;
234 FILE *ifp;
235
236 if (di->flags != FL_LOADED) /* make sure no one beat us to it */
237 {
238 if ((ifp = fopen(get_str("DISTRIBUTIONS"), "rb")) == NULL) {
239 fprintf(stderr, "Error: open of distributions failed: ");
240 perror(get_str("DISTRIBUTIONS"));
241 exit(1);
242 }
243
244 if ((temp = fseek(ifp, di->offset, SEEK_SET)) < 0) {
245 fprintf(stderr, "Error: lseek to distribution failed: ");
246 perror("load_dist()");
247 exit(2);
248 }
249
250 di->dist = (dist_t *)malloc(sizeof(struct DIST_T));
251 MALLOC_CHECK(di->dist);
252 d = di->dist;
253
254 // fprintf(stderr, "\ndist %s ", di->name);
255
256 /* load the type information */
257 d->type_vector = (int *)malloc(sizeof(int32_t) * di->v_width);
258 MALLOC_CHECK(d->type_vector);
259 for (i = 0; i < di->v_width; i++) {
260 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
261 fprintf(stderr, "Error: read of type vector failed for '%s': ", di->name);
262 perror("load_dist()");
263 exit(3);
264 }
265 d->type_vector[i] = ntohl(temp);
266 // fprintf(stderr, "type %d, ", d->type_vector[i]);
267 }
268
269 /* load the weights */
270 d->weight_sets = (int **)malloc(sizeof(int *) * di->w_width);
271 d->maximums = (int *)malloc(sizeof(int32_t) * di->w_width);
272 MALLOC_CHECK(d->weight_sets);
273 MALLOC_CHECK(d->maximums);
274 for (i = 0; i < di->w_width; i++) {
275 *(d->weight_sets + i) = (int *)malloc(di->length * sizeof(int32_t));
276 MALLOC_CHECK(*(d->weight_sets + i));
277 d->maximums[i] = 0;
278 for (j = 0; j < di->length; j++) {
279 if (fread(&temp, 1, sizeof(int32_t), ifp) < 0) {
280 fprintf(stderr, "Error: read of weights failed: ");
281 perror("load_dist()");
282 exit(3);
283 }
284 *(*(d->weight_sets + i) + j) = ntohl(temp);
285 /* calculate the maximum weight and convert sets to cummulative
286 */
287 d->maximums[i] += d->weight_sets[i][j];
288 d->weight_sets[i][j] = d->maximums[i];
289 }
290 }
291
292 /* load the value offsets */
293 d->value_sets = (int **)malloc(sizeof(int *) * di->v_width);
294 MALLOC_CHECK(d->value_sets);
295 for (i = 0; i < di->v_width; i++) {
296 *(d->value_sets + i) = (int *)malloc(di->length * sizeof(int32_t));
297 MALLOC_CHECK(*(d->value_sets + i));
298 for (j = 0; j < di->length; j++) {
299 if (fread(&temp, 1, sizeof(int32_t), ifp) != sizeof(int32_t)) {
300 fprintf(stderr, "Error: read of values failed: ");
301 perror("load_dist()");
302 exit(4);
303 }
304 *(*(d->value_sets + i) + j) = ntohl(temp);
305 }
306 }
307
308 /* load the column aliases, if they were defined */
309 if (di->name_space) {
310 d->names = (char *)malloc(di->name_space);
311 MALLOC_CHECK(d->names);
312 if (fread(d->names, 1, di->name_space * sizeof(char), ifp) < 0) {
313 fprintf(stderr, "Error: read of names failed: ");
314 perror("load_dist()");
315 exit(599);
316 }
317 }
318
319 /* and finally the values themselves */
320 d->strings = (char *)malloc(sizeof(char) * di->str_space);
321 MALLOC_CHECK(d->strings);
322 if (fread(d->strings, 1, di->str_space * sizeof(char), ifp) < 0) {
323 fprintf(stderr, "Error: read of strings failed: ");
324 perror("load_dist()");
325 exit(5);
326 }
327
328 fclose(ifp);
329
330 //
331 // fprintf(stderr, "%s {\n", di->name);
332 //
333 // // type_vector
334 // fprintf(stderr, "{");
335 //
336 // for (int i = 0 ; i < di->v_width; i++) {
337 // fprintf(stderr, "%d", d->type_vector[i]);
338 //
339 // if (i < di->v_width-1) {
340 // fprintf(stderr, ", ");
341 //
342 // }
343 // }
344 // fprintf(stderr, "},");
345 //
346 //// weight_sets
347 // fprintf(stderr, "{");
348 // for (int i = 0 ; i < di->w_width; i++) {
349 // fprintf(stderr, "{");
350 //
351 // for (int j = 0 ; j < di->length; j++) {
352 //
353 // fprintf(stderr, "%d", d->weight_sets[i][j]);
354 //
355 //
356 //
357 // if (j < di->length-1) {
358 // fprintf(stderr, ", ");
359 //
360 // }
361 // }
362 // fprintf(stderr, "},");
363 //
364 //
365 //
366 // if (i < di->w_width-1) {
367 // fprintf(stderr, ", ");
368 //
369 // }
370 // }
371 // fprintf(stderr, "},");
372 //
373 //
374 // // maximums
375 // fprintf(stderr, "{");
376 //
377 // for (int i = 0 ; i < di->w_width; i++) {
378 // fprintf(stderr, "%d", d->maximums[i]);
379 //
380 // if (i < di->w_width-1) {
381 // fprintf(stderr, ", ");
382 //
383 // }
384 // }
385 // fprintf(stderr, "},");
386 //
387 //
388 //
389 // // value sets
390 // fprintf(stderr, "{");
391 // for (int i = 0 ; i < di->v_width; i++) {
392 // fprintf(stderr, "{");
393 //
394 // for (int j = 0 ; j < di->length; j++) {
395 //
396 // fprintf(stderr, "%d", d->value_sets[i][j]);
397 //
398 //
399 //
400 // if (j < di->length-1) {
401 // fprintf(stderr, ", ");
402 //
403 // }
404 // }
405 // fprintf(stderr, "},");
406 //
407 //
408 //
409 // if (i < di->v_width-1) {
410 // fprintf(stderr, ", ");
411 //
412 // }
413 // }
414 // fprintf(stderr, "},");
415 //
416 //
417 //// strings
418 //
419 //
420 // fprintf(stderr, "{");
421 //
422 // for (int i = 0 ; i < di->str_space; i++) {
423 // fprintf(stderr, "%d", (int) d->strings[i]);
424 //
425 // if (i < di->str_space-1) {
426 // fprintf(stderr, ", ");
427 //
428 // }
429 // }
430 // fprintf(stderr, "},");
431 //
432 //
433 //
434 // // names
435 //
436 // fprintf(stderr, "{");
437 //
438 // for (int i = 0 ; i < di->name_space; i++) {
439 // fprintf(stderr, "%d", (int) d->names[i]);
440 //
441 // if (i < di->name_space-1) {
442 // fprintf(stderr, ", ");
443 //
444 // }
445 // }
446 // fprintf(stderr, "},");
447 //
448 //
449 //
450 // // size
451 // fprintf(stderr, "%d}\n", d->size);
452
453 di->flags = FL_LOADED;
454 }
455
456 return (res);
457}
458
459/*
460 * Routine: void *dist_op()
461 * Purpose: select a value/weight from a distribution
462 * Algorithm:
463 * Data Structures:
464 *
465 * Params: char *d_name
466 * int vset: which set of values
467 * int wset: which set of weights
468 * Returns: appropriate data type cast as a void *
469 * Called By:
470 * Calls:
471 * Assumptions:
472 * Side Effects:
473 * TODO: 20000317 Need to be sure this is portable to NT and others
474 */
475int dist_op(void *dest, int op, char *d_name, int vset, int wset, int stream) {
476 d_idx_t *d;
477 dist_t *dist;
478 int level, index = 0, dt;
479 char *char_val;
480 int i_res = 1;
481
482 if ((d = find_dist(d_name)) == NULL) {
483 char msg[80];
484 sprintf(msg, "Invalid distribution name '%s'", d_name);
485 INTERNAL(msg);
486 assert(d != NULL);
487 }
488
489 dist = d->dist;
490
491 if (op == 0) {
492 genrand_integer(&level, DIST_UNIFORM, 1, dist->maximums[wset - 1], 0, stream);
493 while (level > dist->weight_sets[wset - 1][index] && index < d->length)
494 index += 1;
495 dt = vset - 1;
496 if ((index >= d->length) || (dt > d->v_width))
497 INTERNAL("Distribution overrun");
498 char_val = dist->strings + dist->value_sets[dt][index];
499 } else {
500 index = vset - 1;
501 dt = wset - 1;
502 if (index >= d->length || index < 0) {
503 fprintf(stderr, "Runtime ERROR: Distribution over-run/under-run\n");
504 fprintf(stderr, "Check distribution definitions and usage for %s.\n", d->name);
505 fprintf(stderr, "index = %d, length=%d.\n", index, d->length);
506 exit(1);
507 }
508 char_val = dist->strings + dist->value_sets[dt][index];
509 }
510
511 switch (dist->type_vector[dt]) {
512 case TKN_VARCHAR:
513 if (dest)
514 *(char **)dest = (char *)char_val;
515 break;
516 case TKN_INT:
517 i_res = atoi(char_val);
518 if (dest)
519 *(int *)dest = i_res;
520 break;
521 case TKN_DATE:
522 if (dest == NULL) {
523 dest = (date_t *)malloc(sizeof(date_t));
524 MALLOC_CHECK(dest);
525 }
526 strtodt(*(date_t **)dest, char_val);
527 break;
528 case TKN_DECIMAL:
529 if (dest == NULL) {
530 dest = (decimal_t *)malloc(sizeof(decimal_t));
531 MALLOC_CHECK(dest);
532 }
533 strtodec(*(decimal_t **)dest, char_val);
534 break;
535 }
536
537 return ((dest == NULL) ? i_res : index + 1); /* shift back to the 1-based indexing scheme */
538}
539
540/*
541 * Routine: int dist_weight
542 * Purpose: return the weight of a particular member of a distribution
543 * Algorithm:
544 * Data Structures:
545 *
546 * Params: distribution *d
547 * int index: which "row"
548 * int wset: which set of weights
549 * Returns:
550 * Called By:
551 * Calls:
552 * Assumptions:
553 * Side Effects:
554 * TODO:
555 * 20000405 need to add error checking
556 */
557int dist_weight(int *dest, char *d, int index, int wset) {
558 d_idx_t *d_idx;
559 dist_t *dist;
560 int res;
561
562 if ((d_idx = find_dist(d)) == NULL) {
563 char msg[80];
564 sprintf(msg, "Invalid distribution name '%s'", d);
565 INTERNAL(msg);
566 }
567
568 dist = d_idx->dist;
569
570 res = dist->weight_sets[wset - 1][index - 1];
571 /* reverse the accumulation of weights */
572 if (index > 1)
573 res -= dist->weight_sets[wset - 1][index - 2];
574
575 if (dest == NULL)
576 return (res);
577
578 *dest = res;
579
580 return (0);
581}
582
583/*
584 * Routine: int DistNameIndex()
585 * Purpose: return the index of a column alias
586 * Algorithm:
587 * Data Structures:
588 *
589 * Params:
590 * Returns:
591 * Called By:
592 * Calls:
593 * Assumptions:
594 * Side Effects:
595 * TODO:
596 */
597int DistNameIndex(char *szDist, int nNameType, char *szName) {
598 d_idx_t *d_idx;
599 dist_t *dist;
600 int res;
601 char *cp = NULL;
602
603 if ((d_idx = find_dist(szDist)) == NULL)
604 return (-1);
605 dist = d_idx->dist;
606
607 if (dist->names == NULL)
608 return (-1);
609
610 res = 0;
611 cp = dist->names;
612 do {
613 if (strcasecmp(szName, cp) == 0)
614 break;
615 cp += strlen(cp) + 1;
616 res += 1;
617 } while (res < (d_idx->v_width + d_idx->w_width));
618
619 if (res >= 0) {
620 if ((nNameType == VALUE_NAME) && (res < d_idx->v_width))
621 return (res + 1);
622 if ((nNameType == WEIGHT_NAME) && (res > d_idx->v_width))
623 return (res - d_idx->v_width + 1);
624 }
625
626 return (-1);
627}
628
629/*
630 * Routine: int distsize(char *name)
631 * Purpose: return the size of a distribution
632 * Algorithm:
633 * Data Structures:
634 *
635 * Params:
636 * Returns:
637 * Called By:
638 * Calls:
639 * Assumptions:
640 * Side Effects:
641 * TODO:
642 * 20000405 need to add error checking
643 */
644int distsize(char *name) {
645 d_idx_t *dist;
646
647 dist = find_dist(name);
648
649 if (dist == NULL)
650 return (-1);
651
652 return (dist->length);
653}
654
655/*
656 * Routine: int IntegrateDist(char *szDistName, int nPct, int nStartIndex, int
657 *nWeightSet) Purpose: return the index of the entry which, starting from
658 *nStartIndex, would create a range comprising nPct of the total contained in
659 *nWeightSet NOTE: the value can "wrap" -- that is, the returned value can be
660 *less than nStartIndex Algorithm: Data Structures:
661 *
662 * Params:
663 * Returns:
664 * Called By:
665 * Calls:
666 * Assumptions:
667 * Side Effects:
668 * TODO:
669 */
670
671int IntegrateDist(char *szDistName, int nPct, int nStartIndex, int nWeightSet) {
672 d_idx_t *pDistIndex;
673 int nGoal, nSize;
674
675 if ((nPct <= 0) || (nPct >= 100))
676 return (QERR_RANGE_ERROR);
677
678 pDistIndex = find_dist(szDistName);
679 if (pDistIndex == NULL)
680 return (QERR_BAD_NAME);
681
682 if (nStartIndex > pDistIndex->length)
683 return (QERR_RANGE_ERROR);
684
685 nGoal = pDistIndex->dist->maximums[nWeightSet];
686 nGoal = nGoal * nPct / 100;
687 nSize = distsize(szDistName);
688
689 while (nGoal >= 0) {
690 nStartIndex++;
691 nGoal -= dist_weight(NULL, szDistName, nStartIndex % nSize, nWeightSet);
692 }
693
694 return (nStartIndex);
695}
696
697/*
698 * Routine: int dist_type(char *name, int nValueSet)
699 * Purpose: return the type of the n-th value set in a distribution
700 * Algorithm:
701 * Data Structures:
702 *
703 * Params:
704 * Returns:
705 * Called By:
706 * Calls:
707 * Assumptions:
708 * Side Effects:
709 * TODO:
710 */
711int dist_type(char *name, int nValueSet) {
712 d_idx_t *dist;
713
714 dist = find_dist(name);
715
716 if (dist == NULL)
717 return (-1);
718
719 if (nValueSet < 1 || nValueSet > dist->v_width)
720 return (-1);
721
722 return (dist->dist->type_vector[nValueSet - 1]);
723}
724
725/*
726 * Routine:
727 * Purpose:
728 * Algorithm:
729 * Data Structures:
730 *
731 * Params:
732 * Returns:
733 * Called By:
734 * Calls:
735 * Assumptions:
736 * Side Effects:
737 * TODO: None
738 */
739void dump_dist(char *name) {
740 d_idx_t *pIndex;
741 int i, j;
742 char *pCharVal = NULL;
743 int nVal;
744
745 pIndex = find_dist(name);
746 if (pIndex == NULL)
747 ReportErrorNoLine(QERR_BAD_NAME, name, 1);
748 printf("create %s;\n", pIndex->name);
749 printf("set types = (");
750 for (i = 0; i < pIndex->v_width; i++) {
751 if (i > 0)
752 printf(", ");
753 printf("%s", dist_type(name, i + 1) == 7 ? "int" : "varchar");
754 }
755 printf(");\n");
756 printf("set weights = %d;\n", pIndex->w_width);
757 for (i = 0; i < pIndex->length; i++) {
758 printf("add(");
759 for (j = 0; j < pIndex->v_width; j++) {
760 if (j)
761 printf(", ");
762 if (dist_type(name, j + 1) != 7) {
763 dist_member(&pCharVal, name, i + 1, j + 1);
764 printf("\"%s\"", pCharVal);
765 } else {
766 dist_member(&nVal, name, i + 1, j + 1);
767 printf("%d", nVal);
768 }
769 }
770 printf("; ");
771 for (j = 0; j < pIndex->w_width; j++) {
772 if (j)
773 printf(", ");
774 printf("%d", dist_weight(NULL, name, i + 1, j + 1));
775 }
776 printf(");\n");
777 }
778
779 return;
780}
781
782/*
783 * Routine: dist_active(char *szName, int nWeightSet)
784 * Purpose: return number of entries with non-zero weght values
785 * Algorithm:
786 * Data Structures:
787 *
788 * Params:
789 * Returns:
790 * Called By:
791 * Calls:
792 * Assumptions:
793 * Side Effects:
794 * TODO: None
795 */
796int dist_active(char *szName, int nWeightSet) {
797 int nSize, nResult = 0, i;
798
799 nSize = distsize(szName);
800 for (i = 1; i <= nSize; i++) {
801 if (dist_weight(NULL, szName, i, nWeightSet) != 0)
802 nResult += 1;
803 }
804
805 return (nResult);
806}
807
808/*
809 * Routine: DistSizeToShiftWidth(char *szDist)
810 * Purpose: Determine the number of bits required to select a member of the
811 * distribution Algorithm: Data Structures:
812 *
813 * Params:
814 * Returns:
815 * Called By:
816 * Calls:
817 * Assumptions:
818 * Side Effects:
819 * TODO: None
820 */
821int DistSizeToShiftWidth(char *szDist, int nWeightSet) {
822 int nBits = 1, nTotal = 2, nMax;
823 d_idx_t *d;
824
825 d = find_dist(szDist);
826 nMax = dist_max(d->dist, nWeightSet);
827
828 while (nTotal < nMax) {
829 nBits += 1;
830 nTotal <<= 1;
831 }
832
833 return (nBits);
834}
835
836/*
837 * Routine:
838 * Purpose:
839 * Algorithm:
840 * Data Structures:
841 *
842 * Params:
843 * Returns:
844 * Called By:
845 * Calls:
846 * Assumptions:
847 * Side Effects:
848 * TODO: None
849 */
850int MatchDistWeight(void *dest, char *szDist, int nWeight, int nWeightSet, int ValueSet) {
851 d_idx_t *d;
852 dist_t *dist;
853 int index = 0, dt, i_res, nRetcode;
854 char *char_val;
855
856 if ((d = find_dist(szDist)) == NULL) {
857 char msg[80];
858 sprintf(msg, "Invalid distribution name '%s'", szDist);
859 INTERNAL(msg);
860 }
861
862 dist = d->dist;
863 nWeight %= dist->maximums[nWeightSet - 1];
864
865 while (nWeight > dist->weight_sets[nWeightSet - 1][index] && index < d->length)
866 index += 1;
867 dt = ValueSet - 1;
868 if (index >= d->length)
869 index = d->length - 1;
870 char_val = dist->strings + dist->value_sets[dt][index];
871
872 switch (dist->type_vector[dt]) {
873 case TKN_VARCHAR:
874 if (dest)
875 *(char **)dest = (char *)char_val;
876 break;
877 case TKN_INT:
878 i_res = atoi(char_val);
879 if (dest)
880 *(int *)dest = i_res;
881 break;
882 case TKN_DATE:
883 if (dest == NULL) {
884 dest = (date_t *)malloc(sizeof(date_t));
885 MALLOC_CHECK(dest);
886 }
887 strtodt(*(date_t **)dest, char_val);
888 break;
889 case TKN_DECIMAL:
890 if (dest == NULL) {
891 dest = (decimal_t *)malloc(sizeof(decimal_t));
892 MALLOC_CHECK(dest);
893 }
894 strtodec(*(decimal_t **)dest, char_val);
895 break;
896 }
897
898 nRetcode = 1;
899 index = 1;
900 while (index < dist->maximums[nWeightSet - 1]) {
901 nRetcode += 1;
902 index *= 2;
903 }
904
905 return (nRetcode);
906}
907
908/*
909 * Routine: findDistValue(char *szValue, char *szDistName, int nValueSet)
910 * Purpose: Return the row number where the entry is found
911 * Algorithm:
912 * Data Structures:
913 *
914 * Params:
915 * Returns:
916 * Called By:
917 * Calls:
918 * Assumptions:
919 * Side Effects:
920 * TODO:
921 * 20031024 jms this routine needs to handle all data types, not just varchar
922 */
923int findDistValue(char *szValue, char *szDistName, int ValueSet) {
924 int nRetValue = 1, nDistMax;
925 char szDistValue[128];
926
927 nDistMax = distsize(szDistName);
928
929 for (nRetValue = 1; nRetValue < nDistMax; nRetValue++) {
930 dist_member(&szDistValue, szDistName, nRetValue, ValueSet);
931 if (strcmp(szValue, szDistValue) == 0)
932 break;
933 }
934
935 if (nRetValue <= nDistMax)
936 return (nRetValue);
937 return (-1);
938}
939
940#ifdef TEST
941main() {
942 int i_res;
943 char *c_res;
944 decimal_t dec_res;
945
946 init_params();
947
948 dist_member(&i_res, "test_dist", 1, 1);
949 if (i_res != 10) {
950 printf("dist_member(\"test_dist\", 1, 1): %d != 10\n", i_res);
951 exit(1);
952 }
953 dist_member(&i_res, "test_dist", 1, 2);
954 if (i_res != 60) {
955 printf("dist_member(\"test_dist\", 1, 2): %d != 60\n", i_res);
956 exit(1);
957 }
958 dist_member((void *)&c_res, "test_dist", 1, 3);
959 if (strcmp(c_res, "El Camino")) {
960 printf("dist_member(\"test_dist\", 1, 3): %s != El Camino\n", c_res);
961 exit(1);
962 }
963 dist_member((void *)&dec_res, "test_dist", 1, 4);
964 if (strcmp(dec_res.number, "1") || strcmp(dec_res.fraction, "23")) {
965 printf("dist_member(\"test_dist\", 1, 4): %s.%s != 1.23\n", dec_res.number, dec_res.fraction);
966 exit(1);
967 }
968 dist_weight(&i_res, "test_dist", 2, 2);
969 if (3 != i_res) {
970 printf("dist_weight(\"test_dist\", 2, 2): %d != 3\n", i_res);
971 exit(1);
972 }
973}
974#endif /* TEST */
975