/* * Legal Notice * * This document and associated source code (the "Work") is a part of a * benchmark specification maintained by the TPC. * * The TPC reserves all right, title, and interest to the Work as provided * under U.S. and international laws, including without limitation all patent * and trademark rights therein. * * No Warranty * * 1.1 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE INFORMATION * CONTAINED HEREIN IS PROVIDED "AS IS" AND WITH ALL FAULTS, AND THE * AUTHORS AND DEVELOPERS OF THE WORK HEREBY DISCLAIM ALL OTHER * WARRANTIES AND CONDITIONS, EITHER EXPRESS, IMPLIED OR STATUTORY, * INCLUDING, BUT NOT LIMITED TO, ANY (IF ANY) IMPLIED WARRANTIES, * DUTIES OR CONDITIONS OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR * PURPOSE, OF ACCURACY OR COMPLETENESS OF RESPONSES, OF RESULTS, OF * WORKMANLIKE EFFORT, OF LACK OF VIRUSES, AND OF LACK OF NEGLIGENCE. * ALSO, THERE IS NO WARRANTY OR CONDITION OF TITLE, QUIET ENJOYMENT, * QUIET POSSESSION, CORRESPONDENCE TO DESCRIPTION OR NON-INFRINGEMENT * WITH REGARD TO THE WORK. * 1.2 IN NO EVENT WILL ANY AUTHOR OR DEVELOPER OF THE WORK BE LIABLE TO * ANY OTHER PARTY FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO THE * COST OF PROCURING SUBSTITUTE GOODS OR SERVICES, LOST PROFITS, LOSS * OF USE, LOSS OF DATA, OR ANY INCIDENTAL, CONSEQUENTIAL, DIRECT, * INDIRECT, OR SPECIAL DAMAGES WHETHER UNDER CONTRACT, TORT, WARRANTY, * OR OTHERWISE, ARISING IN ANY WAY OUT OF THIS OR ANY OTHER AGREEMENT * RELATING TO THE WORK, WHETHER OR NOT SUCH AUTHOR OR DEVELOPER HAD * ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. * * Contributors * - Sergey Vasilevskiy * - Doug Johnson */ /* * Class representing the Customer Accounts table. */ #ifndef CUSTOMER_ACCOUNTS_AND_PERMISSIONS_TABLE_H #define CUSTOMER_ACCOUNTS_AND_PERMISSIONS_TABLE_H #include "EGenTables_common.h" #include "CustomerTable.h" #include "AddressTable.h" #include "input/DataFileManager.h" namespace TPCE { const UINT iMaxCAPerms = 3; // maximum # of customers having permissions to the same account const UINT iMinAccountsPerCustRange[3] = {1, 2, 5}; const UINT iMaxAccountsPerCustRange[3] = {4, 8, 10}; const UINT iMaxAccountsPerCust = 10; // must be the biggest number in iMaxAccountsPerCustRange array const TIdent iStartingBrokerID = 1; // This is the fixed range from which person ids (like CIDs) are selected // for the *additional* permissions on the account that make the // content of ACCOUNT_PERMISSION table. // // The range is fixed for any size database in order for the parallel loaders // to select person ids the same way and be compatible with runtime driver // (and to avoid database size parameter to the loader executable). // const TIdent iAccountPermissionIDRange = INT64_CONST(4024) * 1024 * 1024 - iDefaultStartFromCustomer; const UINT iPercentAccountsWithPositiveInitialBalance = 80; const double fAccountInitialPositiveBalanceMax = 9999999.99; const double fAccountInitialNegativeBalanceMin = -9999999.99; const UINT iPercentAccountAdditionalPermissions_0 = 60; const UINT iPercentAccountAdditionalPermissions_1 = 38; const UINT iPercentAccountAdditionalPermissions_2 = 2; const UINT iPercentAccountTaxStatusNonTaxable = 20; const UINT iPercentAccountTaxStatusTaxableAndWithhold = 50; const UINT iPercentAccountTaxStatusTaxableAndDontWithhold = 30; // Number of RNG calls to skip for one row in order // to not use any of the random values from the previous row. const UINT iRNGSkipOneRowCustomerAccount = 10; // real max count in v3.5: 7 enum eTaxStatus { eNone = -1, eNonTaxable = 0, eTaxableAndWithhold, eTaxableAndDontWithhold }; typedef struct CUSTOMER_ACCOUNT_AND_PERMISSION_ROW { CUSTOMER_ACCOUNT_ROW m_ca; ACCOUNT_PERMISSION_ROW m_perm[iMaxCAPerms + 1]; } * PCUSTOMER_ACCOUNT_AND_PERMISSION_ROW; class CCustomerAccountsAndPermissionsTable : public TableTemplate { const TaxableAccountNameDataFile_t &m_TaxableAccountName; const NonTaxableAccountNameDataFile_t &m_NonTaxableAccountName; TIdent m_iStartFromCustomer; TIdent m_iCustomerCount; TIdent m_iStartingCA_ID; // first CA_ID for the current customer UINT m_iRowsToGenForCust; // total # of rows to generate for a given // portfolio UINT m_iRowsGeneratedForCust; // rows already generated for a particular // portfolio CCustomerTable m_cust; CPerson m_person; UINT m_iPermsForCA; TIdent m_iBrokersCount; CAddressTable m_addr; // ADDRESS table - to calculate tax for TRADE UINT m_iLoadUnitSize; CCustomerSelection m_CustomerSelection; bool m_bCacheEnabled; int m_iCacheSizeNA; TIdent m_iCacheOffsetNA; UINT *m_CacheNA; int m_iCacheSizeTS; TIdent m_iCacheOffsetTS; eTaxStatus *m_CacheTS; /* * Generate only the Customer Account row. * * PARAMETERS: * none. * * RETURNS: * none. */ void GenerateCARow() { int iAcctType; // Generate customer account row. // GenerateNextCA_AD(); m_row.m_ca.CA_C_ID = GetCurrentC_ID(); // get from CUSTOMER // Generate broker id. m_row.m_ca.CA_B_ID = GenerateBrokerIdForAccount(m_row.m_ca.CA_ID); // Generate tax status and account name. if ((m_row.m_ca.CA_TAX_ST = (char)GetAccountTaxStatus(m_row.m_ca.CA_ID)) == eNonTaxable) { // non-taxable account iAcctType = (int)m_row.m_ca.CA_ID % m_NonTaxableAccountName.size(); // select account type snprintf(m_row.m_ca.CA_NAME, sizeof(m_row.m_ca.CA_NAME), "%s %s %s", m_person.GetFirstName(m_row.m_ca.CA_C_ID).c_str(), m_person.GetLastName(m_row.m_ca.CA_C_ID).c_str(), m_NonTaxableAccountName[iAcctType].NAME_CSTR()); } else { // taxable account iAcctType = (int)m_row.m_ca.CA_ID % m_TaxableAccountName.size(); // select account type snprintf(m_row.m_ca.CA_NAME, sizeof(m_row.m_ca.CA_NAME), "%s %s %s", m_person.GetFirstName(m_row.m_ca.CA_C_ID).c_str(), m_person.GetLastName(m_row.m_ca.CA_C_ID).c_str(), m_TaxableAccountName[iAcctType].NAME_CSTR()); } if (m_rnd.RndPercent(iPercentAccountsWithPositiveInitialBalance)) { m_row.m_ca.CA_BAL = m_rnd.RndDoubleIncrRange(0.00, fAccountInitialPositiveBalanceMax, 0.01); } else { m_row.m_ca.CA_BAL = m_rnd.RndDoubleIncrRange(fAccountInitialNegativeBalanceMin, 0.00, 0.01); } } /* * Helper function to generate parts of an ACCOUNT_PERMISSION row. * * PARAMETERS: * IN CA_ID - customer account id * IN C_ID - customer id * IN szACL - Access-Control-List string on the account * OUT row - ACCOUNT_PERMISSION row structure to fill * * RETURNS: * none. */ void FillAPRow(TIdent CA_ID, TIdent C_ID, const char *szACL, ACCOUNT_PERMISSION_ROW &row) { row.AP_CA_ID = CA_ID; m_cust.GetC_TAX_ID(C_ID, row.AP_TAX_ID); strncpy(row.AP_L_NAME, m_person.GetLastName(C_ID).c_str(), sizeof(row.AP_L_NAME)); strncpy(row.AP_F_NAME, m_person.GetFirstName(C_ID).c_str(), sizeof(row.AP_F_NAME)); strncpy(row.AP_ACL, szACL, sizeof(row.AP_ACL)); } /* * Generate only the Account Permissions row(s). * * PARAMETERS: * none. * * RETURNS: * none. */ void GenerateAPRows() { int iAdditionalPerms; TIdent CID_1, CID_2; // Generate account permissions rows. // Generate the owner row FillAPRow(m_row.m_ca.CA_ID, m_row.m_ca.CA_C_ID, "0000", m_row.m_perm[0]); iAdditionalPerms = GetNumPermsForCA(m_row.m_ca.CA_ID); switch (iAdditionalPerms) { case 0: m_iPermsForCA = 1; // 60% break; case 1: GetCIDsForPermissions(m_row.m_ca.CA_ID, m_row.m_ca.CA_C_ID, &CID_1, NULL); m_iPermsForCA = 2; // 38% // generate second account permission row FillAPRow(m_row.m_ca.CA_ID, CID_1, "0001", m_row.m_perm[1]); break; case 2: GetCIDsForPermissions(m_row.m_ca.CA_ID, m_row.m_ca.CA_C_ID, &CID_1, &CID_2); m_iPermsForCA = 3; // 2% // generate second account permission row FillAPRow(m_row.m_ca.CA_ID, CID_1, "0001", m_row.m_perm[1]); // generate third account permission row FillAPRow(m_row.m_ca.CA_ID, CID_2, "0011", m_row.m_perm[2]); break; } } public: /* * Constructor. * * PARAMETERS: * IN dfm - input flat files loaded in memory * IN iLoadUnitSize - should always be 1000 * IN iCustomerCount - number of customers to generate * IN iStartFromCustomer - ordinal position of the first * customer in the sequence (Note: 1-based) * * RETURNS: * not applicable. */ CCustomerAccountsAndPermissionsTable(const DataFileManager &dfm, UINT iLoadUnitSize, // # of customers in one load unit TIdent iCustomerCount, TIdent iStartFromCustomer, bool bCacheEnabled = false) : TableTemplate(), m_TaxableAccountName(dfm.TaxableAccountNameDataFile()), m_NonTaxableAccountName(dfm.NonTaxableAccountNameDataFile()), m_iStartFromCustomer(iStartFromCustomer), m_iCustomerCount(iCustomerCount), m_iRowsToGenForCust(0), m_iRowsGeneratedForCust(0), m_cust(dfm, iCustomerCount, iStartFromCustomer), m_person(dfm, iStartFromCustomer, bCacheEnabled), m_iPermsForCA(0), m_iBrokersCount(iLoadUnitSize / iBrokersDiv), m_addr(dfm, iCustomerCount, iStartFromCustomer, bCacheEnabled), m_iLoadUnitSize(iLoadUnitSize), m_bCacheEnabled(bCacheEnabled) { if (m_bCacheEnabled) { m_iCacheSizeNA = iDefaultLoadUnitSize; m_iCacheOffsetNA = iStartFromCustomer + iTIdentShift; m_CacheNA = new UINT[m_iCacheSizeNA]; for (int i = 0; i < m_iCacheSizeNA; i++) { m_CacheNA[i] = 0; } m_iCacheSizeTS = iDefaultLoadUnitSize * iMaxAccountsPerCust; m_iCacheOffsetTS = ((iStartFromCustomer - 1) + iTIdentShift) * iMaxAccountsPerCust; m_CacheTS = new eTaxStatus[m_iCacheSizeTS]; for (int i = 0; i < m_iCacheSizeTS; i++) { m_CacheTS[i] = eNone; } } }; /* * Destructor. */ ~CCustomerAccountsAndPermissionsTable() { if (m_bCacheEnabled) { delete[] m_CacheNA; delete[] m_CacheTS; } }; /* * Reset the state for the next load unit. * * PARAMETERS: * none. * * RETURNS: * none. */ void InitNextLoadUnit() { m_rnd.SetSeed(m_rnd.RndNthElement( RNGSeedTableDefault, (RNGSEED)(GetCurrentC_ID() * iMaxAccountsPerCust * iRNGSkipOneRowCustomerAccount))); ClearRecord(); // this is needed for EGenTest to work if (m_bCacheEnabled) { m_iCacheOffsetNA += iDefaultLoadUnitSize; for (int i = 0; i < m_iCacheSizeNA; i++) { m_CacheNA[i] = 0; } m_iCacheOffsetTS += iDefaultLoadUnitSize * iMaxAccountsPerCust; for (int i = 0; i < m_iCacheSizeTS; i++) { m_CacheTS[i] = eNone; } } } /* * Generate the number of accounts for a given customer id. * * PARAMETERS: * IN CID - customer id * IN iCustomerTier - customer tier (indicating trading * frequency) * * RETURNS: * number of accounts */ UINT GetNumberOfAccounts(TIdent CID, eCustomerTier iCustomerTier) { UINT iNumAccounts = 0; // We will sometimes get CID values that are outside the current // load unit (cached range). We need to check for this case // and avoid the lookup (as we will segfault or get bogus data.) TIdent index = CID - m_iCacheOffsetNA; bool bCheckCache = (index >= 0 && index < m_iCacheSizeNA); if (m_bCacheEnabled && bCheckCache) { iNumAccounts = m_CacheNA[index]; } if (iNumAccounts == 0) { UINT iMinAccountCount; UINT iMod; UINT iInverseCID; iMinAccountCount = iMinAccountsPerCustRange[iCustomerTier - eCustomerTierOne]; iMod = iMaxAccountsPerCustRange[iCustomerTier - eCustomerTierOne] - iMinAccountCount + 1; iInverseCID = m_CustomerSelection.GetInverseCID(CID); // Note: the calculations below assume load unit contains 1000 // customers. // if (iInverseCID < 200) // Tier 1 { iNumAccounts = (iInverseCID % iMod) + iMinAccountCount; } else { if (iInverseCID < 800) // Tier 2 { iNumAccounts = ((iInverseCID - 200 + 1) % iMod) + iMinAccountCount; } else // Tier 3 { iNumAccounts = ((iInverseCID - 800 + 2) % iMod) + iMinAccountCount; } } if (m_bCacheEnabled && bCheckCache) { m_CacheNA[index] = iNumAccounts; } } return iNumAccounts; } /* * Generate a random account for the specified customer. * The distribution is uniform across all the accounts for the customer. * * PARAMETERS: * IN RND - external Random Number Generator * IN iCustomerId - customer id * IN iCustomerTier - customer tier (indicating trading * frequency) OUT piCustomerAccount - customer account id OUT * piAccountCount - total number of accounts that the customer has * * RETURNS: * none. */ void GenerateRandomAccountId(CRandom &RND, // in - external RNG TIdent iCustomerId, // in eCustomerTier iCustomerTier, // in TIdent *piCustomerAccount, // out int *piAccountCount) // out { TIdent iCustomerAccount; int iAccountCount; TIdent iStartingAccount; iAccountCount = GetNumberOfAccounts(iCustomerId, iCustomerTier); iStartingAccount = GetStartingCA_ID(iCustomerId); // Select random account for the customer // iCustomerAccount = RND.RndInt64Range(iStartingAccount, iStartingAccount + iAccountCount - 1); if (piCustomerAccount != NULL) { *piCustomerAccount = iCustomerAccount; } if (piAccountCount != NULL) { *piAccountCount = iAccountCount; } } /* * Generate a random account for the specified customer. * * PARAMETERS: * IN RND - external Random Number Generator * IN iCustomerId - customer id * IN iCustomerTier - customer tier (indicating trading * frequency) * * RETURNS: * customer account id. */ TIdent GenerateRandomAccountId(CRandom &RND, TIdent iCustomerId, eCustomerTier iCustomerTier) { TIdent iAccountOffset; INT32 iAccountCount; TIdent iStartingAccount; iAccountCount = GetNumberOfAccounts(iCustomerId, iCustomerTier); iStartingAccount = GetStartingCA_ID(iCustomerId); iAccountOffset = (TIdent)RND.RndInt64Range(0, (INT64)iAccountCount - 1); return (iStartingAccount + iAccountOffset); } /* * Get starting account id for a given customer id. * This is needed for the driver to know what account ids belong to a * given customer. * * PARAMETERS: * IN CID - customer id * * RETURNS: * first account id of the customer. */ TIdent GetStartingCA_ID(TIdent CID) { // start account ids on the next boundary for the new customer return ((CID - 1) * iMaxAccountsPerCust + 1); } /* * Get (maximum potential) ending account id for a given customer id. * This is needed for the driver to restrict query results to active * accounts. * * PARAMETERS: * IN CID - customer id * * RETURNS: * last account id of the customer. */ TIdent GetEndingCA_ID(TIdent CID) { return (CID + iTIdentShift) * iMaxAccountsPerCust; } /* * Generate next CA_ID and update state information. * It is stored in the internal record structure and also returned. * The number of rows generated is incremented. This is why * this function cannot be called more than once for a record. * * PARAMETERS: * none. * * RETURNS: * next account id of the customer. */ TIdent GenerateNextCA_AD() { if (GetCurrentC_ID() % iDefaultLoadUnitSize == 0) { InitNextLoadUnit(); } ++m_iLastRowNumber; if (m_iRowsGeneratedForCust == m_iRowsToGenForCust) { // select next customer id as all the rows // for this customer have been generated m_cust.GenerateNextC_ID(); m_addr.GenerateNextAD_ID(); // next address id (to get the one for // this customer) m_iRowsGeneratedForCust = 0; // no row generated yet // total # of accounts for this customer m_iRowsToGenForCust = GetNumberOfAccounts(m_cust.GetCurrentC_ID(), m_cust.GetC_TIER(m_cust.GetCurrentC_ID())); m_iStartingCA_ID = GetStartingCA_ID(m_cust.GetCurrentC_ID()); } m_row.m_ca.CA_ID = m_iStartingCA_ID + m_iRowsGeneratedForCust; ++m_iRowsGeneratedForCust; // store state info m_bMoreRecords = m_cust.MoreRecords() || m_iRowsGeneratedForCust < m_iRowsToGenForCust; return m_row.m_ca.CA_ID; } /* * Generate the number (0-2) of additional permission rows for a certain * account. This number is needed by the driver. * * PARAMETERS: * IN CA_ID - customer account id * * RETURNS: * number of ACCOUNT_PERMISSION rows. */ int GetNumPermsForCA(TIdent CA_ID) { RNGSEED OldSeed; UINT iThreshold; UINT iNumberOfPermissions; OldSeed = m_rnd.GetSeed(); m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseNumberOfAccountPermissions, (RNGSEED)CA_ID)); iThreshold = m_rnd.RndGenerateIntegerPercentage(); if (iThreshold <= iPercentAccountAdditionalPermissions_0) { iNumberOfPermissions = 0; // 60% of accounts have just the owner row permissions } else { if (iThreshold <= iPercentAccountAdditionalPermissions_0 + iPercentAccountAdditionalPermissions_1) { iNumberOfPermissions = 1; // 38% of accounts have one additional permisison row } else { iNumberOfPermissions = 2; // 2% of accounts have two additional permission rows } } m_rnd.SetSeed(OldSeed); return (iNumberOfPermissions); } /* * Generate customer ids for ACCOUNT_PERMISSION table for a given account * id. Driver needs to know what those customer ids are based on the account * id. * * PARAMETERS: * IN CA_ID - customer account id * IN Owner_CID - customer id of the account owner * OUT CID_1 - first customer id in the ACL list of the * account OUT CID_2 - second customer id in the ACL list of the * account * * RETURNS: * none. */ void GetCIDsForPermissions(TIdent CA_ID, TIdent Owner_CID, TIdent *CID_1, TIdent *CID_2) { RNGSEED OldSeed; if (CID_1 == NULL) return; OldSeed = m_rnd.GetSeed(); m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseCIDForPermission1, (RNGSEED)CA_ID)); // Select from a fixed range that doesn't depend on the number of // customers in the database. This allows not to specify the total // number of customers to EGenLoader, only how many a particular // instance needs to generate (may be a fraction of total). Note: this // is not implemented right now. *CID_1 = m_rnd.RndInt64RangeExclude(iDefaultStartFromCustomer, iDefaultStartFromCustomer + iAccountPermissionIDRange, Owner_CID); if (CID_2 != NULL) { // NOTE: Reseeding the RNG here for the second CID value. The use of // this sequence is fuzzy because the number of RNG values consumed // is dependant on not only the CA_ID, but also the CID value chosen // above for the first permission. Using a different sequence here // may help prevent potential overlaps that might occur if the same // sequence from above were used. m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseCIDForPermission2, (RNGSEED)CA_ID)); do // make sure the second id is different from the first { *CID_2 = m_rnd.RndInt64RangeExclude(iDefaultStartFromCustomer, iDefaultStartFromCustomer + iAccountPermissionIDRange, Owner_CID); } while (*CID_2 == *CID_1); } m_rnd.SetSeed(OldSeed); } /* * Generate tax id for a given CA_ID. * This is needed to calculate tax on sale proceeds for the TRADE table. * * PARAMETERS: * IN iCA_ID - customer account id * * RETURNS: * tax status for the account. */ eTaxStatus GetAccountTaxStatus(TIdent iCA_ID) { eTaxStatus eCATaxStatus = eNone; // We will sometimes get CA values that are outside the current // load unit (cached range). We need to check for this case // and avoid the lookup (as we will segfault or get bogus data.) TIdent index = iCA_ID - m_iCacheOffsetTS; bool bCheckCache = (index >= 0 && index < m_iCacheSizeTS); if (m_bCacheEnabled && bCheckCache) { eCATaxStatus = m_CacheTS[index]; } if (eCATaxStatus == eNone) { RNGSEED OldSeed; UINT iThreshold; OldSeed = m_rnd.GetSeed(); m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseAccountTaxStatus, (RNGSEED)iCA_ID)); iThreshold = m_rnd.RndGenerateIntegerPercentage(); if (iThreshold <= iPercentAccountTaxStatusNonTaxable) { eCATaxStatus = eNonTaxable; } else { if (iThreshold <= iPercentAccountTaxStatusNonTaxable + iPercentAccountTaxStatusTaxableAndWithhold) { eCATaxStatus = eTaxableAndWithhold; } else { eCATaxStatus = eTaxableAndDontWithhold; } } m_rnd.SetSeed(OldSeed); if (m_bCacheEnabled && bCheckCache) { m_CacheTS[index] = eCATaxStatus; } } return eCATaxStatus; } /* * Get the country and division address codes for the customer that * owns the current account. * These codes are used to get the tax rates and calculate tax on trades * in the TRADE table. * * PARAMETERS: * OUT iDivCode - division (state/province) code * OUT iCtryCode - country (USA/CANADA) code * * RETURNS: * none. */ void GetDivisionAndCountryCodesForCurrentAccount(UINT &iDivCode, UINT &iCtryCode) { m_addr.GetDivisionAndCountryCodes(iDivCode, iCtryCode); } /* * Generate a broker id for a certain account. * Used in CTradeGen for updating YTD values. * * PARAMETERS: * IN iCA_ID - customer account id * * RETURNS: * broker id that corresponds to the account. */ TIdent GenerateBrokerIdForAccount(TIdent iCA_ID) { // Customer that own the account (actually, customer id minus 1) // TIdent iCustomerId = ((iCA_ID - 1) / iMaxAccountsPerCust) - iTIdentShift; // Set the starting broker to be the first broker for the current load // unit of customers. // TIdent iStartFromBroker = (iCustomerId / m_iLoadUnitSize) * m_iBrokersCount + iStartingBrokerID + iTIdentShift; // Note: this depends on broker ids being integer numbers from // contiguous range. The method of generating broker ids should be in // sync with the CBrokerTable. return m_rnd.RndNthInt64Range(RNGSeedBaseBrokerId, (RNGSEED)iCA_ID - (10 * iTIdentShift), iStartFromBroker, iStartFromBroker + m_iBrokersCount - 1); } /* * Generate all column values for the next row * and store them in the internal record structure. * Increment the number of rows generated. * * PARAMETERS: * none. * * RETURNS: * TRUE, if there are more records in the ADDRESS table; FALSE * othewise. */ bool GenerateNextRecord() { GenerateCARow(); GenerateAPRows(); // Return false if all the rows have been generated return (MoreRecords()); } /* * Return CUSTOMER_ACCOUNT row from the internal structure. * * PARAMETERS: * none. * * RETURNS: * current CUSTOMER_ACCOUNT record. */ // PCUSTOMER_ACCOUNT_ROW GetCARow() {return &m_row.m_ca;} const CUSTOMER_ACCOUNT_ROW &GetCARow() { return m_row.m_ca; } /* * Return ACCOUNT_PERMISSION row from the internal structure. * * PARAMETERS: * none. * * RETURNS: * current ACCOUNT_PERMISSION record. */ const ACCOUNT_PERMISSION_ROW &GetAPRow(UINT i) { if (i < m_iPermsForCA) return m_row.m_perm[i]; else throw std::range_error("Account Permission row index out of bounds."); } /* * Return the number of ACCOUNT_PERMISSION rows for the current * CUSTOMER_ACCOUNT row. * * PARAMETERS: * none. * * RETURNS: * the number of permissions for the account. */ UINT GetCAPermsCount() { return m_iPermsForCA; } /* * Return the customer ID for the currently generated CA_ID id. * * PARAMETERS: * none. * * RETURNS: * customer id of the account in the current CUSTOMER_ACCOUNT * record. */ TIdent GetCurrentC_ID() { return m_cust.GetCurrentC_ID(); } /* * Return the customer tier for the currently generated CA_ID id. * * PARAMETERS: * none. * * RETURNS: * customer tier of the customer, whose account is in the current * CUSTOMER_ACCOUNT record. */ eCustomerTier GetCurrentC_TIER() { return m_cust.GetC_TIER(m_cust.GetCurrentC_ID()); } }; } // namespace TPCE #endif // CUSTOMER_ACCOUNTS_AND_PERMISSIONS_TABLE_H