@@ -151,6 +151,15 @@ char *index_tablespace = NULL;
151
151
#define ntellers 10
152
152
#define naccounts 100000
153
153
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
+
154
163
bool use_log ; /* log transaction latencies to a file */
155
164
bool use_quiet ; /* quiet logging onto stderr */
156
165
bool is_connect ; /* establish connection for each transaction */
@@ -403,9 +412,77 @@ usage(void)
403
412
progname , progname );
404
413
}
405
414
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 ((unsigned char ) * 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
+ goto gotdigits ;
451
+ }
452
+ sign = -1 ;
453
+ }
454
+ else if (* ptr == '+' )
455
+ ptr ++ ;
456
+
457
+ /* require at least one digit */
458
+ if (!isdigit ((unsigned char ) * ptr ))
459
+ fprintf (stderr , "invalid input syntax for integer: \"%s\"\n" , str );
460
+
461
+ /* process digits */
462
+ while (* ptr && isdigit ((unsigned char ) * 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 ((unsigned char ) * 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
+
406
483
/* 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 )
409
486
{
410
487
/*
411
488
* 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)
416
493
* protected by a mutex, and therefore a bottleneck on machines with many
417
494
* CPUs.
418
495
*/
419
- return min + (int ) ((max - min + 1 ) * pg_erand48 (thread -> random_state ));
496
+ return min + (int64 ) ((max - min + 1 ) * pg_erand48 (thread -> random_state ));
420
497
}
421
498
422
499
/* call PQexec() and exit() on failure */
@@ -960,7 +1037,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
960
1037
if (commands [st -> state ] == NULL )
961
1038
{
962
1039
st -> state = 0 ;
963
- st -> use_file = getrand (thread , 0 , num_files - 1 );
1040
+ st -> use_file = ( int ) getrand (thread , 0 , num_files - 1 );
964
1041
commands = sql_files [st -> use_file ];
965
1042
}
966
1043
}
@@ -1080,7 +1157,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
1080
1157
if (pg_strcasecmp (argv [0 ], "setrandom" ) == 0 )
1081
1158
{
1082
1159
char * var ;
1083
- int min ,
1160
+ int64 min ,
1084
1161
max ;
1085
1162
char res [64 ];
1086
1163
@@ -1092,10 +1169,10 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
1092
1169
st -> ecnt ++ ;
1093
1170
return true;
1094
1171
}
1095
- min = atoi (var );
1172
+ min = strtoint64 (var );
1096
1173
}
1097
1174
else
1098
- min = atoi (argv [2 ]);
1175
+ min = strtoint64 (argv [2 ]);
1099
1176
1100
1177
#ifdef NOT_USED
1101
1178
if (min < 0 )
@@ -1114,10 +1191,10 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
1114
1191
st -> ecnt ++ ;
1115
1192
return true;
1116
1193
}
1117
- max = atoi (var );
1194
+ max = strtoint64 (var );
1118
1195
}
1119
1196
else
1120
- max = atoi (argv [3 ]);
1197
+ max = strtoint64 (argv [3 ]);
1121
1198
1122
1199
if (max < min )
1123
1200
{
@@ -1127,8 +1204,8 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
1127
1204
}
1128
1205
1129
1206
/*
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
+ * one to the result without overflowing. Since we know max > min,
1132
1209
* we can detect overflow just by checking for a negative result.
1133
1210
* But we must check both that the subtraction doesn't overflow,
1134
1211
* 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)
1141
1218
}
1142
1219
1143
1220
#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 ));
1145
1222
#endif
1146
- snprintf (res , sizeof (res ), "%d" , getrand (thread , min , max ));
1223
+ snprintf (res , sizeof (res ), INT64_FORMAT , getrand (thread , min , max ));
1147
1224
1148
1225
if (!putVariable (st , argv [0 ], argv [1 ], res ))
1149
1226
{
@@ -1156,7 +1233,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
1156
1233
else if (pg_strcasecmp (argv [0 ], "set" ) == 0 )
1157
1234
{
1158
1235
char * var ;
1159
- int ope1 ,
1236
+ int64 ope1 ,
1160
1237
ope2 ;
1161
1238
char res [64 ];
1162
1239
@@ -1168,13 +1245,13 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
1168
1245
st -> ecnt ++ ;
1169
1246
return true;
1170
1247
}
1171
- ope1 = atoi (var );
1248
+ ope1 = strtoint64 (var );
1172
1249
}
1173
1250
else
1174
- ope1 = atoi (argv [2 ]);
1251
+ ope1 = strtoint64 (argv [2 ]);
1175
1252
1176
1253
if (argc < 5 )
1177
- snprintf (res , sizeof (res ), "%d" , ope1 );
1254
+ snprintf (res , sizeof (res ), INT64_FORMAT , ope1 );
1178
1255
else
1179
1256
{
1180
1257
if (* argv [4 ] == ':' )
@@ -1185,17 +1262,17 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
1185
1262
st -> ecnt ++ ;
1186
1263
return true;
1187
1264
}
1188
- ope2 = atoi (var );
1265
+ ope2 = strtoint64 (var );
1189
1266
}
1190
1267
else
1191
- ope2 = atoi (argv [4 ]);
1268
+ ope2 = strtoint64 (argv [4 ]);
1192
1269
1193
1270
if (strcmp (argv [3 ], "+" ) == 0 )
1194
- snprintf (res , sizeof (res ), "%d" , ope1 + ope2 );
1271
+ snprintf (res , sizeof (res ), INT64_FORMAT , ope1 + ope2 );
1195
1272
else if (strcmp (argv [3 ], "-" ) == 0 )
1196
- snprintf (res , sizeof (res ), "%d" , ope1 - ope2 );
1273
+ snprintf (res , sizeof (res ), INT64_FORMAT , ope1 - ope2 );
1197
1274
else if (strcmp (argv [3 ], "*" ) == 0 )
1198
- snprintf (res , sizeof (res ), "%d" , ope1 * ope2 );
1275
+ snprintf (res , sizeof (res ), INT64_FORMAT , ope1 * ope2 );
1199
1276
else if (strcmp (argv [3 ], "/" ) == 0 )
1200
1277
{
1201
1278
if (ope2 == 0 )
@@ -1204,7 +1281,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile)
1204
1281
st -> ecnt ++ ;
1205
1282
return true;
1206
1283
}
1207
- snprintf (res , sizeof (res ), "%d" , ope1 / ope2 );
1284
+ snprintf (res , sizeof (res ), INT64_FORMAT , ope1 / ope2 );
1208
1285
}
1209
1286
else
1210
1287
{
@@ -1311,6 +1388,15 @@ disconnect_all(CState *state, int length)
1311
1388
static void
1312
1389
init (bool is_no_vacuum )
1313
1390
{
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
+
1314
1400
/*
1315
1401
* Note: TPC-B requires at least 100 bytes per row, and the "filler"
1316
1402
* fields in these table declarations were intended to comply with that.
@@ -1329,7 +1415,9 @@ init(bool is_no_vacuum)
1329
1415
struct ddlinfo DDLs [] = {
1330
1416
{
1331
1417
"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)" ,
1333
1421
0
1334
1422
},
1335
1423
{
@@ -1339,7 +1427,9 @@ init(bool is_no_vacuum)
1339
1427
},
1340
1428
{
1341
1429
"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)" ,
1343
1433
1
1344
1434
},
1345
1435
{
@@ -1365,6 +1455,7 @@ init(bool is_no_vacuum)
1365
1455
PGresult * res ;
1366
1456
char sql [256 ];
1367
1457
int i ;
1458
+ int64 k ;
1368
1459
1369
1460
/* used to track elapsed time and estimate of the remaining time */
1370
1461
instr_time start , diff ;
@@ -1441,11 +1532,11 @@ init(bool is_no_vacuum)
1441
1532
1442
1533
INSTR_TIME_SET_CURRENT (start );
1443
1534
1444
- for (i = 0 ; i < naccounts * scale ; i ++ )
1535
+ for (k = 0 ; k < ( int64 ) naccounts * scale ; k ++ )
1445
1536
{
1446
- int j = i + 1 ;
1537
+ int64 j = k + 1 ;
1447
1538
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 );
1449
1540
if (PQputline (con , sql ))
1450
1541
{
1451
1542
fprintf (stderr , "PQputline failed\n" );
@@ -1462,8 +1553,8 @@ init(bool is_no_vacuum)
1462
1553
elapsed_sec = INSTR_TIME_GET_DOUBLE (diff );
1463
1554
remaining_sec = (scale * naccounts - j ) * elapsed_sec / j ;
1464
1555
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 ,
1467
1558
(int ) (((int64 ) j * 100 ) / (naccounts * scale )),
1468
1559
elapsed_sec , remaining_sec );
1469
1560
}
@@ -1479,8 +1570,8 @@ init(bool is_no_vacuum)
1479
1570
/* have we reached the next interval (or end)? */
1480
1571
if ((j == scale * naccounts ) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS )) {
1481
1572
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 ,
1484
1575
(int ) (((int64 ) j * 100 ) / (naccounts * scale )), elapsed_sec , remaining_sec );
1485
1576
1486
1577
/* skip to the next interval */
0 commit comments