@@ -151,6 +151,15 @@ char *index_tablespace = NULL;
151151#define ntellers 10
152152#define naccounts 100000
153153
154+ /*
155+ * The scale factor at/beyond which 32bit integers are incapable of storing
156+ * 64bit values.
157+ *
158+ * Although the actual threshold is 21474, we use 20000 because it is easier to
159+ * document and remember, and isn't that far away from the real threshold.
160+ */
161+ #define SCALE_32BIT_THRESHOLD 20000
162+
154163bool use_log ;/* log transaction latencies to a file */
155164bool use_quiet ;/* quiet logging onto stderr */
156165bool is_connect ;/* establish connection for each transaction */
@@ -403,9 +412,77 @@ usage(void)
403412progname ,progname );
404413}
405414
415+ /*
416+ * strtoint64 -- convert a string to 64-bit integer
417+ *
418+ * This function is a modified version of scanint8() from
419+ * src/backend/utils/adt/int8.c.
420+ */
421+ static int64
422+ strtoint64 (const char * str )
423+ {
424+ const char * ptr = str ;
425+ int64 result = 0 ;
426+ int sign = 1 ;
427+
428+ /*
429+ * Do our own scan, rather than relying on sscanf which might be broken
430+ * for long long.
431+ */
432+
433+ /* skip leading spaces */
434+ while (* ptr && isspace ((unsignedchar )* ptr ))
435+ ptr ++ ;
436+
437+ /* handle sign */
438+ if (* ptr == '-' )
439+ {
440+ ptr ++ ;
441+
442+ /*
443+ * Do an explicit check for INT64_MIN.Ugly though this is, it's
444+ * cleaner than trying to get the loop below to handle it portably.
445+ */
446+ if (strncmp (ptr ,"9223372036854775808" ,19 )== 0 )
447+ {
448+ result = - INT64CONST (0x7fffffffffffffff )- 1 ;
449+ ptr += 19 ;
450+ gotogotdigits ;
451+ }
452+ sign = -1 ;
453+ }
454+ else if (* ptr == '+' )
455+ ptr ++ ;
456+
457+ /* require at least one digit */
458+ if (!isdigit ((unsignedchar )* ptr ))
459+ fprintf (stderr ,"invalid input syntax for integer: \"%s\"\n" ,str );
460+
461+ /* process digits */
462+ while (* ptr && isdigit ((unsignedchar )* ptr ))
463+ {
464+ int64 tmp = result * 10 + (* ptr ++ - '0' );
465+
466+ if ((tmp /10 )!= result )/* overflow? */
467+ fprintf (stderr ,"value \"%s\" is out of range for type bigint\n" ,str );
468+ result = tmp ;
469+ }
470+
471+ gotdigits :
472+
473+ /* allow trailing whitespace, but not other trailing chars */
474+ while (* ptr != '\0' && isspace ((unsignedchar )* ptr ))
475+ ptr ++ ;
476+
477+ if (* ptr != '\0' )
478+ fprintf (stderr ,"invalid input syntax for integer: \"%s\"\n" ,str );
479+
480+ return ((sign < 0 ) ?- result :result );
481+ }
482+
406483/* random number generator: uniform distribution from min to max inclusive */
407- static int
408- getrand (TState * thread ,int min ,int max )
484+ static int64
485+ getrand (TState * thread ,int64 min ,int64 max )
409486{
410487/*
411488 * Odd coding is so that min and max have approximately the same chance of
@@ -416,7 +493,7 @@ getrand(TState *thread, int min, int max)
416493 * protected by a mutex, and therefore a bottleneck on machines with many
417494 * CPUs.
418495 */
419- return min + (int ) ((max - min + 1 )* pg_erand48 (thread -> random_state ));
496+ return min + (int64 ) ((max - min + 1 )* pg_erand48 (thread -> random_state ));
420497}
421498
422499/* call PQexec() and exit() on failure */
@@ -960,7 +1037,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
9601037if (commands [st -> state ]== NULL )
9611038{
9621039st -> state = 0 ;
963- st -> use_file = getrand (thread ,0 ,num_files - 1 );
1040+ st -> use_file = ( int ) getrand (thread ,0 ,num_files - 1 );
9641041commands = sql_files [st -> use_file ];
9651042}
9661043}
@@ -1080,7 +1157,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
10801157if (pg_strcasecmp (argv [0 ],"setrandom" )== 0 )
10811158{
10821159char * var ;
1083- int min ,
1160+ int64 min ,
10841161max ;
10851162char res [64 ];
10861163
@@ -1092,10 +1169,10 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
10921169st -> ecnt ++ ;
10931170return true;
10941171}
1095- min = atoi (var );
1172+ min = strtoint64 (var );
10961173}
10971174else
1098- min = atoi (argv [2 ]);
1175+ min = strtoint64 (argv [2 ]);
10991176
11001177#ifdef NOT_USED
11011178if (min < 0 )
@@ -1114,10 +1191,10 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
11141191st -> ecnt ++ ;
11151192return true;
11161193}
1117- max = atoi (var );
1194+ max = strtoint64 (var );
11181195}
11191196else
1120- max = atoi (argv [3 ]);
1197+ max = strtoint64 (argv [3 ]);
11211198
11221199if (max < min )
11231200{
@@ -1127,8 +1204,8 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
11271204}
11281205
11291206/*
1130- * getrand()neeeds to be able to subtract max from min and add
1131- * one the result without overflowing. Since we know max > min,
1207+ * getrand()needs to be able to subtract max from min and add
1208+ * oneto the result without overflowing. Since we know max > min,
11321209 * we can detect overflow just by checking for a negative result.
11331210 * But we must check both that the subtraction doesn't overflow,
11341211 * and that adding one to the result doesn't overflow either.
@@ -1141,9 +1218,9 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
11411218}
11421219
11431220#ifdef DEBUG
1144- printf ("min:%d max:%d random:%d \n" ,min ,max ,getrand (thread ,min ,max ));
1221+ printf ("min:" INT64_FORMAT " max:" INT64_FORMAT " random:" INT64_FORMAT " \n" ,min ,max ,getrand (thread ,min ,max ));
11451222#endif
1146- snprintf (res ,sizeof (res ),"%d" ,getrand (thread ,min ,max ));
1223+ snprintf (res ,sizeof (res ),INT64_FORMAT ,getrand (thread ,min ,max ));
11471224
11481225if (!putVariable (st ,argv [0 ],argv [1 ],res ))
11491226{
@@ -1156,7 +1233,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
11561233else if (pg_strcasecmp (argv [0 ],"set" )== 0 )
11571234{
11581235char * var ;
1159- int ope1 ,
1236+ int64 ope1 ,
11601237ope2 ;
11611238char res [64 ];
11621239
@@ -1168,13 +1245,13 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
11681245st -> ecnt ++ ;
11691246return true;
11701247}
1171- ope1 = atoi (var );
1248+ ope1 = strtoint64 (var );
11721249}
11731250else
1174- ope1 = atoi (argv [2 ]);
1251+ ope1 = strtoint64 (argv [2 ]);
11751252
11761253if (argc < 5 )
1177- snprintf (res ,sizeof (res ),"%d" ,ope1 );
1254+ snprintf (res ,sizeof (res ),INT64_FORMAT ,ope1 );
11781255else
11791256{
11801257if (* argv [4 ]== ':' )
@@ -1185,17 +1262,17 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
11851262st -> ecnt ++ ;
11861263return true;
11871264}
1188- ope2 = atoi (var );
1265+ ope2 = strtoint64 (var );
11891266}
11901267else
1191- ope2 = atoi (argv [4 ]);
1268+ ope2 = strtoint64 (argv [4 ]);
11921269
11931270if (strcmp (argv [3 ],"+" )== 0 )
1194- snprintf (res ,sizeof (res ),"%d" ,ope1 + ope2 );
1271+ snprintf (res ,sizeof (res ),INT64_FORMAT ,ope1 + ope2 );
11951272else if (strcmp (argv [3 ],"-" )== 0 )
1196- snprintf (res ,sizeof (res ),"%d" ,ope1 - ope2 );
1273+ snprintf (res ,sizeof (res ),INT64_FORMAT ,ope1 - ope2 );
11971274else if (strcmp (argv [3 ],"*" )== 0 )
1198- snprintf (res ,sizeof (res ),"%d" ,ope1 * ope2 );
1275+ snprintf (res ,sizeof (res ),INT64_FORMAT ,ope1 * ope2 );
11991276else if (strcmp (argv [3 ],"/" )== 0 )
12001277{
12011278if (ope2 == 0 )
@@ -1204,7 +1281,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
12041281st -> ecnt ++ ;
12051282return true;
12061283}
1207- snprintf (res ,sizeof (res ),"%d" ,ope1 /ope2 );
1284+ snprintf (res ,sizeof (res ),INT64_FORMAT ,ope1 /ope2 );
12081285}
12091286else
12101287{
@@ -1311,6 +1388,15 @@ disconnect_all(CState *state, int length)
13111388static void
13121389init (bool is_no_vacuum )
13131390{
1391+
1392+ /* The scale factor at/beyond which 32bit integers are incapable of storing
1393+ * 64bit values.
1394+ *
1395+ * Although the actual threshold is 21474, we use 20000 because it is easier to
1396+ * document and remember, and isn't that far away from the real threshold.
1397+ */
1398+ #define SCALE_32BIT_THRESHOLD 20000
1399+
13141400/*
13151401 * Note: TPC-B requires at least 100 bytes per row, and the "filler"
13161402 * fields in these table declarations were intended to comply with that.
@@ -1329,7 +1415,9 @@ init(bool is_no_vacuum)
13291415struct ddlinfo DDLs []= {
13301416{
13311417"pgbench_history" ,
1332- "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)" ,
1418+ scale >=SCALE_32BIT_THRESHOLD
1419+ ?"tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)"
1420+ :"tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)" ,
133314210
13341422},
13351423{
@@ -1339,7 +1427,9 @@ init(bool is_no_vacuum)
13391427},
13401428{
13411429"pgbench_accounts" ,
1342- "aid int not null,bid int,abalance int,filler char(84)" ,
1430+ scale >=SCALE_32BIT_THRESHOLD
1431+ ?"aid bigint not null,bid int,abalance int,filler char(84)"
1432+ :"aid int not null,bid int,abalance int,filler char(84)" ,
134314331
13441434},
13451435{
@@ -1365,6 +1455,7 @@ init(bool is_no_vacuum)
13651455PGresult * res ;
13661456char sql [256 ];
13671457int i ;
1458+ int64 k ;
13681459
13691460/* used to track elapsed time and estimate of the remaining time */
13701461instr_time start ,diff ;
@@ -1441,11 +1532,11 @@ init(bool is_no_vacuum)
14411532
14421533INSTR_TIME_SET_CURRENT (start );
14431534
1444- for (i = 0 ;i < naccounts * scale ;i ++ )
1535+ for (k = 0 ;k < ( int64 ) naccounts * scale ;k ++ )
14451536{
1446- int j = i + 1 ;
1537+ int64 j = k + 1 ;
14471538
1448- snprintf (sql ,256 ,"%d\t%d \t%d\t\n" ,j ,i /naccounts + 1 ,0 );
1539+ snprintf (sql ,256 ,INT64_FORMAT "\t" INT64_FORMAT " \t%d\t\n" ,j ,k /naccounts + 1 ,0 );
14491540if (PQputline (con ,sql ))
14501541{
14511542fprintf (stderr ,"PQputline failed\n" );
@@ -1462,8 +1553,8 @@ init(bool is_no_vacuum)
14621553elapsed_sec = INSTR_TIME_GET_DOUBLE (diff );
14631554remaining_sec = (scale * naccounts - j )* elapsed_sec /j ;
14641555
1465- fprintf (stderr ,"%d of%d tuples (%d%%) done (elapsed %.2f s, remaining %.2f s).\n" ,
1466- j ,naccounts * scale ,
1556+ fprintf (stderr ,INT64_FORMAT " of" INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s).\n" ,
1557+ j ,( int64 ) naccounts * scale ,
14671558(int ) (((int64 )j * 100 ) / (naccounts * scale )),
14681559elapsed_sec ,remaining_sec );
14691560}
@@ -1479,8 +1570,8 @@ init(bool is_no_vacuum)
14791570/* have we reached the next interval (or end)? */
14801571if ((j == scale * naccounts )|| (elapsed_sec >=log_interval * LOG_STEP_SECONDS )) {
14811572
1482- fprintf (stderr ,"%d of%d tuples (%d%%) done (elapsed %.2f s, remaining %.2f s).\n" ,
1483- j ,naccounts * scale ,
1573+ fprintf (stderr ,INT64_FORMAT " of" INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s).\n" ,
1574+ j ,( int64 ) naccounts * scale ,
14841575(int ) (((int64 )j * 100 ) / (naccounts * scale )),elapsed_sec ,remaining_sec );
14851576
14861577/* skip to the next interval */