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 | #include "main/EGenTables_stdafx.h" |
39 | |
40 | using namespace TPCE; |
41 | |
42 | namespace TPCE { |
43 | const char *szUSAreaCode = "011" ; // USA/Canada phone area code |
44 | char EMAIL_DOMAINs[iNumEMAIL_DOMAINs][15] = {"@msn.com" , "@hotmail.com" , "@rr.com" , |
45 | "@netzero.com" , "@earthlink.com" , "@attbi.com" }; |
46 | } // namespace TPCE |
47 | |
48 | // Percentages used when generating C_TIER |
49 | const int iPercentCustomersInC_TIER_1 = 20; |
50 | const int iPercentCustomersInC_TIER_2 = 60; |
51 | const int iPercentCustomersInC_TIER_3 = 100 - iPercentCustomersInC_TIER_1 - iPercentCustomersInC_TIER_2; |
52 | |
53 | // Percentages used when generating C_DOB |
54 | const int iPercentUnder18 = 5; |
55 | const int iPercentBetween19And24 = 16; |
56 | const int iPercentBetween25And34 = 17; |
57 | const int iPercentBetween35And44 = 19; |
58 | const int iPercentBetween45And54 = 16; |
59 | const int iPercentBetween55And64 = 11; |
60 | const int iPercentBetween65And74 = 8; |
61 | const int iPercentBetween75And84 = 7; |
62 | const int iPercentOver85 = 1; |
63 | |
64 | // Number of RNG calls to skip for one row in order |
65 | // to not use any of the random values from the previous row. |
66 | const int iRNGSkipOneRowCustomer = 35; // real max count in v3.5: 29 |
67 | |
68 | /* |
69 | * CCustomerTable constructor |
70 | */ |
71 | CCustomerTable::CCustomerTable(const DataFileManager &dfm, TIdent iCustomerCount, TIdent iStartFromCustomer) |
72 | : TableTemplate<CUSTOMER_ROW>(), m_iRowsToGenerate(iCustomerCount), m_person(dfm, iStartFromCustomer, true), |
73 | m_Phones(dfm.AreaCodeDataFile()), m_iStartFromCustomer(iStartFromCustomer), m_iCustomerCount(iCustomerCount), |
74 | m_StatusTypeFile(dfm.StatusTypeDataFile()), m_CustomerSelection() { |
75 | m_iCompanyCount = dfm.CompanyFile().GetSize(); |
76 | m_iExchangeCount = dfm.ExchangeDataFile().size(); |
77 | } |
78 | |
79 | /* |
80 | * Reset the state for the next load unit |
81 | */ |
82 | void CCustomerTable::InitNextLoadUnit() { |
83 | m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedTableDefault, |
84 | ((RNGSEED)m_iLastRowNumber + m_iStartFromCustomer - 1) * iRNGSkipOneRowCustomer)); |
85 | |
86 | ClearRecord(); // this is needed for EGenTest to work |
87 | |
88 | m_person.InitNextLoadUnit(); |
89 | } |
90 | |
91 | /* |
92 | * Generates only the next Customer ID value |
93 | */ |
94 | TIdent CCustomerTable::GenerateNextC_ID() { |
95 | if (m_iLastRowNumber % iDefaultLoadUnitSize == 0) { |
96 | InitNextLoadUnit(); |
97 | } |
98 | |
99 | ++m_iLastRowNumber; // increment state info |
100 | m_bMoreRecords = m_iLastRowNumber < m_iRowsToGenerate; |
101 | |
102 | m_row.C_ID = m_iLastRowNumber + m_iStartFromCustomer - 1 + iTIdentShift; |
103 | |
104 | return m_row.C_ID; |
105 | } |
106 | /* |
107 | * Return current customer id. |
108 | */ |
109 | TIdent CCustomerTable::GetCurrentC_ID() { |
110 | return m_iLastRowNumber + m_iStartFromCustomer - 1 + iTIdentShift; |
111 | } |
112 | |
113 | /* |
114 | * Generate tax id. |
115 | */ |
116 | void CCustomerTable::GetC_TAX_ID(TIdent C_ID, char *szOutput) { |
117 | m_person.GetTaxID(C_ID, szOutput); |
118 | } |
119 | |
120 | /* |
121 | * Generate C_ST_ID. |
122 | */ |
123 | void CCustomerTable::GenerateC_ST_ID() { |
124 | strncpy(m_row.C_ST_ID, m_StatusTypeFile[eActive].ST_ID_CSTR(), sizeof(m_row.C_ST_ID)); |
125 | } |
126 | |
127 | /* |
128 | * Generate first, last name, and the gender. |
129 | */ |
130 | void CCustomerTable::GeneratePersonInfo() { |
131 | // Fill in the first name, last name, and the tax id |
132 | m_person.GetFirstLastAndTaxID(m_row.C_ID, m_row.C_F_NAME, m_row.C_L_NAME, m_row.C_TAX_ID); |
133 | // Fill in the gender |
134 | m_row.C_GNDR = m_person.GetGender(m_row.C_ID); |
135 | // Fill in the middle name |
136 | m_row.C_M_NAME[0] = m_person.GetMiddleName(m_row.C_ID); |
137 | m_row.C_M_NAME[1] = '\0'; |
138 | } |
139 | |
140 | /* |
141 | * Generate C_TIER. |
142 | */ |
143 | eCustomerTier CCustomerTable::GetC_TIER(TIdent C_ID) { |
144 | return m_CustomerSelection.GetTier(C_ID); |
145 | } |
146 | |
147 | /* |
148 | * Generate date of birth. |
149 | */ |
150 | void CCustomerTable::GenerateC_DOB() { |
151 | // min and max age brackets limits in years |
152 | static int age_brackets[] = {10, 19, 25, 35, 45, 55, 65, 75, 85, 100}; |
153 | int age_bracket; |
154 | int dob_daysno_min, dob_daysno_max; // min and max date of birth in days |
155 | int dob_in_days; // generated random date of birth in days |
156 | |
157 | int iThreshold = m_rnd.RndGenerateIntegerPercentage(); |
158 | |
159 | // Determine customer age bracket according to the distribution. |
160 | if (iThreshold <= iPercentUnder18) |
161 | age_bracket = 0; |
162 | else if (iThreshold <= iPercentUnder18 + iPercentBetween19And24) |
163 | age_bracket = 1; |
164 | else if (iThreshold <= iPercentUnder18 + iPercentBetween19And24 + iPercentBetween25And34) |
165 | age_bracket = 2; |
166 | else if (iThreshold <= iPercentUnder18 + iPercentBetween19And24 + iPercentBetween25And34 + iPercentBetween35And44) |
167 | age_bracket = 3; |
168 | else if (iThreshold <= iPercentUnder18 + iPercentBetween19And24 + iPercentBetween25And34 + iPercentBetween35And44 + |
169 | iPercentBetween45And54) |
170 | age_bracket = 4; |
171 | else if (iThreshold <= iPercentUnder18 + iPercentBetween19And24 + iPercentBetween25And34 + iPercentBetween35And44 + |
172 | iPercentBetween45And54 + iPercentBetween55And64) |
173 | age_bracket = 5; |
174 | else if (iThreshold <= iPercentUnder18 + iPercentBetween19And24 + iPercentBetween25And34 + iPercentBetween35And44 + |
175 | iPercentBetween45And54 + iPercentBetween55And64 + iPercentBetween65And74) |
176 | age_bracket = 6; |
177 | else if (iThreshold <= iPercentUnder18 + iPercentBetween19And24 + iPercentBetween25And34 + iPercentBetween35And44 + |
178 | iPercentBetween45And54 + iPercentBetween55And64 + iPercentBetween65And74 + |
179 | iPercentBetween75And84) |
180 | age_bracket = 7; |
181 | else |
182 | age_bracket = 8; |
183 | assert(age_bracket < static_cast<int>(sizeof(age_brackets) / sizeof(age_brackets[0]))); |
184 | |
185 | // Determine the range of valid day numbers for this person's birthday. |
186 | dob_daysno_min = CDateTime::YMDtoDayno(InitialTradePopulationBaseYear - age_brackets[age_bracket + 1], |
187 | InitialTradePopulationBaseMonth, InitialTradePopulationBaseDay) + |
188 | 1; |
189 | dob_daysno_max = CDateTime::YMDtoDayno(InitialTradePopulationBaseYear - age_brackets[age_bracket], |
190 | InitialTradePopulationBaseMonth, InitialTradePopulationBaseDay); |
191 | |
192 | // Generate the random age expressed in days that falls into the particular |
193 | // range. |
194 | dob_in_days = m_rnd.RndIntRange(dob_daysno_min, dob_daysno_max); |
195 | |
196 | m_row.C_DOB.Set(dob_in_days); |
197 | } |
198 | |
199 | /* |
200 | * Generate C_AD_ID (address id). |
201 | */ |
202 | void CCustomerTable::GenerateC_AD_ID() { |
203 | // Generate address id sequentially, allowing space for Exchanges and |
204 | // Companies in the beggining of the address ids range. |
205 | m_row.C_AD_ID = m_iExchangeCount + m_iCompanyCount + GetCurrentC_ID(); |
206 | } |
207 | |
208 | /* |
209 | * Generate C_CTRY_1. |
210 | */ |
211 | void CCustomerTable::GenerateC_CTRY_1() { |
212 | strncpy(m_row.C_CTRY_1, szUSAreaCode, sizeof(m_row.C_CTRY_1)); |
213 | } |
214 | |
215 | /* |
216 | * Generate C_CTRY_2. |
217 | */ |
218 | void CCustomerTable::GenerateC_CTRY_2() { |
219 | strncpy(m_row.C_CTRY_2, szUSAreaCode, sizeof(m_row.C_CTRY_2)); |
220 | } |
221 | |
222 | /* |
223 | * Generate C_CTRY_3. |
224 | */ |
225 | void CCustomerTable::GenerateC_CTRY_3() { |
226 | strncpy(m_row.C_CTRY_3, szUSAreaCode, sizeof(m_row.C_CTRY_3)); |
227 | } |
228 | |
229 | /* |
230 | * Generate C_AREA_1 |
231 | */ |
232 | void CCustomerTable::GenerateC_AREA_1() { |
233 | RNGSEED OldSeed; |
234 | int iThreshold; |
235 | |
236 | OldSeed = m_rnd.GetSeed(); |
237 | |
238 | m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseC_AREA_1, (RNGSEED)m_row.C_ID)); |
239 | |
240 | // generate Threshold up to the value of the last key (first member in a |
241 | // pair) |
242 | iThreshold = m_rnd.RndIntRange(0, m_Phones.size() - 1); |
243 | |
244 | // copy the area code that corresponds to the Threshold |
245 | strncpy(m_row.C_AREA_1, m_Phones[iThreshold].AREA_CODE_CSTR(), sizeof(m_row.C_AREA_1)); |
246 | |
247 | m_rnd.SetSeed(OldSeed); |
248 | } |
249 | |
250 | /* |
251 | * Generate C_AREA_2 |
252 | */ |
253 | void CCustomerTable::GenerateC_AREA_2() { |
254 | RNGSEED OldSeed; |
255 | int iThreshold; |
256 | |
257 | OldSeed = m_rnd.GetSeed(); |
258 | |
259 | m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseC_AREA_2, (RNGSEED)m_row.C_ID)); |
260 | |
261 | // generate Threshold up to the value of the last key (first member in a |
262 | // pair) |
263 | iThreshold = m_rnd.RndIntRange(0, m_Phones.size() - 1); |
264 | |
265 | // copy the area code that corresponds to the Threshold |
266 | strncpy(m_row.C_AREA_2, m_Phones[iThreshold].AREA_CODE_CSTR(), sizeof(m_row.C_AREA_2)); |
267 | |
268 | m_rnd.SetSeed(OldSeed); |
269 | } |
270 | |
271 | /* |
272 | * Generate C_AREA_3 |
273 | */ |
274 | void CCustomerTable::GenerateC_AREA_3() { |
275 | RNGSEED OldSeed; |
276 | int iThreshold; |
277 | |
278 | OldSeed = m_rnd.GetSeed(); |
279 | |
280 | m_rnd.SetSeed(m_rnd.RndNthElement(RNGSeedBaseC_AREA_3, (RNGSEED)m_row.C_ID)); |
281 | |
282 | // generate Threshold up to the value of the last key (first member in a |
283 | // pair) |
284 | iThreshold = m_rnd.RndIntRange(0, m_Phones.size() - 1); |
285 | |
286 | // copy the area code that corresponds to the Threshold |
287 | strncpy(m_row.C_AREA_3, m_Phones[iThreshold].AREA_CODE_CSTR(), sizeof(m_row.C_AREA_3)); |
288 | |
289 | m_rnd.SetSeed(OldSeed); |
290 | } |
291 | |
292 | /* |
293 | * Generate C_LOCAL_1. |
294 | */ |
295 | void CCustomerTable::GenerateC_LOCAL_1() { |
296 | m_rnd.RndAlphaNumFormatted(m_row.C_LOCAL_1, |
297 | "nnnnnnn" ); // 7-digit phone number |
298 | } |
299 | |
300 | /* |
301 | * Generate C_LOCAL_2. |
302 | */ |
303 | void CCustomerTable::GenerateC_LOCAL_2() { |
304 | m_rnd.RndAlphaNumFormatted(m_row.C_LOCAL_2, |
305 | "nnnnnnn" ); // 7-digit phone number |
306 | } |
307 | |
308 | /* |
309 | * Generate C_LOCAL_3. |
310 | */ |
311 | void CCustomerTable::GenerateC_LOCAL_3() { |
312 | m_rnd.RndAlphaNumFormatted(m_row.C_LOCAL_3, |
313 | "nnnnnnn" ); // 7-digit phone number |
314 | } |
315 | |
316 | /* |
317 | * Generate C_EXT_1. |
318 | */ |
319 | void CCustomerTable::GenerateC_EXT_1() { |
320 | int iThreshold = m_rnd.RndGenerateIntegerPercentage(); |
321 | |
322 | if (iThreshold <= 25) { |
323 | m_rnd.RndAlphaNumFormatted(m_row.C_EXT_1, |
324 | "nnn" ); // 3-digit phone extension |
325 | } else { |
326 | *m_row.C_EXT_1 = '\0'; // no extension |
327 | } |
328 | } |
329 | |
330 | /* |
331 | * Generate C_EXT_2. |
332 | */ |
333 | void CCustomerTable::GenerateC_EXT_2() { |
334 | int iThreshold = m_rnd.RndGenerateIntegerPercentage(); |
335 | |
336 | if (iThreshold <= 15) { |
337 | m_rnd.RndAlphaNumFormatted(m_row.C_EXT_2, |
338 | "nnn" ); // 3-digit phone extension |
339 | } else { |
340 | *m_row.C_EXT_2 = '\0'; // no extension |
341 | } |
342 | } |
343 | |
344 | /* |
345 | * Generate C_EXT_3. |
346 | */ |
347 | void CCustomerTable::GenerateC_EXT_3() { |
348 | int iThreshold = m_rnd.RndGenerateIntegerPercentage(); |
349 | |
350 | if (iThreshold <= 5) { |
351 | m_rnd.RndAlphaNumFormatted(m_row.C_EXT_3, |
352 | "nnn" ); // 3-digit phone extension |
353 | } else { |
354 | *m_row.C_EXT_3 = '\0'; // no extension |
355 | } |
356 | } |
357 | |
358 | /* |
359 | * Generate Email 1 and Email 2 that are guaranteed to be different. |
360 | */ |
361 | void CCustomerTable::GenerateC_EMAIL_1_and_C_EMAIL_2() { |
362 | size_t iLen; |
363 | int iEmail1Index; |
364 | |
365 | iEmail1Index = m_rnd.RndIntRange(0, iNumEMAIL_DOMAINs - 1); |
366 | |
367 | // Generate EMAIL_1 |
368 | iLen = strlen(m_row.C_L_NAME); |
369 | m_row.C_EMAIL_1[0] = m_row.C_F_NAME[0]; // first char of the first name |
370 | strncpy(&m_row.C_EMAIL_1[1], m_row.C_L_NAME, // last name |
371 | sizeof(m_row.C_EMAIL_1) - 1); |
372 | strncpy(&m_row.C_EMAIL_1[1 + iLen], |
373 | EMAIL_DOMAINs[iEmail1Index], // domain name |
374 | sizeof(m_row.C_EMAIL_1) - iLen - 1); |
375 | |
376 | // Generate EMAIL_2 that is different from EMAIL_1 |
377 | m_row.C_EMAIL_2[0] = m_row.C_F_NAME[0]; // first char of the first name |
378 | strncpy(&m_row.C_EMAIL_2[1], m_row.C_L_NAME, |
379 | sizeof(m_row.C_EMAIL_2) - 1); // last name |
380 | strncpy(&m_row.C_EMAIL_2[1 + iLen], |
381 | EMAIL_DOMAINs[m_rnd.RndIntRangeExclude(0, iNumEMAIL_DOMAINs - 1, iEmail1Index)], // domain name |
382 | sizeof(m_row.C_EMAIL_2) - iLen - 1); |
383 | } |
384 | |
385 | /* |
386 | * Generates all column values for the next row |
387 | */ |
388 | bool CCustomerTable::GenerateNextRecord() { |
389 | GenerateNextC_ID(); |
390 | GenerateC_ST_ID(); |
391 | GeneratePersonInfo(); // generate last name, first name, gender and tax ID. |
392 | m_row.C_TIER = (char)GetC_TIER(m_row.C_ID); |
393 | GenerateC_DOB(); |
394 | GenerateC_AD_ID(); |
395 | GenerateC_CTRY_1(); |
396 | GenerateC_AREA_1(); |
397 | GenerateC_LOCAL_1(); |
398 | GenerateC_EXT_1(); |
399 | GenerateC_CTRY_2(); |
400 | GenerateC_AREA_2(); |
401 | GenerateC_LOCAL_2(); |
402 | GenerateC_EXT_2(); |
403 | GenerateC_CTRY_3(); |
404 | GenerateC_AREA_3(); |
405 | GenerateC_LOCAL_3(); |
406 | GenerateC_EXT_3(); |
407 | GenerateC_EMAIL_1_and_C_EMAIL_2(); |
408 | |
409 | // Return false if all the rows have been generated |
410 | return MoreRecords(); |
411 | } |
412 | |