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 * - Sergey Vasilevskiy
35 * - Doug Johnson
36 */
37
38/*
39 * Class representing the Customer Accounts table.
40 */
41#ifndef CUSTOMER_ACCOUNTS_AND_PERMISSIONS_TABLE_H
42#define CUSTOMER_ACCOUNTS_AND_PERMISSIONS_TABLE_H
43
44#include "EGenTables_common.h"
45#include "CustomerTable.h"
46#include "AddressTable.h"
47
48#include "input/DataFileManager.h"
49
50namespace TPCE {
51const UINT iMaxCAPerms = 3; // maximum # of customers having permissions to the same account
52const UINT iMinAccountsPerCustRange[3] = {1, 2, 5};
53const UINT iMaxAccountsPerCustRange[3] = {4, 8, 10};
54const UINT iMaxAccountsPerCust = 10; // must be the biggest number in iMaxAccountsPerCustRange array
55const TIdent iStartingBrokerID = 1;
56
57// This is the fixed range from which person ids (like CIDs) are selected
58// for the *additional* permissions on the account that make the
59// content of ACCOUNT_PERMISSION table.
60//
61// The range is fixed for any size database in order for the parallel loaders
62// to select person ids the same way and be compatible with runtime driver
63// (and to avoid database size parameter to the loader executable).
64//
65const TIdent iAccountPermissionIDRange = INT64_CONST(4024) * 1024 * 1024 - iDefaultStartFromCustomer;
66
67const UINT iPercentAccountsWithPositiveInitialBalance = 80;
68
69const double fAccountInitialPositiveBalanceMax = 9999999.99;
70const double fAccountInitialNegativeBalanceMin = -9999999.99;
71
72const UINT iPercentAccountAdditionalPermissions_0 = 60;
73const UINT iPercentAccountAdditionalPermissions_1 = 38;
74const UINT iPercentAccountAdditionalPermissions_2 = 2;
75
76const UINT iPercentAccountTaxStatusNonTaxable = 20;
77const UINT iPercentAccountTaxStatusTaxableAndWithhold = 50;
78const UINT iPercentAccountTaxStatusTaxableAndDontWithhold = 30;
79
80// Number of RNG calls to skip for one row in order
81// to not use any of the random values from the previous row.
82const UINT iRNGSkipOneRowCustomerAccount = 10; // real max count in v3.5: 7
83
84enum eTaxStatus { eNone = -1, eNonTaxable = 0, eTaxableAndWithhold, eTaxableAndDontWithhold };
85
86typedef struct CUSTOMER_ACCOUNT_AND_PERMISSION_ROW {
87 CUSTOMER_ACCOUNT_ROW m_ca;
88 ACCOUNT_PERMISSION_ROW m_perm[iMaxCAPerms + 1];
89} * PCUSTOMER_ACCOUNT_AND_PERMISSION_ROW;
90
91class CCustomerAccountsAndPermissionsTable : public TableTemplate<CUSTOMER_ACCOUNT_AND_PERMISSION_ROW> {
92 const TaxableAccountNameDataFile_t &m_TaxableAccountName;
93 const NonTaxableAccountNameDataFile_t &m_NonTaxableAccountName;
94 TIdent m_iStartFromCustomer;
95 TIdent m_iCustomerCount;
96 TIdent m_iStartingCA_ID; // first CA_ID for the current customer
97 UINT m_iRowsToGenForCust; // total # of rows to generate for a given
98 // portfolio
99 UINT m_iRowsGeneratedForCust; // rows already generated for a particular
100 // portfolio
101 CCustomerTable m_cust;
102 CPerson m_person;
103 UINT m_iPermsForCA;
104 TIdent m_iBrokersCount;
105 CAddressTable m_addr; // ADDRESS table - to calculate tax for TRADE
106 UINT m_iLoadUnitSize;
107 CCustomerSelection m_CustomerSelection;
108 bool m_bCacheEnabled;
109 int m_iCacheSizeNA;
110 TIdent m_iCacheOffsetNA;
111 UINT *m_CacheNA;
112 int m_iCacheSizeTS;
113 TIdent m_iCacheOffsetTS;
114 eTaxStatus *m_CacheTS;
115
116 /*
117 * Generate only the Customer Account row.
118 *
119 * PARAMETERS:
120 * none.
121 *
122 * RETURNS:
123 * none.
124 */
125 void GenerateCARow() {
126 int iAcctType;
127
128 // Generate customer account row.
129 //
130 GenerateNextCA_AD();
131
132 m_row.m_ca.CA_C_ID = GetCurrentC_ID(); // get from CUSTOMER
133
134 // Generate broker id.
135 m_row.m_ca.CA_B_ID = GenerateBrokerIdForAccount(m_row.m_ca.CA_ID);
136
137 // Generate tax status and account name.
138 if ((m_row.m_ca.CA_TAX_ST = (char)GetAccountTaxStatus(m_row.m_ca.CA_ID)) ==
139 eNonTaxable) { // non-taxable account
140 iAcctType = (int)m_row.m_ca.CA_ID % m_NonTaxableAccountName.size(); // select account type
141
142 snprintf(m_row.m_ca.CA_NAME, sizeof(m_row.m_ca.CA_NAME), "%s %s %s",
143 m_person.GetFirstName(m_row.m_ca.CA_C_ID).c_str(),
144 m_person.GetLastName(m_row.m_ca.CA_C_ID).c_str(), m_NonTaxableAccountName[iAcctType].NAME_CSTR());
145 } else { // taxable account
146 iAcctType = (int)m_row.m_ca.CA_ID % m_TaxableAccountName.size(); // select account type
147
148 snprintf(m_row.m_ca.CA_NAME, sizeof(m_row.m_ca.CA_NAME), "%s %s %s",
149 m_person.GetFirstName(m_row.m_ca.CA_C_ID).c_str(),
150 m_person.GetLastName(m_row.m_ca.CA_C_ID).c_str(), m_TaxableAccountName[iAcctType].NAME_CSTR());
151 }
152
153 if (m_rnd.RndPercent(iPercentAccountsWithPositiveInitialBalance)) {
154 m_row.m_ca.CA_BAL = m_rnd.RndDoubleIncrRange(0.00, fAccountInitialPositiveBalanceMax, 0.01);
155 } else {
156 m_row.m_ca.CA_BAL = m_rnd.RndDoubleIncrRange(fAccountInitialNegativeBalanceMin, 0.00, 0.01);
157 }
158 }
159
160 /*
161 * Helper function to generate parts of an ACCOUNT_PERMISSION row.
162 *
163 * PARAMETERS:
164 * IN CA_ID - customer account id
165 * IN C_ID - customer id
166 * IN szACL - Access-Control-List string on the account
167 * OUT row - ACCOUNT_PERMISSION row structure to fill
168 *
169 * RETURNS:
170 * none.
171 */
172 void FillAPRow(TIdent CA_ID, TIdent C_ID, const char *szACL, ACCOUNT_PERMISSION_ROW &row) {
173 row.AP_CA_ID = CA_ID;
174 m_cust.GetC_TAX_ID(C_ID, row.AP_TAX_ID);
175 strncpy(row.AP_L_NAME, m_person.GetLastName(C_ID).c_str(), sizeof(row.AP_L_NAME));
176 strncpy(row.AP_F_NAME, m_person.GetFirstName(C_ID).c_str(), sizeof(row.AP_F_NAME));
177 strncpy(row.AP_ACL, szACL, sizeof(row.AP_ACL));
178 }
179
180 /*
181 * Generate only the Account Permissions row(s).
182 *
183 * PARAMETERS:
184 * none.
185 *
186 * RETURNS:
187 * none.
188 */
189 void GenerateAPRows() {
190 int iAdditionalPerms;
191 TIdent CID_1, CID_2;
192
193 // Generate account permissions rows.
194
195 // Generate the owner row
196 FillAPRow(m_row.m_ca.CA_ID, m_row.m_ca.CA_C_ID, "0000", m_row.m_perm[0]);
197
198 iAdditionalPerms = GetNumPermsForCA(m_row.m_ca.CA_ID);
199 switch (iAdditionalPerms) {
200 case 0:
201 m_iPermsForCA = 1; // 60%
202 break;
203 case 1:
204 GetCIDsForPermissions(m_row.m_ca.CA_ID, m_row.m_ca.CA_C_ID, &CID_1, NULL);
205 m_iPermsForCA = 2; // 38%
206 // generate second account permission row
207 FillAPRow(m_row.m_ca.CA_ID, CID_1, "0001", m_row.m_perm[1]);
208 break;
209 case 2:
210 GetCIDsForPermissions(m_row.m_ca.CA_ID, m_row.m_ca.CA_C_ID, &CID_1, &CID_2);
211 m_iPermsForCA = 3; // 2%
212 // generate second account permission row
213 FillAPRow(m_row.m_ca.CA_ID, CID_1, "0001", m_row.m_perm[1]);
214 // generate third account permission row
215 FillAPRow(m_row.m_ca.CA_ID, CID_2, "0011", m_row.m_perm[2]);
216 break;
217 }
218 }
219
220public:
221 /*
222 * Constructor.
223 *
224 * PARAMETERS:
225 * IN dfm - input flat files loaded in memory
226 * IN iLoadUnitSize - should always be 1000
227 * IN iCustomerCount - number of customers to generate
228 * IN iStartFromCustomer - ordinal position of the first
229 * customer in the sequence (Note: 1-based)
230 *
231 * RETURNS:
232 * not applicable.
233 */
234 CCustomerAccountsAndPermissionsTable(const DataFileManager &dfm,
235 UINT iLoadUnitSize, // # of customers in one load unit
236 TIdent iCustomerCount, TIdent iStartFromCustomer, bool bCacheEnabled = false)
237 : TableTemplate<CUSTOMER_ACCOUNT_AND_PERMISSION_ROW>(), m_TaxableAccountName(dfm.TaxableAccountNameDataFile()),
238 m_NonTaxableAccountName(dfm.NonTaxableAccountNameDataFile()), m_iStartFromCustomer(iStartFromCustomer),
239 m_iCustomerCount(iCustomerCount), m_iRowsToGenForCust(0), m_iRowsGeneratedForCust(0),
240 m_cust(dfm, iCustomerCount, iStartFromCustomer), m_person(dfm, iStartFromCustomer, bCacheEnabled),
241 m_iPermsForCA(0), m_iBrokersCount(iLoadUnitSize / iBrokersDiv),
242 m_addr(dfm, iCustomerCount, iStartFromCustomer, bCacheEnabled), m_iLoadUnitSize(iLoadUnitSize),
243 m_bCacheEnabled(bCacheEnabled) {
244 if (m_bCacheEnabled) {
245 m_iCacheSizeNA = iDefaultLoadUnitSize;
246 m_iCacheOffsetNA = iStartFromCustomer + iTIdentShift;
247 m_CacheNA = new UINT[m_iCacheSizeNA];
248 for (int i = 0; i < m_iCacheSizeNA; i++) {
249 m_CacheNA[i] = 0;
250 }
251
252 m_iCacheSizeTS = iDefaultLoadUnitSize * iMaxAccountsPerCust;
253 m_iCacheOffsetTS = ((iStartFromCustomer - 1) + iTIdentShift) * iMaxAccountsPerCust;
254 m_CacheTS = new eTaxStatus[m_iCacheSizeTS];
255 for (int i = 0; i < m_iCacheSizeTS; i++) {
256 m_CacheTS[i] = eNone;
257 }
258 }
259 };
260
261 /*
262 * Destructor.
263 */
264 ~CCustomerAccountsAndPermissionsTable() {
265 if (m_bCacheEnabled) {
266 delete[] m_CacheNA;
267 delete[] m_CacheTS;
268 }
269 };
270
271 /*
272 * Reset the state for the next load unit.
273 *
274 * PARAMETERS:
275 * none.
276 *
277 * RETURNS:
278 * none.
279 */
280 void InitNextLoadUnit() {
281 m_rnd.SetSeed(m_rnd.RndNthElement(
282 RNGSeedTableDefault, (RNGSEED)(GetCurrentC_ID() * iMaxAccountsPerCust * iRNGSkipOneRowCustomerAccount)));
283
284 ClearRecord(); // this is needed for EGenTest to work
285
286 if (m_bCacheEnabled) {
287 m_iCacheOffsetNA += iDefaultLoadUnitSize;
288 for (int i = 0; i < m_iCacheSizeNA; i++) {
289 m_CacheNA[i] = 0;
290 }
291 m_iCacheOffsetTS += iDefaultLoadUnitSize * iMaxAccountsPerCust;
292 for (int i = 0; i < m_iCacheSizeTS; i++) {
293 m_CacheTS[i] = eNone;
294 }
295 }
296 }
297
298 /*
299 * Generate the number of accounts for a given customer id.
300 *
301 * PARAMETERS:
302 * IN CID - customer id
303 * IN iCustomerTier - customer tier (indicating trading
304 * frequency)
305 *
306 * RETURNS:
307 * number of accounts
308 */
309 UINT GetNumberOfAccounts(TIdent CID, eCustomerTier iCustomerTier) {
310 UINT iNumAccounts = 0;
311
312 // We will sometimes get CID values that are outside the current
313 // load unit (cached range). We need to check for this case
314 // and avoid the lookup (as we will segfault or get bogus data.)
315 TIdent index = CID - m_iCacheOffsetNA;
316 bool bCheckCache = (index >= 0 && index < m_iCacheSizeNA);
317 if (m_bCacheEnabled && bCheckCache) {
318 iNumAccounts = m_CacheNA[index];
319 }
320
321 if (iNumAccounts == 0) {
322 UINT iMinAccountCount;
323 UINT iMod;
324 UINT iInverseCID;
325
326 iMinAccountCount = iMinAccountsPerCustRange[iCustomerTier - eCustomerTierOne];
327 iMod = iMaxAccountsPerCustRange[iCustomerTier - eCustomerTierOne] - iMinAccountCount + 1;
328 iInverseCID = m_CustomerSelection.GetInverseCID(CID);
329
330 // Note: the calculations below assume load unit contains 1000
331 // customers.
332 //
333 if (iInverseCID < 200) // Tier 1
334 {
335 iNumAccounts = (iInverseCID % iMod) + iMinAccountCount;
336 } else {
337 if (iInverseCID < 800) // Tier 2
338 {
339 iNumAccounts = ((iInverseCID - 200 + 1) % iMod) + iMinAccountCount;
340 } else // Tier 3
341 {
342 iNumAccounts = ((iInverseCID - 800 + 2) % iMod) + iMinAccountCount;
343 }
344 }
345
346 if (m_bCacheEnabled && bCheckCache) {
347 m_CacheNA[index] = iNumAccounts;
348 }
349 }
350 return iNumAccounts;
351 }
352
353 /*
354 * Generate a random account for the specified customer.
355 * The distribution is uniform across all the accounts for the customer.
356 *
357 * PARAMETERS:
358 * IN RND - external Random Number Generator
359 * IN iCustomerId - customer id
360 * IN iCustomerTier - customer tier (indicating trading
361 * frequency) OUT piCustomerAccount - customer account id OUT
362 * piAccountCount - total number of accounts that the customer has
363 *
364 * RETURNS:
365 * none.
366 */
367 void GenerateRandomAccountId(CRandom &RND, // in - external RNG
368 TIdent iCustomerId, // in
369 eCustomerTier iCustomerTier, // in
370 TIdent *piCustomerAccount, // out
371 int *piAccountCount) // out
372 {
373 TIdent iCustomerAccount;
374 int iAccountCount;
375 TIdent iStartingAccount;
376
377 iAccountCount = GetNumberOfAccounts(iCustomerId, iCustomerTier);
378
379 iStartingAccount = GetStartingCA_ID(iCustomerId);
380
381 // Select random account for the customer
382 //
383 iCustomerAccount = RND.RndInt64Range(iStartingAccount, iStartingAccount + iAccountCount - 1);
384
385 if (piCustomerAccount != NULL) {
386 *piCustomerAccount = iCustomerAccount;
387 }
388
389 if (piAccountCount != NULL) {
390 *piAccountCount = iAccountCount;
391 }
392 }
393
394 /*
395 * Generate a random account for the specified customer.
396 *
397 * PARAMETERS:
398 * IN RND - external Random Number Generator
399 * IN iCustomerId - customer id
400 * IN iCustomerTier - customer tier (indicating trading
401 * frequency)
402 *
403 * RETURNS:
404 * customer account id.
405 */
406 TIdent GenerateRandomAccountId(CRandom &RND, TIdent iCustomerId, eCustomerTier iCustomerTier) {
407 TIdent iAccountOffset;
408 INT32 iAccountCount;
409 TIdent iStartingAccount;
410
411 iAccountCount = GetNumberOfAccounts(iCustomerId, iCustomerTier);
412
413 iStartingAccount = GetStartingCA_ID(iCustomerId);
414
415 iAccountOffset = (TIdent)RND.RndInt64Range(0, (INT64)iAccountCount - 1);
416
417 return (iStartingAccount + iAccountOffset);
418 }
419
420 /*
421 * Get starting account id for a given customer id.
422 * This is needed for the driver to know what account ids belong to a
423 * given customer.
424 *
425 * PARAMETERS:
426 * IN CID - customer id
427 *
428 * RETURNS:
429 * first account id of the customer.
430 */
431 TIdent GetStartingCA_ID(TIdent CID) {
432 // start account ids on the next boundary for the new customer
433 return ((CID - 1) * iMaxAccountsPerCust + 1);
434 }
435
436 /*
437 * Get (maximum potential) ending account id for a given customer id.
438 * This is needed for the driver to restrict query results to active
439 * accounts.
440 *
441 * PARAMETERS:
442 * IN CID - customer id
443 *
444 * RETURNS:
445 * last account id of the customer.
446 */
447 TIdent GetEndingCA_ID(TIdent CID) {
448 return (CID + iTIdentShift) * iMaxAccountsPerCust;
449 }
450
451 /*
452 * Generate next CA_ID and update state information.
453 * It is stored in the internal record structure and also returned.
454 * The number of rows generated is incremented. This is why
455 * this function cannot be called more than once for a record.
456 *
457 * PARAMETERS:
458 * none.
459 *
460 * RETURNS:
461 * next account id of the customer.
462 */
463 TIdent GenerateNextCA_AD() {
464 if (GetCurrentC_ID() % iDefaultLoadUnitSize == 0) {
465 InitNextLoadUnit();
466 }
467
468 ++m_iLastRowNumber;
469
470 if (m_iRowsGeneratedForCust == m_iRowsToGenForCust) { // select next customer id as all the rows
471 // for this customer have been generated
472 m_cust.GenerateNextC_ID();
473 m_addr.GenerateNextAD_ID(); // next address id (to get the one for
474 // this customer)
475 m_iRowsGeneratedForCust = 0; // no row generated yet
476 // total # of accounts for this customer
477 m_iRowsToGenForCust =
478 GetNumberOfAccounts(m_cust.GetCurrentC_ID(), m_cust.GetC_TIER(m_cust.GetCurrentC_ID()));
479
480 m_iStartingCA_ID = GetStartingCA_ID(m_cust.GetCurrentC_ID());
481 }
482
483 m_row.m_ca.CA_ID = m_iStartingCA_ID + m_iRowsGeneratedForCust;
484
485 ++m_iRowsGeneratedForCust;
486
487 // store state info
488 m_bMoreRecords = m_cust.MoreRecords() || m_iRowsGeneratedForCust < m_iRowsToGenForCust;
489
490 return m_row.m_ca.CA_ID;
491 }
492
493 /*
494 * Generate the number (0-2) of additional permission rows for a certain
495 * account. This number is needed by the driver.
496 *
497 * PARAMETERS:
498 * IN CA_ID - customer account id
499 *
500 * RETURNS:
501 * number of ACCOUNT_PERMISSION rows.
502 */
503 int GetNumPermsForCA(TIdent CA_ID) {
504 RNGSEED OldSeed;
505 UINT iThreshold;
506 UINT iNumberOfPermissions;
507
508 OldSeed = m_rnd.GetSeed();
509
510 m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseNumberOfAccountPermissions, (RNGSEED)CA_ID));
511
512 iThreshold = m_rnd.RndGenerateIntegerPercentage();
513
514 if (iThreshold <= iPercentAccountAdditionalPermissions_0) {
515 iNumberOfPermissions = 0; // 60% of accounts have just the owner row permissions
516 } else {
517 if (iThreshold <= iPercentAccountAdditionalPermissions_0 + iPercentAccountAdditionalPermissions_1) {
518 iNumberOfPermissions = 1; // 38% of accounts have one additional permisison row
519 } else {
520 iNumberOfPermissions = 2; // 2% of accounts have two additional permission rows
521 }
522 }
523
524 m_rnd.SetSeed(OldSeed);
525 return (iNumberOfPermissions);
526 }
527
528 /*
529 * Generate customer ids for ACCOUNT_PERMISSION table for a given account
530 * id. Driver needs to know what those customer ids are based on the account
531 * id.
532 *
533 * PARAMETERS:
534 * IN CA_ID - customer account id
535 * IN Owner_CID - customer id of the account owner
536 * OUT CID_1 - first customer id in the ACL list of the
537 * account OUT CID_2 - second customer id in the ACL list of the
538 * account
539 *
540 * RETURNS:
541 * none.
542 */
543 void GetCIDsForPermissions(TIdent CA_ID, TIdent Owner_CID, TIdent *CID_1, TIdent *CID_2) {
544 RNGSEED OldSeed;
545
546 if (CID_1 == NULL)
547 return;
548
549 OldSeed = m_rnd.GetSeed();
550 m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseCIDForPermission1, (RNGSEED)CA_ID));
551
552 // Select from a fixed range that doesn't depend on the number of
553 // customers in the database. This allows not to specify the total
554 // number of customers to EGenLoader, only how many a particular
555 // instance needs to generate (may be a fraction of total). Note: this
556 // is not implemented right now.
557 *CID_1 = m_rnd.RndInt64RangeExclude(iDefaultStartFromCustomer,
558 iDefaultStartFromCustomer + iAccountPermissionIDRange, Owner_CID);
559
560 if (CID_2 != NULL) {
561 // NOTE: Reseeding the RNG here for the second CID value. The use of
562 // this sequence is fuzzy because the number of RNG values consumed
563 // is dependant on not only the CA_ID, but also the CID value chosen
564 // above for the first permission. Using a different sequence here
565 // may help prevent potential overlaps that might occur if the same
566 // sequence from above were used.
567 m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseCIDForPermission2, (RNGSEED)CA_ID));
568 do // make sure the second id is different from the first
569 {
570 *CID_2 = m_rnd.RndInt64RangeExclude(iDefaultStartFromCustomer,
571 iDefaultStartFromCustomer + iAccountPermissionIDRange, Owner_CID);
572 } while (*CID_2 == *CID_1);
573 }
574
575 m_rnd.SetSeed(OldSeed);
576 }
577
578 /*
579 * Generate tax id for a given CA_ID.
580 * This is needed to calculate tax on sale proceeds for the TRADE table.
581 *
582 * PARAMETERS:
583 * IN iCA_ID - customer account id
584 *
585 * RETURNS:
586 * tax status for the account.
587 */
588 eTaxStatus GetAccountTaxStatus(TIdent iCA_ID) {
589 eTaxStatus eCATaxStatus = eNone;
590
591 // We will sometimes get CA values that are outside the current
592 // load unit (cached range). We need to check for this case
593 // and avoid the lookup (as we will segfault or get bogus data.)
594 TIdent index = iCA_ID - m_iCacheOffsetTS;
595 bool bCheckCache = (index >= 0 && index < m_iCacheSizeTS);
596 if (m_bCacheEnabled && bCheckCache) {
597 eCATaxStatus = m_CacheTS[index];
598 }
599
600 if (eCATaxStatus == eNone) {
601 RNGSEED OldSeed;
602 UINT iThreshold;
603
604 OldSeed = m_rnd.GetSeed();
605
606 m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseAccountTaxStatus, (RNGSEED)iCA_ID));
607
608 iThreshold = m_rnd.RndGenerateIntegerPercentage();
609 if (iThreshold <= iPercentAccountTaxStatusNonTaxable) {
610 eCATaxStatus = eNonTaxable;
611 } else {
612 if (iThreshold <= iPercentAccountTaxStatusNonTaxable + iPercentAccountTaxStatusTaxableAndWithhold) {
613 eCATaxStatus = eTaxableAndWithhold;
614 } else {
615 eCATaxStatus = eTaxableAndDontWithhold;
616 }
617 }
618 m_rnd.SetSeed(OldSeed);
619
620 if (m_bCacheEnabled && bCheckCache) {
621 m_CacheTS[index] = eCATaxStatus;
622 }
623 }
624 return eCATaxStatus;
625 }
626
627 /*
628 * Get the country and division address codes for the customer that
629 * owns the current account.
630 * These codes are used to get the tax rates and calculate tax on trades
631 * in the TRADE table.
632 *
633 * PARAMETERS:
634 * OUT iDivCode - division (state/province) code
635 * OUT iCtryCode - country (USA/CANADA) code
636 *
637 * RETURNS:
638 * none.
639 */
640 void GetDivisionAndCountryCodesForCurrentAccount(UINT &iDivCode, UINT &iCtryCode) {
641 m_addr.GetDivisionAndCountryCodes(iDivCode, iCtryCode);
642 }
643
644 /*
645 * Generate a broker id for a certain account.
646 * Used in CTradeGen for updating YTD values.
647 *
648 * PARAMETERS:
649 * IN iCA_ID - customer account id
650 *
651 * RETURNS:
652 * broker id that corresponds to the account.
653 */
654 TIdent GenerateBrokerIdForAccount(TIdent iCA_ID) {
655 // Customer that own the account (actually, customer id minus 1)
656 //
657 TIdent iCustomerId = ((iCA_ID - 1) / iMaxAccountsPerCust) - iTIdentShift;
658
659 // Set the starting broker to be the first broker for the current load
660 // unit of customers.
661 //
662 TIdent iStartFromBroker = (iCustomerId / m_iLoadUnitSize) * m_iBrokersCount + iStartingBrokerID + iTIdentShift;
663
664 // Note: this depends on broker ids being integer numbers from
665 // contiguous range. The method of generating broker ids should be in
666 // sync with the CBrokerTable.
667 return m_rnd.RndNthInt64Range(RNGSeedBaseBrokerId, (RNGSEED)iCA_ID - (10 * iTIdentShift), iStartFromBroker,
668 iStartFromBroker + m_iBrokersCount - 1);
669 }
670
671 /*
672 * Generate all column values for the next row
673 * and store them in the internal record structure.
674 * Increment the number of rows generated.
675 *
676 * PARAMETERS:
677 * none.
678 *
679 * RETURNS:
680 * TRUE, if there are more records in the ADDRESS table; FALSE
681 * othewise.
682 */
683 bool GenerateNextRecord() {
684 GenerateCARow();
685 GenerateAPRows();
686
687 // Return false if all the rows have been generated
688 return (MoreRecords());
689 }
690
691 /*
692 * Return CUSTOMER_ACCOUNT row from the internal structure.
693 *
694 * PARAMETERS:
695 * none.
696 *
697 * RETURNS:
698 * current CUSTOMER_ACCOUNT record.
699 */
700 // PCUSTOMER_ACCOUNT_ROW GetCARow() {return &m_row.m_ca;}
701 const CUSTOMER_ACCOUNT_ROW &GetCARow() {
702 return m_row.m_ca;
703 }
704 /*
705 * Return ACCOUNT_PERMISSION row from the internal structure.
706 *
707 * PARAMETERS:
708 * none.
709 *
710 * RETURNS:
711 * current ACCOUNT_PERMISSION record.
712 */
713 const ACCOUNT_PERMISSION_ROW &GetAPRow(UINT i) {
714 if (i < m_iPermsForCA)
715 return m_row.m_perm[i];
716 else
717 throw std::range_error("Account Permission row index out of bounds.");
718 }
719
720 /*
721 * Return the number of ACCOUNT_PERMISSION rows for the current
722 * CUSTOMER_ACCOUNT row.
723 *
724 * PARAMETERS:
725 * none.
726 *
727 * RETURNS:
728 * the number of permissions for the account.
729 */
730 UINT GetCAPermsCount() {
731 return m_iPermsForCA;
732 }
733
734 /*
735 * Return the customer ID for the currently generated CA_ID id.
736 *
737 * PARAMETERS:
738 * none.
739 *
740 * RETURNS:
741 * customer id of the account in the current CUSTOMER_ACCOUNT
742 * record.
743 */
744 TIdent GetCurrentC_ID() {
745 return m_cust.GetCurrentC_ID();
746 }
747 /*
748 * Return the customer tier for the currently generated CA_ID id.
749 *
750 * PARAMETERS:
751 * none.
752 *
753 * RETURNS:
754 * customer tier of the customer, whose account is in the current
755 * CUSTOMER_ACCOUNT record.
756 */
757 eCustomerTier GetCurrentC_TIER() {
758 return m_cust.GetC_TIER(m_cust.GetCurrentC_ID());
759 }
760};
761
762} // namespace TPCE
763
764#endif // CUSTOMER_ACCOUNTS_AND_PERMISSIONS_TABLE_H
765