Age Owner TLA Line data Source code
1 : /*
2 : * pgbench.c
3 : *
4 : * A simple benchmark program for PostgreSQL
5 : * Originally written by Tatsuo Ishii and enhanced by many contributors.
6 : *
7 : * src/bin/pgbench/pgbench.c
8 : * Copyright (c) 2000-2023, PostgreSQL Global Development Group
9 : * ALL RIGHTS RESERVED;
10 : *
11 : * Permission to use, copy, modify, and distribute this software and its
12 : * documentation for any purpose, without fee, and without a written agreement
13 : * is hereby granted, provided that the above copyright notice and this
14 : * paragraph and the following two paragraphs appear in all copies.
15 : *
16 : * IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
17 : * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
18 : * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
19 : * DOCUMENTATION, EVEN IF THE AUTHOR OR DISTRIBUTORS HAVE BEEN ADVISED OF THE
20 : * POSSIBILITY OF SUCH DAMAGE.
21 : *
22 : * THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIMS ANY WARRANTIES,
23 : * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24 : * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
25 : * ON AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAS NO OBLIGATIONS TO
26 : * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
27 : *
28 : */
29 :
30 : #if defined(WIN32) && FD_SETSIZE < 1024
31 : #error FD_SETSIZE needs to have been increased
32 : #endif
33 :
34 : #include "postgres_fe.h"
35 :
36 : #include <ctype.h>
37 : #include <float.h>
38 : #include <limits.h>
39 : #include <math.h>
40 : #include <signal.h>
41 : #include <time.h>
42 : #include <sys/time.h>
43 : #include <sys/resource.h> /* for getrlimit */
44 :
45 : /* For testing, PGBENCH_USE_SELECT can be defined to force use of that code */
46 : #if defined(HAVE_PPOLL) && !defined(PGBENCH_USE_SELECT)
47 : #define POLL_USING_PPOLL
48 : #ifdef HAVE_POLL_H
49 : #include <poll.h>
50 : #endif
51 : #else /* no ppoll(), so use select() */
52 : #define POLL_USING_SELECT
53 : #include <sys/select.h>
54 : #endif
55 :
56 : #include "common/int.h"
57 : #include "common/logging.h"
58 : #include "common/pg_prng.h"
59 : #include "common/string.h"
60 : #include "common/username.h"
61 : #include "fe_utils/cancel.h"
62 : #include "fe_utils/conditional.h"
63 : #include "fe_utils/option_utils.h"
64 : #include "fe_utils/string_utils.h"
65 : #include "getopt_long.h"
66 : #include "libpq-fe.h"
67 : #include "pgbench.h"
68 : #include "port/pg_bitutils.h"
69 : #include "portability/instr_time.h"
70 :
71 : /* X/Open (XSI) requires <math.h> to provide M_PI, but core POSIX does not */
72 : #ifndef M_PI
73 : #define M_PI 3.14159265358979323846
74 : #endif
75 :
76 : #define ERRCODE_T_R_SERIALIZATION_FAILURE "40001"
77 : #define ERRCODE_T_R_DEADLOCK_DETECTED "40P01"
78 : #define ERRCODE_UNDEFINED_TABLE "42P01"
79 :
80 : /*
81 : * Hashing constants
82 : */
83 : #define FNV_PRIME UINT64CONST(0x100000001b3)
84 : #define FNV_OFFSET_BASIS UINT64CONST(0xcbf29ce484222325)
85 : #define MM2_MUL UINT64CONST(0xc6a4a7935bd1e995)
86 : #define MM2_MUL_TIMES_8 UINT64CONST(0x35253c9ade8f4ca8)
87 : #define MM2_ROT 47
88 :
89 : /*
90 : * Multi-platform socket set implementations
91 : */
92 :
93 : #ifdef POLL_USING_PPOLL
94 : #define SOCKET_WAIT_METHOD "ppoll"
95 :
96 : typedef struct socket_set
97 : {
98 : int maxfds; /* allocated length of pollfds[] array */
99 : int curfds; /* number currently in use */
100 : struct pollfd pollfds[FLEXIBLE_ARRAY_MEMBER];
101 : } socket_set;
102 :
103 : #endif /* POLL_USING_PPOLL */
104 :
105 : #ifdef POLL_USING_SELECT
106 : #define SOCKET_WAIT_METHOD "select"
107 :
108 : typedef struct socket_set
109 : {
110 : int maxfd; /* largest FD currently set in fds */
111 : fd_set fds;
112 : } socket_set;
113 :
114 : #endif /* POLL_USING_SELECT */
115 :
116 : /*
117 : * Multi-platform thread implementations
118 : */
119 :
120 : #ifdef WIN32
121 : /* Use Windows threads */
122 : #include <windows.h>
123 : #define GETERRNO() (_dosmaperr(GetLastError()), errno)
124 : #define THREAD_T HANDLE
125 : #define THREAD_FUNC_RETURN_TYPE unsigned
126 : #define THREAD_FUNC_RETURN return 0
127 : #define THREAD_FUNC_CC __stdcall
128 : #define THREAD_CREATE(handle, function, arg) \
129 : ((*(handle) = (HANDLE) _beginthreadex(NULL, 0, (function), (arg), 0, NULL)) == 0 ? errno : 0)
130 : #define THREAD_JOIN(handle) \
131 : (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0 ? \
132 : GETERRNO() : CloseHandle(handle) ? 0 : GETERRNO())
133 : #define THREAD_BARRIER_T SYNCHRONIZATION_BARRIER
134 : #define THREAD_BARRIER_INIT(barrier, n) \
135 : (InitializeSynchronizationBarrier((barrier), (n), 0) ? 0 : GETERRNO())
136 : #define THREAD_BARRIER_WAIT(barrier) \
137 : EnterSynchronizationBarrier((barrier), \
138 : SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY)
139 : #define THREAD_BARRIER_DESTROY(barrier)
140 : #elif defined(ENABLE_THREAD_SAFETY)
141 : /* Use POSIX threads */
142 : #include "port/pg_pthread.h"
143 : #define THREAD_T pthread_t
144 : #define THREAD_FUNC_RETURN_TYPE void *
145 : #define THREAD_FUNC_RETURN return NULL
146 : #define THREAD_FUNC_CC
147 : #define THREAD_CREATE(handle, function, arg) \
148 : pthread_create((handle), NULL, (function), (arg))
149 : #define THREAD_JOIN(handle) \
150 : pthread_join((handle), NULL)
151 : #define THREAD_BARRIER_T pthread_barrier_t
152 : #define THREAD_BARRIER_INIT(barrier, n) \
153 : pthread_barrier_init((barrier), NULL, (n))
154 : #define THREAD_BARRIER_WAIT(barrier) pthread_barrier_wait((barrier))
155 : #define THREAD_BARRIER_DESTROY(barrier) pthread_barrier_destroy((barrier))
156 : #else
157 : /* No threads implementation, use none (-j 1) */
158 : #define THREAD_T void *
159 : #define THREAD_FUNC_RETURN_TYPE void *
160 : #define THREAD_FUNC_RETURN return NULL
161 : #define THREAD_FUNC_CC
162 : #define THREAD_BARRIER_T int
163 : #define THREAD_BARRIER_INIT(barrier, n) (*(barrier) = 0)
164 : #define THREAD_BARRIER_WAIT(barrier)
165 : #define THREAD_BARRIER_DESTROY(barrier)
166 : #endif
167 :
168 :
169 : /********************************************************************
170 : * some configurable parameters */
171 :
172 : #define DEFAULT_INIT_STEPS "dtgvp" /* default -I setting */
173 : #define ALL_INIT_STEPS "dtgGvpf" /* all possible steps */
174 :
175 : #define LOG_STEP_SECONDS 5 /* seconds between log messages */
176 : #define DEFAULT_NXACTS 10 /* default nxacts */
177 :
178 : #define MIN_GAUSSIAN_PARAM 2.0 /* minimum parameter for gauss */
179 :
180 : #define MIN_ZIPFIAN_PARAM 1.001 /* minimum parameter for zipfian */
181 : #define MAX_ZIPFIAN_PARAM 1000.0 /* maximum parameter for zipfian */
182 :
183 : int nxacts = 0; /* number of transactions per client */
184 : int duration = 0; /* duration in seconds */
185 : int64 end_time = 0; /* when to stop in micro seconds, under -T */
186 :
187 : /*
188 : * scaling factor. for example, scale = 10 will make 1000000 tuples in
189 : * pgbench_accounts table.
190 : */
191 : int scale = 1;
192 :
193 : /*
194 : * fillfactor. for example, fillfactor = 90 will use only 90 percent
195 : * space during inserts and leave 10 percent free.
196 : */
197 : int fillfactor = 100;
198 :
199 : /*
200 : * use unlogged tables?
201 : */
202 : bool unlogged_tables = false;
203 :
204 : /*
205 : * log sampling rate (1.0 = log everything, 0.0 = option not given)
206 : */
207 : double sample_rate = 0.0;
208 :
209 : /*
210 : * When threads are throttled to a given rate limit, this is the target delay
211 : * to reach that rate in usec. 0 is the default and means no throttling.
212 : */
213 : double throttle_delay = 0;
214 :
215 : /*
216 : * Transactions which take longer than this limit (in usec) are counted as
217 : * late, and reported as such, although they are completed anyway. When
218 : * throttling is enabled, execution time slots that are more than this late
219 : * are skipped altogether, and counted separately.
220 : */
221 : int64 latency_limit = 0;
222 :
223 : /*
224 : * tablespace selection
225 : */
226 : char *tablespace = NULL;
227 : char *index_tablespace = NULL;
228 :
229 : /*
230 : * Number of "pgbench_accounts" partitions. 0 is the default and means no
231 : * partitioning.
232 : */
233 : static int partitions = 0;
234 :
235 : /* partitioning strategy for "pgbench_accounts" */
236 : typedef enum
237 : {
238 : PART_NONE, /* no partitioning */
239 : PART_RANGE, /* range partitioning */
240 : PART_HASH /* hash partitioning */
241 : } partition_method_t;
242 :
243 : static partition_method_t partition_method = PART_NONE;
244 : static const char *PARTITION_METHOD[] = {"none", "range", "hash"};
245 :
246 : /* random seed used to initialize base_random_sequence */
247 : int64 random_seed = -1;
248 :
249 : /*
250 : * end of configurable parameters
251 : *********************************************************************/
252 :
253 : #define nbranches 1 /* Makes little sense to change this. Change
254 : * -s instead */
255 : #define ntellers 10
256 : #define naccounts 100000
257 :
258 : /*
259 : * The scale factor at/beyond which 32bit integers are incapable of storing
260 : * 64bit values.
261 : *
262 : * Although the actual threshold is 21474, we use 20000 because it is easier to
263 : * document and remember, and isn't that far away from the real threshold.
264 : */
265 : #define SCALE_32BIT_THRESHOLD 20000
266 :
267 : bool use_log; /* log transaction latencies to a file */
268 : bool use_quiet; /* quiet logging onto stderr */
269 : int agg_interval; /* log aggregates instead of individual
270 : * transactions */
271 : bool per_script_stats = false; /* whether to collect stats per script */
272 : int progress = 0; /* thread progress report every this seconds */
273 : bool progress_timestamp = false; /* progress report with Unix time */
274 : int nclients = 1; /* number of clients */
275 : int nthreads = 1; /* number of threads */
276 : bool is_connect; /* establish connection for each transaction */
277 : bool report_per_command = false; /* report per-command latencies,
278 : * retries after errors and failures
279 : * (errors without retrying) */
280 : int main_pid; /* main process id used in log filename */
281 :
282 : /*
283 : * There are different types of restrictions for deciding that the current
284 : * transaction with a serialization/deadlock error can no longer be retried and
285 : * should be reported as failed:
286 : * - max_tries (--max-tries) can be used to limit the number of tries;
287 : * - latency_limit (-L) can be used to limit the total time of tries;
288 : * - duration (-T) can be used to limit the total benchmark time.
289 : *
290 : * They can be combined together, and you need to use at least one of them to
291 : * retry the transactions with serialization/deadlock errors. If none of them is
292 : * used, the default value of max_tries is 1 and such transactions will not be
293 : * retried.
294 : */
295 :
296 : /*
297 : * We cannot retry a transaction after the serialization/deadlock error if its
298 : * number of tries reaches this maximum; if its value is zero, it is not used.
299 : */
300 : uint32 max_tries = 1;
301 :
302 : bool failures_detailed = false; /* whether to group failures in
303 : * reports or logs by basic types */
304 :
305 : const char *pghost = NULL;
306 : const char *pgport = NULL;
307 : const char *username = NULL;
308 : const char *dbName = NULL;
309 : char *logfile_prefix = NULL;
310 : const char *progname;
311 :
312 : #define WSEP '@' /* weight separator */
313 :
314 : volatile sig_atomic_t timer_exceeded = false; /* flag from signal handler */
315 :
316 : /*
317 : * We don't want to allocate variables one by one; for efficiency, add a
318 : * constant margin each time it overflows.
319 : */
320 : #define VARIABLES_ALLOC_MARGIN 8
321 :
322 : /*
323 : * Variable definitions.
324 : *
325 : * If a variable only has a string value, "svalue" is that value, and value is
326 : * "not set". If the value is known, "value" contains the value (in any
327 : * variant).
328 : *
329 : * In this case "svalue" contains the string equivalent of the value, if we've
330 : * had occasion to compute that, or NULL if we haven't.
331 : */
332 : typedef struct
333 : {
334 : char *name; /* variable's name */
335 : char *svalue; /* its value in string form, if known */
336 : PgBenchValue value; /* actual variable's value */
337 : } Variable;
338 :
339 : /*
340 : * Data structure for client variables.
341 : */
342 : typedef struct
343 : {
344 : Variable *vars; /* array of variable definitions */
345 : int nvars; /* number of variables */
346 :
347 : /*
348 : * The maximum number of variables that we can currently store in 'vars'
349 : * without having to reallocate more space. We must always have max_vars
350 : * >= nvars.
351 : */
352 : int max_vars;
353 :
354 : bool vars_sorted; /* are variables sorted by name? */
355 : } Variables;
356 :
357 : #define MAX_SCRIPTS 128 /* max number of SQL scripts allowed */
358 : #define SHELL_COMMAND_SIZE 256 /* maximum size allowed for shell command */
359 :
360 : /*
361 : * Simple data structure to keep stats about something.
362 : *
363 : * XXX probably the first value should be kept and used as an offset for
364 : * better numerical stability...
365 : */
366 : typedef struct SimpleStats
367 : {
368 : int64 count; /* how many values were encountered */
369 : double min; /* the minimum seen */
370 : double max; /* the maximum seen */
371 : double sum; /* sum of values */
372 : double sum2; /* sum of squared values */
373 : } SimpleStats;
374 :
375 : /*
376 : * The instr_time type is expensive when dealing with time arithmetic. Define
377 : * a type to hold microseconds instead. Type int64 is good enough for about
378 : * 584500 years.
379 : */
380 : typedef int64 pg_time_usec_t;
381 :
382 : /*
383 : * Data structure to hold various statistics: per-thread and per-script stats
384 : * are maintained and merged together.
385 : */
386 : typedef struct StatsData
387 : {
388 : pg_time_usec_t start_time; /* interval start time, for aggregates */
389 :
390 : /*----------
391 : * Transactions are counted depending on their execution and outcome.
392 : * First a transaction may have started or not: skipped transactions occur
393 : * under --rate and --latency-limit when the client is too late to execute
394 : * them. Secondly, a started transaction may ultimately succeed or fail,
395 : * possibly after some retries when --max-tries is not one. Thus
396 : *
397 : * the number of all transactions =
398 : * 'skipped' (it was too late to execute them) +
399 : * 'cnt' (the number of successful transactions) +
400 : * 'failed' (the number of failed transactions).
401 : *
402 : * A successful transaction can have several unsuccessful tries before a
403 : * successful run. Thus
404 : *
405 : * 'cnt' (the number of successful transactions) =
406 : * successfully retried transactions (they got a serialization or a
407 : * deadlock error(s), but were
408 : * successfully retried from the very
409 : * beginning) +
410 : * directly successful transactions (they were successfully completed on
411 : * the first try).
412 : *
413 : * A failed transaction is defined as unsuccessfully retried transactions.
414 : * It can be one of two types:
415 : *
416 : * failed (the number of failed transactions) =
417 : * 'serialization_failures' (they got a serialization error and were not
418 : * successfully retried) +
419 : * 'deadlock_failures' (they got a deadlock error and were not
420 : * successfully retried).
421 : *
422 : * If the transaction was retried after a serialization or a deadlock
423 : * error this does not guarantee that this retry was successful. Thus
424 : *
425 : * 'retries' (number of retries) =
426 : * number of retries in all retried transactions =
427 : * number of retries in (successfully retried transactions +
428 : * failed transactions);
429 : *
430 : * 'retried' (number of all retried transactions) =
431 : * successfully retried transactions +
432 : * failed transactions.
433 : *----------
434 : */
435 : int64 cnt; /* number of successful transactions, not
436 : * including 'skipped' */
437 : int64 skipped; /* number of transactions skipped under --rate
438 : * and --latency-limit */
439 : int64 retries; /* number of retries after a serialization or
440 : * a deadlock error in all the transactions */
441 : int64 retried; /* number of all transactions that were
442 : * retried after a serialization or a deadlock
443 : * error (perhaps the last try was
444 : * unsuccessful) */
445 : int64 serialization_failures; /* number of transactions that were
446 : * not successfully retried after a
447 : * serialization error */
448 : int64 deadlock_failures; /* number of transactions that were not
449 : * successfully retried after a deadlock
450 : * error */
451 : SimpleStats latency;
452 : SimpleStats lag;
453 : } StatsData;
454 :
455 : /*
456 : * For displaying Unix epoch timestamps, as some time functions may have
457 : * another reference.
458 : */
459 : pg_time_usec_t epoch_shift;
460 :
461 : /*
462 : * Error status for errors during script execution.
463 : */
464 : typedef enum EStatus
465 : {
466 : ESTATUS_NO_ERROR = 0,
467 : ESTATUS_META_COMMAND_ERROR,
468 :
469 : /* SQL errors */
470 : ESTATUS_SERIALIZATION_ERROR,
471 : ESTATUS_DEADLOCK_ERROR,
472 : ESTATUS_OTHER_SQL_ERROR
473 : } EStatus;
474 :
475 : /*
476 : * Transaction status at the end of a command.
477 : */
478 : typedef enum TStatus
479 : {
480 : TSTATUS_IDLE,
481 : TSTATUS_IN_BLOCK,
482 : TSTATUS_CONN_ERROR,
483 : TSTATUS_OTHER_ERROR
484 : } TStatus;
485 :
486 : /* Various random sequences are initialized from this one. */
487 : static pg_prng_state base_random_sequence;
488 :
489 : /* Synchronization barrier for start and connection */
490 : static THREAD_BARRIER_T barrier;
491 :
492 : /*
493 : * Connection state machine states.
494 : */
495 : typedef enum
496 : {
497 : /*
498 : * The client must first choose a script to execute. Once chosen, it can
499 : * either be throttled (state CSTATE_PREPARE_THROTTLE under --rate), start
500 : * right away (state CSTATE_START_TX) or not start at all if the timer was
501 : * exceeded (state CSTATE_FINISHED).
502 : */
503 : CSTATE_CHOOSE_SCRIPT,
504 :
505 : /*
506 : * CSTATE_START_TX performs start-of-transaction processing. Establishes
507 : * a new connection for the transaction in --connect mode, records the
508 : * transaction start time, and proceed to the first command.
509 : *
510 : * Note: once a script is started, it will either error or run till its
511 : * end, where it may be interrupted. It is not interrupted while running,
512 : * so pgbench --time is to be understood as tx are allowed to start in
513 : * that time, and will finish when their work is completed.
514 : */
515 : CSTATE_START_TX,
516 :
517 : /*
518 : * In CSTATE_PREPARE_THROTTLE state, we calculate when to begin the next
519 : * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
520 : * sleeps until that moment, then advances to CSTATE_START_TX, or
521 : * CSTATE_FINISHED if the next transaction would start beyond the end of
522 : * the run.
523 : */
524 : CSTATE_PREPARE_THROTTLE,
525 : CSTATE_THROTTLE,
526 :
527 : /*
528 : * We loop through these states, to process each command in the script:
529 : *
530 : * CSTATE_START_COMMAND starts the execution of a command. On a SQL
531 : * command, the command is sent to the server, and we move to
532 : * CSTATE_WAIT_RESULT state unless in pipeline mode. On a \sleep
533 : * meta-command, the timer is set, and we enter the CSTATE_SLEEP state to
534 : * wait for it to expire. Other meta-commands are executed immediately. If
535 : * the command about to start is actually beyond the end of the script,
536 : * advance to CSTATE_END_TX.
537 : *
538 : * CSTATE_WAIT_RESULT waits until we get a result set back from the server
539 : * for the current command.
540 : *
541 : * CSTATE_SLEEP waits until the end of \sleep.
542 : *
543 : * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
544 : * command counter, and loops back to CSTATE_START_COMMAND state.
545 : *
546 : * CSTATE_SKIP_COMMAND is used by conditional branches which are not
547 : * executed. It quickly skip commands that do not need any evaluation.
548 : * This state can move forward several commands, till there is something
549 : * to do or the end of the script.
550 : */
551 : CSTATE_START_COMMAND,
552 : CSTATE_WAIT_RESULT,
553 : CSTATE_SLEEP,
554 : CSTATE_END_COMMAND,
555 : CSTATE_SKIP_COMMAND,
556 :
557 : /*
558 : * States for failed commands.
559 : *
560 : * If the SQL/meta command fails, in CSTATE_ERROR clean up after an error:
561 : * (1) clear the conditional stack; (2) if we have an unterminated
562 : * (possibly failed) transaction block, send the rollback command to the
563 : * server and wait for the result in CSTATE_WAIT_ROLLBACK_RESULT. If
564 : * something goes wrong with rolling back, go to CSTATE_ABORTED.
565 : *
566 : * But if everything is ok we are ready for future transactions: if this
567 : * is a serialization or deadlock error and we can re-execute the
568 : * transaction from the very beginning, go to CSTATE_RETRY; otherwise go
569 : * to CSTATE_FAILURE.
570 : *
571 : * In CSTATE_RETRY report an error, set the same parameters for the
572 : * transaction execution as in the previous tries and process the first
573 : * transaction command in CSTATE_START_COMMAND.
574 : *
575 : * In CSTATE_FAILURE report a failure, set the parameters for the
576 : * transaction execution as they were before the first run of this
577 : * transaction (except for a random state) and go to CSTATE_END_TX to
578 : * complete this transaction.
579 : */
580 : CSTATE_ERROR,
581 : CSTATE_WAIT_ROLLBACK_RESULT,
582 : CSTATE_RETRY,
583 : CSTATE_FAILURE,
584 :
585 : /*
586 : * CSTATE_END_TX performs end-of-transaction processing. It calculates
587 : * latency, and logs the transaction. In --connect mode, it closes the
588 : * current connection.
589 : *
590 : * Then either starts over in CSTATE_CHOOSE_SCRIPT, or enters
591 : * CSTATE_FINISHED if we have no more work to do.
592 : */
593 : CSTATE_END_TX,
594 :
595 : /*
596 : * Final states. CSTATE_ABORTED means that the script execution was
597 : * aborted because a command failed, CSTATE_FINISHED means success.
598 : */
599 : CSTATE_ABORTED,
600 : CSTATE_FINISHED
601 : } ConnectionStateEnum;
602 :
603 : /*
604 : * Connection state.
605 : */
606 : typedef struct
607 : {
608 : PGconn *con; /* connection handle to DB */
609 : int id; /* client No. */
610 : ConnectionStateEnum state; /* state machine's current state. */
611 : ConditionalStack cstack; /* enclosing conditionals state */
612 :
613 : /*
614 : * Separate randomness for each client. This is used for random functions
615 : * PGBENCH_RANDOM_* during the execution of the script.
616 : */
617 : pg_prng_state cs_func_rs;
618 :
619 : int use_file; /* index in sql_script for this client */
620 : int command; /* command number in script */
621 :
622 : /* client variables */
623 : Variables variables;
624 :
625 : /* various times about current transaction in microseconds */
626 : pg_time_usec_t txn_scheduled; /* scheduled start time of transaction */
627 : pg_time_usec_t sleep_until; /* scheduled start time of next cmd */
628 : pg_time_usec_t txn_begin; /* used for measuring schedule lag times */
629 : pg_time_usec_t stmt_begin; /* used for measuring statement latencies */
630 :
631 : /* whether client prepared each command of each script */
632 : bool **prepared;
633 :
634 : /*
635 : * For processing failures and repeating transactions with serialization
636 : * or deadlock errors:
637 : */
638 : EStatus estatus; /* the error status of the current transaction
639 : * execution; this is ESTATUS_NO_ERROR if
640 : * there were no errors */
641 : pg_prng_state random_state; /* random state */
642 : uint32 tries; /* how many times have we already tried the
643 : * current transaction? */
644 :
645 : /* per client collected stats */
646 : int64 cnt; /* client transaction count, for -t; skipped
647 : * and failed transactions are also counted
648 : * here */
649 : } CState;
650 :
651 : /*
652 : * Thread state
653 : */
654 : typedef struct
655 : {
656 : int tid; /* thread id */
657 : THREAD_T thread; /* thread handle */
658 : CState *state; /* array of CState */
659 : int nstate; /* length of state[] */
660 :
661 : /*
662 : * Separate randomness for each thread. Each thread option uses its own
663 : * random state to make all of them independent of each other and
664 : * therefore deterministic at the thread level.
665 : */
666 : pg_prng_state ts_choose_rs; /* random state for selecting a script */
667 : pg_prng_state ts_throttle_rs; /* random state for transaction throttling */
668 : pg_prng_state ts_sample_rs; /* random state for log sampling */
669 :
670 : int64 throttle_trigger; /* previous/next throttling (us) */
671 : FILE *logfile; /* where to log, or NULL */
672 :
673 : /* per thread collected stats in microseconds */
674 : pg_time_usec_t create_time; /* thread creation time */
675 : pg_time_usec_t started_time; /* thread is running */
676 : pg_time_usec_t bench_start; /* thread is benchmarking */
677 : pg_time_usec_t conn_duration; /* cumulated connection and disconnection
678 : * delays */
679 :
680 : StatsData stats;
681 : int64 latency_late; /* count executed but late transactions */
682 : } TState;
683 :
684 : /*
685 : * queries read from files
686 : */
687 : #define SQL_COMMAND 1
688 : #define META_COMMAND 2
689 :
690 : /*
691 : * max number of backslash command arguments or SQL variables,
692 : * including the command or SQL statement itself
693 : */
694 : #define MAX_ARGS 256
695 :
696 : typedef enum MetaCommand
697 : {
698 : META_NONE, /* not a known meta-command */
699 : META_SET, /* \set */
700 : META_SETSHELL, /* \setshell */
701 : META_SHELL, /* \shell */
702 : META_SLEEP, /* \sleep */
703 : META_GSET, /* \gset */
704 : META_ASET, /* \aset */
705 : META_IF, /* \if */
706 : META_ELIF, /* \elif */
707 : META_ELSE, /* \else */
708 : META_ENDIF, /* \endif */
709 : META_STARTPIPELINE, /* \startpipeline */
710 : META_ENDPIPELINE /* \endpipeline */
711 : } MetaCommand;
712 :
713 : typedef enum QueryMode
714 : {
715 : QUERY_SIMPLE, /* simple query */
716 : QUERY_EXTENDED, /* extended query */
717 : QUERY_PREPARED, /* extended query with prepared statements */
718 : NUM_QUERYMODE
719 : } QueryMode;
720 :
721 : static QueryMode querymode = QUERY_SIMPLE;
722 : static const char *QUERYMODE[] = {"simple", "extended", "prepared"};
723 :
724 : /*
725 : * struct Command represents one command in a script.
726 : *
727 : * lines The raw, possibly multi-line command text. Variable substitution
728 : * not applied.
729 : * first_line A short, single-line extract of 'lines', for error reporting.
730 : * type SQL_COMMAND or META_COMMAND
731 : * meta The type of meta-command, with META_NONE/GSET/ASET if command
732 : * is SQL.
733 : * argc Number of arguments of the command, 0 if not yet processed.
734 : * argv Command arguments, the first of which is the command or SQL
735 : * string itself. For SQL commands, after post-processing
736 : * argv[0] is the same as 'lines' with variables substituted.
737 : * prepname The name that this command is prepared under, in prepare mode
738 : * varprefix SQL commands terminated with \gset or \aset have this set
739 : * to a non NULL value. If nonempty, it's used to prefix the
740 : * variable name that receives the value.
741 : * aset do gset on all possible queries of a combined query (\;).
742 : * expr Parsed expression, if needed.
743 : * stats Time spent in this command.
744 : * retries Number of retries after a serialization or deadlock error in the
745 : * current command.
746 : * failures Number of errors in the current command that were not retried.
747 : */
748 : typedef struct Command
749 : {
750 : PQExpBufferData lines;
751 : char *first_line;
752 : int type;
753 : MetaCommand meta;
754 : int argc;
755 : char *argv[MAX_ARGS];
756 : char *prepname;
757 : char *varprefix;
758 : PgBenchExpr *expr;
759 : SimpleStats stats;
760 : int64 retries;
761 : int64 failures;
762 : } Command;
763 :
764 : typedef struct ParsedScript
765 : {
766 : const char *desc; /* script descriptor (eg, file name) */
767 : int weight; /* selection weight */
768 : Command **commands; /* NULL-terminated array of Commands */
769 : StatsData stats; /* total time spent in script */
770 : } ParsedScript;
771 :
772 : static ParsedScript sql_script[MAX_SCRIPTS]; /* SQL script files */
773 : static int num_scripts; /* number of scripts in sql_script[] */
774 : static int64 total_weight = 0;
775 :
776 : static bool verbose_errors = false; /* print verbose messages of all errors */
777 :
778 : /* Builtin test scripts */
779 : typedef struct BuiltinScript
780 : {
781 : const char *name; /* very short name for -b ... */
782 : const char *desc; /* short description */
783 : const char *script; /* actual pgbench script */
784 : } BuiltinScript;
785 :
786 : static const BuiltinScript builtin_script[] =
787 : {
788 : {
789 : "tpcb-like",
790 : "<builtin: TPC-B (sort of)>",
791 : "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
792 : "\\set bid random(1, " CppAsString2(nbranches) " * :scale)\n"
793 : "\\set tid random(1, " CppAsString2(ntellers) " * :scale)\n"
794 : "\\set delta random(-5000, 5000)\n"
795 : "BEGIN;\n"
796 : "UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
797 : "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
798 : "UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;\n"
799 : "UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;\n"
800 : "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
801 : "END;\n"
802 : },
803 : {
804 : "simple-update",
805 : "<builtin: simple update>",
806 : "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
807 : "\\set bid random(1, " CppAsString2(nbranches) " * :scale)\n"
808 : "\\set tid random(1, " CppAsString2(ntellers) " * :scale)\n"
809 : "\\set delta random(-5000, 5000)\n"
810 : "BEGIN;\n"
811 : "UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;\n"
812 : "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
813 : "INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);\n"
814 : "END;\n"
815 : },
816 : {
817 : "select-only",
818 : "<builtin: select only>",
819 : "\\set aid random(1, " CppAsString2(naccounts) " * :scale)\n"
820 : "SELECT abalance FROM pgbench_accounts WHERE aid = :aid;\n"
821 : }
822 : };
823 :
824 :
825 : /* Function prototypes */
826 : static void setNullValue(PgBenchValue *pv);
827 : static void setBoolValue(PgBenchValue *pv, bool bval);
828 : static void setIntValue(PgBenchValue *pv, int64 ival);
829 : static void setDoubleValue(PgBenchValue *pv, double dval);
830 : static bool evaluateExpr(CState *st, PgBenchExpr *expr,
831 : PgBenchValue *retval);
832 : static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now);
833 : static void doLog(TState *thread, CState *st,
834 : StatsData *agg, bool skipped, double latency, double lag);
835 : static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now,
836 : bool skipped, StatsData *agg);
837 : static void addScript(const ParsedScript *script);
838 : static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun(void *arg);
839 : static void finishCon(CState *st);
840 : static void setalarm(int seconds);
841 : static socket_set *alloc_socket_set(int count);
842 : static void free_socket_set(socket_set *sa);
843 : static void clear_socket_set(socket_set *sa);
844 : static void add_socket_to_set(socket_set *sa, int fd, int idx);
845 : static int wait_on_socket_set(socket_set *sa, int64 usecs);
846 : static bool socket_has_input(socket_set *sa, int fd, int idx);
847 :
848 :
849 : /* callback functions for our flex lexer */
850 : static const PsqlScanCallbacks pgbench_callbacks = {
851 : NULL, /* don't need get_variable functionality */
2576 tgl 852 ECB : };
853 :
854 : static inline pg_time_usec_t
760 tmunro 855 GIC 6227 : pg_time_now(void)
760 tmunro 856 ECB : {
857 : instr_time now;
858 :
760 tmunro 859 GIC 6227 : INSTR_TIME_SET_CURRENT(now);
860 :
861 6227 : return (pg_time_usec_t) INSTR_TIME_GET_MICROSEC(now);
760 tmunro 862 ECB : }
863 :
864 : static inline void
760 tmunro 865 CBC 5222 : pg_time_now_lazy(pg_time_usec_t *now)
760 tmunro 866 ECB : {
760 tmunro 867 GIC 5222 : if ((*now) == 0)
868 4200 : (*now) = pg_time_now();
869 5222 : }
870 :
760 tmunro 871 ECB : #define PG_TIME_GET_DOUBLE(t) (0.000001 * (t))
872 :
8397 bruce 873 : static void
3931 rhaas 874 GIC 1 : usage(void)
875 : {
5154 peter_e 876 1 : printf("%s is a benchmarking tool for PostgreSQL.\n\n"
877 : "Usage:\n"
878 : " %s [OPTION]... [DBNAME]\n"
879 : "\nInitialization options:\n"
880 : " -i, --initialize invokes initialization mode\n"
881 : " -I, --init-steps=[" ALL_INIT_STEPS "]+ (default \"" DEFAULT_INIT_STEPS "\")\n"
882 : " run selected initialization steps\n"
883 : " -F, --fillfactor=NUM set fill factor\n"
884 : " -n, --no-vacuum do not run VACUUM during initialization\n"
885 : " -q, --quiet quiet logging (one message each 5 seconds)\n"
886 : " -s, --scale=NUM scaling factor\n"
887 : " --foreign-keys create foreign key constraints between tables\n"
888 : " --index-tablespace=TABLESPACE\n"
889 : " create indexes in the specified tablespace\n"
890 : " --partition-method=(range|hash)\n"
891 : " partition pgbench_accounts with this method (default: range)\n"
892 : " --partitions=NUM partition pgbench_accounts into NUM parts (default: 0)\n"
893 : " --tablespace=TABLESPACE create tables in the specified tablespace\n"
894 : " --unlogged-tables create tables as unlogged tables\n"
895 : "\nOptions to select what to run:\n"
896 : " -b, --builtin=NAME[@W] add builtin script NAME weighted at W (default: 1)\n"
897 : " (use \"-b list\" to list available scripts)\n"
898 : " -f, --file=FILENAME[@W] add script FILENAME weighted at W (default: 1)\n"
899 : " -N, --skip-some-updates skip updates of pgbench_tellers and pgbench_branches\n"
900 : " (same as \"-b simple-update\")\n"
901 : " -S, --select-only perform SELECT-only transactions\n"
902 : " (same as \"-b select-only\")\n"
903 : "\nBenchmarking options:\n"
904 : " -c, --client=NUM number of concurrent database clients (default: 1)\n"
905 : " -C, --connect establish new connection for each transaction\n"
906 : " -D, --define=VARNAME=VALUE\n"
907 : " define variable for use by custom script\n"
908 : " -j, --jobs=NUM number of threads (default: 1)\n"
909 : " -l, --log write transaction times to log file\n"
910 : " -L, --latency-limit=NUM count transactions lasting more than NUM ms as late\n"
911 : " -M, --protocol=simple|extended|prepared\n"
912 : " protocol for submitting queries (default: simple)\n"
913 : " -n, --no-vacuum do not run VACUUM before tests\n"
914 : " -P, --progress=NUM show thread progress report every NUM seconds\n"
915 : " -r, --report-per-command report latencies, failures, and retries per command\n"
916 : " -R, --rate=NUM target rate in transactions per second\n"
917 : " -s, --scale=NUM report this scale factor in output\n"
918 : " -t, --transactions=NUM number of transactions each client runs (default: 10)\n"
919 : " -T, --time=NUM duration of benchmark test in seconds\n"
920 : " -v, --vacuum-all vacuum all four standard tables before tests\n"
921 : " --aggregate-interval=NUM aggregate data over NUM seconds\n"
922 : " --failures-detailed report the failures grouped by basic types\n"
923 : " --log-prefix=PREFIX prefix for transaction time log file\n"
924 : " (default: \"pgbench_log\")\n"
925 : " --max-tries=NUM max number of tries to run transaction (default: 1)\n"
926 : " --progress-timestamp use Unix epoch timestamps for progress\n"
927 : " --random-seed=SEED set random seed (\"time\", \"rand\", integer)\n"
928 : " --sampling-rate=NUM fraction of transactions to log (e.g., 0.01 for 1%%)\n"
929 : " --show-script=NAME show builtin script code, then exit\n"
930 : " --verbose-errors print messages of all errors\n"
931 : "\nCommon options:\n"
932 : " -d, --debug print debugging output\n"
933 : " -h, --host=HOSTNAME database server host or socket directory\n"
934 : " -p, --port=PORT database server port number\n"
935 : " -U, --username=USERNAME connect as specified database user\n"
936 : " -V, --version output version information, then exit\n"
937 : " -?, --help show this help, then exit\n"
938 : "\n"
1136 peter 939 ECB : "Report bugs to <%s>.\n"
940 : "%s home page: <%s>\n",
941 : progname, progname, PACKAGE_BUGREPORT, PACKAGE_NAME, PACKAGE_URL);
8485 ishii 942 GIC 1 : }
8485 ishii 943 ECB :
944 : /* return whether str matches "^\s*[-+]?[0-9]+$" */
2568 rhaas 945 : static bool
2568 rhaas 946 GIC 422 : is_an_int(const char *str)
947 : {
2568 rhaas 948 CBC 422 : const char *ptr = str;
2568 rhaas 949 EUB :
950 : /* skip leading spaces; cast is consistent with strtoint64 */
2568 rhaas 951 GIC 422 : while (*ptr && isspace((unsigned char) *ptr))
2568 rhaas 952 LBC 0 : ptr++;
2568 rhaas 953 ECB :
954 : /* skip sign */
2568 rhaas 955 GIC 422 : if (*ptr == '+' || *ptr == '-')
2568 rhaas 956 CBC 3 : ptr++;
2568 rhaas 957 ECB :
958 : /* at least one digit */
2568 rhaas 959 GIC 422 : if (*ptr && !isdigit((unsigned char) *ptr))
2568 rhaas 960 CBC 2 : return false;
2568 rhaas 961 ECB :
962 : /* eat all digits */
2568 rhaas 963 GIC 895 : while (*ptr && isdigit((unsigned char) *ptr))
2568 rhaas 964 CBC 475 : ptr++;
965 :
966 : /* must have reached end of string */
2568 rhaas 967 GIC 420 : return *ptr == '\0';
968 : }
969 :
970 :
971 : /*
972 : * strtoint64 -- convert a string to 64-bit integer
973 : *
974 : * This function is a slightly modified version of pg_strtoint64() from
975 : * src/backend/utils/adt/numutils.c.
976 : *
977 : * The function returns whether the conversion worked, and if so
978 : * "*result" is set to the result.
979 : *
1655 andres 980 ECB : * If not errorOK, an error message is also printed out on errors.
981 : */
982 : bool
1655 andres 983 CBC 1213 : strtoint64(const char *str, bool errorOK, int64 *result)
3722 heikki.linnakangas 984 ECB : {
3722 heikki.linnakangas 985 GIC 1213 : const char *ptr = str;
1655 andres 986 1213 : int64 tmp = 0;
987 1213 : bool neg = false;
988 :
989 : /*
990 : * Do our own scan, rather than relying on sscanf which might be broken
991 : * for long long.
992 : *
993 : * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate
994 : * value as a negative number.
3722 heikki.linnakangas 995 ECB : */
3722 heikki.linnakangas 996 EUB :
997 : /* skip leading spaces */
3722 heikki.linnakangas 998 GIC 1213 : while (*ptr && isspace((unsigned char) *ptr))
3722 heikki.linnakangas 999 LBC 0 : ptr++;
1000 :
3722 heikki.linnakangas 1001 ECB : /* handle sign */
3722 heikki.linnakangas 1002 CBC 1213 : if (*ptr == '-')
1003 : {
1004 2 : ptr++;
1655 andres 1005 GBC 2 : neg = true;
1006 : }
3722 heikki.linnakangas 1007 GIC 1211 : else if (*ptr == '+')
3722 heikki.linnakangas 1008 LBC 0 : ptr++;
3722 heikki.linnakangas 1009 EUB :
1010 : /* require at least one digit */
1655 andres 1011 GIC 1213 : if (unlikely(!isdigit((unsigned char) *ptr)))
1655 andres 1012 LBC 0 : goto invalid_syntax;
1013 :
3722 heikki.linnakangas 1014 ECB : /* process digits */
3722 heikki.linnakangas 1015 GIC 3729 : while (*ptr && isdigit((unsigned char) *ptr))
3722 heikki.linnakangas 1016 ECB : {
1655 andres 1017 CBC 2517 : int8 digit = (*ptr++ - '0');
3722 heikki.linnakangas 1018 ECB :
1655 andres 1019 GIC 2517 : if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) ||
1020 2516 : unlikely(pg_sub_s64_overflow(tmp, digit, &tmp)))
1021 1 : goto out_of_range;
3722 heikki.linnakangas 1022 ECB : }
3722 heikki.linnakangas 1023 EUB :
1024 : /* allow trailing whitespace, but not other trailing chars */
3722 heikki.linnakangas 1025 CBC 1212 : while (*ptr != '\0' && isspace((unsigned char) *ptr))
3722 heikki.linnakangas 1026 UBC 0 : ptr++;
1027 :
1655 andres 1028 CBC 1212 : if (unlikely(*ptr != '\0'))
1655 andres 1029 UIC 0 : goto invalid_syntax;
1655 andres 1030 ECB :
1655 andres 1031 GBC 1212 : if (!neg)
1655 andres 1032 ECB : {
1655 andres 1033 GIC 1210 : if (unlikely(tmp == PG_INT64_MIN))
1655 andres 1034 UIC 0 : goto out_of_range;
1655 andres 1035 CBC 1210 : tmp = -tmp;
1655 andres 1036 ECB : }
1037 :
1655 andres 1038 CBC 1212 : *result = tmp;
1039 1212 : return true;
1655 andres 1040 EUB :
1655 andres 1041 CBC 1 : out_of_range:
1655 andres 1042 GIC 1 : if (!errorOK)
1187 peter 1043 UBC 0 : pg_log_error("value \"%s\" is out of range for type bigint", str);
1655 andres 1044 GBC 1 : return false;
3722 heikki.linnakangas 1045 EUB :
1655 andres 1046 UBC 0 : invalid_syntax:
1655 andres 1047 UIC 0 : if (!errorOK)
1187 peter 1048 0 : pg_log_error("invalid input syntax for type bigint: \"%s\"", str);
1655 andres 1049 0 : return false;
1050 : }
1655 andres 1051 ECB :
1052 : /* convert string to double, detecting overflows/underflows */
1053 : bool
1655 andres 1054 GIC 66 : strtodouble(const char *str, bool errorOK, double *dv)
1655 andres 1055 ECB : {
1418 tgl 1056 : char *end;
1057 :
1655 andres 1058 CBC 66 : errno = 0;
1655 andres 1059 GIC 66 : *dv = strtod(str, &end);
1655 andres 1060 ECB :
1655 andres 1061 GBC 66 : if (unlikely(errno != 0))
1655 andres 1062 ECB : {
1655 andres 1063 GIC 2 : if (!errorOK)
1187 peter 1064 UIC 0 : pg_log_error("value \"%s\" is out of range for type double", str);
1655 andres 1065 CBC 2 : return false;
1066 : }
1655 andres 1067 ECB :
1655 andres 1068 GBC 64 : if (unlikely(end == str || *end != '\0'))
1655 andres 1069 ECB : {
1655 andres 1070 GIC 2 : if (!errorOK)
1187 peter 1071 LBC 0 : pg_log_error("invalid input syntax for type double: \"%s\"", str);
1655 andres 1072 GIC 2 : return false;
1073 : }
1074 62 : return true;
1075 : }
1076 :
1077 : /*
1078 : * Initialize a prng state struct.
1079 : *
1536 tgl 1080 ECB : * We derive the seed from base_random_sequence, which must be set up already.
1081 : */
1605 alvherre 1082 : static void
497 tgl 1083 CBC 308 : initRandomState(pg_prng_state *state)
1084 : {
497 tgl 1085 GIC 308 : pg_prng_seed(state, pg_prng_uint64(&base_random_sequence));
1605 alvherre 1086 308 : }
1087 :
1088 :
1089 : /*
1090 : * random number generator: uniform distribution from min to max inclusive.
1091 : *
1092 : * Although the limits are expressed as int64, you can't generate the full
1093 : * int64 range in one call, because the difference of the limits mustn't
497 tgl 1094 ECB : * overflow int64. This is not checked.
1095 : */
3722 heikki.linnakangas 1096 : static int64
497 tgl 1097 GIC 2617 : getrand(pg_prng_state *state, int64 min, int64 max)
1098 : {
1099 2617 : return min + (int64) pg_prng_uint64_range(state, 0, max - min);
1100 : }
1101 :
1102 : /*
1103 : * random number generator: exponential distribution from min to max inclusive.
1104 : * the parameter is so that the density of probability for the last cut-off max
2669 rhaas 1105 ECB : * value is exp(-parameter).
1106 : */
1107 : static int64
497 tgl 1108 GIC 3 : getExponentialRand(pg_prng_state *state, int64 min, int64 max,
1109 : double parameter)
1110 : {
1111 : double cut,
1112 : uniform,
2878 bruce 1113 ECB : rand;
1114 :
1115 : /* abort if wrong parameter, but must really be checked beforehand */
2669 rhaas 1116 CBC 3 : Assert(parameter > 0.0);
2669 rhaas 1117 GIC 3 : cut = exp(-parameter);
1118 : /* pg_prng_double value in [0, 1), uniform in (0, 1] */
497 tgl 1119 3 : uniform = 1.0 - pg_prng_double(state);
1120 :
3175 rhaas 1121 ECB : /*
2581 1122 : * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
1123 : */
3175 rhaas 1124 CBC 3 : Assert((1.0 - cut) != 0.0);
2669 rhaas 1125 GIC 3 : rand = -log(cut + (1.0 - cut) * uniform) / parameter;
1126 : /* return int64 random number within between min and max */
2878 bruce 1127 3 : return min + (int64) ((max - min + 1) * rand);
1128 : }
3175 rhaas 1129 ECB :
1130 : /* random number generator: gaussian distribution from min to max inclusive */
1131 : static int64
497 tgl 1132 GIC 3 : getGaussianRand(pg_prng_state *state, int64 min, int64 max,
1133 : double parameter)
1134 : {
1135 : double stdev;
3175 rhaas 1136 ECB : double rand;
1137 :
1138 : /* abort if parameter is too low, but must really be checked beforehand */
2568 rhaas 1139 GIC 3 : Assert(parameter >= MIN_GAUSSIAN_PARAM);
1140 :
1141 : /*
1142 : * Get normally-distributed random number in the range -parameter <= stdev
1143 : * < parameter.
1144 : *
1145 : * This loop is executed until the number is in the expected range.
1146 : *
1147 : * As the minimum parameter is 2.0, the probability of looping is low:
1148 : * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
1149 : * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
1150 : * the worst case. For a parameter value of 5.0, the looping probability
1151 : * is about e^{-5} * 2 / pi ~ 0.43%.
3175 rhaas 1152 ECB : */
1153 : do
1154 : {
90 tgl 1155 GNC 3 : stdev = pg_prng_double_normal(state);
1156 : }
2669 rhaas 1157 GIC 3 : while (stdev < -parameter || stdev >= parameter);
1158 :
1159 : /* stdev is in [-parameter, parameter), normalization to [0,1) */
1160 3 : rand = (stdev + parameter) / (parameter * 2.0);
1161 :
3175 rhaas 1162 ECB : /* return int64 random number within between min and max */
2878 bruce 1163 GIC 3 : return min + (int64) ((max - min + 1) * rand);
3175 rhaas 1164 ECB : }
1165 :
1166 : /*
1167 : * random number generator: generate a value, such that the series of values
1168 : * will approximate a Poisson distribution centered on the given value.
1169 : *
1170 : * Individual results are rounded to integers, though the center value need
1171 : * not be one.
1172 : */
1173 : static int64
497 tgl 1174 GIC 210 : getPoissonRand(pg_prng_state *state, double center)
3132 heikki.linnakangas 1175 ECB : {
1176 : /*
1177 : * Use inverse transform sampling to generate a value > 0, such that the
1178 : * expected (i.e. average) value is the given argument.
1179 : */
1180 : double uniform;
1181 :
1182 : /* pg_prng_double value in [0, 1), uniform in (0, 1] */
497 tgl 1183 GIC 210 : uniform = 1.0 - pg_prng_double(state);
3132 heikki.linnakangas 1184 ECB :
1657 tgl 1185 GBC 210 : return (int64) (-log(uniform) * center + 0.5);
1186 : }
1187 :
1188 : /*
1189 : * Computing zipfian using rejection method, based on
1942 teodor 1190 ECB : * "Non-Uniform Random Variate Generation",
1191 : * Luc Devroye, p. 550-551, Springer 1986.
1192 : *
1469 tgl 1193 : * This works for s > 1.0, but may perform badly for s very close to 1.0.
1194 : */
1942 teodor 1195 : static int64
497 tgl 1196 GIC 3 : computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
1942 teodor 1197 ECB : {
1942 teodor 1198 CBC 3 : double b = pow(2.0, s - 1.0);
1199 : double x,
1942 teodor 1200 ECB : t,
1201 : u,
1202 : v;
1203 :
1204 : /* Ensure n is sane */
1469 tgl 1205 CBC 3 : if (n <= 1)
1469 tgl 1206 UIC 0 : return 1;
1469 tgl 1207 ECB :
1208 : while (true)
1209 : {
1942 teodor 1210 : /* random variates */
497 tgl 1211 GIC 3 : u = pg_prng_double(state);
497 tgl 1212 CBC 3 : v = pg_prng_double(state);
1213 :
1942 teodor 1214 GIC 3 : x = floor(pow(u, -1.0 / (s - 1.0)));
1215 :
1216 3 : t = pow(1.0 + 1.0 / x, s - 1.0);
1217 : /* reject if too large or out of bound */
1218 3 : if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1942 teodor 1219 CBC 3 : break;
1220 : }
1942 teodor 1221 GIC 3 : return (int64) x;
1222 : }
1223 :
1942 teodor 1224 ECB : /* random number generator: zipfian distribution from min to max inclusive */
1225 : static int64
497 tgl 1226 GIC 3 : getZipfianRand(pg_prng_state *state, int64 min, int64 max, double s)
1942 teodor 1227 ECB : {
1942 teodor 1228 GIC 3 : int64 n = max - min + 1;
1942 teodor 1229 ECB :
1230 : /* abort if parameter is invalid */
1469 tgl 1231 CBC 3 : Assert(MIN_ZIPFIAN_PARAM <= s && s <= MAX_ZIPFIAN_PARAM);
1232 :
497 tgl 1233 GIC 3 : return min - 1 + computeIterativeZipfian(state, n, s);
1942 teodor 1234 ECB : }
1235 :
1236 : /*
1237 : * FNV-1a hash function
1238 : */
1239 : static int64
1845 teodor 1240 GIC 1 : getHashFnv1a(int64 val, uint64 seed)
1241 : {
1242 : int64 result;
1243 : int i;
1845 teodor 1244 ECB :
1845 teodor 1245 GIC 1 : result = FNV_OFFSET_BASIS ^ seed;
1845 teodor 1246 CBC 9 : for (i = 0; i < 8; ++i)
1845 teodor 1247 ECB : {
1809 tgl 1248 GIC 8 : int32 octet = val & 0xff;
1845 teodor 1249 ECB :
1845 teodor 1250 CBC 8 : val = val >> 8;
1251 8 : result = result ^ octet;
1845 teodor 1252 GIC 8 : result = result * FNV_PRIME;
1845 teodor 1253 ECB : }
1254 :
1845 teodor 1255 GIC 1 : return result;
1845 teodor 1256 ECB : }
1257 :
1258 : /*
1259 : * Murmur2 hash function
1260 : *
1261 : * Based on original work of Austin Appleby
1262 : * https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp
1263 : */
1264 : static int64
1845 teodor 1265 GIC 5 : getHashMurmur2(int64 val, uint64 seed)
1266 : {
1804 tgl 1267 5 : uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1809 1268 5 : uint64 k = (uint64) val;
1269 :
1845 teodor 1270 5 : k *= MM2_MUL;
1271 5 : k ^= k >> MM2_ROT;
1272 5 : k *= MM2_MUL;
1273 :
1274 5 : result ^= k;
1275 5 : result *= MM2_MUL;
1276 :
1845 teodor 1277 CBC 5 : result ^= result >> MM2_ROT;
1845 teodor 1278 GIC 5 : result *= MM2_MUL;
1279 5 : result ^= result >> MM2_ROT;
1280 :
1281 5 : return (int64) result;
1282 : }
1283 :
1284 : /*
1285 : * Pseudorandom permutation function
1286 : *
733 dean.a.rasheed 1287 ECB : * For small sizes, this generates each of the (size!) possible permutations
1288 : * of integers in the range [0, size) with roughly equal probability. Once
1289 : * the size is larger than 20, the number of possible permutations exceeds the
1290 : * number of distinct states of the internal pseudorandom number generator,
1291 : * and so not all possible permutations can be generated, but the permutations
1292 : * chosen should continue to give the appearance of being random.
1293 : *
1294 : * THIS FUNCTION IS NOT CRYPTOGRAPHICALLY SECURE.
1295 : * DO NOT USE FOR SUCH PURPOSE.
1296 : */
1297 : static int64
733 dean.a.rasheed 1298 CBC 45 : permute(const int64 val, const int64 isize, const int64 seed)
733 dean.a.rasheed 1299 ECB : {
1300 : /* using a high-end PRNG is probably overkill */
1301 : pg_prng_state state;
1302 : uint64 size;
1303 : uint64 v;
1304 : int masklen;
1305 : uint64 mask;
1306 : int i;
1307 :
733 dean.a.rasheed 1308 GIC 45 : if (isize < 2)
1309 1 : return 0; /* nothing to permute */
1310 :
1311 : /* Initialize prng state using the seed */
497 tgl 1312 44 : pg_prng_seed(&state, (uint64) seed);
1313 :
1314 : /* Computations are performed on unsigned values */
733 dean.a.rasheed 1315 44 : size = (uint64) isize;
1316 44 : v = (uint64) val % size;
1317 :
1318 : /* Mask to work modulo largest power of 2 less than or equal to size */
1319 44 : masklen = pg_leftmost_one_pos64(size);
1320 44 : mask = (((uint64) 1) << masklen) - 1;
1321 :
1322 : /*
1323 : * Permute the input value by applying several rounds of pseudorandom
1324 : * bijective transformations. The intention here is to distribute each
1325 : * input uniformly randomly across the range, and separate adjacent inputs
1326 : * approximately uniformly randomly from each other, leading to a fairly
1327 : * random overall choice of permutation.
1328 : *
1329 : * To separate adjacent inputs, we multiply by a random number modulo
733 dean.a.rasheed 1330 ECB : * (mask + 1), which is a power of 2. For this to be a bijection, the
1331 : * multiplier must be odd. Since this is known to lead to less randomness
1332 : * in the lower bits, we also apply a rotation that shifts the topmost bit
1333 : * into the least significant bit. In the special cases where size <= 3,
1334 : * mask = 1 and each of these operations is actually a no-op, so we also
1335 : * XOR the value with a different random number to inject additional
1336 : * randomness. Since the size is generally not a power of 2, we apply
1337 : * this bijection on overlapping upper and lower halves of the input.
1338 : *
1339 : * To distribute the inputs uniformly across the range, we then also apply
1340 : * a random offset modulo the full range.
1341 : *
1342 : * Taken together, these operations resemble a modified linear
1343 : * congruential generator, as is commonly used in pseudorandom number
1344 : * generators. The number of rounds is fairly arbitrary, but six has been
1345 : * found empirically to give a fairly good tradeoff between performance
1346 : * and uniform randomness. For small sizes it selects each of the (size!)
1347 : * possible permutations with roughly equal probability. For larger
1348 : * sizes, not all permutations can be generated, but the intended random
1349 : * spread is still produced.
1350 : */
733 dean.a.rasheed 1351 CBC 308 : for (i = 0; i < 6; i++)
733 dean.a.rasheed 1352 ECB : {
1353 : uint64 m,
1354 : r,
1355 : t;
1356 :
1357 : /* Random multiply (by an odd number), XOR and rotate of lower half */
497 tgl 1358 CBC 264 : m = (pg_prng_uint64(&state) & mask) | 1;
497 tgl 1359 GIC 264 : r = pg_prng_uint64(&state) & mask;
733 dean.a.rasheed 1360 264 : if (v <= mask)
733 dean.a.rasheed 1361 ECB : {
733 dean.a.rasheed 1362 GIC 219 : v = ((v * m) ^ r) & mask;
1363 219 : v = ((v << 1) & mask) | (v >> (masklen - 1));
1364 : }
1365 :
1366 : /* Random multiply (by an odd number), XOR and rotate of upper half */
497 tgl 1367 264 : m = (pg_prng_uint64(&state) & mask) | 1;
497 tgl 1368 CBC 264 : r = pg_prng_uint64(&state) & mask;
733 dean.a.rasheed 1369 GIC 264 : t = size - 1 - v;
733 dean.a.rasheed 1370 CBC 264 : if (t <= mask)
733 dean.a.rasheed 1371 ECB : {
733 dean.a.rasheed 1372 GIC 235 : t = ((t * m) ^ r) & mask;
1373 235 : t = ((t << 1) & mask) | (t >> (masklen - 1));
1374 235 : v = size - 1 - t;
1375 : }
1376 :
733 dean.a.rasheed 1377 ECB : /* Random offset */
497 tgl 1378 GIC 264 : r = pg_prng_uint64_range(&state, 0, size - 1);
733 dean.a.rasheed 1379 CBC 264 : v = (v + r) % size;
733 dean.a.rasheed 1380 ECB : }
1381 :
733 dean.a.rasheed 1382 CBC 44 : return (int64) v;
733 dean.a.rasheed 1383 ECB : }
1384 :
2627 alvherre 1385 : /*
1386 : * Initialize the given SimpleStats struct to all zeroes
1387 : */
1388 : static void
2627 alvherre 1389 GIC 1772 : initSimpleStats(SimpleStats *ss)
1390 : {
1391 1772 : memset(ss, 0, sizeof(SimpleStats));
2627 alvherre 1392 CBC 1772 : }
1393 :
2627 alvherre 1394 ECB : /*
1395 : * Accumulate one value into a SimpleStats struct.
1396 : */
1397 : static void
2627 alvherre 1398 CBC 4131 : addToSimpleStats(SimpleStats *ss, double val)
2627 alvherre 1399 ECB : {
2627 alvherre 1400 CBC 4131 : if (ss->count == 0 || val < ss->min)
1401 116 : ss->min = val;
2627 alvherre 1402 GIC 4131 : if (ss->count == 0 || val > ss->max)
1403 506 : ss->max = val;
1404 4131 : ss->count++;
1405 4131 : ss->sum += val;
1406 4131 : ss->sum2 += val * val;
1407 4131 : }
2627 alvherre 1408 ECB :
1409 : /*
1410 : * Merge two SimpleStats objects
1411 : */
1412 : static void
2627 alvherre 1413 CBC 138 : mergeSimpleStats(SimpleStats *acc, SimpleStats *ss)
2627 alvherre 1414 ECB : {
2627 alvherre 1415 CBC 138 : if (acc->count == 0 || ss->min < acc->min)
1416 137 : acc->min = ss->min;
1417 138 : if (acc->count == 0 || ss->max > acc->max)
1418 137 : acc->max = ss->max;
1419 138 : acc->count += ss->count;
2627 alvherre 1420 GIC 138 : acc->sum += ss->sum;
1421 138 : acc->sum2 += ss->sum2;
1422 138 : }
1423 :
1424 : /*
2627 alvherre 1425 ECB : * Initialize a StatsData struct to mostly zeroes, with its start time set to
1426 : * the given value.
1427 : */
1428 : static void
760 tmunro 1429 CBC 468 : initStats(StatsData *sd, pg_time_usec_t start)
1430 : {
760 tmunro 1431 GIC 468 : sd->start_time = start;
2627 alvherre 1432 CBC 468 : sd->cnt = 0;
1433 468 : sd->skipped = 0;
382 ishii 1434 GIC 468 : sd->retries = 0;
1435 468 : sd->retried = 0;
1436 468 : sd->serialization_failures = 0;
1437 468 : sd->deadlock_failures = 0;
2627 alvherre 1438 468 : initSimpleStats(&sd->latency);
1439 468 : initSimpleStats(&sd->lag);
2627 alvherre 1440 CBC 468 : }
1441 :
2627 alvherre 1442 ECB : /*
1443 : * Accumulate one additional item into the given stats object.
1444 : */
1445 : static void
382 ishii 1446 CBC 3538 : accumStats(StatsData *stats, bool skipped, double lat, double lag,
1447 : EStatus estatus, int64 tries)
1448 : {
382 ishii 1449 ECB : /* Record the skipped transaction */
2627 alvherre 1450 CBC 3538 : if (skipped)
1451 : {
2627 alvherre 1452 ECB : /* no latency to record on skipped transactions */
2627 alvherre 1453 GIC 9 : stats->skipped++;
382 ishii 1454 9 : return;
2627 alvherre 1455 ECB : }
382 ishii 1456 :
1457 : /*
1458 : * Record the number of retries regardless of whether the transaction was
1459 : * successful or failed.
382 ishii 1460 EUB : */
382 ishii 1461 GBC 3529 : if (tries > 1)
2627 alvherre 1462 EUB : {
382 ishii 1463 GBC 2 : stats->retries += (tries - 1);
1464 2 : stats->retried++;
382 ishii 1465 EUB : }
2627 alvherre 1466 :
382 ishii 1467 GIC 3529 : switch (estatus)
382 ishii 1468 EUB : {
1469 : /* Record the successful transaction */
382 ishii 1470 GIC 3529 : case ESTATUS_NO_ERROR:
1471 3529 : stats->cnt++;
1472 :
1473 3529 : addToSimpleStats(&stats->latency, lat);
382 ishii 1474 ECB :
1475 : /* and possibly the same for schedule lag */
382 ishii 1476 GIC 3529 : if (throttle_delay)
1477 201 : addToSimpleStats(&stats->lag, lag);
382 ishii 1478 CBC 3529 : break;
382 ishii 1479 ECB :
1480 : /* Record the failed transaction */
382 ishii 1481 UBC 0 : case ESTATUS_SERIALIZATION_ERROR:
1482 0 : stats->serialization_failures++;
1483 0 : break;
382 ishii 1484 UIC 0 : case ESTATUS_DEADLOCK_ERROR:
382 ishii 1485 LBC 0 : stats->deadlock_failures++;
1486 0 : break;
382 ishii 1487 UIC 0 : default:
1488 : /* internal error which should never occur */
366 tgl 1489 0 : pg_fatal("unexpected error status: %d", estatus);
2627 alvherre 1490 ECB : }
1491 : }
1492 :
1493 : /* call PQexec() and exit() on failure */
5847 ishii 1494 : static void
5624 bruce 1495 CBC 81 : executeStatement(PGconn *con, const char *sql)
1496 : {
5847 ishii 1497 EUB : PGresult *res;
1498 :
5847 ishii 1499 GIC 81 : res = PQexec(con, sql);
5847 ishii 1500 CBC 81 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
5847 ishii 1501 ECB : {
366 tgl 1502 UIC 0 : pg_log_error("query failed: %s", PQerrorMessage(con));
1503 0 : pg_log_error_detail("Query was: %s", sql);
5847 ishii 1504 0 : exit(1);
5847 ishii 1505 ECB : }
5847 ishii 1506 GIC 81 : PQclear(res);
1507 81 : }
1508 :
1509 : /* call PQexec() and complain, but without exiting, on failure */
1510 : static void
2889 sfrost 1511 27 : tryExecuteStatement(PGconn *con, const char *sql)
1512 : {
1513 : PGresult *res;
1514 :
1515 27 : res = PQexec(con, sql);
1516 27 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
1517 : {
1187 peter 1518 UIC 0 : pg_log_error("%s", PQerrorMessage(con));
366 tgl 1519 0 : pg_log_error_detail("(ignoring this error and continuing anyway)");
1520 : }
2889 sfrost 1521 GIC 27 : PQclear(res);
2889 sfrost 1522 CBC 27 : }
2889 sfrost 1523 ECB :
7882 ishii 1524 : /* set up a connection to the backend */
7836 bruce 1525 : static PGconn *
6740 tgl 1526 CBC 275 : doConnect(void)
7882 ishii 1527 ECB : {
5598 tgl 1528 : PGconn *conn;
1529 : bool new_pass;
948 1530 : static char *password = NULL;
7188 bruce 1531 :
5598 tgl 1532 : /*
1533 : * Start the connection. Loop until we have a password if requested by
1534 : * backend.
1535 : */
1536 : do
7836 bruce 1537 : {
1538 : #define PARAMS_ARRAY_SIZE 7
3931 rhaas 1539 :
1540 : const char *keywords[PARAMS_ARRAY_SIZE];
1541 : const char *values[PARAMS_ARRAY_SIZE];
1542 :
3931 rhaas 1543 GBC 275 : keywords[0] = "host";
1544 275 : values[0] = pghost;
3931 rhaas 1545 GIC 275 : keywords[1] = "port";
1546 275 : values[1] = pgport;
3931 rhaas 1547 CBC 275 : keywords[2] = "user";
764 michael 1548 275 : values[2] = username;
3931 rhaas 1549 GBC 275 : keywords[3] = "password";
948 tgl 1550 GIC 275 : values[3] = password;
3931 rhaas 1551 GBC 275 : keywords[4] = "dbname";
1552 275 : values[4] = dbName;
1553 275 : keywords[5] = "fallback_application_name";
3931 rhaas 1554 GIC 275 : values[5] = progname;
3931 rhaas 1555 CBC 275 : keywords[6] = NULL;
3931 rhaas 1556 GIC 275 : values[6] = NULL;
1557 :
5598 tgl 1558 CBC 275 : new_pass = false;
1559 :
3931 rhaas 1560 275 : conn = PQconnectdbParams(keywords, values, true);
3931 rhaas 1561 ECB :
5598 tgl 1562 CBC 275 : if (!conn)
1563 : {
1187 peter 1564 UIC 0 : pg_log_error("connection to database \"%s\" failed", dbName);
5598 tgl 1565 LBC 0 : return NULL;
1566 : }
1567 :
5598 tgl 1568 GIC 276 : if (PQstatus(conn) == CONNECTION_BAD &&
1569 1 : PQconnectionNeedsPassword(conn) &&
948 tgl 1570 LBC 0 : !password)
1571 : {
5598 1572 0 : PQfinish(conn);
948 1573 0 : password = simple_prompt("Password: ", false);
5598 tgl 1574 UIC 0 : new_pass = true;
1575 : }
5598 tgl 1576 GIC 275 : } while (new_pass);
1577 :
5598 tgl 1578 ECB : /* check to see that the backend connection was successfully made */
5598 tgl 1579 GIC 275 : if (PQstatus(conn) == CONNECTION_BAD)
1580 : {
807 1581 1 : pg_log_error("%s", PQerrorMessage(conn));
5598 1582 1 : PQfinish(conn);
5598 tgl 1583 CBC 1 : return NULL;
7836 bruce 1584 ECB : }
1585 :
5598 tgl 1586 GIC 274 : return conn;
7882 ishii 1587 ECB : }
1588 :
2529 tgl 1589 : /* qsort comparator for Variable array */
1590 : static int
2529 tgl 1591 CBC 53126 : compareVariableNames(const void *v1, const void *v2)
1592 : {
6393 tgl 1593 GIC 106252 : return strcmp(((const Variable *) v1)->name,
1594 53126 : ((const Variable *) v2)->name);
6401 ishii 1595 ECB : }
1596 :
2529 tgl 1597 : /* Locate a variable by name; returns NULL if unknown */
1598 : static Variable *
382 ishii 1599 GIC 7754 : lookupVariable(Variables *variables, char *name)
1600 : {
1601 : Variable key;
1602 :
1603 : /* On some versions of Solaris, bsearch of zero items dumps core */
1604 7754 : if (variables->nvars <= 0)
6393 tgl 1605 CBC 154 : return NULL;
1606 :
1607 : /* Sort if we have to */
382 ishii 1608 GIC 7600 : if (!variables->vars_sorted)
1609 : {
61 peter 1610 GNC 926 : qsort(variables->vars, variables->nvars, sizeof(Variable),
2529 tgl 1611 ECB : compareVariableNames);
382 ishii 1612 CBC 926 : variables->vars_sorted = true;
1613 : }
2529 tgl 1614 ECB :
1615 : /* Now we can search */
6385 tgl 1616 GIC 7600 : key.name = name;
61 peter 1617 GNC 7600 : return (Variable *) bsearch(&key,
1618 7600 : variables->vars,
382 ishii 1619 CBC 7600 : variables->nvars,
2529 tgl 1620 ECB : sizeof(Variable),
1621 : compareVariableNames);
1622 : }
1623 :
1624 : /* Get the value of a variable, in string form; returns NULL if unknown */
1625 : static char *
382 ishii 1626 GIC 2616 : getVariable(Variables *variables, char *name)
2529 tgl 1627 ECB : {
1628 : Variable *var;
1629 : char stringform[64];
1630 :
382 ishii 1631 GBC 2616 : var = lookupVariable(variables, name);
2529 tgl 1632 CBC 2616 : if (var == NULL)
1633 4 : return NULL; /* not found */
1634 :
1916 teodor 1635 GIC 2612 : if (var->svalue)
1636 1006 : return var->svalue; /* we have it in string form */
1637 :
1916 teodor 1638 ECB : /* We need to produce a string equivalent of the value */
1916 teodor 1639 GIC 1606 : Assert(var->value.type != PGBT_NO_VALUE);
1640 1606 : if (var->value.type == PGBT_NULL)
1641 1 : snprintf(stringform, sizeof(stringform), "NULL");
1916 teodor 1642 CBC 1605 : else if (var->value.type == PGBT_BOOLEAN)
2529 tgl 1643 1 : snprintf(stringform, sizeof(stringform),
1916 teodor 1644 GIC 1 : "%s", var->value.u.bval ? "true" : "false");
1916 teodor 1645 CBC 1604 : else if (var->value.type == PGBT_INT)
2529 tgl 1646 GIC 1602 : snprintf(stringform, sizeof(stringform),
1916 teodor 1647 ECB : INT64_FORMAT, var->value.u.ival);
1916 teodor 1648 GIC 2 : else if (var->value.type == PGBT_DOUBLE)
1916 teodor 1649 GBC 2 : snprintf(stringform, sizeof(stringform),
1650 : "%.*g", DBL_DIG, var->value.u.dval);
1809 tgl 1651 ECB : else /* internal error, unexpected type */
1916 teodor 1652 UIC 0 : Assert(0);
1916 teodor 1653 CBC 1606 : var->svalue = pg_strdup(stringform);
1916 teodor 1654 GIC 1606 : return var->svalue;
1655 : }
1656 :
1657 : /* Try to convert variable to a value; return false on failure */
1658 : static bool
1659 1915 : makeVariableValue(Variable *var)
2529 tgl 1660 ECB : {
1809 1661 : size_t slen;
1916 teodor 1662 :
1916 teodor 1663 GIC 1915 : if (var->value.type != PGBT_NO_VALUE)
2529 tgl 1664 CBC 1490 : return true; /* no work */
1665 :
1916 teodor 1666 425 : slen = strlen(var->svalue);
1916 teodor 1667 ECB :
1916 teodor 1668 CBC 425 : if (slen == 0)
1916 teodor 1669 ECB : /* what should it do on ""? */
1916 teodor 1670 UIC 0 : return false;
1916 teodor 1671 ECB :
1916 teodor 1672 GIC 425 : if (pg_strcasecmp(var->svalue, "null") == 0)
2529 tgl 1673 ECB : {
1916 teodor 1674 GIC 1 : setNullValue(&var->value);
1675 : }
1676 :
1677 : /*
1809 tgl 1678 ECB : * accept prefixes such as y, ye, n, no... but not for "o". 0/1 are
1809 tgl 1679 EUB : * recognized later as an int, which is converted to bool if needed.
1680 : */
1916 teodor 1681 CBC 847 : else if (pg_strncasecmp(var->svalue, "true", slen) == 0 ||
1916 teodor 1682 GIC 846 : pg_strncasecmp(var->svalue, "yes", slen) == 0 ||
1683 423 : pg_strcasecmp(var->svalue, "on") == 0)
1684 : {
1685 1 : setBoolValue(&var->value, true);
1686 : }
1916 teodor 1687 CBC 846 : else if (pg_strncasecmp(var->svalue, "false", slen) == 0 ||
1916 teodor 1688 GIC 846 : pg_strncasecmp(var->svalue, "no", slen) == 0 ||
1916 teodor 1689 CBC 846 : pg_strcasecmp(var->svalue, "off") == 0 ||
1916 teodor 1690 GIC 423 : pg_strcasecmp(var->svalue, "of") == 0)
1916 teodor 1691 ECB : {
1916 teodor 1692 GIC 1 : setBoolValue(&var->value, false);
1916 teodor 1693 ECB : }
1916 teodor 1694 GIC 422 : else if (is_an_int(var->svalue))
1916 teodor 1695 ECB : {
1696 : /* if it looks like an int, it must be an int without overflow */
1697 : int64 iv;
1698 :
1655 andres 1699 GIC 419 : if (!strtoint64(var->svalue, false, &iv))
1655 andres 1700 UIC 0 : return false;
1701 :
1655 andres 1702 GIC 419 : setIntValue(&var->value, iv);
1703 : }
1704 : else /* type should be double */
1705 : {
1706 : double dv;
1707 :
1708 3 : if (!strtodouble(var->svalue, true, &dv))
1709 : {
1187 peter 1710 2 : pg_log_error("malformed variable \"%s\" value: \"%s\"",
1711 : var->name, var->svalue);
2529 tgl 1712 CBC 2 : return false;
1713 : }
1916 teodor 1714 1 : setDoubleValue(&var->value, dv);
1715 : }
2529 tgl 1716 GIC 423 : return true;
6401 ishii 1717 ECB : }
6401 ishii 1718 EUB :
1719 : /*
1720 : * Check whether a variable's name is allowed.
2043 tgl 1721 ECB : *
1722 : * We allow any non-ASCII character, as well as ASCII letters, digits, and
1723 : * underscore.
1724 : *
1725 : * Keep this in sync with the definitions of variable name characters in
1726 : * "src/fe_utils/psqlscan.l", "src/bin/psql/psqlscanslash.l" and
1727 : * "src/bin/pgbench/exprscan.l". Also see parseVariable(), below.
1728 : *
1729 : * Note: this static function is copied from "src/bin/psql/variables.c"
1730 : * but changed to disallow variable names starting with a digit.
1731 : */
4841 itagaki.takahiro 1732 : static bool
2043 tgl 1733 CBC 991 : valid_variable_name(const char *name)
4841 itagaki.takahiro 1734 ECB : {
2043 tgl 1735 GIC 991 : const unsigned char *ptr = (const unsigned char *) name;
2043 tgl 1736 ECB :
1737 : /* Mustn't be zero-length */
2043 tgl 1738 GIC 991 : if (*ptr == '\0')
2043 tgl 1739 LBC 0 : return false;
1740 :
1741 : /* must not start with [0-9] */
816 tgl 1742 GIC 991 : if (IS_HIGHBIT_SET(*ptr) ||
1743 991 : strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1744 991 : "_", *ptr) != NULL)
1745 989 : ptr++;
1746 : else
816 tgl 1747 CBC 2 : return false;
1748 :
1749 : /* remaining characters can include [0-9] */
2043 1750 6168 : while (*ptr)
1751 : {
1752 5180 : if (IS_HIGHBIT_SET(*ptr) ||
2043 tgl 1753 GIC 5180 : strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
2043 tgl 1754 CBC 5180 : "_0123456789", *ptr) != NULL)
1755 5179 : ptr++;
2043 tgl 1756 ECB : else
4841 itagaki.takahiro 1757 GIC 1 : return false;
4841 itagaki.takahiro 1758 ECB : }
1759 :
2043 tgl 1760 GIC 988 : return true;
1761 : }
1762 :
1763 : /*
1764 : * Make sure there is enough space for 'needed' more variable in the variables
1765 : * array.
382 ishii 1766 ECB : */
1767 : static void
382 ishii 1768 GIC 988 : enlargeVariables(Variables *variables, int needed)
1769 : {
382 ishii 1770 ECB : /* total number of variables required now */
382 ishii 1771 CBC 988 : needed += variables->nvars;
1772 :
382 ishii 1773 GIC 988 : if (variables->max_vars < needed)
1774 : {
1775 161 : variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
1776 161 : variables->vars = (Variable *)
382 ishii 1777 CBC 161 : pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
1778 : }
1779 988 : }
382 ishii 1780 ECB :
1781 : /*
1782 : * Lookup a variable by name, creating it if need be.
1783 : * Caller is expected to assign a value to the variable.
2529 tgl 1784 : * Returns NULL on failure (bad name).
1785 : */
1786 : static Variable *
382 ishii 1787 GIC 2949 : lookupCreateVariable(Variables *variables, const char *context, char *name)
6401 ishii 1788 ECB : {
2529 tgl 1789 : Variable *var;
1790 :
382 ishii 1791 GIC 2949 : var = lookupVariable(variables, name);
6401 ishii 1792 CBC 2949 : if (var == NULL)
1793 : {
4841 itagaki.takahiro 1794 ECB : /*
1795 : * Check for the name only when declaring a new variable to avoid
1796 : * overhead.
1797 : */
2043 tgl 1798 GIC 991 : if (!valid_variable_name(name))
1799 : {
1187 peter 1800 3 : pg_log_error("%s: invalid variable name: \"%s\"", context, name);
2529 tgl 1801 3 : return NULL;
1802 : }
4841 itagaki.takahiro 1803 ECB :
1804 : /* Create variable at the end of the array */
382 ishii 1805 GIC 988 : enlargeVariables(variables, 1);
1806 :
1807 988 : var = &(variables->vars[variables->nvars]);
1808 :
3841 tgl 1809 CBC 988 : var->name = pg_strdup(name);
1916 teodor 1810 988 : var->svalue = NULL;
2529 tgl 1811 ECB : /* caller is expected to initialize remaining fields */
1812 :
382 ishii 1813 GIC 988 : variables->nvars++;
2529 tgl 1814 ECB : /* we don't re-sort the array till we have to */
382 ishii 1815 GIC 988 : variables->vars_sorted = false;
6401 ishii 1816 ECB : }
6052 1817 :
2529 tgl 1818 CBC 2946 : return var;
1819 : }
2529 tgl 1820 ECB :
1821 : /* Assign a string value to a variable, creating it if need be */
1822 : /* Returns false on failure (bad name) */
1823 : static bool
382 ishii 1824 GIC 863 : putVariable(Variables *variables, const char *context, char *name,
1825 : const char *value)
2529 tgl 1826 ECB : {
1827 : Variable *var;
1828 : char *val;
1829 :
382 ishii 1830 GIC 863 : var = lookupCreateVariable(variables, context, name);
2529 tgl 1831 CBC 863 : if (!var)
1832 2 : return false;
2529 tgl 1833 ECB :
1834 : /* dup then free, in case value is pointing at this variable */
2529 tgl 1835 CBC 861 : val = pg_strdup(value);
6052 ishii 1836 ECB :
297 peter 1837 GNC 861 : free(var->svalue);
1916 teodor 1838 CBC 861 : var->svalue = val;
1916 teodor 1839 GIC 861 : var->value.type = PGBT_NO_VALUE;
1840 :
2529 tgl 1841 861 : return true;
1842 : }
1843 :
1916 teodor 1844 ECB : /* Assign a value to a variable, creating it if need be */
1845 : /* Returns false on failure (bad name) */
1846 : static bool
382 ishii 1847 GIC 2086 : putVariableValue(Variables *variables, const char *context, char *name,
1848 : const PgBenchValue *value)
2529 tgl 1849 ECB : {
1850 : Variable *var;
1851 :
382 ishii 1852 GIC 2086 : var = lookupCreateVariable(variables, context, name);
2529 tgl 1853 2086 : if (!var)
1854 1 : return false;
1855 :
297 peter 1856 GNC 2085 : free(var->svalue);
1916 teodor 1857 GIC 2085 : var->svalue = NULL;
1858 2085 : var->value = *value;
1859 :
6401 ishii 1860 2085 : return true;
6401 ishii 1861 ECB : }
1862 :
2529 tgl 1863 : /* Assign an integer value to a variable, creating it if need be */
1864 : /* Returns false on failure (bad name) */
1865 : static bool
382 ishii 1866 GIC 397 : putVariableInt(Variables *variables, const char *context, char *name,
382 ishii 1867 ECB : int64 value)
2529 tgl 1868 : {
1869 : PgBenchValue val;
1870 :
2529 tgl 1871 GIC 397 : setIntValue(&val, value);
382 ishii 1872 CBC 397 : return putVariableValue(variables, context, name, &val);
1873 : }
2529 tgl 1874 ECB :
2043 1875 : /*
1876 : * Parse a possible variable reference (:varname).
1877 : *
1878 : * "sql" points at a colon. If what follows it looks like a valid
1879 : * variable name, return a malloc'd string containing the variable name,
816 1880 : * and set *eaten to the number of characters consumed (including the colon).
2043 1881 : * Otherwise, return NULL.
1882 : */
5499 ishii 1883 : static char *
5499 ishii 1884 CBC 1664 : parseVariable(const char *sql, int *eaten)
1885 : {
816 tgl 1886 GIC 1664 : int i = 1; /* starting at 1 skips the colon */
1887 : char *name;
5499 ishii 1888 ECB :
1889 : /* keep this logic in sync with valid_variable_name() */
816 tgl 1890 CBC 1664 : if (IS_HIGHBIT_SET(sql[i]) ||
816 tgl 1891 GIC 1664 : strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
816 tgl 1892 CBC 1664 : "_", sql[i]) != NULL)
816 tgl 1893 GIC 1218 : i++;
816 tgl 1894 ECB : else
816 tgl 1895 GIC 446 : return NULL;
816 tgl 1896 ECB :
816 tgl 1897 CBC 6211 : while (IS_HIGHBIT_SET(sql[i]) ||
816 tgl 1898 GIC 6211 : strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1899 6211 : "_0123456789", sql[i]) != NULL)
5499 ishii 1900 CBC 4993 : i++;
5499 ishii 1901 ECB :
3841 tgl 1902 CBC 1218 : name = pg_malloc(i);
5499 ishii 1903 GIC 1218 : memcpy(name, &sql[1], i - 1);
5499 ishii 1904 CBC 1218 : name[i - 1] = '\0';
1905 :
5499 ishii 1906 GIC 1218 : *eaten = i;
1907 1218 : return name;
5499 ishii 1908 ECB : }
1909 :
1910 : static char *
5499 ishii 1911 GIC 1217 : replaceVariable(char **sql, char *param, int len, char *value)
1912 : {
5050 bruce 1913 1217 : int valueln = strlen(value);
5499 ishii 1914 ECB :
5499 ishii 1915 CBC 1217 : if (valueln > len)
1916 : {
5050 bruce 1917 GIC 576 : size_t offset = param - *sql;
1918 :
3841 tgl 1919 CBC 576 : *sql = pg_realloc(*sql, strlen(*sql) - len + valueln + 1);
5499 ishii 1920 576 : param = *sql + offset;
1921 : }
5499 ishii 1922 ECB :
5499 ishii 1923 GIC 1217 : if (valueln != len)
5499 ishii 1924 CBC 1180 : memmove(param + valueln, param + len, strlen(param + len) + 1);
2997 tgl 1925 GIC 1217 : memcpy(param, value, valueln);
5499 ishii 1926 ECB :
5499 ishii 1927 GIC 1217 : return param + valueln;
1928 : }
5499 ishii 1929 ECB :
6401 1930 : static char *
382 ishii 1931 CBC 3333 : assignVariables(Variables *variables, char *sql)
1932 : {
6385 bruce 1933 EUB : char *p,
1934 : *name,
1935 : *val;
1936 :
5499 ishii 1937 CBC 3333 : p = sql;
5499 ishii 1938 GIC 4700 : while ((p = strchr(p, ':')) != NULL)
1939 : {
5050 bruce 1940 ECB : int eaten;
1941 :
5499 ishii 1942 GIC 1367 : name = parseVariable(p, &eaten);
1943 1367 : if (name == NULL)
6385 bruce 1944 ECB : {
5050 bruce 1945 GIC 1290 : while (*p == ':')
1946 : {
1947 860 : p++;
1948 : }
6401 ishii 1949 CBC 430 : continue;
5499 ishii 1950 ECB : }
6401 1951 :
382 ishii 1952 GIC 937 : val = getVariable(variables, name);
6401 1953 937 : free(name);
6401 ishii 1954 CBC 937 : if (val == NULL)
1955 : {
5499 ishii 1956 LBC 0 : p++;
5499 ishii 1957 UBC 0 : continue;
6401 ishii 1958 ECB : }
6401 ishii 1959 EUB :
4623 tgl 1960 CBC 937 : p = replaceVariable(&sql, p, eaten, val);
5499 ishii 1961 EUB : }
6401 ishii 1962 ECB :
5499 ishii 1963 CBC 3333 : return sql;
5499 ishii 1964 ECB : }
6401 1965 :
1966 : static void
382 ishii 1967 GIC 2272 : getQueryParams(Variables *variables, const Command *command,
1968 : const char **params)
5499 ishii 1969 EUB : {
1970 : int i;
1971 :
5499 ishii 1972 GIC 3946 : for (i = 0; i < command->argc - 1; i++)
382 1973 1674 : params[i] = getVariable(variables, command->argv[i + 1]);
5499 1974 2272 : }
1975 :
1916 teodor 1976 ECB : static char *
1916 teodor 1977 GIC 4 : valueTypeName(PgBenchValue *pval)
1916 teodor 1978 ECB : {
1916 teodor 1979 GIC 4 : if (pval->type == PGBT_NO_VALUE)
1916 teodor 1980 LBC 0 : return "none";
1916 teodor 1981 CBC 4 : else if (pval->type == PGBT_NULL)
1916 teodor 1982 UIC 0 : return "null";
1916 teodor 1983 GIC 4 : else if (pval->type == PGBT_INT)
1916 teodor 1984 UIC 0 : return "int";
1916 teodor 1985 CBC 4 : else if (pval->type == PGBT_DOUBLE)
1986 1 : return "double";
1987 3 : else if (pval->type == PGBT_BOOLEAN)
1916 teodor 1988 GIC 3 : return "boolean";
1989 : else
1990 : {
1991 : /* internal error, should never get there */
1916 teodor 1992 UIC 0 : Assert(false);
1993 : return NULL;
1994 : }
1995 : }
1916 teodor 1996 ECB :
1997 : /* get a value as a boolean, or tell if there is a problem */
1998 : static bool
1916 teodor 1999 GIC 108 : coerceToBool(PgBenchValue *pval, bool *bval)
1916 teodor 2000 ECB : {
1916 teodor 2001 CBC 108 : if (pval->type == PGBT_BOOLEAN)
1916 teodor 2002 ECB : {
1916 teodor 2003 CBC 107 : *bval = pval->u.bval;
2004 107 : return true;
1916 teodor 2005 ECB : }
1809 tgl 2006 : else /* NULL, INT or DOUBLE */
1916 teodor 2007 : {
1187 peter 2008 GBC 1 : pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
1880 tgl 2009 GIC 1 : *bval = false; /* suppress uninitialized-variable warnings */
1916 teodor 2010 GBC 1 : return false;
2011 : }
2012 : }
2013 :
2014 : /*
2015 : * Return true or false from an expression for conditional purposes.
2016 : * Non zero numerical values are true, zero and NULL are false.
1916 teodor 2017 ECB : */
2018 : static bool
1916 teodor 2019 CBC 432 : valueTruth(PgBenchValue *pval)
2020 : {
2021 432 : switch (pval->type)
1916 teodor 2022 ECB : {
1916 teodor 2023 GIC 1 : case PGBT_NULL:
1916 teodor 2024 CBC 1 : return false;
1916 teodor 2025 GIC 21 : case PGBT_BOOLEAN:
1916 teodor 2026 CBC 21 : return pval->u.bval;
1916 teodor 2027 GIC 409 : case PGBT_INT:
1916 teodor 2028 CBC 409 : return pval->u.ival != 0;
1916 teodor 2029 GIC 1 : case PGBT_DOUBLE:
1916 teodor 2030 CBC 1 : return pval->u.dval != 0.0;
1916 teodor 2031 LBC 0 : default:
2032 : /* internal error, unexpected type */
2033 0 : Assert(0);
1916 teodor 2034 ECB : return false;
2035 : }
2036 : }
2037 :
2568 rhaas 2038 : /* get a value as an int, tell if there is a problem */
2039 : static bool
2568 rhaas 2040 GIC 6568 : coerceToInt(PgBenchValue *pval, int64 *ival)
2041 : {
2042 6568 : if (pval->type == PGBT_INT)
2043 : {
2044 6564 : *ival = pval->u.ival;
2568 rhaas 2045 CBC 6564 : return true;
2046 : }
1916 teodor 2047 4 : else if (pval->type == PGBT_DOUBLE)
2048 : {
1249 tgl 2049 2 : double dval = rint(pval->u.dval);
2495 rhaas 2050 ECB :
1249 tgl 2051 GIC 2 : if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
2568 rhaas 2052 ECB : {
1187 peter 2053 GIC 1 : pg_log_error("double to int overflow for %f", dval);
2568 rhaas 2054 CBC 1 : return false;
2568 rhaas 2055 ECB : }
2568 rhaas 2056 GIC 1 : *ival = (int64) dval;
2057 1 : return true;
2058 : }
1809 tgl 2059 ECB : else /* BOOLEAN or NULL */
1916 teodor 2060 : {
1187 peter 2061 GIC 2 : pg_log_error("cannot coerce %s to int", valueTypeName(pval));
1916 teodor 2062 2 : return false;
2063 : }
2064 : }
2065 :
2568 rhaas 2066 ECB : /* get a value as a double, or tell if there is a problem */
2067 : static bool
2568 rhaas 2068 CBC 104 : coerceToDouble(PgBenchValue *pval, double *dval)
2568 rhaas 2069 ECB : {
2568 rhaas 2070 CBC 104 : if (pval->type == PGBT_DOUBLE)
2071 : {
2568 rhaas 2072 GIC 73 : *dval = pval->u.dval;
2073 73 : return true;
2568 rhaas 2074 ECB : }
1916 teodor 2075 GIC 31 : else if (pval->type == PGBT_INT)
2568 rhaas 2076 ECB : {
2568 rhaas 2077 CBC 30 : *dval = (double) pval->u.ival;
2078 30 : return true;
2079 : }
2080 : else /* BOOLEAN or NULL */
2081 : {
1187 peter 2082 1 : pg_log_error("cannot coerce %s to double", valueTypeName(pval));
1916 teodor 2083 GIC 1 : return false;
1916 teodor 2084 ECB : }
2085 : }
2086 :
2087 : /* assign a null value */
2088 : static void
1916 teodor 2089 GIC 4 : setNullValue(PgBenchValue *pv)
1916 teodor 2090 ECB : {
1916 teodor 2091 GIC 4 : pv->type = PGBT_NULL;
1916 teodor 2092 CBC 4 : pv->u.ival = 0;
2093 4 : }
1916 teodor 2094 ECB :
2095 : /* assign a boolean value */
2096 : static void
1916 teodor 2097 CBC 134 : setBoolValue(PgBenchValue *pv, bool bval)
2098 : {
2099 134 : pv->type = PGBT_BOOLEAN;
1916 teodor 2100 GIC 134 : pv->u.bval = bval;
2568 rhaas 2101 134 : }
2102 :
2103 : /* assign an integer value */
2568 rhaas 2104 ECB : static void
2568 rhaas 2105 GIC 4014 : setIntValue(PgBenchValue *pv, int64 ival)
2106 : {
2107 4014 : pv->type = PGBT_INT;
2108 4014 : pv->u.ival = ival;
2109 4014 : }
2110 :
2111 : /* assign a double value */
2568 rhaas 2112 ECB : static void
2568 rhaas 2113 GIC 39 : setDoubleValue(PgBenchValue *pv, double dval)
2114 : {
2568 rhaas 2115 CBC 39 : pv->type = PGBT_DOUBLE;
2116 39 : pv->u.dval = dval;
2568 rhaas 2117 GIC 39 : }
2118 :
1809 tgl 2119 ECB : static bool
1809 tgl 2120 GIC 3555 : isLazyFunc(PgBenchFunction func)
1916 teodor 2121 ECB : {
1916 teodor 2122 GIC 3555 : return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
1916 teodor 2123 ECB : }
2124 :
2125 : /* lazy evaluation of some functions */
1916 teodor 2126 EUB : static bool
1467 tgl 2127 GBC 65 : evalLazyFunc(CState *st,
2128 : PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
2129 : {
1809 tgl 2130 ECB : PgBenchValue a1,
1809 tgl 2131 EUB : a2;
2132 : bool ba1,
1809 tgl 2133 ECB : ba2;
2134 :
1916 teodor 2135 CBC 65 : Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
1916 teodor 2136 ECB :
2137 : /* args points to first condition */
1467 tgl 2138 GIC 65 : if (!evaluateExpr(st, args->expr, &a1))
1916 teodor 2139 CBC 1 : return false;
1916 teodor 2140 EUB :
2141 : /* second condition for AND/OR and corresponding branch for CASE */
1916 teodor 2142 CBC 64 : args = args->next;
2143 :
1916 teodor 2144 GBC 64 : switch (func)
1916 teodor 2145 EUB : {
1809 tgl 2146 GIC 44 : case PGBENCH_AND:
1809 tgl 2147 CBC 44 : if (a1.type == PGBT_NULL)
1809 tgl 2148 EUB : {
1809 tgl 2149 UIC 0 : setNullValue(retval);
2150 0 : return true;
1809 tgl 2151 ECB : }
1916 teodor 2152 :
1809 tgl 2153 GIC 44 : if (!coerceToBool(&a1, &ba1))
1809 tgl 2154 UIC 0 : return false;
2155 :
1809 tgl 2156 GIC 44 : if (!ba1)
1809 tgl 2157 ECB : {
1809 tgl 2158 GIC 3 : setBoolValue(retval, false);
1809 tgl 2159 CBC 3 : return true;
2160 : }
1916 teodor 2161 EUB :
1467 tgl 2162 GBC 41 : if (!evaluateExpr(st, args->expr, &a2))
1809 tgl 2163 UIC 0 : return false;
2164 :
1809 tgl 2165 CBC 41 : if (a2.type == PGBT_NULL)
1809 tgl 2166 EUB : {
1809 tgl 2167 UIC 0 : setNullValue(retval);
1809 tgl 2168 LBC 0 : return true;
2169 : }
1809 tgl 2170 CBC 41 : else if (!coerceToBool(&a2, &ba2))
1809 tgl 2171 LBC 0 : return false;
2172 : else
2173 : {
1809 tgl 2174 CBC 41 : setBoolValue(retval, ba2);
1809 tgl 2175 GBC 41 : return true;
2176 : }
1916 teodor 2177 ECB :
2178 : return true;
1916 teodor 2179 EUB :
1809 tgl 2180 GBC 4 : case PGBENCH_OR:
2181 :
1809 tgl 2182 CBC 4 : if (a1.type == PGBT_NULL)
1809 tgl 2183 EUB : {
1809 tgl 2184 UIC 0 : setNullValue(retval);
2185 0 : return true;
1809 tgl 2186 ECB : }
1916 teodor 2187 :
1809 tgl 2188 GIC 4 : if (!coerceToBool(&a1, &ba1))
1809 tgl 2189 UIC 0 : return false;
1916 teodor 2190 ECB :
1809 tgl 2191 GIC 4 : if (ba1)
1809 tgl 2192 ECB : {
1809 tgl 2193 CBC 1 : setBoolValue(retval, true);
1809 tgl 2194 GIC 1 : return true;
2195 : }
1916 teodor 2196 ECB :
1467 tgl 2197 GIC 3 : if (!evaluateExpr(st, args->expr, &a2))
1809 tgl 2198 UIC 0 : return false;
1916 teodor 2199 ECB :
1809 tgl 2200 CBC 3 : if (a2.type == PGBT_NULL)
2201 : {
1809 tgl 2202 UIC 0 : setNullValue(retval);
1809 tgl 2203 LBC 0 : return true;
2204 : }
1809 tgl 2205 GBC 3 : else if (!coerceToBool(&a2, &ba2))
1809 tgl 2206 UIC 0 : return false;
1809 tgl 2207 EUB : else
2208 : {
1809 tgl 2209 GIC 3 : setBoolValue(retval, ba2);
2210 3 : return true;
2211 : }
2212 :
2213 16 : case PGBENCH_CASE:
2214 : /* when true, execute branch */
2215 16 : if (valueTruth(&a1))
1467 2216 11 : return evaluateExpr(st, args->expr, retval);
2217 :
2218 : /* now args contains next condition or final else expression */
1809 2219 5 : args = args->next;
2220 :
1809 tgl 2221 ECB : /* final else case? */
1809 tgl 2222 GIC 5 : if (args->next == NULL)
1467 2223 3 : return evaluateExpr(st, args->expr, retval);
2224 :
2225 : /* no, another when, proceed */
1467 tgl 2226 CBC 2 : return evalLazyFunc(st, PGBENCH_CASE, args, retval);
2227 :
1809 tgl 2228 LBC 0 : default:
1809 tgl 2229 ECB : /* internal error, cannot get here */
1809 tgl 2230 UIC 0 : Assert(0);
1809 tgl 2231 ECB : break;
2232 : }
1916 teodor 2233 : return false;
2234 : }
2235 :
2236 : /* maximum number of function arguments */
2237 : #define MAX_FARGS 16
2595 rhaas 2238 :
2239 : /*
1916 teodor 2240 : * Recursive evaluation of standard functions,
2241 : * which do not require lazy evaluation.
2242 : */
2243 : static bool
1467 tgl 2244 GIC 3427 : evalStandardFunc(CState *st,
1880 tgl 2245 ECB : PgBenchFunction func, PgBenchExprLink *args,
2246 : PgBenchValue *retval)
2960 rhaas 2247 : {
2595 2248 : /* evaluate all function arguments */
1809 tgl 2249 GIC 3427 : int nargs = 0;
2250 : PgBenchValue vargs[MAX_FARGS];
2595 rhaas 2251 3427 : PgBenchExprLink *l = args;
1809 tgl 2252 CBC 3427 : bool has_null = false;
2253 :
2595 rhaas 2254 GIC 10244 : for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
1916 teodor 2255 ECB : {
1467 tgl 2256 GIC 6819 : if (!evaluateExpr(st, l->expr, &vargs[nargs]))
2595 rhaas 2257 2 : return false;
1916 teodor 2258 6817 : has_null |= vargs[nargs].type == PGBT_NULL;
2259 : }
2260 :
2595 rhaas 2261 3425 : if (l != NULL)
2262 : {
1187 peter 2263 1 : pg_log_error("too many function arguments, maximum is %d", MAX_FARGS);
2595 rhaas 2264 1 : return false;
2595 rhaas 2265 ECB : }
2960 2266 :
2267 : /* NULL arguments */
1916 teodor 2268 CBC 3424 : if (has_null && func != PGBENCH_IS && func != PGBENCH_DEBUG)
2269 : {
1916 teodor 2270 GIC 3 : setNullValue(retval);
1916 teodor 2271 CBC 3 : return true;
1916 teodor 2272 ECB : }
2273 :
2274 : /* then evaluate function */
2595 rhaas 2275 GIC 3421 : switch (func)
2276 : {
2495 rhaas 2277 ECB : /* overloaded operators */
2595 rhaas 2278 CBC 1689 : case PGBENCH_ADD:
2595 rhaas 2279 ECB : case PGBENCH_SUB:
2280 : case PGBENCH_MUL:
2281 : case PGBENCH_DIV:
2282 : case PGBENCH_MOD:
1916 teodor 2283 : case PGBENCH_EQ:
2284 : case PGBENCH_NE:
2285 : case PGBENCH_LE:
2286 : case PGBENCH_LT:
2960 rhaas 2287 : {
2495 rhaas 2288 CBC 1689 : PgBenchValue *lval = &vargs[0],
2289 1689 : *rval = &vargs[1];
2290 :
2595 2291 1689 : Assert(nargs == 2);
2595 rhaas 2292 ECB :
2568 2293 : /* overloaded type management, double if some double */
2568 rhaas 2294 GIC 1689 : if ((lval->type == PGBT_DOUBLE ||
2568 rhaas 2295 CBC 1689 : rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
2960 rhaas 2296 ECB : {
2495 2297 : double ld,
2298 : rd;
2960 2299 :
2568 rhaas 2300 CBC 31 : if (!coerceToDouble(lval, &ld) ||
2301 31 : !coerceToDouble(rval, &rd))
2568 rhaas 2302 GIC 31 : return false;
2960 rhaas 2303 ECB :
2568 rhaas 2304 CBC 31 : switch (func)
2568 rhaas 2305 ECB : {
2568 rhaas 2306 GIC 1 : case PGBENCH_ADD:
2568 rhaas 2307 CBC 1 : setDoubleValue(retval, ld + rd);
2308 1 : return true;
2960 rhaas 2309 ECB :
2568 rhaas 2310 GIC 10 : case PGBENCH_SUB:
2568 rhaas 2311 CBC 10 : setDoubleValue(retval, ld - rd);
2312 10 : return true;
2568 rhaas 2313 ECB :
2568 rhaas 2314 GIC 8 : case PGBENCH_MUL:
2568 rhaas 2315 GBC 8 : setDoubleValue(retval, ld * rd);
2568 rhaas 2316 GIC 8 : return true;
2568 rhaas 2317 EUB :
2568 rhaas 2318 GIC 2 : case PGBENCH_DIV:
2319 2 : setDoubleValue(retval, ld / rd);
2320 2 : return true;
2321 :
1916 teodor 2322 4 : case PGBENCH_EQ:
2323 4 : setBoolValue(retval, ld == rd);
2324 4 : return true;
2325 :
1916 teodor 2326 CBC 2 : case PGBENCH_NE:
2327 2 : setBoolValue(retval, ld != rd);
2328 2 : return true;
2329 :
2330 2 : case PGBENCH_LE:
1916 teodor 2331 GIC 2 : setBoolValue(retval, ld <= rd);
1916 teodor 2332 CBC 2 : return true;
1916 teodor 2333 ECB :
1916 teodor 2334 GIC 2 : case PGBENCH_LT:
1916 teodor 2335 CBC 2 : setBoolValue(retval, ld < rd);
2336 2 : return true;
2337 :
2568 rhaas 2338 LBC 0 : default:
2568 rhaas 2339 ECB : /* cannot get here */
2568 rhaas 2340 UIC 0 : Assert(0);
2568 rhaas 2341 ECB : }
2342 : }
2343 : else /* we have integer operands, or % */
2344 : {
2495 2345 : int64 li,
2346 : ri,
1655 andres 2347 : res;
2568 rhaas 2348 :
2568 rhaas 2349 GIC 1658 : if (!coerceToInt(lval, &li) ||
2568 rhaas 2350 CBC 1657 : !coerceToInt(rval, &ri))
2351 1658 : return false;
2352 :
2353 1657 : switch (func)
2568 rhaas 2354 ECB : {
2568 rhaas 2355 GIC 44 : case PGBENCH_ADD:
1655 andres 2356 CBC 44 : if (pg_add_s64_overflow(li, ri, &res))
1655 andres 2357 ECB : {
1187 peter 2358 GIC 1 : pg_log_error("bigint add out of range");
1655 andres 2359 CBC 1 : return false;
1655 andres 2360 ECB : }
1655 andres 2361 CBC 43 : setIntValue(retval, res);
2568 rhaas 2362 GIC 43 : return true;
2568 rhaas 2363 ECB :
2568 rhaas 2364 CBC 149 : case PGBENCH_SUB:
1655 andres 2365 149 : if (pg_sub_s64_overflow(li, ri, &res))
2366 : {
1187 peter 2367 1 : pg_log_error("bigint sub out of range");
1655 andres 2368 1 : return false;
1655 andres 2369 ECB : }
1655 andres 2370 GIC 148 : setIntValue(retval, res);
2568 rhaas 2371 CBC 148 : return true;
2568 rhaas 2372 ECB :
2568 rhaas 2373 CBC 1406 : case PGBENCH_MUL:
1655 andres 2374 GIC 1406 : if (pg_mul_s64_overflow(li, ri, &res))
1655 andres 2375 ECB : {
1187 peter 2376 GIC 1 : pg_log_error("bigint mul out of range");
1655 andres 2377 CBC 1 : return false;
2378 : }
2379 1405 : setIntValue(retval, res);
2568 rhaas 2380 1405 : return true;
2381 :
1916 teodor 2382 GIC 27 : case PGBENCH_EQ:
1916 teodor 2383 CBC 27 : setBoolValue(retval, li == ri);
1916 teodor 2384 GIC 27 : return true;
1916 teodor 2385 ECB :
1916 teodor 2386 GIC 5 : case PGBENCH_NE:
2387 5 : setBoolValue(retval, li != ri);
1916 teodor 2388 CBC 5 : return true;
2389 :
2390 5 : case PGBENCH_LE:
2391 5 : setBoolValue(retval, li <= ri);
1916 teodor 2392 GIC 5 : return true;
2393 :
1916 teodor 2394 CBC 12 : case PGBENCH_LT:
1916 teodor 2395 GIC 12 : setBoolValue(retval, li < ri);
2396 12 : return true;
1916 teodor 2397 ECB :
2568 rhaas 2398 CBC 9 : case PGBENCH_DIV:
2399 : case PGBENCH_MOD:
2568 rhaas 2400 GIC 9 : if (ri == 0)
2568 rhaas 2401 ECB : {
1187 peter 2402 CBC 1 : pg_log_error("division by zero");
2568 rhaas 2403 GIC 1 : return false;
2568 rhaas 2404 ECB : }
2405 : /* special handling of -1 divisor */
2568 rhaas 2406 CBC 8 : if (ri == -1)
2407 : {
2568 rhaas 2408 GBC 3 : if (func == PGBENCH_DIV)
2409 : {
2568 rhaas 2410 EUB : /* overflow check (needed for INT64_MIN) */
2568 rhaas 2411 GIC 2 : if (li == PG_INT64_MIN)
2412 : {
1187 peter 2413 1 : pg_log_error("bigint div out of range");
2568 rhaas 2414 1 : return false;
2415 : }
2416 : else
2495 2417 1 : setIntValue(retval, -li);
2418 : }
2595 rhaas 2419 ECB : else
2568 rhaas 2420 GIC 1 : setIntValue(retval, 0);
2421 2 : return true;
2422 : }
2423 : /* else divisor is not -1 */
2424 5 : if (func == PGBENCH_DIV)
2425 2 : setIntValue(retval, li / ri);
2426 : else /* func == PGBENCH_MOD */
2427 3 : setIntValue(retval, li % ri);
2568 rhaas 2428 ECB :
2595 rhaas 2429 GBC 5 : return true;
2430 :
2568 rhaas 2431 LBC 0 : default:
2568 rhaas 2432 ECB : /* cannot get here */
2568 rhaas 2433 LBC 0 : Assert(0);
2568 rhaas 2434 ECB : }
2595 2435 : }
1804 tgl 2436 :
1803 2437 : Assert(0);
2438 : return false; /* NOTREACHED */
2595 rhaas 2439 : }
2624 2440 :
2441 : /* integer bitwise operators */
1916 teodor 2442 GBC 14 : case PGBENCH_BITAND:
2443 : case PGBENCH_BITOR:
1916 teodor 2444 ECB : case PGBENCH_BITXOR:
2445 : case PGBENCH_LSHIFT:
2446 : case PGBENCH_RSHIFT:
2447 : {
1809 tgl 2448 : int64 li,
2449 : ri;
2450 :
1916 teodor 2451 GIC 14 : if (!coerceToInt(&vargs[0], &li) || !coerceToInt(&vargs[1], &ri))
1916 teodor 2452 LBC 0 : return false;
1916 teodor 2453 ECB :
1916 teodor 2454 GIC 14 : if (func == PGBENCH_BITAND)
1916 teodor 2455 CBC 1 : setIntValue(retval, li & ri);
2456 13 : else if (func == PGBENCH_BITOR)
1916 teodor 2457 GIC 2 : setIntValue(retval, li | ri);
2458 11 : else if (func == PGBENCH_BITXOR)
2459 3 : setIntValue(retval, li ^ ri);
1916 teodor 2460 CBC 8 : else if (func == PGBENCH_LSHIFT)
2461 7 : setIntValue(retval, li << ri);
2462 1 : else if (func == PGBENCH_RSHIFT)
1916 teodor 2463 GIC 1 : setIntValue(retval, li >> ri);
2464 : else /* cannot get here */
1916 teodor 2465 LBC 0 : Assert(0);
2466 :
1916 teodor 2467 CBC 14 : return true;
2468 : }
1916 teodor 2469 ECB :
2470 : /* logical operators */
1916 teodor 2471 CBC 16 : case PGBENCH_NOT:
2472 : {
1809 tgl 2473 ECB : bool b;
2474 :
1916 teodor 2475 CBC 16 : if (!coerceToBool(&vargs[0], &b))
1916 teodor 2476 GIC 1 : return false;
2477 :
2478 15 : setBoolValue(retval, !b);
1916 teodor 2479 CBC 15 : return true;
2480 : }
1916 teodor 2481 ECB :
2495 rhaas 2482 : /* no arguments */
2568 rhaas 2483 GIC 1 : case PGBENCH_PI:
2484 1 : setDoubleValue(retval, M_PI);
2568 rhaas 2485 CBC 1 : return true;
2486 :
2487 : /* 1 overloaded argument */
2595 2488 2 : case PGBENCH_ABS:
2489 : {
2568 2490 2 : PgBenchValue *varg = &vargs[0];
2491 :
2595 2492 2 : Assert(nargs == 1);
2493 :
2568 2494 2 : if (varg->type == PGBT_INT)
2568 rhaas 2495 ECB : {
2495 rhaas 2496 GIC 1 : int64 i = varg->u.ival;
2495 rhaas 2497 ECB :
2568 rhaas 2498 CBC 1 : setIntValue(retval, i < 0 ? -i : i);
2568 rhaas 2499 ECB : }
2595 2500 : else
2568 2501 : {
2495 rhaas 2502 CBC 1 : double d = varg->u.dval;
2495 rhaas 2503 ECB :
2568 rhaas 2504 CBC 1 : Assert(varg->type == PGBT_DOUBLE);
2495 rhaas 2505 GIC 1 : setDoubleValue(retval, d < 0.0 ? -d : d);
2568 rhaas 2506 EUB : }
2507 :
2595 rhaas 2508 CBC 2 : return true;
2509 : }
2595 rhaas 2510 ECB :
2595 rhaas 2511 GIC 84 : case PGBENCH_DEBUG:
2512 : {
2568 2513 84 : PgBenchValue *varg = &vargs[0];
2495 rhaas 2514 ECB :
2568 rhaas 2515 GIC 84 : Assert(nargs == 1);
2516 :
2495 2517 84 : fprintf(stderr, "debug(script=%d,command=%d): ",
2386 heikki.linnakangas 2518 84 : st->use_file, st->command + 1);
2519 :
1916 teodor 2520 84 : if (varg->type == PGBT_NULL)
1916 teodor 2521 CBC 2 : fprintf(stderr, "null\n");
1916 teodor 2522 GIC 82 : else if (varg->type == PGBT_BOOLEAN)
1916 teodor 2523 CBC 19 : fprintf(stderr, "boolean %s\n", varg->u.bval ? "true" : "false");
2524 63 : else if (varg->type == PGBT_INT)
2495 rhaas 2525 GIC 47 : fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
1916 teodor 2526 CBC 16 : else if (varg->type == PGBT_DOUBLE)
2529 tgl 2527 16 : fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
1809 tgl 2528 ECB : else /* internal error, unexpected type */
1916 teodor 2529 LBC 0 : Assert(0);
2568 rhaas 2530 ECB :
2568 rhaas 2531 CBC 84 : *retval = *varg;
2532 :
2568 rhaas 2533 GIC 84 : return true;
2568 rhaas 2534 ECB : }
2535 :
2536 : /* 1 double argument */
2568 rhaas 2537 GIC 5 : case PGBENCH_DOUBLE:
2538 : case PGBENCH_SQRT:
1916 teodor 2539 ECB : case PGBENCH_LN:
2540 : case PGBENCH_EXP:
2541 : {
2542 : double dval;
2495 rhaas 2543 :
2595 rhaas 2544 GIC 5 : Assert(nargs == 1);
2595 rhaas 2545 ECB :
2568 rhaas 2546 CBC 5 : if (!coerceToDouble(&vargs[0], &dval))
2568 rhaas 2547 GIC 1 : return false;
2568 rhaas 2548 ECB :
2568 rhaas 2549 CBC 4 : if (func == PGBENCH_SQRT)
2568 rhaas 2550 GIC 1 : dval = sqrt(dval);
1916 teodor 2551 3 : else if (func == PGBENCH_LN)
2552 1 : dval = log(dval);
1916 teodor 2553 CBC 2 : else if (func == PGBENCH_EXP)
1916 teodor 2554 GIC 1 : dval = exp(dval);
2555 : /* else is cast: do nothing */
2556 :
2568 rhaas 2557 4 : setDoubleValue(retval, dval);
2558 4 : return true;
2568 rhaas 2559 ECB : }
2560 :
2561 : /* 1 int argument */
2568 rhaas 2562 CBC 2 : case PGBENCH_INT:
2568 rhaas 2563 ECB : {
2564 : int64 ival;
2495 2565 :
2568 rhaas 2566 GIC 2 : Assert(nargs == 1);
2595 rhaas 2567 ECB :
2568 rhaas 2568 CBC 2 : if (!coerceToInt(&vargs[0], &ival))
2568 rhaas 2569 GIC 1 : return false;
2570 :
2568 rhaas 2571 CBC 1 : setIntValue(retval, ival);
2595 rhaas 2572 GIC 1 : return true;
2573 : }
2574 :
2495 rhaas 2575 ECB : /* variable number of arguments */
2530 tgl 2576 GBC 4 : case PGBENCH_LEAST:
2530 tgl 2577 ECB : case PGBENCH_GREATEST:
2578 : {
2579 : bool havedouble;
2580 : int i;
2595 rhaas 2581 :
2530 tgl 2582 GBC 4 : Assert(nargs >= 1);
2568 rhaas 2583 ECB :
2530 tgl 2584 : /* need double result if any input is double */
2530 tgl 2585 GIC 4 : havedouble = false;
2530 tgl 2586 CBC 14 : for (i = 0; i < nargs; i++)
2587 : {
2588 12 : if (vargs[i].type == PGBT_DOUBLE)
2589 : {
2530 tgl 2590 GIC 2 : havedouble = true;
2591 2 : break;
2592 : }
2593 : }
2530 tgl 2594 CBC 4 : if (havedouble)
2595 rhaas 2595 EUB : {
2530 tgl 2596 ECB : double extremum;
2597 :
2530 tgl 2598 GIC 2 : if (!coerceToDouble(&vargs[0], &extremum))
2568 rhaas 2599 UIC 0 : return false;
2530 tgl 2600 CBC 6 : for (i = 1; i < nargs; i++)
2530 tgl 2601 EUB : {
2530 tgl 2602 ECB : double dval;
2603 :
2530 tgl 2604 GIC 4 : if (!coerceToDouble(&vargs[i], &dval))
2530 tgl 2605 LBC 0 : return false;
2530 tgl 2606 GIC 4 : if (func == PGBENCH_LEAST)
2530 tgl 2607 CBC 2 : extremum = Min(extremum, dval);
2608 : else
2609 2 : extremum = Max(extremum, dval);
2610 : }
2530 tgl 2611 GIC 2 : setDoubleValue(retval, extremum);
2612 : }
2530 tgl 2613 ECB : else
2614 : {
2615 : int64 extremum;
2616 :
2530 tgl 2617 GIC 2 : if (!coerceToInt(&vargs[0], &extremum))
2530 tgl 2618 UIC 0 : return false;
2530 tgl 2619 GIC 8 : for (i = 1; i < nargs; i++)
2620 : {
2621 : int64 ival;
2530 tgl 2622 ECB :
2530 tgl 2623 GIC 6 : if (!coerceToInt(&vargs[i], &ival))
2530 tgl 2624 LBC 0 : return false;
2530 tgl 2625 CBC 6 : if (func == PGBENCH_LEAST)
2626 3 : extremum = Min(extremum, ival);
2627 : else
2530 tgl 2628 GIC 3 : extremum = Max(extremum, ival);
2530 tgl 2629 ECB : }
2530 tgl 2630 GIC 2 : setIntValue(retval, extremum);
2530 tgl 2631 ECB : }
2595 rhaas 2632 CBC 4 : return true;
2633 : }
2595 rhaas 2634 ECB :
2635 : /* random functions */
2568 rhaas 2636 GIC 1533 : case PGBENCH_RANDOM:
2637 : case PGBENCH_RANDOM_EXPONENTIAL:
2568 rhaas 2638 ECB : case PGBENCH_RANDOM_GAUSSIAN:
1942 teodor 2639 : case PGBENCH_RANDOM_ZIPFIAN:
2640 : {
2641 : int64 imin,
650 tgl 2642 : imax,
2643 : delta;
2568 rhaas 2644 :
2495 rhaas 2645 CBC 1533 : Assert(nargs >= 2);
2646 :
2495 rhaas 2647 GIC 1533 : if (!coerceToInt(&vargs[0], &imin) ||
2648 1532 : !coerceToInt(&vargs[1], &imax))
2568 2649 1 : return false;
2650 :
2495 rhaas 2651 ECB : /* check random range */
650 tgl 2652 GIC 1532 : if (unlikely(imin > imax))
2568 rhaas 2653 ECB : {
1187 peter 2654 CBC 1 : pg_log_error("empty range given to random");
2495 rhaas 2655 GIC 1 : return false;
2495 rhaas 2656 ECB : }
650 tgl 2657 GIC 1531 : else if (unlikely(pg_sub_s64_overflow(imax, imin, &delta) ||
650 tgl 2658 ECB : pg_add_s64_overflow(delta, 1, &delta)))
2659 : {
2495 rhaas 2660 : /* prevent int overflows in random functions */
1187 peter 2661 GIC 1 : pg_log_error("random range is too large");
2495 rhaas 2662 CBC 1 : return false;
2663 : }
2664 :
2665 1530 : if (func == PGBENCH_RANDOM)
2666 : {
2495 rhaas 2667 GIC 1517 : Assert(nargs == 2);
1605 alvherre 2668 1517 : setIntValue(retval, getrand(&st->cs_func_rs, imin, imax));
2568 rhaas 2669 ECB : }
2670 : else /* gaussian & exponential */
2671 : {
2672 : double param;
2495 2673 :
2495 rhaas 2674 GIC 13 : Assert(nargs == 3);
2495 rhaas 2675 ECB :
2495 rhaas 2676 GIC 13 : if (!coerceToDouble(&vargs[2], ¶m))
2568 2677 4 : return false;
2495 rhaas 2678 ECB :
2495 rhaas 2679 GIC 13 : if (func == PGBENCH_RANDOM_GAUSSIAN)
2680 : {
2681 4 : if (param < MIN_GAUSSIAN_PARAM)
2682 : {
1187 peter 2683 CBC 1 : pg_log_error("gaussian parameter must be at least %f (not %f)",
2684 : MIN_GAUSSIAN_PARAM, param);
2495 rhaas 2685 1 : return false;
2686 : }
2495 rhaas 2687 ECB :
2495 rhaas 2688 GIC 3 : setIntValue(retval,
2689 : getGaussianRand(&st->cs_func_rs,
1605 alvherre 2690 ECB : imin, imax, param));
2691 : }
1942 teodor 2692 GIC 9 : else if (func == PGBENCH_RANDOM_ZIPFIAN)
2693 : {
1469 tgl 2694 5 : if (param < MIN_ZIPFIAN_PARAM || param > MAX_ZIPFIAN_PARAM)
2695 : {
1187 peter 2696 CBC 2 : pg_log_error("zipfian parameter must be in range [%.3f, %.0f] (not %f)",
2697 : MIN_ZIPFIAN_PARAM, MAX_ZIPFIAN_PARAM, param);
1942 teodor 2698 GIC 2 : return false;
1942 teodor 2699 ECB : }
2700 :
1942 teodor 2701 CBC 3 : setIntValue(retval,
1469 tgl 2702 ECB : getZipfianRand(&st->cs_func_rs, imin, imax, param));
2703 : }
2704 : else /* exponential */
2705 : {
2495 rhaas 2706 CBC 4 : if (param <= 0.0)
2707 : {
1187 peter 2708 1 : pg_log_error("exponential parameter must be greater than zero (not %f)",
1187 peter 2709 ECB : param);
2495 rhaas 2710 GBC 1 : return false;
2711 : }
2568 rhaas 2712 ECB :
2495 rhaas 2713 GIC 3 : setIntValue(retval,
1605 alvherre 2714 ECB : getExponentialRand(&st->cs_func_rs,
2715 : imin, imax, param));
2716 : }
2568 rhaas 2717 : }
2718 :
2495 rhaas 2719 CBC 1526 : return true;
2720 : }
2721 :
1929 rhaas 2722 GIC 9 : case PGBENCH_POW:
2723 : {
2724 9 : PgBenchValue *lval = &vargs[0];
1929 rhaas 2725 CBC 9 : PgBenchValue *rval = &vargs[1];
1929 rhaas 2726 ECB : double ld,
2727 : rd;
2728 :
1929 rhaas 2729 GIC 9 : Assert(nargs == 2);
2730 :
2731 9 : if (!coerceToDouble(lval, &ld) ||
1929 rhaas 2732 CBC 9 : !coerceToDouble(rval, &rd))
1929 rhaas 2733 UIC 0 : return false;
2734 :
1929 rhaas 2735 GIC 9 : setDoubleValue(retval, pow(ld, rd));
2736 :
2737 9 : return true;
1929 rhaas 2738 ECB : }
2739 :
1916 teodor 2740 CBC 10 : case PGBENCH_IS:
1916 teodor 2741 ECB : {
1916 teodor 2742 GBC 10 : Assert(nargs == 2);
2743 :
1809 tgl 2744 ECB : /*
2745 : * note: this simple implementation is more permissive than
2746 : * SQL
2747 : */
1916 teodor 2748 GIC 10 : setBoolValue(retval,
2749 15 : vargs[0].type == vargs[1].type &&
1916 teodor 2750 GBC 5 : vargs[0].u.bval == vargs[1].u.bval);
1916 teodor 2751 GIC 10 : return true;
1916 teodor 2752 ECB : }
2753 :
2754 : /* hashing */
1845 teodor 2755 CBC 6 : case PGBENCH_HASH_FNV1A:
2756 : case PGBENCH_HASH_MURMUR2:
2757 : {
2758 : int64 val,
2759 : seed;
2760 :
2761 6 : Assert(nargs == 2);
2762 :
2763 6 : if (!coerceToInt(&vargs[0], &val) ||
2764 6 : !coerceToInt(&vargs[1], &seed))
1845 teodor 2765 LBC 0 : return false;
1845 teodor 2766 EUB :
1845 teodor 2767 GIC 6 : if (func == PGBENCH_HASH_MURMUR2)
1845 teodor 2768 CBC 5 : setIntValue(retval, getHashMurmur2(val, seed));
1845 teodor 2769 GIC 1 : else if (func == PGBENCH_HASH_FNV1A)
1845 teodor 2770 CBC 1 : setIntValue(retval, getHashFnv1a(val, seed));
1845 teodor 2771 ECB : else
2772 : /* cannot get here */
1845 teodor 2773 UIC 0 : Assert(0);
1845 teodor 2774 ECB :
1845 teodor 2775 CBC 6 : return true;
2776 : }
2777 :
733 dean.a.rasheed 2778 GBC 46 : case PGBENCH_PERMUTE:
2779 : {
733 dean.a.rasheed 2780 EUB : int64 val,
2781 : size,
2782 : seed;
2783 :
733 dean.a.rasheed 2784 GIC 46 : Assert(nargs == 3);
2785 :
2786 46 : if (!coerceToInt(&vargs[0], &val) ||
2787 46 : !coerceToInt(&vargs[1], &size) ||
733 dean.a.rasheed 2788 CBC 46 : !coerceToInt(&vargs[2], &seed))
733 dean.a.rasheed 2789 UIC 0 : return false;
2790 :
733 dean.a.rasheed 2791 CBC 46 : if (size <= 0)
733 dean.a.rasheed 2792 ECB : {
733 dean.a.rasheed 2793 GIC 1 : pg_log_error("permute size parameter must be greater than zero");
733 dean.a.rasheed 2794 CBC 1 : return false;
2795 : }
2796 :
733 dean.a.rasheed 2797 GIC 45 : setIntValue(retval, permute(val, size, seed));
2798 45 : return true;
2799 : }
2800 :
2595 rhaas 2801 UIC 0 : default:
2802 : /* cannot get here */
2568 2803 0 : Assert(0);
2568 rhaas 2804 ECB : /* dead code to avoid a compiler warning */
2805 : return false;
2595 2806 : }
2807 : }
2808 :
2809 : /* evaluate some function */
1916 teodor 2810 : static bool
1467 tgl 2811 CBC 3490 : evalFunc(CState *st,
2812 : PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
2813 : {
1916 teodor 2814 3490 : if (isLazyFunc(func))
1467 tgl 2815 GIC 63 : return evalLazyFunc(st, func, args, retval);
2816 : else
2817 3427 : return evalStandardFunc(st, func, args, retval);
1916 teodor 2818 ECB : }
2819 :
2595 rhaas 2820 : /*
2821 : * Recursive evaluation of an expression in a pgbench script
2822 : * using the current state of variables.
2823 : * Returns whether the evaluation was ok,
2824 : * the value itself is returned through the retval pointer.
2825 : */
2826 : static bool
1467 tgl 2827 CBC 9069 : evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
2595 rhaas 2828 ECB : {
2595 rhaas 2829 GIC 9069 : switch (expr->etype)
2830 : {
2568 rhaas 2831 CBC 3662 : case ENODE_CONSTANT:
2595 rhaas 2832 ECB : {
2568 rhaas 2833 GIC 3662 : *retval = expr->u.constant;
2595 2834 3662 : return true;
2835 : }
2836 :
2595 rhaas 2837 GBC 1917 : case ENODE_VARIABLE:
2838 : {
2529 tgl 2839 EUB : Variable *var;
2840 :
382 ishii 2841 GIC 1917 : if ((var = lookupVariable(&st->variables, expr->u.variable.varname)) == NULL)
2842 : {
1187 peter 2843 2 : pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2595 rhaas 2844 2 : return false;
2845 : }
2846 :
1916 teodor 2847 CBC 1915 : if (!makeVariableValue(var))
2529 tgl 2848 GIC 2 : return false;
2849 :
1916 teodor 2850 1913 : *retval = var->value;
2595 rhaas 2851 CBC 1913 : return true;
2960 rhaas 2852 EUB : }
2960 rhaas 2853 ECB :
2595 rhaas 2854 CBC 3490 : case ENODE_FUNCTION:
1467 tgl 2855 3490 : return evalFunc(st,
2595 rhaas 2856 ECB : expr->u.function.function,
2857 : expr->u.function.args,
2858 : retval);
2859 :
2960 rhaas 2860 LBC 0 : default:
2568 rhaas 2861 ECB : /* internal error which should never occur */
366 tgl 2862 LBC 0 : pg_fatal("unexpected enode type in evaluation: %d", expr->etype);
2960 rhaas 2863 ECB : }
2864 : }
2865 :
1984 tgl 2866 : /*
2867 : * Convert command name to meta-command enum identifier
2868 : */
2869 : static MetaCommand
1984 tgl 2870 CBC 467 : getMetaCommand(const char *cmd)
1984 tgl 2871 ECB : {
2872 : MetaCommand mc;
2873 :
1984 tgl 2874 CBC 467 : if (cmd == NULL)
1984 tgl 2875 LBC 0 : mc = META_NONE;
1984 tgl 2876 CBC 467 : else if (pg_strcasecmp(cmd, "set") == 0)
1984 tgl 2877 GIC 362 : mc = META_SET;
1984 tgl 2878 CBC 105 : else if (pg_strcasecmp(cmd, "setshell") == 0)
2879 4 : mc = META_SETSHELL;
1984 tgl 2880 GIC 101 : else if (pg_strcasecmp(cmd, "shell") == 0)
2881 5 : mc = META_SHELL;
2882 96 : else if (pg_strcasecmp(cmd, "sleep") == 0)
2883 9 : mc = META_SLEEP;
1844 teodor 2884 87 : else if (pg_strcasecmp(cmd, "if") == 0)
2885 15 : mc = META_IF;
2886 72 : else if (pg_strcasecmp(cmd, "elif") == 0)
1844 teodor 2887 CBC 8 : mc = META_ELIF;
1844 teodor 2888 GIC 64 : else if (pg_strcasecmp(cmd, "else") == 0)
2889 8 : mc = META_ELSE;
2890 56 : else if (pg_strcasecmp(cmd, "endif") == 0)
1844 teodor 2891 CBC 12 : mc = META_ENDIF;
1550 alvherre 2892 GIC 44 : else if (pg_strcasecmp(cmd, "gset") == 0)
2893 29 : mc = META_GSET;
1101 michael 2894 15 : else if (pg_strcasecmp(cmd, "aset") == 0)
2895 3 : mc = META_ASET;
755 alvherre 2896 12 : else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2897 6 : mc = META_STARTPIPELINE;
2898 6 : else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2899 5 : mc = META_ENDPIPELINE;
2900 : else
1984 tgl 2901 1 : mc = META_NONE;
2902 467 : return mc;
2903 : }
2904 :
4863 itagaki.takahiro 2905 ECB : /*
2906 : * Run a shell command. The result is assigned to the variable if not NULL.
2907 : * Return true if succeeded, or false on error.
2908 : */
2909 : static bool
382 ishii 2910 CBC 6 : runShellCommand(Variables *variables, char *variable, char **argv, int argc)
2911 : {
4790 bruce 2912 ECB : char command[SHELL_COMMAND_SIZE];
2913 : int i,
4790 bruce 2914 CBC 6 : len = 0;
2915 : FILE *fp;
4790 bruce 2916 ECB : char res[64];
2917 : char *endptr;
2918 : int retval;
2919 :
4623 tgl 2920 : /*----------
2921 : * Join arguments with whitespace separators. Arguments starting with
2922 : * exactly one colon are treated as variables:
2923 : * name - append a string "name"
2924 : * :var - append a variable named 'var'
2925 : * ::name - append a string ":name"
2926 : *----------
4863 itagaki.takahiro 2927 EUB : */
4863 itagaki.takahiro 2928 GBC 17 : for (i = 0; i < argc; i++)
2929 : {
2930 : char *arg;
4790 bruce 2931 ECB : int arglen;
4863 itagaki.takahiro 2932 :
4863 itagaki.takahiro 2933 CBC 12 : if (argv[i][0] != ':')
4863 itagaki.takahiro 2934 ECB : {
4790 bruce 2935 GIC 9 : arg = argv[i]; /* a string literal */
2936 : }
4863 itagaki.takahiro 2937 CBC 3 : else if (argv[i][1] == ':')
2938 : {
2939 1 : arg = argv[i] + 1; /* a string literal starting with colons */
2940 : }
382 ishii 2941 GIC 2 : else if ((arg = getVariable(variables, argv[i] + 1)) == NULL)
4863 itagaki.takahiro 2942 ECB : {
1187 peter 2943 GIC 1 : pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[i]);
4863 itagaki.takahiro 2944 CBC 1 : return false;
2945 : }
4863 itagaki.takahiro 2946 ECB :
4863 itagaki.takahiro 2947 CBC 11 : arglen = strlen(arg);
2948 11 : if (len + arglen + (i > 0 ? 1 : 0) >= SHELL_COMMAND_SIZE - 1)
2949 : {
1187 peter 2950 LBC 0 : pg_log_error("%s: shell command is too long", argv[0]);
4863 itagaki.takahiro 2951 UIC 0 : return false;
2952 : }
2953 :
4863 itagaki.takahiro 2954 CBC 11 : if (i > 0)
4863 itagaki.takahiro 2955 GIC 5 : command[len++] = ' ';
4863 itagaki.takahiro 2956 GBC 11 : memcpy(command + len, arg, arglen);
2957 11 : len += arglen;
2958 : }
4863 itagaki.takahiro 2959 ECB :
4863 itagaki.takahiro 2960 GIC 5 : command[len] = '\0';
4863 itagaki.takahiro 2961 ECB :
223 tgl 2962 GNC 5 : fflush(NULL); /* needed before either system() or popen() */
2963 :
4863 itagaki.takahiro 2964 ECB : /* Fast path for non-assignment case */
4863 itagaki.takahiro 2965 CBC 5 : if (variable == NULL)
4863 itagaki.takahiro 2966 ECB : {
4863 itagaki.takahiro 2967 GIC 2 : if (system(command))
4863 itagaki.takahiro 2968 ECB : {
4863 itagaki.takahiro 2969 GIC 1 : if (!timer_exceeded)
1187 peter 2970 GBC 1 : pg_log_error("%s: could not launch shell command", argv[0]);
4863 itagaki.takahiro 2971 1 : return false;
2972 : }
4863 itagaki.takahiro 2973 GIC 1 : return true;
2974 : }
4863 itagaki.takahiro 2975 ECB :
2976 : /* Execute the command with pipe and read the standard output. */
4863 itagaki.takahiro 2977 CBC 3 : if ((fp = popen(command, "r")) == NULL)
4863 itagaki.takahiro 2978 ECB : {
1187 peter 2979 UIC 0 : pg_log_error("%s: could not launch shell command", argv[0]);
4863 itagaki.takahiro 2980 LBC 0 : return false;
4863 itagaki.takahiro 2981 ECB : }
4863 itagaki.takahiro 2982 GIC 3 : if (fgets(res, sizeof(res), fp) == NULL)
4863 itagaki.takahiro 2983 ECB : {
4863 itagaki.takahiro 2984 GBC 1 : if (!timer_exceeded)
1187 peter 2985 GIC 1 : pg_log_error("%s: could not read result of shell command", argv[0]);
3036 tgl 2986 CBC 1 : (void) pclose(fp);
4863 itagaki.takahiro 2987 GIC 1 : return false;
4863 itagaki.takahiro 2988 ECB : }
4863 itagaki.takahiro 2989 GIC 2 : if (pclose(fp) < 0)
2990 : {
145 peter 2991 UNC 0 : pg_log_error("%s: could not run shell command: %m", argv[0]);
4863 itagaki.takahiro 2992 UIC 0 : return false;
2993 : }
2994 :
4863 itagaki.takahiro 2995 ECB : /* Check whether the result is an integer and assign it to the variable */
4863 itagaki.takahiro 2996 GIC 2 : retval = (int) strtol(res, &endptr, 10);
4863 itagaki.takahiro 2997 CBC 3 : while (*endptr != '\0' && isspace((unsigned char) *endptr))
4863 itagaki.takahiro 2998 GIC 1 : endptr++;
4863 itagaki.takahiro 2999 CBC 2 : if (*res == '\0' || *endptr != '\0')
3000 : {
1187 peter 3001 GIC 1 : pg_log_error("%s: shell command must return an integer (not \"%s\")", argv[0], res);
4863 itagaki.takahiro 3002 1 : return false;
3003 : }
382 ishii 3004 1 : if (!putVariableInt(variables, "setshell", variable, retval))
4863 itagaki.takahiro 3005 LBC 0 : return false;
3006 :
1187 peter 3007 CBC 1 : pg_log_debug("%s: shell parameter name: \"%s\", value: \"%s\"", argv[0], argv[1], res);
1187 peter 3008 ECB :
4863 itagaki.takahiro 3009 GIC 1 : return true;
4863 itagaki.takahiro 3010 ECB : }
3011 :
3012 : /*
3013 : * Report the abortion of the client when processing SQL commands.
382 ishii 3014 : */
3015 : static void
1844 teodor 3016 CBC 31 : commandFailed(CState *st, const char *cmd, const char *message)
3017 : {
1187 peter 3018 GIC 31 : pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
1187 peter 3019 ECB : st->id, st->command, cmd, st->use_file, message);
4997 ishii 3020 CBC 31 : }
3021 :
382 ishii 3022 ECB : /*
3023 : * Report the error in the command while the script is executing.
3024 : */
3025 : static void
382 ishii 3026 CBC 2 : commandError(CState *st, const char *message)
3027 : {
3028 2 : Assert(sql_script[st->use_file].commands[st->command]->type == SQL_COMMAND);
382 ishii 3029 GIC 2 : pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3030 : st->id, st->command, st->use_file, message);
3031 2 : }
3032 :
3033 : /* return a script number with a weighted choice. */
3034 : static int
2629 alvherre 3035 CBC 2473 : chooseScript(TState *thread)
3036 : {
2577 3037 2473 : int i = 0;
3038 : int64 w;
3039 :
2629 3040 2473 : if (num_scripts == 1)
2629 alvherre 3041 GBC 1373 : return 0;
3042 :
1605 alvherre 3043 GIC 1100 : w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3044 : do
3045 : {
2577 3046 2471 : w -= sql_script[i++].weight;
2577 alvherre 3047 CBC 2471 : } while (w >= 0);
3048 :
3049 1100 : return i - 1;
2629 alvherre 3050 ECB : }
3051 :
47 3052 : /*
3053 : * Prepare the SQL command from st->use_file at command_num.
3054 : */
3055 : static void
47 alvherre 3056 GIC 1760 : prepareCommand(CState *st, int command_num)
47 alvherre 3057 ECB : {
47 alvherre 3058 GIC 1760 : Command *command = sql_script[st->use_file].commands[command_num];
3059 :
3060 : /* No prepare for non-SQL commands */
47 alvherre 3061 CBC 1760 : if (command->type != SQL_COMMAND)
47 alvherre 3062 UIC 0 : return;
3063 :
3064 : /*
47 alvherre 3065 ECB : * If not already done, allocate space for 'prepared' flags: one boolean
3066 : * for each command of each script.
3067 : */
47 alvherre 3068 CBC 1760 : if (!st->prepared)
47 alvherre 3069 ECB : {
47 alvherre 3070 CBC 29 : st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
3071 59 : for (int i = 0; i < num_scripts; i++)
3072 : {
47 alvherre 3073 GIC 30 : ParsedScript *script = &sql_script[i];
3074 : int numcmds;
3075 :
3076 148 : for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
3077 : ;
3078 30 : st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
3079 : }
3080 : }
3081 :
3082 1760 : if (!st->prepared[st->use_file][command_num])
47 alvherre 3083 ECB : {
3084 : PGresult *res;
3085 :
47 alvherre 3086 CBC 99 : pg_log_debug("client %d preparing %s", st->id, command->prepname);
47 alvherre 3087 GIC 99 : res = PQprepare(st->con, command->prepname,
47 alvherre 3088 CBC 99 : command->argv[0], command->argc - 1, NULL);
47 alvherre 3089 GIC 99 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
3090 1 : pg_log_error("%s", PQerrorMessage(st->con));
3091 99 : PQclear(res);
3092 99 : st->prepared[st->use_file][command_num] = true;
3093 : }
3094 : }
3095 :
47 alvherre 3096 ECB : /*
3097 : * Prepare all the commands in the script that come after the \startpipeline
3098 : * that's at position st->command, and the first \endpipeline we find.
3099 : *
3100 : * This sets the ->prepared flag for each relevant command as well as the
3101 : * \startpipeline itself, but doesn't move the st->command counter.
3102 : */
3103 : static void
47 alvherre 3104 CBC 41 : prepareCommandsInPipeline(CState *st)
3105 : {
47 alvherre 3106 ECB : int j;
47 alvherre 3107 GIC 41 : Command **commands = sql_script[st->use_file].commands;
3108 :
47 alvherre 3109 CBC 41 : Assert(commands[st->command]->type == META_COMMAND &&
3110 : commands[st->command]->meta == META_STARTPIPELINE);
3111 :
3112 : /*
3113 : * We set the 'prepared' flag on the \startpipeline itself to flag that we
47 alvherre 3114 ECB : * don't need to do this next time without calling prepareCommand(), even
3115 : * though we don't actually prepare this command.
3116 : */
47 alvherre 3117 GIC 41 : if (st->prepared &&
47 alvherre 3118 CBC 36 : st->prepared[st->use_file][st->command])
47 alvherre 3119 GIC 36 : return;
3120 :
3121 63 : for (j = st->command + 1; commands[j] != NULL; j++)
47 alvherre 3122 ECB : {
47 alvherre 3123 CBC 63 : if (commands[j]->type == META_COMMAND &&
47 alvherre 3124 GIC 5 : commands[j]->meta == META_ENDPIPELINE)
47 alvherre 3125 CBC 5 : break;
47 alvherre 3126 ECB :
47 alvherre 3127 CBC 58 : prepareCommand(st, j);
3128 : }
47 alvherre 3129 ECB :
47 alvherre 3130 GIC 5 : st->prepared[st->use_file][st->command] = true;
47 alvherre 3131 ECB : }
3132 :
3133 : /* Send a SQL command, using the chosen querymode */
4997 ishii 3134 : static bool
2386 heikki.linnakangas 3135 GIC 5605 : sendCommand(CState *st, Command *command)
6401 ishii 3136 ECB : {
2386 heikki.linnakangas 3137 : int r;
3138 :
2386 heikki.linnakangas 3139 GIC 5605 : if (querymode == QUERY_SIMPLE)
2386 heikki.linnakangas 3140 ECB : {
3141 : char *sql;
3142 :
2386 heikki.linnakangas 3143 GIC 3333 : sql = pg_strdup(command->argv[0]);
382 ishii 3144 CBC 3333 : sql = assignVariables(&st->variables, sql);
6401 ishii 3145 ECB :
1187 peter 3146 GIC 3333 : pg_log_debug("client %d sending %s", st->id, sql);
2386 heikki.linnakangas 3147 CBC 3333 : r = PQsendQuery(st->con, sql);
3148 3333 : free(sql);
3149 : }
2386 heikki.linnakangas 3150 GIC 2272 : else if (querymode == QUERY_EXTENDED)
3151 : {
2386 heikki.linnakangas 3152 GBC 570 : const char *sql = command->argv[0];
3153 : const char *params[MAX_ARGS];
3547 ishii 3154 ECB :
382 ishii 3155 GIC 570 : getQueryParams(&st->variables, command, params);
3100 heikki.linnakangas 3156 EUB :
1187 peter 3157 GBC 570 : pg_log_debug("client %d sending %s", st->id, sql);
2386 heikki.linnakangas 3158 GIC 570 : r = PQsendQueryParams(st->con, sql, command->argc - 1,
3159 : NULL, params, NULL, NULL, 0);
2386 heikki.linnakangas 3160 ECB : }
2386 heikki.linnakangas 3161 GIC 1702 : else if (querymode == QUERY_PREPARED)
3162 : {
3163 : const char *params[MAX_ARGS];
3164 :
47 alvherre 3165 1702 : prepareCommand(st, st->command);
382 ishii 3166 1702 : getQueryParams(&st->variables, command, params);
2386 heikki.linnakangas 3167 ECB :
47 alvherre 3168 GIC 1702 : pg_log_debug("client %d sending %s", st->id, command->prepname);
47 alvherre 3169 CBC 1702 : r = PQsendQueryPrepared(st->con, command->prepname, command->argc - 1,
3170 : params, NULL, NULL, 0);
3547 ishii 3171 ECB : }
2118 tgl 3172 : else /* unknown sql mode */
2386 heikki.linnakangas 3173 LBC 0 : r = 0;
3547 ishii 3174 ECB :
2386 heikki.linnakangas 3175 GIC 5605 : if (r == 0)
3176 : {
1187 peter 3177 LBC 0 : pg_log_debug("client %d could not send %s", st->id, command->argv[0]);
2386 heikki.linnakangas 3178 UIC 0 : return false;
3179 : }
3180 : else
2386 heikki.linnakangas 3181 GIC 5605 : return true;
3182 : }
3183 :
382 ishii 3184 ECB : /*
3185 : * Get the error status from the error code.
3186 : */
3187 : static EStatus
382 ishii 3188 GIC 9 : getSQLErrorStatus(const char *sqlState)
3189 : {
3190 9 : if (sqlState != NULL)
3191 : {
3192 9 : if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3193 1 : return ESTATUS_SERIALIZATION_ERROR;
3194 8 : else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3195 1 : return ESTATUS_DEADLOCK_ERROR;
3196 : }
3197 :
3198 7 : return ESTATUS_OTHER_SQL_ERROR;
3199 : }
382 ishii 3200 ECB :
3201 : /*
3202 : * Returns true if this type of error can be retried.
3203 : */
3204 : static bool
382 ishii 3205 GIC 25 : canRetryError(EStatus estatus)
3206 : {
3207 25 : return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3208 : estatus == ESTATUS_DEADLOCK_ERROR);
3209 : }
382 ishii 3210 ECB :
3211 : /*
3212 : * Process query response from the backend.
3213 : *
1476 alvherre 3214 : * If varprefix is not NULL, it's the variable name prefix where to store
3215 : * the results of the *last* command (META_GSET) or *all* commands
1101 michael 3216 : * (META_ASET).
3217 : *
3218 : * Returns true if everything is A-OK, false if any error occurs.
3219 : */
3220 : static bool
1101 michael 3221 CBC 5647 : readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
1550 alvherre 3222 ECB : {
3223 : PGresult *res;
1461 3224 : PGresult *next_res;
1550 alvherre 3225 GIC 5647 : int qrynum = 0;
1550 alvherre 3226 ECB :
3227 : /*
755 3228 : * varprefix should be set only with \gset or \aset, and \endpipeline and
3229 : * SQL commands do not need it.
1101 michael 3230 : */
1101 michael 3231 GIC 5647 : Assert((meta == META_NONE && varprefix == NULL) ||
755 alvherre 3232 ECB : ((meta == META_ENDPIPELINE) && varprefix == NULL) ||
1101 michael 3233 : ((meta == META_GSET || meta == META_ASET) && varprefix != NULL));
3234 :
1476 alvherre 3235 CBC 5647 : res = PQgetResult(st->con);
3236 :
3237 11282 : while (res != NULL)
1550 alvherre 3238 ECB : {
3239 : bool is_last;
1460 3240 :
3241 : /* peek at the next result to know whether the current is last */
1461 alvherre 3242 CBC 5649 : next_res = PQgetResult(st->con);
1460 alvherre 3243 GIC 5649 : is_last = (next_res == NULL);
3244 :
1550 alvherre 3245 CBC 5649 : switch (PQresultStatus(res))
3246 : {
3247 3400 : case PGRES_COMMAND_OK: /* non-SELECT commands */
1550 alvherre 3248 ECB : case PGRES_EMPTY_QUERY: /* may be used for testing no-op overhead */
1101 michael 3249 GIC 3400 : if (is_last && meta == META_GSET)
1550 alvherre 3250 ECB : {
1187 peter 3251 GIC 1 : pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3252 : st->id, st->use_file, st->command, qrynum, 0);
382 ishii 3253 CBC 1 : st->estatus = ESTATUS_META_COMMAND_ERROR;
1461 alvherre 3254 GIC 1 : goto error;
3255 : }
1550 3256 3399 : break;
1550 alvherre 3257 ECB :
1550 alvherre 3258 GIC 2198 : case PGRES_TUPLES_OK:
1101 michael 3259 CBC 2198 : if ((is_last && meta == META_GSET) || meta == META_ASET)
3260 : {
1101 michael 3261 GIC 431 : int ntuples = PQntuples(res);
1101 michael 3262 ECB :
1101 michael 3263 CBC 431 : if (meta == META_GSET && ntuples != 1)
3264 : {
3265 : /* under \gset, report the error */
1187 peter 3266 2 : pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
1187 peter 3267 ECB : st->id, st->use_file, st->command, qrynum, PQntuples(res));
382 ishii 3268 GIC 2 : st->estatus = ESTATUS_META_COMMAND_ERROR;
1461 alvherre 3269 2 : goto error;
1550 alvherre 3270 ECB : }
1101 michael 3271 GIC 429 : else if (meta == META_ASET && ntuples <= 0)
1101 michael 3272 ECB : {
3273 : /* coldly skip empty result under \aset */
1101 michael 3274 GIC 1 : break;
3275 : }
1550 alvherre 3276 ECB :
3277 : /* store results into variables */
1550 alvherre 3278 GIC 856 : for (int fld = 0; fld < PQnfields(res); fld++)
3279 : {
3280 430 : char *varname = PQfname(res, fld);
1550 alvherre 3281 ECB :
3282 : /* allocate varname only if necessary, freed below */
1476 alvherre 3283 CBC 430 : if (*varprefix != '\0')
3284 1 : varname = psprintf("%s%s", varprefix, varname);
1550 alvherre 3285 ECB :
1101 michael 3286 EUB : /* store last row result as a string */
382 ishii 3287 GIC 430 : if (!putVariable(&st->variables, meta == META_ASET ? "aset" : "gset", varname,
1101 michael 3288 CBC 430 : PQgetvalue(res, ntuples - 1, fld)))
3289 : {
1550 alvherre 3290 ECB : /* internal error */
1187 peter 3291 GIC 2 : pg_log_error("client %d script %d command %d query %d: error storing into variable %s",
1187 peter 3292 ECB : st->id, st->use_file, st->command, qrynum, varname);
382 ishii 3293 GIC 2 : st->estatus = ESTATUS_META_COMMAND_ERROR;
1461 alvherre 3294 CBC 2 : goto error;
3295 : }
1550 alvherre 3296 ECB :
1476 alvherre 3297 CBC 428 : if (*varprefix != '\0')
1550 3298 1 : pg_free(varname);
3299 : }
3300 : }
3301 : /* otherwise the result is simply thrown away by PQclear below */
1550 alvherre 3302 GIC 2193 : break;
3303 :
755 alvherre 3304 CBC 42 : case PGRES_PIPELINE_SYNC:
755 alvherre 3305 GIC 42 : pg_log_debug("client %d pipeline ending", st->id);
3306 42 : if (PQexitPipelineMode(st->con) != 1)
755 alvherre 3307 LBC 0 : pg_log_error("client %d failed to exit pipeline mode: %s", st->id,
3308 : PQerrorMessage(st->con));
755 alvherre 3309 GIC 42 : break;
755 alvherre 3310 ECB :
382 ishii 3311 CBC 9 : case PGRES_NONFATAL_ERROR:
382 ishii 3312 ECB : case PGRES_FATAL_ERROR:
332 tgl 3313 GIC 9 : st->estatus = getSQLErrorStatus(PQresultErrorField(res,
3314 : PG_DIAG_SQLSTATE));
382 ishii 3315 CBC 9 : if (canRetryError(st->estatus))
3316 : {
382 ishii 3317 GBC 2 : if (verbose_errors)
3318 2 : commandError(st, PQerrorMessage(st->con));
382 ishii 3319 GIC 2 : goto error;
3320 : }
382 ishii 3321 ECB : /* fall through */
3322 :
1550 alvherre 3323 : default:
3324 : /* anything else is unexpected */
1187 peter 3325 CBC 7 : pg_log_error("client %d script %d aborted in command %d query %d: %s",
3326 : st->id, st->use_file, st->command, qrynum,
3327 : PQerrorMessage(st->con));
1461 alvherre 3328 7 : goto error;
1550 alvherre 3329 ECB : }
3330 :
1550 alvherre 3331 GIC 5635 : PQclear(res);
1550 alvherre 3332 CBC 5635 : qrynum++;
1476 alvherre 3333 GIC 5635 : res = next_res;
3334 : }
3335 :
1550 3336 5633 : if (qrynum == 0)
3337 : {
1187 peter 3338 UIC 0 : pg_log_error("client %d command %d: no results", st->id, st->command);
1550 alvherre 3339 0 : return false;
1550 alvherre 3340 ECB : }
3341 :
1550 alvherre 3342 GIC 5633 : return true;
3343 :
1461 3344 14 : error:
1461 alvherre 3345 CBC 14 : PQclear(res);
1461 alvherre 3346 GIC 14 : PQclear(next_res);
1461 alvherre 3347 ECB : do
3348 : {
1461 alvherre 3349 CBC 14 : res = PQgetResult(st->con);
3350 14 : PQclear(res);
1461 alvherre 3351 GIC 14 : } while (res);
3352 :
1461 alvherre 3353 CBC 14 : return false;
3354 : }
3355 :
2386 heikki.linnakangas 3356 ECB : /*
3357 : * Parse the argument to a \sleep command, and return the requested amount
2386 heikki.linnakangas 3358 EUB : * of delay, in microseconds. Returns true on success, false on error.
3359 : */
3360 : static bool
382 ishii 3361 GIC 6 : evaluateSleep(Variables *variables, int argc, char **argv, int *usecs)
3362 : {
3363 : char *var;
2386 heikki.linnakangas 3364 ECB : int usec;
3365 :
2386 heikki.linnakangas 3366 CBC 6 : if (*argv[1] == ':')
3367 : {
382 ishii 3368 3 : if ((var = getVariable(variables, argv[1] + 1)) == NULL)
6401 ishii 3369 ECB : {
1187 peter 3370 CBC 1 : pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
2386 heikki.linnakangas 3371 1 : return false;
3372 : }
3373 :
3374 2 : usec = atoi(var);
3375 :
748 fujii 3376 ECB : /* Raise an error if the value of a variable is not a number */
748 fujii 3377 CBC 2 : if (usec == 0 && !isdigit((unsigned char) *var))
3378 : {
748 fujii 3379 UIC 0 : pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3380 : argv[0], var, argv[1] + 1);
3381 0 : return false;
3382 : }
3383 : }
3384 : else
2386 heikki.linnakangas 3385 CBC 3 : usec = atoi(argv[1]);
3386 :
3387 5 : if (argc > 2)
3388 : {
2386 heikki.linnakangas 3389 GIC 4 : if (pg_strcasecmp(argv[2], "ms") == 0)
2386 heikki.linnakangas 3390 CBC 2 : usec *= 1000;
2386 heikki.linnakangas 3391 GBC 2 : else if (pg_strcasecmp(argv[2], "s") == 0)
2386 heikki.linnakangas 3392 GIC 1 : usec *= 1000000;
3393 : }
3394 : else
3395 1 : usec *= 1000000;
3396 :
2386 heikki.linnakangas 3397 CBC 5 : *usecs = usec;
2386 heikki.linnakangas 3398 GIC 5 : return true;
3399 : }
3400 :
3401 :
3402 : /*
382 ishii 3403 ECB : * Returns true if the error can be retried.
382 ishii 3404 EUB : */
3405 : static bool
382 ishii 3406 GIC 2 : doRetry(CState *st, pg_time_usec_t *now)
3407 : {
3408 2 : Assert(st->estatus != ESTATUS_NO_ERROR);
3409 :
382 ishii 3410 ECB : /* We can only retry serialization or deadlock errors. */
382 ishii 3411 GIC 2 : if (!canRetryError(st->estatus))
382 ishii 3412 UBC 0 : return false;
382 ishii 3413 EUB :
3414 : /*
3415 : * We must have at least one option to limit the retrying of transactions
3416 : * that got an error.
3417 : */
382 ishii 3418 GIC 2 : Assert(max_tries || latency_limit || duration > 0);
3419 :
382 ishii 3420 ECB : /*
332 tgl 3421 EUB : * We cannot retry the error if we have reached the maximum number of
3422 : * tries.
3423 : */
382 ishii 3424 CBC 2 : if (max_tries && st->tries >= max_tries)
382 ishii 3425 UIC 0 : return false;
3426 :
3427 : /*
3428 : * We cannot retry the error if we spent too much time on this
3429 : * transaction.
3430 : */
382 ishii 3431 GBC 2 : if (latency_limit)
3432 : {
382 ishii 3433 UIC 0 : pg_time_now_lazy(now);
382 ishii 3434 UBC 0 : if (*now - st->txn_scheduled > latency_limit)
382 ishii 3435 UIC 0 : return false;
382 ishii 3436 EUB : }
3437 :
3438 : /*
3439 : * We cannot retry the error if the benchmark duration is over.
3440 : */
382 ishii 3441 GIC 2 : if (timer_exceeded)
382 ishii 3442 UIC 0 : return false;
382 ishii 3443 EUB :
3444 : /* OK */
382 ishii 3445 GIC 2 : return true;
382 ishii 3446 EUB : }
3447 :
3448 : /*
3449 : * Read results and discard it until a sync point.
3450 : */
3451 : static int
382 ishii 3452 UIC 0 : discardUntilSync(CState *st)
382 ishii 3453 EUB : {
3454 : /* send a sync */
382 ishii 3455 UIC 0 : if (!PQpipelineSync(st->con))
3456 : {
382 ishii 3457 UBC 0 : pg_log_error("client %d aborted: failed to send a pipeline sync",
3458 : st->id);
3459 0 : return 0;
3460 : }
382 ishii 3461 EUB :
3462 : /* receive PGRES_PIPELINE_SYNC and null following it */
332 tgl 3463 : for (;;)
382 ishii 3464 UIC 0 : {
332 tgl 3465 0 : PGresult *res = PQgetResult(st->con);
3466 :
382 ishii 3467 0 : if (PQresultStatus(res) == PGRES_PIPELINE_SYNC)
3468 : {
3469 0 : PQclear(res);
3470 0 : res = PQgetResult(st->con);
382 ishii 3471 LBC 0 : Assert(res == NULL);
382 ishii 3472 UIC 0 : break;
3473 : }
3474 0 : PQclear(res);
382 ishii 3475 ECB : }
3476 :
3477 : /* exit pipeline */
382 ishii 3478 LBC 0 : if (PQexitPipelineMode(st->con) != 1)
382 ishii 3479 ECB : {
382 ishii 3480 LBC 0 : pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3481 : st->id);
3482 0 : return 0;
382 ishii 3483 EUB : }
382 ishii 3484 UIC 0 : return 1;
382 ishii 3485 EUB : }
3486 :
3487 : /*
3488 : * Get the transaction status at the end of a command especially for
3489 : * checking if we are in a (failed) transaction block.
3490 : */
3491 : static TStatus
382 ishii 3492 GIC 2431 : getTransactionStatus(PGconn *con)
3493 : {
3494 : PGTransactionStatusType tx_status;
382 ishii 3495 EUB :
382 ishii 3496 GBC 2431 : tx_status = PQtransactionStatus(con);
382 ishii 3497 GIC 2431 : switch (tx_status)
3498 : {
3499 2429 : case PQTRANS_IDLE:
3500 2429 : return TSTATUS_IDLE;
3501 2 : case PQTRANS_INTRANS:
3502 : case PQTRANS_INERROR:
3503 2 : return TSTATUS_IN_BLOCK;
382 ishii 3504 UIC 0 : case PQTRANS_UNKNOWN:
3505 : /* PQTRANS_UNKNOWN is expected given a broken connection */
3506 0 : if (PQstatus(con) == CONNECTION_BAD)
3507 0 : return TSTATUS_CONN_ERROR;
382 ishii 3508 ECB : /* fall through */
3509 : case PQTRANS_ACTIVE:
3510 : default:
3511 :
3512 : /*
332 tgl 3513 : * We cannot find out whether we are in a transaction block or
3514 : * not. Internal error which should never occur.
382 ishii 3515 EUB : */
382 ishii 3516 UIC 0 : pg_log_error("unexpected transaction status %d", tx_status);
382 ishii 3517 LBC 0 : return TSTATUS_OTHER_ERROR;
382 ishii 3518 ECB : }
3519 :
3520 : /* not reached */
3521 : Assert(false);
3522 : return TSTATUS_OTHER_ERROR;
3523 : }
3524 :
3525 : /*
3526 : * Print verbose messages of an error
3527 : */
3528 : static void
382 ishii 3529 GIC 2 : printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry)
3530 : {
382 ishii 3531 ECB : static PQExpBuffer buf = NULL;
3532 :
382 ishii 3533 GBC 2 : if (buf == NULL)
3534 2 : buf = createPQExpBuffer();
382 ishii 3535 EUB : else
382 ishii 3536 UIC 0 : resetPQExpBuffer(buf);
382 ishii 3537 ECB :
382 ishii 3538 GIC 2 : printfPQExpBuffer(buf, "client %d ", st->id);
215 drowley 3539 GNC 2 : appendPQExpBufferStr(buf, (is_retry ?
3540 : "repeats the transaction after the error" :
3541 : "ends the failed transaction"));
354 peter 3542 GIC 2 : appendPQExpBuffer(buf, " (try %u", st->tries);
3543 :
3544 : /* Print max_tries if it is not unlimitted. */
382 ishii 3545 CBC 2 : if (max_tries)
354 peter 3546 GIC 2 : appendPQExpBuffer(buf, "/%u", max_tries);
3547 :
3548 : /*
3549 : * If the latency limit is used, print a percentage of the current
3550 : * transaction latency from the latency limit.
3551 : */
382 ishii 3552 2 : if (latency_limit)
3553 : {
382 ishii 3554 UIC 0 : pg_time_now_lazy(now);
3555 0 : appendPQExpBuffer(buf, ", %.3f%% of the maximum time of tries was used",
382 ishii 3556 LBC 0 : (100.0 * (*now - st->txn_scheduled) / latency_limit));
3557 : }
215 drowley 3558 GNC 2 : appendPQExpBufferStr(buf, ")\n");
3559 :
382 ishii 3560 GIC 2 : pg_log_info("%s", buf->data);
3561 2 : }
3562 :
3563 : /*
3564 : * Advance the state machine of a connection.
3565 : */
3566 : static void
1600 alvherre 3567 7624 : advanceConnectionState(TState *thread, CState *st, StatsData *agg)
2386 heikki.linnakangas 3568 ECB : {
3569 :
3570 : /*
3571 : * gettimeofday() isn't free, so we get the current timestamp lazily the
3572 : * first time it's needed, and reuse the same value throughout this
3573 : * function after that. This also ensures that e.g. the calculated
3574 : * latency reported in the log file and in the totals are the same. Zero
3575 : * means "not set yet". Reset "now" when we execute shell commands or
3576 : * expressions, which might take a non-negligible amount of time, though.
3577 : */
760 tmunro 3578 GIC 7624 : pg_time_usec_t now = 0;
6401 ishii 3579 ECB :
2386 heikki.linnakangas 3580 : /*
3581 : * Loop in the state machine, until we have to wait for a result from the
1600 alvherre 3582 : * server or have to sleep for throttling or \sleep.
3583 : *
3584 : * Note: In the switch-statement below, 'break' will loop back here,
3585 : * meaning "continue in the state machine". Return is used to return to
3586 : * the caller, giving the thread the opportunity to advance another
3587 : * client.
3588 : */
2386 heikki.linnakangas 3589 : for (;;)
2386 heikki.linnakangas 3590 CBC 29581 : {
1474 alvherre 3591 ECB : Command *command;
3592 :
2386 heikki.linnakangas 3593 GIC 37205 : switch (st->state)
6401 ishii 3594 ECB : {
1600 alvherre 3595 : /* Select transaction (script) to run. */
2386 heikki.linnakangas 3596 GIC 2473 : case CSTATE_CHOOSE_SCRIPT:
3597 2473 : st->use_file = chooseScript(thread);
1600 alvherre 3598 CBC 2473 : Assert(conditional_stack_empty(st->cstack));
3599 :
382 ishii 3600 ECB : /* reset transaction variables to default values */
382 ishii 3601 GIC 2473 : st->estatus = ESTATUS_NO_ERROR;
382 ishii 3602 CBC 2473 : st->tries = 1;
3603 :
1187 peter 3604 GIC 2473 : pg_log_debug("client %d executing script \"%s\"",
3605 : st->id, sql_script[st->use_file].desc);
3606 :
3607 : /*
1600 alvherre 3608 EUB : * If time is over, we're done; otherwise, get ready to start
3609 : * a new transaction, or to get throttled if that's requested.
3610 : */
1600 alvherre 3611 GIC 4946 : st->state = timer_exceeded ? CSTATE_FINISHED :
3612 2473 : throttle_delay > 0 ? CSTATE_PREPARE_THROTTLE : CSTATE_START_TX;
3613 2473 : break;
1600 alvherre 3614 ECB :
3615 : /* Start new transaction (script) */
1600 alvherre 3616 CBC 2472 : case CSTATE_START_TX:
760 tmunro 3617 GIC 2472 : pg_time_now_lazy(&now);
3618 :
1600 alvherre 3619 ECB : /* establish connection if needed, i.e. under --connect */
1600 alvherre 3620 CBC 2472 : if (st->con == NULL)
3621 : {
760 tmunro 3622 GIC 110 : pg_time_usec_t start = now;
3623 :
1600 alvherre 3624 110 : if ((st->con = doConnect()) == NULL)
3625 : {
3626 : /*
3627 : * as the bench is already running, we do not abort
523 fujii 3628 ECB : * the process
3629 : */
1187 peter 3630 UIC 0 : pg_log_error("client %d aborted while establishing connection", st->id);
1600 alvherre 3631 LBC 0 : st->state = CSTATE_ABORTED;
1600 alvherre 3632 UIC 0 : break;
3633 : }
3634 :
3635 : /* reset now after connection */
760 tmunro 3636 GIC 110 : now = pg_time_now();
760 tmunro 3637 ECB :
760 tmunro 3638 CBC 110 : thread->conn_duration += now - start;
3639 :
3640 : /* Reset session-local state */
47 alvherre 3641 110 : pg_free(st->prepared);
3642 110 : st->prepared = NULL;
1600 alvherre 3643 ECB : }
3644 :
3645 : /*
3646 : * It is the first try to run this transaction. Remember the
3647 : * random state: maybe it will get an error and we will need
332 tgl 3648 : * to run it again.
3649 : */
382 ishii 3650 GIC 2472 : st->random_state = st->cs_func_rs;
3651 :
3652 : /* record transaction start time */
1600 alvherre 3653 2472 : st->txn_begin = now;
3654 :
3655 : /*
3656 : * When not throttling, this is also the transaction's
3657 : * scheduled start time.
3658 : */
1600 alvherre 3659 CBC 2472 : if (!throttle_delay)
760 tmunro 3660 GIC 2271 : st->txn_scheduled = now;
1600 alvherre 3661 ECB :
3662 : /* Begin with the first command */
1600 alvherre 3663 CBC 2472 : st->state = CSTATE_START_COMMAND;
1600 alvherre 3664 GIC 2472 : st->command = 0;
2386 heikki.linnakangas 3665 2472 : break;
3666 :
3667 : /*
3668 : * Handle throttling once per transaction by sleeping.
3669 : */
1600 alvherre 3670 210 : case CSTATE_PREPARE_THROTTLE:
6401 ishii 3671 ECB :
3672 : /*
2386 heikki.linnakangas 3673 : * Generate a delay such that the series of delays will
3674 : * approximate a Poisson distribution centered on the
3675 : * throttle_delay time.
3676 : *
3677 : * If transactions are too slow or a given wait is shorter
3678 : * than a transaction, the next transaction will start right
3679 : * away.
3680 : */
2386 heikki.linnakangas 3681 GIC 210 : Assert(throttle_delay > 0);
3682 :
1600 alvherre 3683 210 : thread->throttle_trigger +=
3684 210 : getPoissonRand(&thread->ts_throttle_rs, throttle_delay);
2386 heikki.linnakangas 3685 210 : st->txn_scheduled = thread->throttle_trigger;
3686 :
3687 : /*
3688 : * If --latency-limit is used, and this slot is already late
3689 : * so that the transaction will miss the latency limit even if
3690 : * it completed immediately, skip this time slot and loop to
3691 : * reschedule.
3692 : */
3693 210 : if (latency_limit)
2386 heikki.linnakangas 3694 ECB : {
760 tmunro 3695 CBC 210 : pg_time_now_lazy(&now);
3696 :
576 fujii 3697 GIC 210 : if (thread->throttle_trigger < now - latency_limit)
2386 heikki.linnakangas 3698 ECB : {
2386 heikki.linnakangas 3699 GIC 9 : processXactStats(thread, st, &now, true, agg);
3700 :
3701 : /*
3702 : * Finish client if -T or -t was exceeded.
3703 : *
3704 : * Stop counting skipped transactions under -T as soon
3705 : * as the timer is exceeded. Because otherwise it can
576 fujii 3706 EUB : * take a very long time to count all of them
576 fujii 3707 ECB : * especially when quite a lot of them happen with
3708 : * unrealistically high rate setting in -R, which
3709 : * would prevent pgbench from ending immediately.
3710 : * Because of this behavior, note that there is no
3711 : * guarantee that all skipped transactions are counted
3712 : * under -T though there is under -t. This is OK in
3713 : * practice because it's very unlikely to happen with
3714 : * realistic setting.
3715 : */
576 fujii 3716 CBC 9 : if (timer_exceeded || (nxacts > 0 && st->cnt >= nxacts))
576 fujii 3717 GBC 1 : st->state = CSTATE_FINISHED;
3718 :
3719 : /* Go back to top of loop with CSTATE_PREPARE_THROTTLE */
2043 tgl 3720 CBC 9 : break;
2043 tgl 3721 ECB : }
3722 : }
3723 :
3724 : /*
3725 : * stop client if next transaction is beyond pgbench end of
1600 alvherre 3726 : * execution; otherwise, throttle it.
2386 heikki.linnakangas 3727 : */
1600 alvherre 3728 UIC 0 : st->state = end_time > 0 && st->txn_scheduled > end_time ?
1600 alvherre 3729 GIC 201 : CSTATE_FINISHED : CSTATE_THROTTLE;
2386 heikki.linnakangas 3730 CBC 201 : break;
3731 :
2386 heikki.linnakangas 3732 ECB : /*
1600 alvherre 3733 : * Wait until it's time to start next transaction.
3734 : */
1600 alvherre 3735 GIC 201 : case CSTATE_THROTTLE:
760 tmunro 3736 201 : pg_time_now_lazy(&now);
2386 heikki.linnakangas 3737 ECB :
760 tmunro 3738 GIC 201 : if (now < st->txn_scheduled)
1600 alvherre 3739 LBC 0 : return; /* still sleeping, nothing to do here */
5499 ishii 3740 ECB :
3741 : /* done sleeping, but don't start transaction if we're done */
1600 alvherre 3742 GIC 201 : st->state = timer_exceeded ? CSTATE_FINISHED : CSTATE_START_TX;
2386 heikki.linnakangas 3743 201 : break;
2386 heikki.linnakangas 3744 ECB :
3745 : /*
3746 : * Send a command to server (or execute a meta-command)
3747 : */
2386 heikki.linnakangas 3748 GIC 10305 : case CSTATE_START_COMMAND:
1474 alvherre 3749 CBC 10305 : command = sql_script[st->use_file].commands[st->command];
3750 :
1600 alvherre 3751 ECB : /* Transition to script end processing if done */
1474 alvherre 3752 CBC 10305 : if (command == NULL)
2386 heikki.linnakangas 3753 ECB : {
2386 heikki.linnakangas 3754 GIC 2429 : st->state = CSTATE_END_TX;
2386 heikki.linnakangas 3755 CBC 2429 : break;
3756 : }
5499 ishii 3757 EUB :
1600 alvherre 3758 : /* record begin time of next command, and initiate it */
1600 alvherre 3759 GBC 7876 : if (report_per_command)
3760 : {
760 tmunro 3761 GIC 401 : pg_time_now_lazy(&now);
2386 heikki.linnakangas 3762 401 : st->stmt_begin = now;
2386 heikki.linnakangas 3763 ECB : }
3764 :
1474 alvherre 3765 EUB : /* Execute the command */
1474 alvherre 3766 GBC 7876 : if (command->type == SQL_COMMAND)
3767 : {
3768 : /* disallow \aset and \gset in pipeline mode */
755 alvherre 3769 GIC 5606 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
3770 : {
755 alvherre 3771 CBC 501 : if (command->meta == META_GSET)
755 alvherre 3772 ECB : {
755 alvherre 3773 GIC 1 : commandFailed(st, "gset", "\\gset is not allowed in pipeline mode");
755 alvherre 3774 CBC 1 : st->state = CSTATE_ABORTED;
755 alvherre 3775 GIC 1 : break;
3776 : }
755 alvherre 3777 CBC 500 : else if (command->meta == META_ASET)
3778 : {
755 alvherre 3779 UIC 0 : commandFailed(st, "aset", "\\aset is not allowed in pipeline mode");
3780 0 : st->state = CSTATE_ABORTED;
3781 0 : break;
3782 : }
3783 : }
3784 :
1474 alvherre 3785 CBC 5605 : if (!sendCommand(st, command))
1474 alvherre 3786 ECB : {
1474 alvherre 3787 LBC 0 : commandFailed(st, "SQL", "SQL command send failed");
1474 alvherre 3788 UIC 0 : st->state = CSTATE_ABORTED;
3789 : }
3790 : else
3791 : {
3792 : /* Wait for results, unless in pipeline mode */
755 alvherre 3793 GIC 5605 : if (PQpipelineStatus(st->con) == PQ_PIPELINE_OFF)
3794 5105 : st->state = CSTATE_WAIT_RESULT;
755 alvherre 3795 ECB : else
755 alvherre 3796 GIC 500 : st->state = CSTATE_END_COMMAND;
3797 : }
3798 : }
1474 alvherre 3799 CBC 2270 : else if (command->type == META_COMMAND)
3800 : {
3801 : /*-----
3802 : * Possible state changes when executing meta commands:
3803 : * - on errors CSTATE_ABORTED
1474 alvherre 3804 ECB : * - on sleep CSTATE_SLEEP
3805 : * - else CSTATE_END_COMMAND
3806 : */
1467 tgl 3807 GIC 2270 : st->state = executeMetaCommand(st, &now);
382 ishii 3808 2270 : if (st->state == CSTATE_ABORTED)
382 ishii 3809 CBC 30 : st->estatus = ESTATUS_META_COMMAND_ERROR;
3810 : }
3811 :
1600 alvherre 3812 ECB : /*
3813 : * We're now waiting for an SQL command to complete, or
3814 : * finished processing a metacommand, or need to sleep, or
3815 : * something bad happened.
3816 : */
1600 alvherre 3817 GIC 7875 : Assert(st->state == CSTATE_WAIT_RESULT ||
1600 alvherre 3818 ECB : st->state == CSTATE_END_COMMAND ||
3819 : st->state == CSTATE_SLEEP ||
3820 : st->state == CSTATE_ABORTED);
1844 teodor 3821 CBC 7875 : break;
1844 teodor 3822 ECB :
3823 : /*
3824 : * non executed conditional branch
3825 : */
1844 teodor 3826 CBC 377 : case CSTATE_SKIP_COMMAND:
3827 377 : Assert(!conditional_active(st->cstack));
1844 teodor 3828 ECB : /* quickly skip commands until something to do... */
3829 : while (true)
3830 : {
1844 teodor 3831 CBC 1743 : command = sql_script[st->use_file].commands[st->command];
3832 :
3833 : /* cannot reach end of script in that state */
3834 1743 : Assert(command != NULL);
3835 :
1809 tgl 3836 ECB : /*
3837 : * if this is conditional related, update conditional
3838 : * state
3839 : */
1844 teodor 3840 GIC 1743 : if (command->type == META_COMMAND &&
1844 teodor 3841 CBC 386 : (command->meta == META_IF ||
3842 386 : command->meta == META_ELIF ||
3843 383 : command->meta == META_ELSE ||
3844 381 : command->meta == META_ENDIF))
3845 : {
1844 teodor 3846 GIC 756 : switch (conditional_stack_peek(st->cstack))
3847 : {
1809 tgl 3848 374 : case IFSTATE_FALSE:
1600 alvherre 3849 374 : if (command->meta == META_IF ||
1600 alvherre 3850 CBC 374 : command->meta == META_ELIF)
3851 : {
1809 tgl 3852 ECB : /* we must evaluate the condition */
1809 tgl 3853 GIC 3 : st->state = CSTATE_START_COMMAND;
1809 tgl 3854 ECB : }
1809 tgl 3855 GIC 371 : else if (command->meta == META_ELSE)
1809 tgl 3856 ECB : {
1809 tgl 3857 EUB : /* we must execute next command */
1600 alvherre 3858 GIC 1 : conditional_stack_poke(st->cstack,
1600 alvherre 3859 ECB : IFSTATE_ELSE_TRUE);
1844 teodor 3860 GIC 1 : st->state = CSTATE_START_COMMAND;
1809 tgl 3861 CBC 1 : st->command++;
1809 tgl 3862 ECB : }
1809 tgl 3863 CBC 370 : else if (command->meta == META_ENDIF)
1809 tgl 3864 ECB : {
1809 tgl 3865 GIC 370 : Assert(!conditional_stack_empty(st->cstack));
3866 370 : conditional_stack_pop(st->cstack);
1809 tgl 3867 CBC 370 : if (conditional_active(st->cstack))
3868 370 : st->state = CSTATE_START_COMMAND;
3869 :
1809 tgl 3870 EUB : /*
3871 : * else state remains in
3872 : * CSTATE_SKIP_COMMAND
3873 : */
1809 tgl 3874 GIC 370 : st->command++;
3875 : }
3876 374 : break;
3877 :
3878 4 : case IFSTATE_IGNORED:
1809 tgl 3879 EUB : case IFSTATE_ELSE_FALSE:
1809 tgl 3880 GIC 4 : if (command->meta == META_IF)
1474 alvherre 3881 UIC 0 : conditional_stack_push(st->cstack,
3882 : IFSTATE_IGNORED);
1809 tgl 3883 GIC 4 : else if (command->meta == META_ENDIF)
3884 : {
1809 tgl 3885 CBC 3 : Assert(!conditional_stack_empty(st->cstack));
1809 tgl 3886 GIC 3 : conditional_stack_pop(st->cstack);
3887 3 : if (conditional_active(st->cstack))
1809 tgl 3888 CBC 3 : st->state = CSTATE_START_COMMAND;
3889 : }
1809 tgl 3890 ECB : /* could detect "else" & "elif" after "else" */
1844 teodor 3891 GIC 4 : st->command++;
1809 tgl 3892 CBC 4 : break;
3893 :
1809 tgl 3894 UIC 0 : case IFSTATE_NONE:
3895 : case IFSTATE_TRUE:
3896 : case IFSTATE_ELSE_TRUE:
1809 tgl 3897 ECB : default:
2386 heikki.linnakangas 3898 :
3899 : /*
3900 : * inconsistent if inactive, unreachable dead
3901 : * code
3902 : */
1809 tgl 3903 UIC 0 : Assert(false);
3904 : }
3905 : }
1844 teodor 3906 ECB : else
3907 : {
3908 : /* skip and consider next */
1844 teodor 3909 GBC 1365 : st->command++;
1844 teodor 3910 EUB : }
3911 :
1844 teodor 3912 GIC 1743 : if (st->state != CSTATE_SKIP_COMMAND)
1600 alvherre 3913 ECB : /* out of quick skip command loop */
1844 teodor 3914 CBC 377 : break;
3915 : }
2386 heikki.linnakangas 3916 GIC 377 : break;
2386 heikki.linnakangas 3917 ECB :
3918 : /*
3919 : * Wait for the current SQL command to complete
3920 : */
2386 heikki.linnakangas 3921 GIC 10794 : case CSTATE_WAIT_RESULT:
1187 peter 3922 10794 : pg_log_debug("client %d receiving", st->id);
3923 :
3924 : /*
3925 : * Only check for new network data if we processed all data
613 andres 3926 ECB : * fetched prior. Otherwise we end up doing a syscall for each
3927 : * individual pipelined query, which has a measurable
3928 : * performance impact.
3929 : */
613 andres 3930 CBC 10794 : if (PQisBusy(st->con) && !PQconsumeInput(st->con))
3931 : {
1600 alvherre 3932 ECB : /* there's something wrong */
1844 teodor 3933 LBC 0 : commandFailed(st, "SQL", "perhaps the backend died while processing");
2386 heikki.linnakangas 3934 UIC 0 : st->state = CSTATE_ABORTED;
3935 0 : break;
3936 : }
2386 heikki.linnakangas 3937 GIC 10794 : if (PQisBusy(st->con))
3938 5147 : return; /* don't have the whole result yet */
3939 :
3940 : /* store or discard the query results */
1101 michael 3941 CBC 5647 : if (readCommandResponse(st,
3942 5647 : sql_script[st->use_file].commands[st->command]->meta,
3943 5647 : sql_script[st->use_file].commands[st->command]->varprefix))
755 alvherre 3944 ECB : {
3945 : /*
3946 : * outside of pipeline mode: stop reading results.
3947 : * pipeline mode: continue reading results until an
3948 : * end-of-pipeline response.
3949 : */
755 alvherre 3950 GIC 5633 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
3951 5133 : st->state = CSTATE_END_COMMAND;
755 alvherre 3952 ECB : }
382 ishii 3953 GIC 14 : else if (canRetryError(st->estatus))
3954 2 : st->state = CSTATE_ERROR;
3955 : else
1550 alvherre 3956 12 : st->state = CSTATE_ABORTED;
2386 heikki.linnakangas 3957 5647 : break;
3958 :
2386 heikki.linnakangas 3959 ECB : /*
3960 : * Wait until sleep is done. This state is entered after a
3961 : * \sleep metacommand. The behavior is similar to
3962 : * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3963 : * instead of CSTATE_START_TX.
3964 : */
2386 heikki.linnakangas 3965 CBC 8 : case CSTATE_SLEEP:
760 tmunro 3966 8 : pg_time_now_lazy(&now);
760 tmunro 3967 GIC 8 : if (now < st->sleep_until)
1600 alvherre 3968 3 : return; /* still sleeping, nothing to do here */
3969 : /* Else done sleeping. */
2386 heikki.linnakangas 3970 CBC 5 : st->state = CSTATE_END_COMMAND;
3971 5 : break;
5756 JanWieck 3972 ECB :
2386 heikki.linnakangas 3973 : /*
3974 : * End of command: record stats and proceed to next command.
3975 : */
2386 heikki.linnakangas 3976 GIC 7831 : case CSTATE_END_COMMAND:
3977 :
2386 heikki.linnakangas 3978 ECB : /*
3979 : * command completed: accumulate per-command execution times
3980 : * in thread-local data structure, if per-command latencies
3981 : * are requested.
3982 : */
1600 alvherre 3983 GIC 7831 : if (report_per_command)
3984 : {
760 tmunro 3985 401 : pg_time_now_lazy(&now);
4863 itagaki.takahiro 3986 ECB :
1550 alvherre 3987 GIC 401 : command = sql_script[st->use_file].commands[st->command];
2386 heikki.linnakangas 3988 EUB : /* XXX could use a mutex here, but we choose not to */
2386 heikki.linnakangas 3989 GIC 401 : addToSimpleStats(&command->stats,
760 tmunro 3990 GBC 401 : PG_TIME_GET_DOUBLE(now - st->stmt_begin));
2386 heikki.linnakangas 3991 EUB : }
3992 :
3993 : /* Go ahead with next command, to be executed or skipped */
2386 heikki.linnakangas 3994 GIC 7831 : st->command++;
1844 teodor 3995 7831 : st->state = conditional_active(st->cstack) ?
3996 7831 : CSTATE_START_COMMAND : CSTATE_SKIP_COMMAND;
2386 heikki.linnakangas 3997 7831 : break;
3998 :
2386 heikki.linnakangas 3999 ECB : /*
382 ishii 4000 : * Clean up after an error.
4001 : */
382 ishii 4002 GIC 2 : case CSTATE_ERROR:
382 ishii 4003 ECB : {
4004 : TStatus tstatus;
4997 ishii 4005 EUB :
382 ishii 4006 GIC 2 : Assert(st->estatus != ESTATUS_NO_ERROR);
2386 heikki.linnakangas 4007 EUB :
4008 : /* Clear the conditional stack */
382 ishii 4009 GIC 2 : conditional_stack_reset(st->cstack);
1844 teodor 4010 ECB :
4011 : /* Read and discard until a sync point in pipeline mode */
382 ishii 4012 CBC 2 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4013 : {
382 ishii 4014 UIC 0 : if (!discardUntilSync(st))
4015 : {
4016 0 : st->state = CSTATE_ABORTED;
4017 0 : break;
382 ishii 4018 ECB : }
4019 : }
4020 :
4021 : /*
4022 : * Check if we have a (failed) transaction block or not,
332 tgl 4023 EUB : * and roll it back if any.
382 ishii 4024 : */
382 ishii 4025 GIC 2 : tstatus = getTransactionStatus(st->con);
382 ishii 4026 GBC 2 : if (tstatus == TSTATUS_IN_BLOCK)
382 ishii 4027 EUB : {
4028 : /* Try to rollback a (failed) transaction block. */
382 ishii 4029 CBC 1 : if (!PQsendQuery(st->con, "ROLLBACK"))
4030 : {
382 ishii 4031 UIC 0 : pg_log_error("client %d aborted: failed to send sql command for rolling back the failed transaction",
4032 : st->id);
4033 0 : st->state = CSTATE_ABORTED;
4034 : }
382 ishii 4035 ECB : else
382 ishii 4036 GIC 1 : st->state = CSTATE_WAIT_ROLLBACK_RESULT;
4037 : }
4038 1 : else if (tstatus == TSTATUS_IDLE)
382 ishii 4039 ECB : {
4040 : /*
4041 : * If time is over, we're done; otherwise, check if we
332 tgl 4042 EUB : * can retry the error.
4043 : */
382 ishii 4044 GBC 2 : st->state = timer_exceeded ? CSTATE_FINISHED :
4045 1 : doRetry(st, &now) ? CSTATE_RETRY : CSTATE_FAILURE;
4046 : }
382 ishii 4047 ECB : else
4048 : {
382 ishii 4049 UIC 0 : if (tstatus == TSTATUS_CONN_ERROR)
4050 0 : pg_log_error("perhaps the backend died while processing");
4051 :
4052 0 : pg_log_error("client %d aborted while receiving the transaction status", st->id);
382 ishii 4053 LBC 0 : st->state = CSTATE_ABORTED;
382 ishii 4054 ECB : }
382 ishii 4055 GIC 2 : break;
2386 heikki.linnakangas 4056 ECB : }
4057 :
382 ishii 4058 : /*
4059 : * Wait for the rollback command to complete
4060 : */
382 ishii 4061 CBC 2 : case CSTATE_WAIT_ROLLBACK_RESULT:
4062 : {
4063 : PGresult *res;
4064 :
382 ishii 4065 GIC 2 : pg_log_debug("client %d receiving", st->id);
4066 2 : if (!PQconsumeInput(st->con))
382 ishii 4067 ECB : {
382 ishii 4068 LBC 0 : pg_log_error("client %d aborted while rolling back the transaction after an error; perhaps the backend died while processing",
382 ishii 4069 ECB : st->id);
382 ishii 4070 UBC 0 : st->state = CSTATE_ABORTED;
4071 0 : break;
4072 : }
382 ishii 4073 GBC 2 : if (PQisBusy(st->con))
332 tgl 4074 1 : return; /* don't have the whole result yet */
382 ishii 4075 EUB :
4076 : /*
382 ishii 4077 ECB : * Read and discard the query result;
4078 : */
382 ishii 4079 GIC 1 : res = PQgetResult(st->con);
4080 1 : switch (PQresultStatus(res))
4081 : {
4082 1 : case PGRES_COMMAND_OK:
382 ishii 4083 ECB : /* OK */
382 ishii 4084 CBC 1 : PQclear(res);
4085 : /* null must be returned */
382 ishii 4086 GIC 1 : res = PQgetResult(st->con);
4087 1 : Assert(res == NULL);
4088 :
4089 : /*
332 tgl 4090 ECB : * If time is over, we're done; otherwise, check
4091 : * if we can retry the error.
4092 : */
382 ishii 4093 GIC 2 : st->state = timer_exceeded ? CSTATE_FINISHED :
382 ishii 4094 CBC 1 : doRetry(st, &now) ? CSTATE_RETRY : CSTATE_FAILURE;
4095 1 : break;
382 ishii 4096 UIC 0 : default:
4097 0 : pg_log_error("client %d aborted while rolling back the transaction after an error; %s",
4098 : st->id, PQerrorMessage(st->con));
4099 0 : PQclear(res);
4100 0 : st->state = CSTATE_ABORTED;
382 ishii 4101 LBC 0 : break;
4102 : }
2386 heikki.linnakangas 4103 GIC 1 : break;
2386 heikki.linnakangas 4104 ECB : }
4105 :
382 ishii 4106 : /*
4107 : * Retry the transaction after an error.
4108 : */
382 ishii 4109 GIC 2 : case CSTATE_RETRY:
4110 2 : command = sql_script[st->use_file].commands[st->command];
4111 :
2386 heikki.linnakangas 4112 EUB : /*
332 tgl 4113 : * Inform that the transaction will be retried after the
4114 : * error.
4115 : */
382 ishii 4116 GBC 2 : if (verbose_errors)
382 ishii 4117 GIC 2 : printVerboseErrorMessages(st, &now, true);
4118 :
4119 : /* Count tries and retries */
4120 2 : st->tries++;
382 ishii 4121 GBC 2 : command->retries++;
382 ishii 4122 EUB :
4123 : /*
4124 : * Reset the random state as they were at the beginning of the
332 tgl 4125 : * transaction.
382 ishii 4126 : */
382 ishii 4127 GIC 2 : st->cs_func_rs = st->random_state;
4128 :
4129 : /* Process the first transaction command. */
4130 2 : st->command = 0;
382 ishii 4131 CBC 2 : st->estatus = ESTATUS_NO_ERROR;
382 ishii 4132 GIC 2 : st->state = CSTATE_START_COMMAND;
4133 2 : break;
4134 :
4135 : /*
382 ishii 4136 ECB : * Record a failed transaction.
4137 : */
382 ishii 4138 UIC 0 : case CSTATE_FAILURE:
4139 0 : command = sql_script[st->use_file].commands[st->command];
4140 :
4141 : /* Accumulate the failure. */
382 ishii 4142 LBC 0 : command->failures++;
4143 :
4144 : /*
4145 : * Inform that the failed transaction will not be retried.
4146 : */
382 ishii 4147 UIC 0 : if (verbose_errors)
382 ishii 4148 LBC 0 : printVerboseErrorMessages(st, &now, false);
382 ishii 4149 ECB :
4150 : /* End the failed transaction. */
382 ishii 4151 LBC 0 : st->state = CSTATE_END_TX;
382 ishii 4152 UIC 0 : break;
382 ishii 4153 ECB :
4154 : /*
4155 : * End of transaction (end of script, really).
4156 : */
382 ishii 4157 GIC 2429 : case CSTATE_END_TX:
382 ishii 4158 EUB : {
4159 : TStatus tstatus;
4160 :
4161 : /* transaction finished: calculate latency and do log */
382 ishii 4162 GBC 2429 : processXactStats(thread, st, &now, false, agg);
382 ishii 4163 EUB :
4164 : /*
4165 : * missing \endif... cannot happen if CheckConditional was
382 ishii 4166 ECB : * okay
4167 : */
382 ishii 4168 CBC 2429 : Assert(conditional_stack_empty(st->cstack));
4169 :
382 ishii 4170 ECB : /*
4171 : * We must complete all the transaction blocks that were
4172 : * started in this script.
4173 : */
382 ishii 4174 GIC 2429 : tstatus = getTransactionStatus(st->con);
4175 2429 : if (tstatus == TSTATUS_IN_BLOCK)
382 ishii 4176 ECB : {
382 ishii 4177 GIC 1 : pg_log_error("client %d aborted: end of script reached without completing the last transaction",
4178 : st->id);
382 ishii 4179 CBC 1 : st->state = CSTATE_ABORTED;
4180 1 : break;
4181 : }
382 ishii 4182 GIC 2428 : else if (tstatus != TSTATUS_IDLE)
4183 : {
382 ishii 4184 LBC 0 : if (tstatus == TSTATUS_CONN_ERROR)
382 ishii 4185 UIC 0 : pg_log_error("perhaps the backend died while processing");
4186 :
4187 0 : pg_log_error("client %d aborted while receiving the transaction status", st->id);
4188 0 : st->state = CSTATE_ABORTED;
4189 0 : break;
4190 : }
382 ishii 4191 ECB :
382 ishii 4192 GIC 2428 : if (is_connect)
4193 : {
4194 110 : pg_time_usec_t start = now;
4195 :
4196 110 : pg_time_now_lazy(&start);
382 ishii 4197 CBC 110 : finishCon(st);
382 ishii 4198 GIC 110 : now = pg_time_now();
4199 110 : thread->conn_duration += now - start;
4200 : }
4201 :
4202 2428 : if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
4203 : {
4204 : /* script completed */
4205 54 : st->state = CSTATE_FINISHED;
4206 54 : break;
4207 : }
4208 :
4209 : /* next transaction (script) */
4210 2374 : st->state = CSTATE_CHOOSE_SCRIPT;
4211 :
382 ishii 4212 ECB : /*
332 tgl 4213 : * Ensure that we always return on this point, so as to
4214 : * avoid an infinite loop if the script only contains meta
4215 : * commands.
4216 : */
382 ishii 4217 GIC 2374 : return;
4218 : }
4219 :
4220 : /*
4221 : * Final states. Close the connection if it's still open.
4222 : */
2386 heikki.linnakangas 4223 99 : case CSTATE_ABORTED:
4224 : case CSTATE_FINISHED:
4225 :
585 fujii 4226 ECB : /*
4227 : * Don't measure the disconnection delays here even if in
4228 : * CSTATE_FINISHED and -C/--connect option is specified.
4229 : * Because in this case all the connections that this thread
4230 : * established are closed at the end of transactions and the
4231 : * disconnection delays should have already been measured at
4232 : * that moment.
4233 : *
4234 : * In CSTATE_ABORTED state, the measurement is no longer
4235 : * necessary because we cannot report complete results anyways
4236 : * in this case.
4237 : */
1865 andres 4238 GIC 99 : finishCon(st);
2386 heikki.linnakangas 4239 99 : return;
4240 : }
2386 heikki.linnakangas 4241 ECB : }
4242 : }
6401 ishii 4243 :
1600 alvherre 4244 : /*
1474 4245 : * Subroutine for advanceConnectionState -- initiate or execute the current
4246 : * meta command, and return the next state to set.
1600 4247 : *
4248 : * *now is updated to the current time, unless the command is expected to
1474 4249 : * take no time to execute.
4250 : */
4251 : static ConnectionStateEnum
760 tmunro 4252 CBC 2270 : executeMetaCommand(CState *st, pg_time_usec_t *now)
4253 : {
1600 alvherre 4254 GIC 2270 : Command *command = sql_script[st->use_file].commands[st->command];
4255 : int argc;
4256 : char **argv;
4257 :
1474 4258 2270 : Assert(command != NULL && command->type == META_COMMAND);
4259 :
4260 2270 : argc = command->argc;
4261 2270 : argv = command->argv;
1474 alvherre 4262 ECB :
1187 peter 4263 GIC 2270 : if (unlikely(__pg_log_level <= PG_LOG_DEBUG))
1474 alvherre 4264 ECB : {
1060 tgl 4265 : PQExpBufferData buf;
4266 :
1185 michael 4267 GIC 703 : initPQExpBuffer(&buf);
1185 michael 4268 ECB :
1185 michael 4269 CBC 703 : printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
1474 alvherre 4270 1406 : for (int i = 1; i < argc; i++)
1185 michael 4271 GIC 703 : appendPQExpBuffer(&buf, " %s", argv[i]);
1185 michael 4272 ECB :
1185 michael 4273 GIC 703 : pg_log_debug("%s", buf.data);
1185 michael 4274 ECB :
1185 michael 4275 GIC 703 : termPQExpBuffer(&buf);
4276 : }
1600 alvherre 4277 ECB :
1474 alvherre 4278 GIC 2270 : if (command->meta == META_SLEEP)
1600 alvherre 4279 ECB : {
1474 4280 : int usec;
4281 :
4282 : /*
4283 : * A \sleep doesn't execute anything, we just get the delay from the
4284 : * argument, and enter the CSTATE_SLEEP state. (The per-command
4285 : * latency will be recorded in CSTATE_SLEEP state, not here, after the
4286 : * delay has elapsed.)
4287 : */
382 ishii 4288 GIC 6 : if (!evaluateSleep(&st->variables, argc, argv, &usec))
1600 alvherre 4289 ECB : {
1474 alvherre 4290 GIC 1 : commandFailed(st, "sleep", "execution of meta-command failed");
4291 1 : return CSTATE_ABORTED;
1600 alvherre 4292 ECB : }
4293 :
760 tmunro 4294 GIC 5 : pg_time_now_lazy(now);
4295 5 : st->sleep_until = (*now) + usec;
1474 alvherre 4296 CBC 5 : return CSTATE_SLEEP;
4297 : }
1474 alvherre 4298 GBC 2264 : else if (command->meta == META_SET)
1600 alvherre 4299 EUB : {
1474 alvherre 4300 GIC 1711 : PgBenchExpr *expr = command->expr;
4301 : PgBenchValue result;
1600 alvherre 4302 ECB :
1467 tgl 4303 CBC 1711 : if (!evaluateExpr(st, expr, &result))
4304 : {
1474 alvherre 4305 22 : commandFailed(st, argv[0], "evaluation of meta-command failed");
1474 alvherre 4306 GIC 23 : return CSTATE_ABORTED;
4307 : }
1600 alvherre 4308 ECB :
382 ishii 4309 GIC 1689 : if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4310 : {
1474 alvherre 4311 1 : commandFailed(st, "set", "assignment of meta-command failed");
1474 alvherre 4312 CBC 1 : return CSTATE_ABORTED;
4313 : }
4314 : }
4315 553 : else if (command->meta == META_IF)
1474 alvherre 4316 ECB : {
4317 : /* backslash commands with an expression to evaluate */
1474 alvherre 4318 GIC 413 : PgBenchExpr *expr = command->expr;
1474 alvherre 4319 ECB : PgBenchValue result;
4320 : bool cond;
1600 alvherre 4321 EUB :
1467 tgl 4322 GBC 413 : if (!evaluateExpr(st, expr, &result))
4323 : {
1474 alvherre 4324 UIC 0 : commandFailed(st, argv[0], "evaluation of meta-command failed");
1474 alvherre 4325 LBC 0 : return CSTATE_ABORTED;
1600 alvherre 4326 ECB : }
4327 :
1474 alvherre 4328 GIC 413 : cond = valueTruth(&result);
1474 alvherre 4329 CBC 413 : conditional_stack_push(st->cstack, cond ? IFSTATE_TRUE : IFSTATE_FALSE);
4330 : }
4331 140 : else if (command->meta == META_ELIF)
4332 : {
1474 alvherre 4333 ECB : /* backslash commands with an expression to evaluate */
1474 alvherre 4334 CBC 5 : PgBenchExpr *expr = command->expr;
1474 alvherre 4335 ECB : PgBenchValue result;
1474 alvherre 4336 EUB : bool cond;
4337 :
1474 alvherre 4338 GIC 5 : if (conditional_stack_peek(st->cstack) == IFSTATE_TRUE)
4339 : {
4340 : /* elif after executed block, skip eval and wait for endif. */
4341 2 : conditional_stack_poke(st->cstack, IFSTATE_IGNORED);
4342 2 : return CSTATE_END_COMMAND;
1600 alvherre 4343 EUB : }
4344 :
1467 tgl 4345 GIC 3 : if (!evaluateExpr(st, expr, &result))
1600 alvherre 4346 ECB : {
1474 alvherre 4347 UIC 0 : commandFailed(st, argv[0], "evaluation of meta-command failed");
1474 alvherre 4348 LBC 0 : return CSTATE_ABORTED;
1600 alvherre 4349 ECB : }
4350 :
1474 alvherre 4351 CBC 3 : cond = valueTruth(&result);
1474 alvherre 4352 GIC 3 : Assert(conditional_stack_peek(st->cstack) == IFSTATE_FALSE);
1474 alvherre 4353 CBC 3 : conditional_stack_poke(st->cstack, cond ? IFSTATE_TRUE : IFSTATE_FALSE);
4354 : }
4355 135 : else if (command->meta == META_ELSE)
1474 alvherre 4356 ECB : {
1474 alvherre 4357 GIC 1 : switch (conditional_stack_peek(st->cstack))
4358 : {
1474 alvherre 4359 CBC 1 : case IFSTATE_TRUE:
1474 alvherre 4360 GIC 1 : conditional_stack_poke(st->cstack, IFSTATE_ELSE_FALSE);
1474 alvherre 4361 CBC 1 : break;
1474 alvherre 4362 UIC 0 : case IFSTATE_FALSE: /* inconsistent if active */
1474 alvherre 4363 ECB : case IFSTATE_IGNORED: /* inconsistent if active */
4364 : case IFSTATE_NONE: /* else without if */
4365 : case IFSTATE_ELSE_TRUE: /* else after else */
4366 : case IFSTATE_ELSE_FALSE: /* else after else */
4367 : default:
4368 : /* dead code if conditional check is ok */
1474 alvherre 4369 UIC 0 : Assert(false);
4370 : }
4371 : }
1474 alvherre 4372 GIC 134 : else if (command->meta == META_ENDIF)
1474 alvherre 4373 ECB : {
1474 alvherre 4374 GIC 40 : Assert(!conditional_stack_empty(st->cstack));
1474 alvherre 4375 GBC 40 : conditional_stack_pop(st->cstack);
1474 alvherre 4376 EUB : }
1474 alvherre 4377 GIC 94 : else if (command->meta == META_SETSHELL)
4378 : {
382 ishii 4379 3 : if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4380 : {
1474 alvherre 4381 2 : commandFailed(st, "setshell", "execution of meta-command failed");
4382 2 : return CSTATE_ABORTED;
4383 : }
4384 : }
4385 91 : else if (command->meta == META_SHELL)
1474 alvherre 4386 ECB : {
382 ishii 4387 CBC 3 : if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4388 : {
1474 alvherre 4389 2 : commandFailed(st, "shell", "execution of meta-command failed");
1474 alvherre 4390 GIC 2 : return CSTATE_ABORTED;
1600 alvherre 4391 ECB : }
4392 : }
755 alvherre 4393 GIC 88 : else if (command->meta == META_STARTPIPELINE)
755 alvherre 4394 ECB : {
4395 : /*
755 alvherre 4396 EUB : * In pipeline mode, we use a workflow based on libpq pipeline
4397 : * functions.
4398 : */
755 alvherre 4399 GIC 45 : if (querymode == QUERY_SIMPLE)
755 alvherre 4400 ECB : {
755 alvherre 4401 UIC 0 : commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
755 alvherre 4402 LBC 0 : return CSTATE_ABORTED;
4403 : }
755 alvherre 4404 ECB :
47 4405 : /*
4406 : * If we're in prepared-query mode, we need to prepare all the
4407 : * commands that are inside the pipeline before we actually start the
4408 : * pipeline itself. This solves the problem that running BEGIN
47 alvherre 4409 EUB : * ISOLATION LEVEL SERIALIZABLE in a pipeline would fail due to a
4410 : * snapshot having been acquired by the prepare within the pipeline.
4411 : */
47 alvherre 4412 GIC 45 : if (querymode == QUERY_PREPARED)
4413 41 : prepareCommandsInPipeline(st);
47 alvherre 4414 ECB :
755 alvherre 4415 GIC 45 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4416 : {
4417 1 : commandFailed(st, "startpipeline", "already in pipeline mode");
4418 1 : return CSTATE_ABORTED;
4419 : }
4420 44 : if (PQenterPipelineMode(st->con) == 0)
755 alvherre 4421 ECB : {
755 alvherre 4422 UIC 0 : commandFailed(st, "startpipeline", "failed to enter pipeline mode");
755 alvherre 4423 LBC 0 : return CSTATE_ABORTED;
4424 : }
4425 : }
755 alvherre 4426 GIC 43 : else if (command->meta == META_ENDPIPELINE)
4427 : {
4428 43 : if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
4429 : {
755 alvherre 4430 CBC 1 : commandFailed(st, "endpipeline", "not in pipeline mode");
755 alvherre 4431 GIC 1 : return CSTATE_ABORTED;
755 alvherre 4432 ECB : }
755 alvherre 4433 CBC 42 : if (!PQpipelineSync(st->con))
4434 : {
755 alvherre 4435 UIC 0 : commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4436 0 : return CSTATE_ABORTED;
4437 : }
4438 : /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4439 : /* collect pending results before getting out of pipeline mode */
755 alvherre 4440 GIC 42 : return CSTATE_WAIT_RESULT;
755 alvherre 4441 EUB : }
4442 :
1474 4443 : /*
4444 : * executing the expression or shell command might have taken a
4445 : * non-negligible amount of time, so reset 'now'
4446 : */
760 tmunro 4447 GBC 2191 : *now = 0;
4448 :
1474 alvherre 4449 2191 : return CSTATE_END_COMMAND;
1600 alvherre 4450 EUB : }
4451 :
382 ishii 4452 : /*
4453 : * Return the number of failed transactions.
4454 : */
4455 : static int64
382 ishii 4456 GIC 77 : getFailures(const StatsData *stats)
4457 : {
4458 154 : return (stats->serialization_failures +
382 ishii 4459 GBC 77 : stats->deadlock_failures);
4460 : }
4461 :
4462 : /*
4463 : * Return a string constant representing the result of a transaction
4464 : * that is not successfully processed.
4465 : */
4466 : static const char *
382 ishii 4467 UIC 0 : getResultString(bool skipped, EStatus estatus)
4468 : {
4469 0 : if (skipped)
4470 0 : return "skipped";
4471 0 : else if (failures_detailed)
382 ishii 4472 ECB : {
382 ishii 4473 UIC 0 : switch (estatus)
4474 : {
382 ishii 4475 LBC 0 : case ESTATUS_SERIALIZATION_ERROR:
4476 0 : return "serialization";
382 ishii 4477 UIC 0 : case ESTATUS_DEADLOCK_ERROR:
382 ishii 4478 LBC 0 : return "deadlock";
382 ishii 4479 UIC 0 : default:
4480 : /* internal error which should never occur */
366 tgl 4481 0 : pg_fatal("unexpected error status: %d", estatus);
4482 : }
4483 : }
382 ishii 4484 ECB : else
382 ishii 4485 LBC 0 : return "failed";
382 ishii 4486 ECB : }
4487 :
4488 : /*
2288 tgl 4489 : * Print log entry after completing one transaction.
4490 : *
4491 : * We print Unix-epoch timestamps in the log, so that entries can be
4492 : * correlated against other logs.
4493 : *
4494 : * XXX We could obtain the time from the caller and just shift it here, to
4495 : * avoid the cost of an extra call to pg_time_now().
4496 : */
4497 : static void
2288 tgl 4498 GIC 110 : doLog(TState *thread, CState *st,
2627 alvherre 4499 EUB : StatsData *agg, bool skipped, double latency, double lag)
4500 : {
2495 rhaas 4501 GBC 110 : FILE *logfile = thread->logfile;
637 tmunro 4502 110 : pg_time_usec_t now = pg_time_now() + epoch_shift;
2613 alvherre 4503 EUB :
2613 alvherre 4504 GBC 110 : Assert(use_log);
2613 alvherre 4505 EUB :
3111 heikki.linnakangas 4506 : /*
4507 : * Skip the log entry if sampling is enabled and this row doesn't belong
4508 : * to the random sample.
4509 : */
3111 heikki.linnakangas 4510 GIC 110 : if (sample_rate != 0.0 &&
497 tgl 4511 100 : pg_prng_double(&thread->ts_sample_rs) > sample_rate)
3111 heikki.linnakangas 4512 GBC 52 : return;
3111 heikki.linnakangas 4513 EUB :
4514 : /* should we aggregate the results or not? */
3111 heikki.linnakangas 4515 GIC 58 : if (agg_interval > 0)
4516 : {
4517 : pg_time_usec_t next;
4518 :
4519 : /*
2288 tgl 4520 EUB : * Loop until we reach the interval of the current moment, and print
4521 : * any empty intervals in between (this may happen with very low tps,
4522 : * e.g. --rate=0.1).
3111 heikki.linnakangas 4523 : */
2288 tgl 4524 :
637 tmunro 4525 UBC 0 : while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4526 : {
368 ishii 4527 0 : double lag_sum = 0.0;
368 ishii 4528 UIC 0 : double lag_sum2 = 0.0;
4529 0 : double lag_min = 0.0;
4530 0 : double lag_max = 0.0;
4531 0 : int64 skipped = 0;
4532 0 : int64 serialization_failures = 0;
368 ishii 4533 UBC 0 : int64 deadlock_failures = 0;
4534 0 : int64 retried = 0;
4535 0 : int64 retries = 0;
4536 :
2627 alvherre 4537 EUB : /* print aggregated report to logfile */
760 tmunro 4538 UIC 0 : fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
637 tmunro 4539 UBC 0 : agg->start_time / 1000000, /* seconds since Unix epoch */
2627 alvherre 4540 EUB : agg->cnt,
4541 : agg->latency.sum,
4542 : agg->latency.sum2,
4543 : agg->latency.min,
4544 : agg->latency.max);
4545 :
2627 alvherre 4546 UBC 0 : if (throttle_delay)
3100 heikki.linnakangas 4547 EUB : {
368 ishii 4548 UIC 0 : lag_sum = agg->lag.sum;
368 ishii 4549 UBC 0 : lag_sum2 = agg->lag.sum2;
368 ishii 4550 UIC 0 : lag_min = agg->lag.min;
4551 0 : lag_max = agg->lag.max;
4552 : }
368 ishii 4553 UBC 0 : fprintf(logfile, " %.0f %.0f %.0f %.0f",
4554 : lag_sum,
4555 : lag_sum2,
332 tgl 4556 EUB : lag_min,
4557 : lag_max);
4558 :
368 ishii 4559 UIC 0 : if (latency_limit)
368 ishii 4560 UBC 0 : skipped = agg->skipped;
368 ishii 4561 UIC 0 : fprintf(logfile, " " INT64_FORMAT, skipped);
4562 :
382 4563 0 : if (max_tries != 1)
4564 : {
368 ishii 4565 LBC 0 : retried = agg->retried;
4566 0 : retries = agg->retries;
4567 : }
368 ishii 4568 UIC 0 : fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4569 :
4570 0 : if (failures_detailed)
368 ishii 4571 EUB : {
368 ishii 4572 UIC 0 : serialization_failures = agg->serialization_failures;
4573 0 : deadlock_failures = agg->deadlock_failures;
4574 : }
355 4575 0 : fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT,
368 ishii 4576 ECB : serialization_failures,
368 ishii 4577 EUB : deadlock_failures);
368 ishii 4578 ECB :
2627 alvherre 4579 UBC 0 : fputc('\n', logfile);
3111 heikki.linnakangas 4580 ECB :
4581 : /* reset data and move to next interval */
637 tmunro 4582 UIC 0 : initStats(agg, next);
4583 : }
4584 :
4585 : /* accumulate the current transaction */
382 ishii 4586 0 : accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4587 : }
4588 : else
4589 : {
4590 : /* no, print raw transactions */
382 ishii 4591 GIC 58 : if (!skipped && st->estatus == ESTATUS_NO_ERROR)
760 tmunro 4592 CBC 58 : fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4593 : INT64_FORMAT,
4594 : st->id, st->cnt, latency, st->use_file,
760 tmunro 4595 ECB : now / 1000000, now % 1000000);
382 ishii 4596 : else
382 ishii 4597 LBC 0 : fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
382 ishii 4598 ECB : INT64_FORMAT,
4599 : st->id, st->cnt, getResultString(skipped, st->estatus),
4600 : st->use_file, now / 1000000, now % 1000000);
4601 :
3111 heikki.linnakangas 4602 CBC 58 : if (throttle_delay)
3111 heikki.linnakangas 4603 UIC 0 : fprintf(logfile, " %.0f", lag);
382 ishii 4604 GIC 58 : if (max_tries != 1)
354 peter 4605 LBC 0 : fprintf(logfile, " %u", st->tries - 1);
3111 heikki.linnakangas 4606 CBC 58 : fputc('\n', logfile);
4607 : }
4608 : }
4609 :
2627 alvherre 4610 ECB : /*
4611 : * Accumulate and report statistics at end of a transaction.
4612 : *
2043 tgl 4613 : * (This is also called when a transaction is late and thus skipped.
382 ishii 4614 : * Note that even skipped and failed transactions are counted in the CState
4615 : * "cnt" field.)
4616 : */
2627 alvherre 4617 : static void
760 tmunro 4618 GIC 2438 : processXactStats(TState *thread, CState *st, pg_time_usec_t *now,
2613 alvherre 4619 ECB : bool skipped, StatsData *agg)
2627 4620 : {
2627 alvherre 4621 GIC 2438 : double latency = 0.0,
4622 2438 : lag = 0.0;
382 ishii 4623 CBC 2438 : bool detailed = progress || throttle_delay || latency_limit ||
332 tgl 4624 4876 : use_log || per_script_stats;
2627 alvherre 4625 ECB :
382 ishii 4626 CBC 2438 : if (detailed && !skipped && st->estatus == ESTATUS_NO_ERROR)
4627 : {
760 tmunro 4628 GIC 1411 : pg_time_now_lazy(now);
4629 :
4630 : /* compute latency & lag */
760 tmunro 4631 CBC 1411 : latency = (*now) - st->txn_scheduled;
760 tmunro 4632 GIC 1411 : lag = st->txn_begin - st->txn_scheduled;
4633 : }
4634 :
382 ishii 4635 ECB : /* keep detailed thread stats */
382 ishii 4636 CBC 2438 : accumStats(&thread->stats, skipped, latency, lag, st->estatus, st->tries);
2627 alvherre 4637 ECB :
4638 : /* count transactions over the latency limit, if needed */
382 ishii 4639 GIC 2438 : if (latency_limit && latency > latency_limit)
4640 1 : thread->latency_late++;
4641 :
4642 : /* client stat is just counting */
2043 tgl 4643 CBC 2438 : st->cnt++;
4644 :
2627 alvherre 4645 2438 : if (use_log)
2288 tgl 4646 GIC 110 : doLog(thread, st, agg, skipped, latency, lag);
4647 :
4648 : /* XXX could use a mutex here, but we choose not to */
2624 alvherre 4649 2438 : if (per_script_stats)
382 ishii 4650 1100 : accumStats(&sql_script[st->use_file].stats, skipped, latency, lag,
382 ishii 4651 CBC 1100 : st->estatus, st->tries);
2627 alvherre 4652 GIC 2438 : }
4653 :
4654 :
4655 : /* discard connections */
8397 bruce 4656 ECB : static void
4997 ishii 4657 GIC 137 : disconnect_all(CState *state, int length)
4658 : {
4659 : int i;
4660 :
4661 335 : for (i = 0; i < length; i++)
1865 andres 4662 198 : finishCon(&state[i]);
8485 ishii 4663 137 : }
4664 :
1973 tgl 4665 ECB : /*
4666 : * Remove old pgbench tables, if any exist
4667 : */
4668 : static void
1973 tgl 4669 GIC 3 : initDropTables(PGconn *con)
8397 bruce 4670 ECB : {
1973 tgl 4671 GIC 3 : fprintf(stderr, "dropping old tables...\n");
1973 tgl 4672 ECB :
4673 : /*
4674 : * We drop all the tables in one command, so that whether there are
4675 : * foreign key dependencies or not doesn't matter.
4676 : */
1973 tgl 4677 GIC 3 : executeStatement(con, "drop table if exists "
1973 tgl 4678 ECB : "pgbench_accounts, "
4679 : "pgbench_branches, "
4680 : "pgbench_history, "
4681 : "pgbench_tellers");
1973 tgl 4682 CBC 3 : }
4683 :
4684 : /*
4685 : * Create "pgbench_accounts" partitions if needed.
1286 akapila 4686 ECB : *
4687 : * This is the larger table of pgbench default tpc-b like schema
4688 : * with a known size, so we choose to partition it.
4689 : */
4690 : static void
1286 akapila 4691 GIC 2 : createPartitions(PGconn *con)
4692 : {
4693 : PQExpBufferData query;
1286 akapila 4694 ECB :
4695 : /* we must have to create some partitions */
1286 akapila 4696 GIC 2 : Assert(partitions > 0);
1286 akapila 4697 ECB :
1286 akapila 4698 GIC 2 : fprintf(stderr, "creating %d partitions...\n", partitions);
1286 akapila 4699 ECB :
921 heikki.linnakangas 4700 GIC 2 : initPQExpBuffer(&query);
921 heikki.linnakangas 4701 ECB :
1286 akapila 4702 CBC 7 : for (int p = 1; p <= partitions; p++)
4703 : {
4704 5 : if (partition_method == PART_RANGE)
4705 : {
4706 3 : int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4707 :
921 heikki.linnakangas 4708 3 : printfPQExpBuffer(&query,
921 heikki.linnakangas 4709 ECB : "create%s table pgbench_accounts_%d\n"
4710 : " partition of pgbench_accounts\n"
4711 : " for values from (",
921 heikki.linnakangas 4712 GIC 3 : unlogged_tables ? " unlogged" : "", p);
1286 akapila 4713 ECB :
4714 : /*
4715 : * For RANGE, we use open-ended partitions at the beginning and
1286 akapila 4716 EUB : * end to allow any valid value for the primary key. Although the
4717 : * actual minimum and maximum values can be derived from the
4718 : * scale, it is more generic and the performance is better.
4719 : */
1286 akapila 4720 GIC 3 : if (p == 1)
921 heikki.linnakangas 4721 1 : appendPQExpBufferStr(&query, "minvalue");
1286 akapila 4722 ECB : else
921 heikki.linnakangas 4723 GIC 2 : appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
921 heikki.linnakangas 4724 ECB :
921 heikki.linnakangas 4725 GIC 3 : appendPQExpBufferStr(&query, ") to (");
4726 :
1286 akapila 4727 CBC 3 : if (p < partitions)
921 heikki.linnakangas 4728 2 : appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4729 : else
921 heikki.linnakangas 4730 GIC 1 : appendPQExpBufferStr(&query, "maxvalue");
4731 :
4732 3 : appendPQExpBufferChar(&query, ')');
4733 : }
1286 akapila 4734 CBC 2 : else if (partition_method == PART_HASH)
921 heikki.linnakangas 4735 GIC 2 : printfPQExpBuffer(&query,
4736 : "create%s table pgbench_accounts_%d\n"
4737 : " partition of pgbench_accounts\n"
4738 : " for values with (modulus %d, remainder %d)",
4739 2 : unlogged_tables ? " unlogged" : "", p,
4740 : partitions, p - 1);
4741 : else /* cannot get there */
1286 akapila 4742 UIC 0 : Assert(0);
4743 :
4744 : /*
4745 : * Per ddlinfo in initCreateTables, fillfactor is needed on table
4746 : * pgbench_accounts.
4747 : */
921 heikki.linnakangas 4748 GIC 5 : appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4749 :
4750 5 : executeStatement(con, query.data);
4751 : }
4752 :
4753 2 : termPQExpBuffer(&query);
1286 akapila 4754 2 : }
4755 :
4756 : /*
4757 : * Create pgbench's standard tables
4758 : */
4759 : static void
1973 tgl 4760 3 : initCreateTables(PGconn *con)
4761 : {
4762 : /*
4763 : * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4764 : * fields in these table declarations were intended to comply with that.
4765 : * The pgbench_accounts table complies with that because the "filler"
4766 : * column is set to blank-padded empty string. But for all other tables
4767 : * the columns default to NULL and so don't actually take any space. We
4768 : * could fix that by giving them non-null default values. However, that
4769 : * would completely break comparability of pgbench results with prior
4770 : * versions. Since pgbench has never pretended to be fully TPC-B compliant
4771 : * anyway, we stick with the historical behavior.
4772 : */
4773 : struct ddlinfo
4774 : {
4775 : const char *table; /* table name */
4776 : const char *smcols; /* column decls if accountIDs are 32 bits */
4777 : const char *bigcols; /* column decls if accountIDs are 64 bits */
4778 : int declare_fillfactor;
4779 : };
4780 : static const struct ddlinfo DDLs[] = {
4781 : {
4782 : "pgbench_history",
3247 tgl 4783 ECB : "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4784 : "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
3946 4785 : 0
4786 : },
4276 rhaas 4787 : {
4788 : "pgbench_tellers",
4789 : "tid int not null,bid int,tbalance int,filler char(84)",
4790 : "tid int not null,bid int,tbalance int,filler char(84)",
4791 : 1
4792 : },
4793 : {
4794 : "pgbench_accounts",
3247 tgl 4795 : "aid int not null,bid int,abalance int,filler char(84)",
4796 : "aid bigint not null,bid int,abalance int,filler char(84)",
4797 : 1
4276 rhaas 4798 : },
4799 : {
4800 : "pgbench_branches",
3946 tgl 4801 : "bid int not null,bbalance int,filler char(88)",
4802 : "bid int not null,bbalance int,filler char(88)",
4803 : 1
4276 rhaas 4804 : }
4805 : };
4806 : int i;
921 heikki.linnakangas 4807 : PQExpBufferData query;
4808 :
1973 tgl 4809 GIC 3 : fprintf(stderr, "creating tables...\n");
4810 :
921 heikki.linnakangas 4811 CBC 3 : initPQExpBuffer(&query);
921 heikki.linnakangas 4812 ECB :
5847 ishii 4813 CBC 15 : for (i = 0; i < lengthof(DDLs); i++)
4814 : {
3247 tgl 4815 GIC 12 : const struct ddlinfo *ddl = &DDLs[i];
4276 rhaas 4816 ECB :
4817 : /* Construct new create table statement. */
921 heikki.linnakangas 4818 GIC 24 : printfPQExpBuffer(&query, "create%s table %s(%s)",
921 heikki.linnakangas 4819 CBC 12 : unlogged_tables ? " unlogged" : "",
921 heikki.linnakangas 4820 GIC 12 : ddl->table,
921 heikki.linnakangas 4821 CBC 12 : (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
1286 akapila 4822 ECB :
4823 : /* Partition pgbench_accounts table */
1286 akapila 4824 GIC 12 : if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
921 heikki.linnakangas 4825 2 : appendPQExpBuffer(&query,
4826 : " partition by %s (aid)", PARTITION_METHOD[partition_method]);
1286 akapila 4827 10 : else if (ddl->declare_fillfactor)
4828 : {
1286 akapila 4829 ECB : /* fillfactor is only expected on actual tables */
921 heikki.linnakangas 4830 GIC 7 : appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
921 heikki.linnakangas 4831 ECB : }
4832 :
4276 rhaas 4833 GIC 12 : if (tablespace != NULL)
4834 : {
4835 : char *escape_tablespace;
3955 bruce 4836 ECB :
921 heikki.linnakangas 4837 GIC 4 : escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4838 4 : appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4276 rhaas 4839 4 : PQfreemem(escape_tablespace);
4840 : }
4841 :
921 heikki.linnakangas 4842 CBC 12 : executeStatement(con, query.data);
4843 : }
4844 :
921 heikki.linnakangas 4845 GIC 3 : termPQExpBuffer(&query);
4846 :
1286 akapila 4847 3 : if (partition_method != PART_NONE)
4848 2 : createPartitions(con);
4849 3 : }
4850 :
4851 : /*
1250 fujii 4852 ECB : * Truncate away any old data, in one command in case there are foreign keys
4853 : */
4854 : static void
1250 fujii 4855 CBC 3 : initTruncateTables(PGconn *con)
4856 : {
4857 3 : executeStatement(con, "truncate table "
4858 : "pgbench_accounts, "
4859 : "pgbench_branches, "
4860 : "pgbench_history, "
4861 : "pgbench_tellers");
1250 fujii 4862 GIC 3 : }
1250 fujii 4863 ECB :
4864 : /*
4865 : * Fill the standard tables with some data generated and sent from the client
4866 : */
4867 : static void
1250 fujii 4868 CBC 2 : initGenerateDataClientSide(PGconn *con)
4869 : {
4870 : PQExpBufferData sql;
4871 : PGresult *res;
4872 : int i;
4873 : int64 k;
332 tgl 4874 ECB : char *copy_statement;
4875 :
4876 : /* used to track elapsed time and estimate of the remaining time */
760 tmunro 4877 : pg_time_usec_t start;
1973 tgl 4878 GIC 2 : int log_interval = 1;
4879 :
1222 michael 4880 ECB : /* Stay on the same line if reporting to a terminal */
1222 michael 4881 GIC 2 : char eol = isatty(fileno(stderr)) ? '\r' : '\n';
4882 :
1250 fujii 4883 CBC 2 : fprintf(stderr, "generating data (client-side)...\n");
4884 :
4885 : /*
1973 tgl 4886 ECB : * we do all of this in one transaction to enable the backend's
4887 : * data-loading optimizations
4888 : */
5847 ishii 4889 CBC 2 : executeStatement(con, "begin");
4890 :
4891 : /* truncate away any old data */
1250 fujii 4892 GIC 2 : initTruncateTables(con);
4893 :
921 heikki.linnakangas 4894 2 : initPQExpBuffer(&sql);
4895 :
4896 : /*
1973 tgl 4897 ECB : * fill branches, tellers, accounts in that order in case foreign keys
4898 : * already exist
4899 : */
6052 ishii 4900 CBC 4 : for (i = 0; i < nbranches * scale; i++)
4901 : {
3478 fujii 4902 ECB : /* "filler" column defaults to NULL */
921 heikki.linnakangas 4903 GIC 2 : printfPQExpBuffer(&sql,
921 heikki.linnakangas 4904 ECB : "insert into pgbench_branches(bid,bbalance) values(%d,0)",
921 heikki.linnakangas 4905 EUB : i + 1);
921 heikki.linnakangas 4906 CBC 2 : executeStatement(con, sql.data);
4907 : }
8485 ishii 4908 ECB :
6052 ishii 4909 GIC 22 : for (i = 0; i < ntellers * scale; i++)
8397 bruce 4910 ECB : {
4911 : /* "filler" column defaults to NULL */
921 heikki.linnakangas 4912 CBC 20 : printfPQExpBuffer(&sql,
4913 : "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
921 heikki.linnakangas 4914 GIC 20 : i + 1, i / ntellers + 1);
921 heikki.linnakangas 4915 CBC 20 : executeStatement(con, sql.data);
4916 : }
8485 ishii 4917 ECB :
5847 4918 : /*
1973 tgl 4919 EUB : * accounts is big enough to be worth using COPY and tracking runtime
4920 : */
584 ishii 4921 ECB :
390 michael 4922 EUB : /* use COPY with FREEZE on v14 and later without partitioning */
584 ishii 4923 GIC 2 : if (partitions == 0 && PQserverVersion(con) >= 140000)
4924 1 : copy_statement = "copy pgbench_accounts from stdin with (freeze on)";
4925 : else
4926 1 : copy_statement = "copy pgbench_accounts from stdin";
4927 :
584 ishii 4928 CBC 2 : res = PQexec(con, copy_statement);
584 ishii 4929 ECB :
5847 ishii 4930 CBC 2 : if (PQresultStatus(res) != PGRES_COPY_IN)
366 tgl 4931 LBC 0 : pg_fatal("unexpected copy in result: %s", PQerrorMessage(con));
6873 ishii 4932 GIC 2 : PQclear(res);
7921 ishii 4933 ECB :
760 tmunro 4934 GIC 2 : start = pg_time_now();
3744 ishii 4935 ECB :
3722 heikki.linnakangas 4936 GIC 200002 : for (k = 0; k < (int64) naccounts * scale; k++)
4937 : {
4938 200000 : int64 j = k + 1;
8397 bruce 4939 ECB :
4940 : /* "filler" column defaults to blank padded empty string */
921 heikki.linnakangas 4941 CBC 200000 : printfPQExpBuffer(&sql,
921 heikki.linnakangas 4942 ECB : INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
921 heikki.linnakangas 4943 GIC 200000 : j, k / naccounts + 1, 0);
4944 200000 : if (PQputline(con, sql.data))
366 tgl 4945 LBC 0 : pg_fatal("PQputline failed");
4946 :
1224 michael 4947 CBC 200000 : if (CancelRequested)
1224 michael 4948 UIC 0 : break;
1224 michael 4949 ECB :
4950 : /*
4951 : * If we want to stick with the original logging, print a message each
3602 bruce 4952 : * 100k inserted rows.
4953 : */
3602 bruce 4954 GIC 200000 : if ((!use_quiet) && (j % 100000 == 0))
3744 ishii 4955 1 : {
760 tmunro 4956 1 : double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
760 tmunro 4957 CBC 1 : double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
3744 ishii 4958 EUB :
1222 michael 4959 GIC 1 : fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
3602 bruce 4960 ECB : j, (int64) naccounts * scale,
3405 ishii 4961 GBC 1 : (int) (((int64) j * 100) / (naccounts * (int64) scale)),
1222 michael 4962 ECB : elapsed_sec, remaining_sec, eol);
3744 ishii 4963 EUB : }
4964 : /* let's not call the timing for each row, but only each 100 rows */
3744 ishii 4965 CBC 199999 : else if (use_quiet && (j % 100 == 0))
4966 : {
760 tmunro 4967 1000 : double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4968 1000 : double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4969 :
4970 : /* have we reached the next interval (or end)? */
3602 bruce 4971 GIC 1000 : if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
4972 : {
1222 michael 4973 2 : fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4974 : j, (int64) naccounts * scale,
4975 2 : (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
4976 :
4977 : /* skip to the next interval */
3602 bruce 4978 CBC 2 : log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
4979 : }
4980 : }
4981 : }
1222 michael 4982 ECB :
1222 michael 4983 GIC 2 : if (eol != '\n')
1222 michael 4984 UIC 0 : fputc('\n', stderr); /* Need to move to next line */
4985 :
5847 ishii 4986 GIC 2 : if (PQputline(con, "\\.\n"))
366 tgl 4987 UIC 0 : pg_fatal("very last PQputline failed");
5847 ishii 4988 CBC 2 : if (PQendcopy(con))
366 tgl 4989 UIC 0 : pg_fatal("PQendcopy failed");
4990 :
921 heikki.linnakangas 4991 CBC 2 : termPQExpBuffer(&sql);
4992 :
5847 ishii 4993 2 : executeStatement(con, "commit");
1973 tgl 4994 GIC 2 : }
5847 ishii 4995 ECB :
4996 : /*
4997 : * Fill the standard tables with some data generated on the server
4998 : *
1250 fujii 4999 : * As already the case with the client-side data generation, the filler
5000 : * column defaults to NULL in pgbench_branches and pgbench_tellers,
5001 : * and is a blank-padded string in pgbench_accounts.
5002 : */
5003 : static void
1250 fujii 5004 GIC 1 : initGenerateDataServerSide(PGconn *con)
1250 fujii 5005 ECB : {
5006 : PQExpBufferData sql;
5007 :
1250 fujii 5008 GIC 1 : fprintf(stderr, "generating data (server-side)...\n");
5009 :
5010 : /*
5011 : * we do all of this in one transaction to enable the backend's
1250 fujii 5012 ECB : * data-loading optimizations
5013 : */
1250 fujii 5014 CBC 1 : executeStatement(con, "begin");
5015 :
1250 fujii 5016 ECB : /* truncate away any old data */
1250 fujii 5017 CBC 1 : initTruncateTables(con);
5018 :
921 heikki.linnakangas 5019 GIC 1 : initPQExpBuffer(&sql);
5020 :
5021 1 : printfPQExpBuffer(&sql,
5022 : "insert into pgbench_branches(bid,bbalance) "
921 heikki.linnakangas 5023 ECB : "select bid, 0 "
5024 : "from generate_series(1, %d) as bid", nbranches * scale);
921 heikki.linnakangas 5025 CBC 1 : executeStatement(con, sql.data);
921 heikki.linnakangas 5026 ECB :
921 heikki.linnakangas 5027 CBC 1 : printfPQExpBuffer(&sql,
921 heikki.linnakangas 5028 ECB : "insert into pgbench_tellers(tid,bid,tbalance) "
5029 : "select tid, (tid - 1) / %d + 1, 0 "
5030 : "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
921 heikki.linnakangas 5031 GIC 1 : executeStatement(con, sql.data);
5032 :
5033 1 : printfPQExpBuffer(&sql,
5034 : "insert into pgbench_accounts(aid,bid,abalance,filler) "
5035 : "select aid, (aid - 1) / %d + 1, 0, '' "
921 heikki.linnakangas 5036 ECB : "from generate_series(1, " INT64_FORMAT ") as aid",
5037 : naccounts, (int64) naccounts * scale);
921 heikki.linnakangas 5038 GIC 1 : executeStatement(con, sql.data);
5039 :
5040 1 : termPQExpBuffer(&sql);
5041 :
1250 fujii 5042 1 : executeStatement(con, "commit");
5043 1 : }
5044 :
5045 : /*
1973 tgl 5046 ECB : * Invoke vacuum on the standard tables
5047 : */
5048 : static void
1973 tgl 5049 CBC 2 : initVacuum(PGconn *con)
5050 : {
5051 2 : fprintf(stderr, "vacuuming...\n");
5052 2 : executeStatement(con, "vacuum analyze pgbench_branches");
1973 tgl 5053 GIC 2 : executeStatement(con, "vacuum analyze pgbench_tellers");
1973 tgl 5054 CBC 2 : executeStatement(con, "vacuum analyze pgbench_accounts");
1973 tgl 5055 GIC 2 : executeStatement(con, "vacuum analyze pgbench_history");
5056 2 : }
5057 :
1973 tgl 5058 ECB : /*
5059 : * Create primary keys on the standard tables
5060 : */
5061 : static void
1973 tgl 5062 GIC 3 : initCreatePKeys(PGconn *con)
5063 : {
1973 tgl 5064 ECB : static const char *const DDLINDEXes[] = {
5065 : "alter table pgbench_branches add primary key (bid)",
5066 : "alter table pgbench_tellers add primary key (tid)",
5067 : "alter table pgbench_accounts add primary key (aid)"
5068 : };
5069 : int i;
5070 : PQExpBufferData query;
5071 :
1973 tgl 5072 GIC 3 : fprintf(stderr, "creating primary keys...\n");
921 heikki.linnakangas 5073 3 : initPQExpBuffer(&query);
921 heikki.linnakangas 5074 ECB :
3247 tgl 5075 GIC 12 : for (i = 0; i < lengthof(DDLINDEXes); i++)
5076 : {
921 heikki.linnakangas 5077 9 : resetPQExpBuffer(&query);
5078 9 : appendPQExpBufferStr(&query, DDLINDEXes[i]);
5079 :
4276 rhaas 5080 9 : if (index_tablespace != NULL)
5081 : {
5082 : char *escape_tablespace;
5083 :
5084 3 : escape_tablespace = PQescapeIdentifier(con, index_tablespace,
4276 rhaas 5085 ECB : strlen(index_tablespace));
921 heikki.linnakangas 5086 CBC 3 : appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
4276 rhaas 5087 GIC 3 : PQfreemem(escape_tablespace);
4276 rhaas 5088 ECB : }
5089 :
921 heikki.linnakangas 5090 CBC 9 : executeStatement(con, query.data);
5091 : }
5092 :
921 heikki.linnakangas 5093 GIC 3 : termPQExpBuffer(&query);
1973 tgl 5094 3 : }
5095 :
5096 : /*
5097 : * Create foreign key constraints between the standard tables
5098 : */
5099 : static void
1973 tgl 5100 CBC 2 : initCreateFKeys(PGconn *con)
5101 : {
1973 tgl 5102 ECB : static const char *const DDLKEYs[] = {
1973 tgl 5103 EUB : "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5104 : "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
1973 tgl 5105 ECB : "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5106 : "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5107 : "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5108 : };
5109 : int i;
5110 :
1973 tgl 5111 CBC 2 : fprintf(stderr, "creating foreign keys...\n");
1973 tgl 5112 GIC 12 : for (i = 0; i < lengthof(DDLKEYs); i++)
5113 : {
1973 tgl 5114 CBC 10 : executeStatement(con, DDLKEYs[i]);
5115 : }
1973 tgl 5116 GIC 2 : }
5117 :
5118 : /*
5119 : * Validate an initialization-steps string
1973 tgl 5120 ECB : *
5121 : * (We could just leave it to runInitSteps() to fail if there are wrong
5122 : * characters, but since initialization can take awhile, it seems friendlier
5123 : * to check during option parsing.)
5124 : */
5125 : static void
1973 tgl 5126 CBC 4 : checkInitSteps(const char *initialize_steps)
5127 : {
5128 4 : if (initialize_steps[0] == '\0')
366 tgl 5129 UIC 0 : pg_fatal("no initialization steps specified");
1973 tgl 5130 ECB :
1250 fujii 5131 GBC 21 : for (const char *step = initialize_steps; *step != '\0'; step++)
5132 : {
1250 fujii 5133 CBC 18 : if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
1973 tgl 5134 ECB : {
366 tgl 5135 GIC 1 : pg_log_error("unrecognized initialization step \"%c\"", *step);
366 tgl 5136 CBC 1 : pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
1973 tgl 5137 GIC 1 : exit(1);
1973 tgl 5138 ECB : }
5139 : }
1973 tgl 5140 GIC 3 : }
1973 tgl 5141 ECB :
5142 : /*
5143 : * Invoke each initialization step in the given string
5144 : */
5145 : static void
1973 tgl 5146 CBC 3 : runInitSteps(const char *initialize_steps)
1973 tgl 5147 ECB : {
1363 tmunro 5148 : PQExpBufferData stats;
1973 tgl 5149 : PGconn *con;
5150 : const char *step;
1363 tmunro 5151 CBC 3 : double run_time = 0.0;
5152 3 : bool first = true;
1363 tmunro 5153 ECB :
1363 tmunro 5154 CBC 3 : initPQExpBuffer(&stats);
1973 tgl 5155 ECB :
1973 tgl 5156 CBC 3 : if ((con = doConnect()) == NULL)
366 tgl 5157 LBC 0 : pg_fatal("could not create connection for initialization");
1973 tgl 5158 ECB :
1224 michael 5159 CBC 3 : setup_cancel_handler(NULL);
5160 3 : SetCancelConn(con);
1224 michael 5161 ECB :
1973 tgl 5162 CBC 22 : for (step = initialize_steps; *step != '\0'; step++)
3946 tgl 5163 ECB : {
1363 tmunro 5164 CBC 19 : char *op = NULL;
760 5165 19 : pg_time_usec_t start = pg_time_now();
1363 tmunro 5166 ECB :
1973 tgl 5167 CBC 19 : switch (*step)
3946 tgl 5168 ECB : {
1973 tgl 5169 CBC 3 : case 'd':
1363 tmunro 5170 3 : op = "drop tables";
1973 tgl 5171 3 : initDropTables(con);
5172 3 : break;
1973 tgl 5173 GBC 3 : case 't':
1363 tmunro 5174 3 : op = "create tables";
1973 tgl 5175 3 : initCreateTables(con);
5176 3 : break;
1973 tgl 5177 GIC 2 : case 'g':
1250 fujii 5178 2 : op = "client-side generate";
1250 fujii 5179 CBC 2 : initGenerateDataClientSide(con);
1250 fujii 5180 GIC 2 : break;
1250 fujii 5181 CBC 1 : case 'G':
1250 fujii 5182 GIC 1 : op = "server-side generate";
1250 fujii 5183 CBC 1 : initGenerateDataServerSide(con);
1973 tgl 5184 1 : break;
1973 tgl 5185 GIC 2 : case 'v':
1363 tmunro 5186 CBC 2 : op = "vacuum";
1973 tgl 5187 GIC 2 : initVacuum(con);
1973 tgl 5188 CBC 2 : break;
1973 tgl 5189 GIC 3 : case 'p':
1363 tmunro 5190 CBC 3 : op = "primary keys";
1973 tgl 5191 GIC 3 : initCreatePKeys(con);
5192 3 : break;
5193 2 : case 'f':
1363 tmunro 5194 CBC 2 : op = "foreign keys";
1973 tgl 5195 2 : initCreateFKeys(con);
5196 2 : break;
5197 3 : case ' ':
5198 3 : break; /* ignore */
1973 tgl 5199 UIC 0 : default:
366 5200 0 : pg_log_error("unrecognized initialization step \"%c\"", *step);
1973 5201 0 : PQfinish(con);
5202 0 : exit(1);
5203 : }
5204 :
1363 tmunro 5205 CBC 19 : if (op != NULL)
5206 : {
760 tmunro 5207 GIC 16 : double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5208 :
1363 5209 16 : if (!first)
5210 13 : appendPQExpBufferStr(&stats, ", ");
5211 : else
5212 3 : first = false;
1363 tmunro 5213 ECB :
1363 tmunro 5214 CBC 16 : appendPQExpBuffer(&stats, "%s %.2f s", op, elapsed_sec);
5215 :
5216 16 : run_time += elapsed_sec;
5217 : }
3946 tgl 5218 ECB : }
5219 :
1363 tmunro 5220 CBC 3 : fprintf(stderr, "done in %.2f s (%s).\n", run_time, stats.data);
1224 michael 5221 3 : ResetCancelConn();
8397 bruce 5222 GIC 3 : PQfinish(con);
1363 tmunro 5223 3 : termPQExpBuffer(&stats);
8397 bruce 5224 CBC 3 : }
5225 :
1286 akapila 5226 ECB : /*
888 michael 5227 : * Extract pgbench table information into global variables scale,
1286 akapila 5228 EUB : * partition_method and partitions.
5229 : */
1286 akapila 5230 ECB : static void
1286 akapila 5231 GIC 7 : GetTableInfo(PGconn *con, bool scale_given)
5232 : {
1286 akapila 5233 ECB : PGresult *res;
5234 :
5235 : /*
5236 : * get the scaling factor that should be same as count(*) from
5237 : * pgbench_branches if this is not a custom query
5238 : */
1286 akapila 5239 GIC 7 : res = PQexec(con, "select count(*) from pgbench_branches");
5240 7 : if (PQresultStatus(res) != PGRES_TUPLES_OK)
5241 : {
5242 1 : char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5243 :
366 tgl 5244 1 : pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5245 :
1286 akapila 5246 1 : if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
366 tgl 5247 1 : pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5248 : PQdb(con));
5249 :
1286 akapila 5250 1 : exit(1);
5251 : }
1286 akapila 5252 CBC 6 : scale = atoi(PQgetvalue(res, 0, 0));
1286 akapila 5253 GIC 6 : if (scale < 0)
366 tgl 5254 UIC 0 : pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5255 : PQgetvalue(res, 0, 0));
1286 akapila 5256 GIC 6 : PQclear(res);
5257 :
5258 : /* warn if we override user-given -s switch */
5259 6 : if (scale_given)
1187 peter 5260 1 : pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5261 : scale);
5262 :
5263 : /*
1286 akapila 5264 ECB : * Get the partition information for the first "pgbench_accounts" table
5265 : * found in search_path.
5266 : *
1286 akapila 5267 EUB : * The result is empty if no "pgbench_accounts" is found.
5268 : *
5269 : * Otherwise, it always returns one row even if the table is not
1286 akapila 5270 ECB : * partitioned (in which case the partition strategy is NULL).
5271 : *
5272 : * The number of partitions can be 0 even for partitioned tables, if no
5273 : * partition is attached.
5274 : *
5275 : * We assume no partitioning on any failure, so as to avoid failing on an
1286 akapila 5276 EUB : * old version without "pg_partitioned_table".
5277 : */
1286 akapila 5278 GBC 6 : res = PQexec(con,
5279 : "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5280 : "from pg_catalog.pg_class as c "
5281 : "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5282 : "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
1286 akapila 5283 ECB : "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
1286 akapila 5284 EUB : "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5285 : "where c.relname = 'pgbench_accounts' and o.n is not null "
5286 : "group by 1, 2 "
1286 akapila 5287 ECB : "order by 1 asc "
5288 : "limit 1");
5289 :
1286 akapila 5290 CBC 6 : if (PQresultStatus(res) != PGRES_TUPLES_OK)
5291 : {
1286 akapila 5292 ECB : /* probably an older version, coldly assume no partitioning */
1286 akapila 5293 LBC 0 : partition_method = PART_NONE;
1286 akapila 5294 UBC 0 : partitions = 0;
1286 akapila 5295 EUB : }
1286 akapila 5296 GIC 6 : else if (PQntuples(res) == 0)
5297 : {
5298 : /*
1286 akapila 5299 EUB : * This case is unlikely as pgbench already found "pgbench_branches"
5300 : * above to compute the scale.
5301 : */
366 tgl 5302 UIC 0 : pg_log_error("no pgbench_accounts table found in search_path");
366 tgl 5303 LBC 0 : pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
1286 akapila 5304 UIC 0 : exit(1);
5305 : }
1286 akapila 5306 ECB : else /* PQntupes(res) == 1 */
5307 : {
5308 : /* normal case, extract partition information */
1286 akapila 5309 GIC 6 : if (PQgetisnull(res, 0, 1))
1286 akapila 5310 UIC 0 : partition_method = PART_NONE;
5311 : else
5312 : {
1286 akapila 5313 GIC 6 : char *ps = PQgetvalue(res, 0, 1);
1286 akapila 5314 ECB :
5315 : /* column must be there */
1286 akapila 5316 GIC 6 : Assert(ps != NULL);
5317 :
5318 6 : if (strcmp(ps, "r") == 0)
1286 akapila 5319 CBC 6 : partition_method = PART_RANGE;
1286 akapila 5320 UIC 0 : else if (strcmp(ps, "h") == 0)
1286 akapila 5321 LBC 0 : partition_method = PART_HASH;
1286 akapila 5322 ECB : else
5323 : {
5324 : /* possibly a newer version with new partition method */
366 tgl 5325 UIC 0 : pg_fatal("unexpected partition method: \"%s\"", ps);
5326 : }
5327 : }
1286 akapila 5328 ECB :
1286 akapila 5329 CBC 6 : partitions = atoi(PQgetvalue(res, 0, 2));
5330 : }
1286 akapila 5331 ECB :
1286 akapila 5332 GIC 6 : PQclear(res);
1286 akapila 5333 CBC 6 : }
5334 :
5499 ishii 5335 ECB : /*
5336 : * Replace :param with $n throughout the command's SQL text, which
5337 : * is a modifiable string in cmd->lines.
5338 : */
5339 : static bool
2067 tgl 5340 GIC 69 : parseQuery(Command *cmd)
5341 : {
5499 ishii 5342 ECB : char *sql,
5343 : *p;
5344 :
5499 ishii 5345 GIC 69 : cmd->argc = 1;
5499 ishii 5346 ECB :
1550 alvherre 5347 CBC 69 : p = sql = pg_strdup(cmd->lines.data);
5499 ishii 5348 GIC 365 : while ((p = strchr(p, ':')) != NULL)
5349 : {
1851 peter_e 5350 ECB : char var[13];
5050 bruce 5351 : char *name;
5352 : int eaten;
5499 ishii 5353 :
5499 ishii 5354 CBC 297 : name = parseVariable(p, &eaten);
5499 ishii 5355 GIC 297 : if (name == NULL)
5356 : {
5050 bruce 5357 CBC 48 : while (*p == ':')
5050 bruce 5358 ECB : {
5050 bruce 5359 CBC 32 : p++;
5360 : }
5499 ishii 5361 GIC 16 : continue;
5362 : }
5363 :
5364 : /*
5365 : * cmd->argv[0] is the SQL statement itself, so the max number of
5366 : * arguments is one less than MAX_ARGS
5367 : */
5368 281 : if (cmd->argc >= MAX_ARGS)
5369 : {
1187 peter 5370 1 : pg_log_error("statement has too many arguments (maximum is %d): %s",
5371 : MAX_ARGS - 1, cmd->lines.data);
3022 ishii 5372 1 : pg_free(name);
5499 5373 1 : return false;
5374 : }
5499 ishii 5375 ECB :
5499 ishii 5376 GIC 280 : sprintf(var, "$%d", cmd->argc);
4623 tgl 5377 280 : p = replaceVariable(&sql, p, eaten, var);
5378 :
5499 ishii 5379 280 : cmd->argv[cmd->argc] = name;
5380 280 : cmd->argc++;
5499 ishii 5381 ECB : }
5382 :
1550 alvherre 5383 CBC 68 : Assert(cmd->argv[0] == NULL);
5499 ishii 5384 68 : cmd->argv[0] = sql;
5385 68 : return true;
5499 ishii 5386 ECB : }
5499 ishii 5387 EUB :
2576 tgl 5388 ECB : /*
5389 : * syntax error while parsing a script (in practice, while parsing a
5390 : * backslash command, because we don't detect syntax errors in SQL)
5391 : *
5392 : * source: source of script (filename or builtin-script ID)
5393 : * lineno: line number within script (count from 1)
5394 : * line: whole line of backslash command, if available
5395 : * command: backslash command name, if available
5396 : * msg: the actual error message
5397 : * more: optional extra message
5398 : * column: zero-based column number, or -1 if unknown
5399 : */
5400 : void
2576 tgl 5401 GIC 33 : syntax_error(const char *source, int lineno,
2929 rhaas 5402 ECB : const char *line, const char *command,
5403 : const char *msg, const char *more, int column)
5404 : {
5405 : PQExpBufferData buf;
5406 :
1187 peter 5407 GIC 33 : initPQExpBuffer(&buf);
5408 :
5409 33 : printfPQExpBuffer(&buf, "%s:%d: %s", source, lineno, msg);
2929 rhaas 5410 33 : if (more != NULL)
1187 peter 5411 CBC 15 : appendPQExpBuffer(&buf, " (%s)", more);
2576 tgl 5412 GIC 33 : if (column >= 0 && line == NULL)
1187 peter 5413 LBC 0 : appendPQExpBuffer(&buf, " at column %d", column + 1);
2576 tgl 5414 GIC 33 : if (command != NULL)
1187 peter 5415 30 : appendPQExpBuffer(&buf, " in command \"%s\"", command);
5416 :
366 tgl 5417 33 : pg_log_error("%s", buf.data);
1187 peter 5418 ECB :
1187 peter 5419 GBC 33 : termPQExpBuffer(&buf);
1187 peter 5420 ECB :
2929 rhaas 5421 GIC 33 : if (line != NULL)
2929 rhaas 5422 EUB : {
2929 rhaas 5423 GBC 28 : fprintf(stderr, "%s\n", line);
2576 tgl 5424 28 : if (column >= 0)
1060 5425 21 : fprintf(stderr, "%*c error found here\n", column + 1, '^');
5426 : }
5427 :
2929 rhaas 5428 CBC 33 : exit(1);
5429 : }
5430 :
5431 : /*
1550 alvherre 5432 ECB : * Return a pointer to the start of the SQL command, after skipping over
5433 : * whitespace and "--" comments.
5434 : * If the end of the string is reached, return NULL.
2576 tgl 5435 : */
5436 : static char *
1550 alvherre 5437 GIC 1035 : skip_sql_comments(char *sql_command)
5438 : {
5439 1035 : char *p = sql_command;
5440 :
5441 : /* Skip any leading whitespace, as well as "--" style comments */
5442 : for (;;)
5443 : {
2576 tgl 5444 1035 : if (isspace((unsigned char) *p))
2576 tgl 5445 UIC 0 : p++;
2576 tgl 5446 CBC 1035 : else if (strncmp(p, "--", 2) == 0)
5447 : {
2576 tgl 5448 UIC 0 : p = strchr(p, '\n');
2576 tgl 5449 LBC 0 : if (p == NULL)
2576 tgl 5450 UIC 0 : return NULL;
2576 tgl 5451 LBC 0 : p++;
2576 tgl 5452 ECB : }
5453 : else
2576 tgl 5454 GIC 1035 : break;
2576 tgl 5455 ECB : }
5456 :
1550 alvherre 5457 : /* NULL if there's nothing but whitespace and comments */
2576 tgl 5458 CBC 1035 : if (*p == '\0')
5459 666 : return NULL;
2576 tgl 5460 ECB :
1550 alvherre 5461 CBC 369 : return p;
1550 alvherre 5462 ECB : }
5463 :
5464 : /*
5465 : * Parse a SQL command; return a Command struct, or NULL if it's a comment
5466 : *
5467 : * On entry, psqlscan.l has collected the command into "buf", so we don't
5468 : * really need to do much here except check for comments and set up a Command
5469 : * struct.
5470 : */
5471 : static Command *
1476 alvherre 5472 GIC 1035 : create_sql_command(PQExpBuffer buf, const char *source)
5473 : {
5474 : Command *my_command;
1550 alvherre 5475 CBC 1035 : char *p = skip_sql_comments(buf->data);
5476 :
5477 1035 : if (p == NULL)
5478 666 : return NULL;
1550 alvherre 5479 ECB :
2576 tgl 5480 : /* Allocate and initialize Command structure */
1550 alvherre 5481 CBC 369 : my_command = (Command *) pg_malloc(sizeof(Command));
1550 alvherre 5482 GIC 369 : initPQExpBuffer(&my_command->lines);
5483 369 : appendPQExpBufferStr(&my_command->lines, p);
5484 369 : my_command->first_line = NULL; /* this is set later */
2576 tgl 5485 369 : my_command->type = SQL_COMMAND;
1984 5486 369 : my_command->meta = META_NONE;
1550 alvherre 5487 CBC 369 : my_command->argc = 0;
382 ishii 5488 369 : my_command->retries = 0;
382 ishii 5489 GIC 369 : my_command->failures = 0;
1550 alvherre 5490 369 : memset(my_command->argv, 0, sizeof(my_command->argv));
5491 369 : my_command->varprefix = NULL; /* allocated later, if needed */
5492 369 : my_command->expr = NULL;
2576 tgl 5493 369 : initSimpleStats(&my_command->stats);
47 alvherre 5494 369 : my_command->prepname = NULL; /* set later, if needed */
2576 tgl 5495 ECB :
1550 alvherre 5496 GIC 369 : return my_command;
5497 : }
5498 :
5499 : /* Free a Command structure and associated data */
1550 alvherre 5500 ECB : static void
1550 alvherre 5501 GIC 28 : free_command(Command *command)
5502 : {
1550 alvherre 5503 CBC 28 : termPQExpBuffer(&command->lines);
296 peter 5504 GNC 28 : pg_free(command->first_line);
1550 alvherre 5505 GIC 58 : for (int i = 0; i < command->argc; i++)
5506 30 : pg_free(command->argv[i]);
296 peter 5507 GNC 28 : pg_free(command->varprefix);
1474 alvherre 5508 ECB :
2576 tgl 5509 : /*
1550 alvherre 5510 : * It should also free expr recursively, but this is currently not needed
1476 5511 : * as only gset commands (which do not have an expression) are freed.
2576 tgl 5512 : */
1550 alvherre 5513 CBC 28 : pg_free(command);
1550 alvherre 5514 GIC 28 : }
1550 alvherre 5515 ECB :
5516 : /*
5517 : * Once an SQL command is fully parsed, possibly by accumulating several
5518 : * parts, complete other fields of the Command structure.
1550 alvherre 5519 EUB : */
5520 : static void
1550 alvherre 5521 GIC 238 : postprocess_sql_command(Command *my_command)
1550 alvherre 5522 ECB : {
5523 : char buffer[128];
5524 : static int prepnum = 0;
5525 :
1550 alvherre 5526 GIC 238 : Assert(my_command->type == SQL_COMMAND);
5527 :
5528 : /* Save the first line for error display. */
5529 238 : strlcpy(buffer, my_command->lines.data, sizeof(buffer));
1550 alvherre 5530 CBC 238 : buffer[strcspn(buffer, "\n\r")] = '\0';
1550 alvherre 5531 GIC 238 : my_command->first_line = pg_strdup(buffer);
5532 :
5533 : /* Parse query and generate prepared statement name, if necessary */
5534 238 : switch (querymode)
5535 : {
5536 169 : case QUERY_SIMPLE:
5537 169 : my_command->argv[0] = my_command->lines.data;
5538 169 : my_command->argc++;
5539 169 : break;
1550 alvherre 5540 CBC 50 : case QUERY_PREPARED:
47 alvherre 5541 GIC 50 : my_command->prepname = psprintf("P_%d", prepnum++);
5542 : /* fall through */
47 alvherre 5543 CBC 69 : case QUERY_EXTENDED:
1550 5544 69 : if (!parseQuery(my_command))
1550 alvherre 5545 GIC 1 : exit(1);
5546 68 : break;
1550 alvherre 5547 LBC 0 : default:
1550 alvherre 5548 UIC 0 : exit(1);
2576 tgl 5549 EUB : }
1550 alvherre 5550 GBC 237 : }
5551 :
5552 : /*
5553 : * Parse a backslash command; return a Command struct, or NULL if comment
2576 tgl 5554 ECB : *
5555 : * At call, we have scanned only the initial backslash.
5556 : */
5557 : static Command *
2576 tgl 5558 GIC 467 : process_backslash_command(PsqlScanState sstate, const char *source)
5559 : {
2576 tgl 5560 ECB : Command *my_command;
5561 : PQExpBufferData word_buf;
5562 : int word_offset;
2118 5563 : int offsets[MAX_ARGS]; /* offsets of argument words */
5564 : int start_offset;
5565 : int lineno;
6396 ishii 5566 : int j;
5567 :
2576 tgl 5568 CBC 467 : initPQExpBuffer(&word_buf);
6396 ishii 5569 ECB :
2576 tgl 5570 : /* Remember location of the backslash */
2576 tgl 5571 GIC 467 : start_offset = expr_scanner_offset(sstate) - 1;
5572 467 : lineno = expr_scanner_get_lineno(sstate, start_offset);
5573 :
5574 : /* Collect first word of command */
2576 tgl 5575 CBC 467 : if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5576 : {
2576 tgl 5577 LBC 0 : termPQExpBuffer(&word_buf);
6396 ishii 5578 0 : return NULL;
5579 : }
5580 :
4623 tgl 5581 ECB : /* Allocate and initialize Command structure */
2576 tgl 5582 CBC 467 : my_command = (Command *) pg_malloc0(sizeof(Command));
5583 467 : my_command->type = META_COMMAND;
2576 tgl 5584 GIC 467 : my_command->argc = 0;
5585 467 : initSimpleStats(&my_command->stats);
5586 :
2576 tgl 5587 ECB : /* Save first word (command name) */
2576 tgl 5588 CBC 467 : j = 0;
2576 tgl 5589 GIC 467 : offsets[j] = word_offset;
2576 tgl 5590 CBC 467 : my_command->argv[j++] = pg_strdup(word_buf.data);
2576 tgl 5591 GIC 467 : my_command->argc++;
5592 :
1984 tgl 5593 EUB : /* ... and convert it to enum form */
1984 tgl 5594 GIC 467 : my_command->meta = getMetaCommand(my_command->argv[0]);
5595 :
1844 teodor 5596 CBC 467 : if (my_command->meta == META_SET ||
1844 teodor 5597 GIC 105 : my_command->meta == META_IF ||
5598 90 : my_command->meta == META_ELIF)
6396 ishii 5599 ECB : {
2576 tgl 5600 : yyscan_t yyscanner;
5601 :
5602 : /* For \set, collect var name */
1844 teodor 5603 GIC 385 : if (my_command->meta == META_SET)
5604 : {
1844 teodor 5605 CBC 362 : if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
1550 alvherre 5606 GIC 1 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
1844 teodor 5607 ECB : "missing argument", NULL, -1);
5608 :
1844 teodor 5609 CBC 361 : offsets[j] = word_offset;
1844 teodor 5610 GIC 361 : my_command->argv[j++] = pg_strdup(word_buf.data);
5611 361 : my_command->argc++;
5612 : }
6401 ishii 5613 ECB :
5614 : /* then for all parse the expression */
2576 tgl 5615 GIC 384 : yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
5616 384 : my_command->argv[0]);
5617 :
5618 384 : if (expr_yyparse(yyscanner) != 0)
6401 ishii 5619 ECB : {
2576 tgl 5620 : /* dead code: exit done from syntax_error called by yyerror */
2576 tgl 5621 UIC 0 : exit(1);
5622 : }
6385 bruce 5623 ECB :
2576 tgl 5624 CBC 365 : my_command->expr = expr_parse_result;
3175 rhaas 5625 ECB :
5626 : /* Save line, trimming any trailing newline */
1550 alvherre 5627 GIC 365 : my_command->first_line =
5628 365 : expr_scanner_get_substring(sstate,
1550 alvherre 5629 ECB : start_offset,
5630 : expr_scanner_offset(sstate),
5631 : true);
5632 :
2576 tgl 5633 GIC 365 : expr_scanner_finish(yyscanner);
5634 :
2576 tgl 5635 CBC 365 : termPQExpBuffer(&word_buf);
5636 :
5637 365 : return my_command;
2576 tgl 5638 ECB : }
5639 :
5640 : /* For all other commands, collect remaining words. */
2576 tgl 5641 CBC 373 : while (expr_lex_one_word(sstate, &word_buf, &word_offset))
2576 tgl 5642 ECB : {
5643 : /*
1490 andrew 5644 : * my_command->argv[0] is the command itself, so the max number of
5645 : * arguments is one less than MAX_ARGS
5646 : */
2576 tgl 5647 GIC 292 : if (j >= MAX_ARGS)
1550 alvherre 5648 1 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5649 : "too many arguments", NULL, -1);
5650 :
2576 tgl 5651 291 : offsets[j] = word_offset;
2576 tgl 5652 CBC 291 : my_command->argv[j++] = pg_strdup(word_buf.data);
2576 tgl 5653 GIC 291 : my_command->argc++;
2576 tgl 5654 ECB : }
2960 rhaas 5655 :
5656 : /* Save line, trimming any trailing newline */
1550 alvherre 5657 GIC 81 : my_command->first_line =
1550 alvherre 5658 CBC 81 : expr_scanner_get_substring(sstate,
1550 alvherre 5659 EUB : start_offset,
5660 : expr_scanner_offset(sstate),
5661 : true);
4997 tgl 5662 ECB :
1984 tgl 5663 CBC 81 : if (my_command->meta == META_SLEEP)
5664 : {
2576 tgl 5665 GIC 9 : if (my_command->argc < 2)
1550 alvherre 5666 CBC 1 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
2576 tgl 5667 ECB : "missing argument", NULL, -1);
5668 :
2576 tgl 5669 CBC 8 : if (my_command->argc > 3)
1550 alvherre 5670 GIC 1 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
2576 tgl 5671 ECB : "too many arguments", NULL,
2576 tgl 5672 GIC 1 : offsets[3] - start_offset);
2576 tgl 5673 ECB :
5674 : /*
5675 : * Split argument into number and unit to allow "sleep 1ms" etc. We
5676 : * don't have to terminate the number argument with null because it
5677 : * will be parsed with atoi, which ignores trailing non-digit
5678 : * characters.
5679 : */
748 fujii 5680 GIC 7 : if (my_command->argv[1][0] != ':')
5681 : {
2576 tgl 5682 4 : char *c = my_command->argv[1];
748 fujii 5683 GBC 4 : bool have_digit = false;
5684 :
748 fujii 5685 EUB : /* Skip sign */
748 fujii 5686 GIC 4 : if (*c == '+' || *c == '-')
748 fujii 5687 UIC 0 : c++;
5688 :
5689 : /* Require at least one digit */
748 fujii 5690 CBC 4 : if (*c && isdigit((unsigned char) *c))
748 fujii 5691 GIC 4 : have_digit = true;
2576 tgl 5692 ECB :
748 fujii 5693 : /* Eat all digits */
748 fujii 5694 CBC 10 : while (*c && isdigit((unsigned char) *c))
2576 tgl 5695 6 : c++;
5696 :
5697 4 : if (*c)
5698 : {
748 fujii 5699 GIC 1 : if (my_command->argc == 2 && have_digit)
748 fujii 5700 ECB : {
748 fujii 5701 GIC 1 : my_command->argv[2] = c;
748 fujii 5702 CBC 1 : offsets[2] = offsets[1] + (c - my_command->argv[1]);
5703 1 : my_command->argc = 3;
5704 : }
5705 : else
748 fujii 5706 ECB : {
5707 : /*
5708 : * Raise an error if argument starts with non-digit
5709 : * character (after sign).
5710 : */
748 fujii 5711 UIC 0 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
748 fujii 5712 ECB : "invalid sleep time, must be an integer",
748 fujii 5713 LBC 0 : my_command->argv[1], offsets[1] - start_offset);
748 fujii 5714 ECB : }
5715 : }
4863 itagaki.takahiro 5716 : }
2576 tgl 5717 :
2576 tgl 5718 GIC 7 : if (my_command->argc == 3)
5719 : {
2576 tgl 5720 CBC 9 : if (pg_strcasecmp(my_command->argv[2], "us") != 0 &&
2576 tgl 5721 GIC 6 : pg_strcasecmp(my_command->argv[2], "ms") != 0 &&
2576 tgl 5722 CBC 2 : pg_strcasecmp(my_command->argv[2], "s") != 0)
1550 alvherre 5723 1 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5724 : "unrecognized time unit, must be us, ms or s",
2576 tgl 5725 GIC 1 : my_command->argv[2], offsets[2] - start_offset);
5726 : }
5727 : }
1984 5728 72 : else if (my_command->meta == META_SETSHELL)
2576 tgl 5729 ECB : {
2576 tgl 5730 GIC 4 : if (my_command->argc < 3)
1550 alvherre 5731 1 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5732 : "missing argument", NULL, -1);
2576 tgl 5733 ECB : }
1984 tgl 5734 GIC 68 : else if (my_command->meta == META_SHELL)
2576 tgl 5735 ECB : {
2576 tgl 5736 GIC 4 : if (my_command->argc < 2)
1550 alvherre 5737 1 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5738 : "missing command", NULL, -1);
2576 tgl 5739 ECB : }
755 alvherre 5740 GIC 64 : else if (my_command->meta == META_ELSE || my_command->meta == META_ENDIF ||
755 alvherre 5741 CBC 44 : my_command->meta == META_STARTPIPELINE ||
755 alvherre 5742 GIC 38 : my_command->meta == META_ENDPIPELINE)
5743 : {
1844 teodor 5744 31 : if (my_command->argc != 1)
1550 alvherre 5745 2 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5746 : "unexpected argument", NULL, -1);
5747 : }
1101 michael 5748 33 : else if (my_command->meta == META_GSET || my_command->meta == META_ASET)
1550 alvherre 5749 ECB : {
1550 alvherre 5750 GIC 32 : if (my_command->argc > 2)
5751 1 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
1550 alvherre 5752 ECB : "too many arguments", NULL, -1);
5753 : }
5754 : else
6396 ishii 5755 : {
5756 : /* my_command->meta == META_NONE */
1550 alvherre 5757 CBC 1 : syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5758 : "invalid command", NULL, -1);
2576 tgl 5759 ECB : }
5760 :
2576 tgl 5761 CBC 72 : termPQExpBuffer(&word_buf);
5762 :
5763 72 : return my_command;
2576 tgl 5764 ECB : }
5765 :
1844 teodor 5766 : static void
1844 teodor 5767 CBC 6 : ConditionError(const char *desc, int cmdn, const char *msg)
1844 teodor 5768 ECB : {
366 tgl 5769 CBC 6 : pg_fatal("condition error in script \"%s\" command %d: %s",
366 tgl 5770 ECB : desc, cmdn, msg);
1844 teodor 5771 : }
5772 :
5773 : /*
5774 : * Partial evaluation of conditionals before recording and running the script.
5775 : */
5776 : static void
378 tgl 5777 CBC 227 : CheckConditional(const ParsedScript *ps)
1844 teodor 5778 ECB : {
5779 : /* statically check conditional structure */
1844 teodor 5780 CBC 227 : ConditionalStack cs = conditional_stack_create();
1809 tgl 5781 ECB : int i;
5782 :
378 tgl 5783 CBC 987 : for (i = 0; ps->commands[i] != NULL; i++)
5784 : {
5785 765 : Command *cmd = ps->commands[i];
5786 :
1844 teodor 5787 GIC 765 : if (cmd->type == META_COMMAND)
5788 : {
1844 teodor 5789 CBC 399 : switch (cmd->meta)
1844 teodor 5790 ECB : {
1809 tgl 5791 CBC 11 : case META_IF:
5792 11 : conditional_stack_push(cs, IFSTATE_FALSE);
1809 tgl 5793 GIC 11 : break;
5794 7 : case META_ELIF:
5795 7 : if (conditional_stack_empty(cs))
378 5796 1 : ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
1809 5797 6 : if (conditional_stack_peek(cs) == IFSTATE_ELSE_FALSE)
378 5798 1 : ConditionError(ps->desc, i + 1, "\\elif after \\else");
1809 tgl 5799 CBC 5 : break;
1809 tgl 5800 GIC 7 : case META_ELSE:
5801 7 : if (conditional_stack_empty(cs))
378 5802 1 : ConditionError(ps->desc, i + 1, "\\else without matching \\if");
1809 5803 6 : if (conditional_stack_peek(cs) == IFSTATE_ELSE_FALSE)
378 5804 1 : ConditionError(ps->desc, i + 1, "\\else after \\else");
1809 5805 5 : conditional_stack_poke(cs, IFSTATE_ELSE_FALSE);
5806 5 : break;
5807 9 : case META_ENDIF:
5808 9 : if (!conditional_stack_pop(cs))
378 5809 1 : ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
1809 tgl 5810 CBC 8 : break;
1809 tgl 5811 GIC 365 : default:
5812 : /* ignore anything else... */
1809 tgl 5813 CBC 365 : break;
1844 teodor 5814 ECB : }
5815 : }
5816 : }
1844 teodor 5817 GIC 222 : if (!conditional_stack_empty(cs))
378 tgl 5818 1 : ConditionError(ps->desc, i + 1, "\\if without matching \\endif");
1844 teodor 5819 CBC 221 : conditional_stack_destroy(cs);
1844 teodor 5820 GIC 221 : }
5821 :
5822 : /*
5823 : * Parse a script (either the contents of a file, or a built-in script)
5824 : * and add it to the list of scripts.
5825 : */
5826 : static void
2576 tgl 5827 262 : ParseScript(const char *script, const char *desc, int weight)
5828 : {
5829 : ParsedScript ps;
2576 tgl 5830 ECB : PsqlScanState sstate;
5831 : PQExpBufferData line_buf;
5832 : int alloc_num;
5833 : int index;
5834 : int lineno;
1550 alvherre 5835 : int start_offset;
5836 :
5837 : #define COMMANDS_ALLOC_NUM 128
2576 tgl 5838 CBC 262 : alloc_num = COMMANDS_ALLOC_NUM;
5839 :
5840 : /* Initialize all fields of ps */
5841 262 : ps.desc = desc;
2576 tgl 5842 GIC 262 : ps.weight = weight;
2576 tgl 5843 CBC 262 : ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
2288 5844 262 : initStats(&ps.stats, 0);
5845 :
2576 tgl 5846 ECB : /* Prepare to parse script */
2576 tgl 5847 GIC 262 : sstate = psql_scan_create(&pgbench_callbacks);
5848 :
2576 tgl 5849 ECB : /*
5850 : * Ideally, we'd scan scripts using the encoding and stdstrings settings
5851 : * we get from a DB connection. However, without major rearrangement of
5852 : * pgbench's argument parsing, we can't have a DB connection at the time
5853 : * we parse scripts. Using SQL_ASCII (encoding 0) should work well enough
5854 : * with any backend-safe encoding, though conceivably we could be fooled
5855 : * if a script file uses a client-only encoding. We also assume that
5856 : * stdstrings should be true, which is a bit riskier.
5857 : */
2576 tgl 5858 CBC 262 : psql_scan_setup(sstate, script, strlen(script), 0, true);
1550 alvherre 5859 GIC 262 : start_offset = expr_scanner_offset(sstate) - 1;
2576 tgl 5860 ECB :
2576 tgl 5861 GIC 262 : initPQExpBuffer(&line_buf);
5862 :
5863 262 : index = 0;
5864 :
5865 : for (;;)
2576 tgl 5866 CBC 773 : {
2576 tgl 5867 ECB : PsqlScanResult sr;
5868 : promptStatus_t prompt;
1550 alvherre 5869 GIC 1035 : Command *command = NULL;
2576 tgl 5870 ECB :
2576 tgl 5871 CBC 1035 : resetPQExpBuffer(&line_buf);
1550 alvherre 5872 GIC 1035 : lineno = expr_scanner_get_lineno(sstate, start_offset);
5873 :
2576 tgl 5874 1035 : sr = psql_scan(sstate, &line_buf, &prompt);
6396 ishii 5875 ECB :
5876 : /* If we collected a new SQL command, process that */
1476 alvherre 5877 CBC 1035 : command = create_sql_command(&line_buf, desc);
2576 tgl 5878 ECB :
1476 alvherre 5879 : /* store new command */
1476 alvherre 5880 GIC 1035 : if (command)
1476 alvherre 5881 CBC 369 : ps.commands[index++] = command;
5882 :
5883 : /* If we reached a backslash, process that */
2576 tgl 5884 1035 : if (sr == PSCAN_BACKSLASH)
2576 tgl 5885 ECB : {
2576 tgl 5886 GIC 467 : command = process_backslash_command(sstate, desc);
1550 alvherre 5887 ECB :
2576 tgl 5888 GIC 437 : if (command)
5889 : {
1550 alvherre 5890 ECB : /*
5891 : * If this is gset or aset, merge into the preceding command.
5892 : * (We don't use a command slot in this case).
5893 : */
1101 michael 5894 GIC 437 : if (command->meta == META_GSET || command->meta == META_ASET)
2576 tgl 5895 CBC 28 : {
5896 : Command *cmd;
5897 :
1550 alvherre 5898 GIC 31 : if (index == 0)
1550 alvherre 5899 CBC 1 : syntax_error(desc, lineno, NULL, NULL,
5900 : "\\gset must follow an SQL command",
5901 : NULL, -1);
5902 :
1550 alvherre 5903 GIC 30 : cmd = ps.commands[index - 1];
5904 :
1476 5905 30 : if (cmd->type != SQL_COMMAND ||
5906 29 : cmd->varprefix != NULL)
1550 5907 2 : syntax_error(desc, lineno, NULL, NULL,
667 drowley 5908 ECB : "\\gset must follow an SQL command",
1550 alvherre 5909 GIC 2 : cmd->first_line, -1);
1550 alvherre 5910 EUB :
5911 : /* get variable prefix */
1550 alvherre 5912 GBC 28 : if (command->argc <= 1 || command->argv[1][0] == '\0')
1476 alvherre 5913 GIC 26 : cmd->varprefix = pg_strdup("");
5914 : else
5915 2 : cmd->varprefix = pg_strdup(command->argv[1]);
1550 alvherre 5916 ECB :
5917 : /* update the sql command meta */
1101 michael 5918 GIC 28 : cmd->meta = command->meta;
5919 :
1550 alvherre 5920 ECB : /* cleanup unused command */
1550 alvherre 5921 GIC 28 : free_command(command);
1550 alvherre 5922 ECB :
1550 alvherre 5923 GIC 28 : continue;
2576 tgl 5924 ECB : }
1550 alvherre 5925 :
5926 : /* Attach any other backslash command as a new command */
1550 alvherre 5927 CBC 406 : ps.commands[index++] = command;
5928 : }
5929 : }
5930 :
5931 : /*
5932 : * Since we used a command slot, allocate more if needed. Note we
5933 : * always allocate one more in order to accommodate the NULL
5934 : * terminator below.
5935 : */
5936 974 : if (index >= alloc_num)
5937 : {
1550 alvherre 5938 UIC 0 : alloc_num += COMMANDS_ALLOC_NUM;
1550 alvherre 5939 LBC 0 : ps.commands = (Command **)
5940 0 : pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
5941 : }
1550 alvherre 5942 ECB :
5943 : /* Done if we reached EOF */
2576 tgl 5944 GIC 974 : if (sr == PSCAN_INCOMPLETE || sr == PSCAN_EOL)
2576 tgl 5945 EUB : break;
5946 : }
5947 :
2576 tgl 5948 CBC 229 : ps.commands[index] = NULL;
2576 tgl 5949 ECB :
378 tgl 5950 GIC 229 : addScript(&ps);
2576 tgl 5951 ECB :
2576 tgl 5952 CBC 221 : termPQExpBuffer(&line_buf);
2576 tgl 5953 GIC 221 : psql_scan_finish(sstate);
2576 tgl 5954 GBC 221 : psql_scan_destroy(sstate);
6396 ishii 5955 221 : }
5956 :
5957 : /*
2576 tgl 5958 ECB : * Read the entire contents of file fd, and return it in a malloc'd buffer.
5959 : *
3432 5960 : * The buffer will typically be larger than necessary, but we don't care
5961 : * in this program, because we'll free it as soon as we've parsed the script.
5962 : */
5963 : static char *
2576 tgl 5964 GIC 109 : read_file_contents(FILE *fd)
5965 : {
5966 : char *buf;
3432 5967 109 : size_t buflen = BUFSIZ;
5968 109 : size_t used = 0;
3432 tgl 5969 ECB :
2576 tgl 5970 GIC 109 : buf = (char *) pg_malloc(buflen);
5971 :
5972 : for (;;)
3432 tgl 5973 UIC 0 : {
5974 : size_t nread;
3432 tgl 5975 ECB :
2576 tgl 5976 GBC 109 : nread = fread(buf + used, 1, BUFSIZ, fd);
2576 tgl 5977 CBC 109 : used += nread;
2576 tgl 5978 ECB : /* If fread() read less than requested, must be EOF or error */
2576 tgl 5979 GIC 109 : if (nread < BUFSIZ)
3432 tgl 5980 CBC 109 : break;
5981 : /* Enlarge buf so we can read some more */
3432 tgl 5982 LBC 0 : buflen += BUFSIZ;
3432 tgl 5983 UBC 0 : buf = (char *) pg_realloc(buf, buflen);
5984 : }
2576 tgl 5985 ECB : /* There is surely room for a terminator */
2576 tgl 5986 CBC 109 : buf[used] = '\0';
5987 :
5988 109 : return buf;
5989 : }
3432 tgl 5990 ECB :
2577 alvherre 5991 : /*
5992 : * Given a file name, read it and add its script to the list.
5993 : * "-" means to read stdin.
5994 : * NB: filename must be storage that won't disappear.
5995 : */
5996 : static void
2576 tgl 5997 CBC 110 : process_file(const char *filename, int weight)
2577 alvherre 5998 ECB : {
5999 : FILE *fd;
6000 : char *buf;
6001 :
2576 tgl 6002 : /* Slurp the file contents into "buf" */
6396 ishii 6003 GIC 110 : if (strcmp(filename, "-") == 0)
6396 ishii 6004 UIC 0 : fd = stdin;
6396 ishii 6005 GIC 110 : else if ((fd = fopen(filename, "r")) == NULL)
366 tgl 6006 CBC 1 : pg_fatal("could not open file \"%s\": %m", filename);
6401 ishii 6007 ECB :
2576 tgl 6008 CBC 109 : buf = read_file_contents(fd);
2577 alvherre 6009 ECB :
2576 tgl 6010 CBC 109 : if (ferror(fd))
366 tgl 6011 UIC 0 : pg_fatal("could not read file \"%s\": %m", filename);
6012 :
2576 tgl 6013 GIC 109 : if (fd != stdin)
2576 tgl 6014 CBC 109 : fclose(fd);
6015 :
2576 tgl 6016 GIC 109 : ParseScript(buf, filename, weight);
2576 tgl 6017 ECB :
2576 tgl 6018 CBC 69 : free(buf);
6396 ishii 6019 69 : }
6020 :
2576 tgl 6021 ECB : /* Parse the given builtin script and add it to the list. */
6022 : static void
2576 tgl 6023 CBC 153 : process_builtin(const BuiltinScript *bi, int weight)
6024 : {
6025 153 : ParseScript(bi->script, bi->desc, weight);
6401 ishii 6026 152 : }
6027 :
6028 : /* show available builtin scripts */
6029 : static void
2629 alvherre 6030 GIC 3 : listAvailableScripts(void)
2629 alvherre 6031 ECB : {
2627 6032 : int i;
6033 :
2629 alvherre 6034 GIC 3 : fprintf(stderr, "Available builtin scripts:\n");
2577 alvherre 6035 CBC 12 : for (i = 0; i < lengthof(builtin_script); i++)
1363 tmunro 6036 9 : fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
2629 alvherre 6037 GIC 3 : fprintf(stderr, "\n");
2629 alvherre 6038 CBC 3 : }
6039 :
2576 tgl 6040 ECB : /* return builtin script "name" if unambiguous, fails if not found */
6041 : static const BuiltinScript *
2577 alvherre 6042 GIC 156 : findBuiltin(const char *name)
6043 : {
6044 : int i,
2593 6045 156 : found = 0,
6046 156 : len = strlen(name);
2576 tgl 6047 156 : const BuiltinScript *result = NULL;
6048 :
2577 alvherre 6049 624 : for (i = 0; i < lengthof(builtin_script); i++)
2629 alvherre 6050 ECB : {
2593 alvherre 6051 GIC 468 : if (strncmp(builtin_script[i].name, name, len) == 0)
6052 : {
2577 6053 156 : result = &builtin_script[i];
2593 6054 156 : found++;
2629 alvherre 6055 ECB : }
6056 : }
6057 :
6058 : /* ok, unambiguous result */
2593 alvherre 6059 GIC 156 : if (found == 1)
2577 6060 154 : return result;
6061 :
2593 alvherre 6062 ECB : /* error cases */
2593 alvherre 6063 CBC 2 : if (found == 0)
366 tgl 6064 1 : pg_log_error("no builtin script found for name \"%s\"", name);
6065 : else /* found > 1 */
366 tgl 6066 GIC 1 : pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
2593 alvherre 6067 ECB :
2629 alvherre 6068 CBC 2 : listAvailableScripts();
6069 2 : exit(1);
2629 alvherre 6070 ECB : }
6071 :
2577 6072 : /*
6073 : * Determine the weight specification from a script option (-b, -f), if any,
6074 : * and return it as an integer (1 is returned if there's no weight). The
6075 : * script name is returned in *script as a malloc'd string.
6076 : */
6077 : static int
2577 alvherre 6078 CBC 121 : parseScriptWeight(const char *option, char **script)
2577 alvherre 6079 ECB : {
6080 : char *sep;
6081 : int weight;
6082 :
2577 alvherre 6083 GIC 121 : if ((sep = strrchr(option, WSEP)))
6084 : {
6085 7 : int namelen = sep - option;
6086 : long wtmp;
2577 alvherre 6087 ECB : char *badp;
6088 :
6089 : /* generate the script name */
2577 alvherre 6090 CBC 7 : *script = pg_malloc(namelen + 1);
2577 alvherre 6091 GIC 7 : strncpy(*script, option, namelen);
2577 alvherre 6092 CBC 7 : (*script)[namelen] = '\0';
2577 alvherre 6093 ECB :
6094 : /* process digits of the weight spec */
2577 alvherre 6095 CBC 7 : errno = 0;
2577 alvherre 6096 GIC 7 : wtmp = strtol(sep + 1, &badp, 10);
2577 alvherre 6097 CBC 7 : if (errno != 0 || badp == sep + 1 || *badp != '\0')
366 tgl 6098 1 : pg_fatal("invalid weight specification: %s", sep);
2567 alvherre 6099 6 : if (wtmp > INT_MAX || wtmp < 0)
366 tgl 6100 GIC 1 : pg_fatal("weight specification out of range (0 .. %d): %lld",
6101 : INT_MAX, (long long) wtmp);
2577 alvherre 6102 5 : weight = wtmp;
6103 : }
6104 : else
6105 : {
6106 114 : *script = pg_strdup(option);
6107 114 : weight = 1;
2577 alvherre 6108 EUB : }
6109 :
2577 alvherre 6110 GIC 119 : return weight;
6111 : }
2577 alvherre 6112 EUB :
6113 : /* append a script to the list of scripts to process */
6114 : static void
378 tgl 6115 GIC 229 : addScript(const ParsedScript *script)
6116 : {
6117 229 : if (script->commands == NULL || script->commands[0] == NULL)
366 6118 1 : pg_fatal("empty command list for script \"%s\"", script->desc);
6119 :
2629 alvherre 6120 228 : if (num_scripts >= MAX_SCRIPTS)
366 tgl 6121 1 : pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6122 :
1844 teodor 6123 227 : CheckConditional(script);
6124 :
378 tgl 6125 221 : sql_script[num_scripts] = *script;
2629 alvherre 6126 221 : num_scripts++;
6127 221 : }
6128 :
6129 : /*
6130 : * Print progress report.
6131 : *
6132 : * On entry, *last and *last_report contain the statistics and time of last
6133 : * progress report. On exit, they are updated with the new stats.
6134 : */
1476 heikki.linnakangas 6135 EUB : static void
760 tmunro 6136 UBC 0 : printProgressReport(TState *threads, int64 test_start, pg_time_usec_t now,
6137 : StatsData *last, int64 *last_report)
1476 heikki.linnakangas 6138 EUB : {
6139 : /* generate and show report */
760 tmunro 6140 UBC 0 : pg_time_usec_t run = now - *last_report;
382 ishii 6141 EUB : int64 cnt,
6142 : failures,
6143 : retried;
1476 heikki.linnakangas 6144 : double tps,
6145 : total_run,
6146 : latency,
6147 : sqlat,
6148 : lag,
6149 : stdev;
6150 : char tbuf[315];
6151 : StatsData cur;
6152 :
6153 : /*
6154 : * Add up the statistics of all threads.
6155 : *
6156 : * XXX: No locking. There is no guarantee that we get an atomic snapshot
6157 : * of the transaction count and latencies, so these figures can well be
6158 : * off by a small amount. The progress report's purpose is to give a
6159 : * quick overview of how the test is going, so that shouldn't matter too
6160 : * much. (If a read from a 64-bit integer is not atomic, you might get a
6161 : * "torn" read and completely bogus latencies though!)
6162 : */
1476 heikki.linnakangas 6163 UIC 0 : initStats(&cur, 0);
1476 heikki.linnakangas 6164 UBC 0 : for (int i = 0; i < nthreads; i++)
1476 heikki.linnakangas 6165 EUB : {
1467 tgl 6166 UIC 0 : mergeSimpleStats(&cur.latency, &threads[i].stats.latency);
1467 tgl 6167 UBC 0 : mergeSimpleStats(&cur.lag, &threads[i].stats.lag);
1467 tgl 6168 UIC 0 : cur.cnt += threads[i].stats.cnt;
1467 tgl 6169 UBC 0 : cur.skipped += threads[i].stats.skipped;
382 ishii 6170 0 : cur.retries += threads[i].stats.retries;
382 ishii 6171 UIC 0 : cur.retried += threads[i].stats.retried;
6172 0 : cur.serialization_failures +=
6173 0 : threads[i].stats.serialization_failures;
6174 0 : cur.deadlock_failures += threads[i].stats.deadlock_failures;
1476 heikki.linnakangas 6175 EUB : }
6176 :
6177 : /* we count only actually executed transactions */
382 ishii 6178 UBC 0 : cnt = cur.cnt - last->cnt;
1476 heikki.linnakangas 6179 UIC 0 : total_run = (now - test_start) / 1000000.0;
382 ishii 6180 0 : tps = 1000000.0 * cnt / run;
6181 0 : if (cnt > 0)
1476 heikki.linnakangas 6182 EUB : {
382 ishii 6183 UIC 0 : latency = 0.001 * (cur.latency.sum - last->latency.sum) / cnt;
382 ishii 6184 UBC 0 : sqlat = 1.0 * (cur.latency.sum2 - last->latency.sum2) / cnt;
1476 heikki.linnakangas 6185 0 : stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
382 ishii 6186 0 : lag = 0.001 * (cur.lag.sum - last->lag.sum) / cnt;
1476 heikki.linnakangas 6187 EUB : }
6188 : else
6189 : {
1476 heikki.linnakangas 6190 UIC 0 : latency = sqlat = stdev = lag = 0;
1476 heikki.linnakangas 6191 EUB : }
382 ishii 6192 UBC 0 : failures = getFailures(&cur) - getFailures(last);
382 ishii 6193 UIC 0 : retried = cur.retried - last->retried;
1476 heikki.linnakangas 6194 EUB :
1476 heikki.linnakangas 6195 UBC 0 : if (progress_timestamp)
6196 : {
637 tmunro 6197 0 : snprintf(tbuf, sizeof(tbuf), "%.3f s",
6198 0 : PG_TIME_GET_DOUBLE(now + epoch_shift));
1476 heikki.linnakangas 6199 EUB : }
6200 : else
6201 : {
1476 heikki.linnakangas 6202 ECB : /* round seconds are expected, but the thread may be late */
1476 heikki.linnakangas 6203 UIC 0 : snprintf(tbuf, sizeof(tbuf), "%.1f s", total_run);
1476 heikki.linnakangas 6204 ECB : }
6205 :
1476 heikki.linnakangas 6206 LBC 0 : fprintf(stderr,
382 ishii 6207 ECB : "progress: %s, %.1f tps, lat %.3f ms stddev %.3f, " INT64_FORMAT " failed",
6208 : tbuf, tps, latency, stdev, failures);
1476 heikki.linnakangas 6209 :
1476 heikki.linnakangas 6210 LBC 0 : if (throttle_delay)
6211 : {
6212 0 : fprintf(stderr, ", lag %.3f ms", lag);
1476 heikki.linnakangas 6213 UIC 0 : if (latency_limit)
6214 0 : fprintf(stderr, ", " INT64_FORMAT " skipped",
6215 0 : cur.skipped - last->skipped);
1476 heikki.linnakangas 6216 ECB : }
6217 :
382 ishii 6218 : /* it can be non-zero only if max_tries is not equal to one */
382 ishii 6219 LBC 0 : if (max_tries != 1)
382 ishii 6220 UIC 0 : fprintf(stderr,
382 ishii 6221 ECB : ", " INT64_FORMAT " retried, " INT64_FORMAT " retries",
382 ishii 6222 UIC 0 : retried, cur.retries - last->retries);
1476 heikki.linnakangas 6223 0 : fprintf(stderr, "\n");
6224 :
6225 0 : *last = cur;
6226 0 : *last_report = now;
1476 heikki.linnakangas 6227 UBC 0 : }
6228 :
2627 alvherre 6229 EUB : static void
1986 peter_e 6230 GIC 11 : printSimpleStats(const char *prefix, SimpleStats *ss)
2627 alvherre 6231 EUB : {
1965 tgl 6232 GIC 11 : if (ss->count > 0)
1965 tgl 6233 EUB : {
1965 tgl 6234 GIC 11 : double latency = ss->sum / ss->count;
6235 11 : double stddev = sqrt(ss->sum2 / ss->count - latency * latency);
2627 alvherre 6236 EUB :
1965 tgl 6237 GIC 11 : printf("%s average = %.3f ms\n", prefix, 0.001 * latency);
6238 11 : printf("%s stddev = %.3f ms\n", prefix, 0.001 * stddev);
6239 : }
2627 alvherre 6240 11 : }
2627 alvherre 6241 ECB :
660 tgl 6242 : /* print version banner */
6243 : static void
660 tgl 6244 GIC 69 : printVersion(PGconn *con)
6245 : {
6246 69 : int server_ver = PQserverVersion(con);
660 tgl 6247 CBC 69 : int client_ver = PG_VERSION_NUM;
6248 :
660 tgl 6249 GIC 69 : if (server_ver != client_ver)
6250 : {
6251 : const char *server_version;
6252 : char sverbuf[32];
6253 :
660 tgl 6254 ECB : /* Try to get full text form, might include "devel" etc */
660 tgl 6255 LBC 0 : server_version = PQparameterStatus(con, "server_version");
660 tgl 6256 ECB : /* Otherwise fall back on server_ver */
660 tgl 6257 LBC 0 : if (!server_version)
6258 : {
660 tgl 6259 UIC 0 : formatPGVersionNumber(server_ver, true,
660 tgl 6260 ECB : sverbuf, sizeof(sverbuf));
660 tgl 6261 UIC 0 : server_version = sverbuf;
660 tgl 6262 ECB : }
6263 :
660 tgl 6264 LBC 0 : printf(_("%s (%s, server %s)\n"),
660 tgl 6265 ECB : "pgbench", PG_VERSION, server_version);
6266 : }
6267 : /* For version match, only print pgbench version */
6268 : else
660 tgl 6269 CBC 69 : printf("%s (%s)\n", "pgbench", PG_VERSION);
660 tgl 6270 GIC 69 : fflush(stdout);
660 tgl 6271 CBC 69 : }
660 tgl 6272 ECB :
6273 : /* print out results */
8397 bruce 6274 : static void
760 tmunro 6275 GIC 68 : printResults(StatsData *total,
760 tmunro 6276 ECB : pg_time_usec_t total_duration, /* benchmarking time */
6277 : pg_time_usec_t conn_total_duration, /* is_connect */
6278 : pg_time_usec_t conn_elapsed_duration, /* !is_connect */
6279 : int64 latency_late)
6280 : {
6281 : /* tps is about actually executed transactions during benchmarking */
382 ishii 6282 GBC 68 : int64 failures = getFailures(total);
6283 68 : int64 total_cnt = total->cnt + total->skipped + failures;
760 tmunro 6284 GIC 68 : double bench_duration = PG_TIME_GET_DOUBLE(total_duration);
382 ishii 6285 68 : double tps = total->cnt / bench_duration;
6286 :
2391 heikki.linnakangas 6287 ECB : /* Report test parameters. */
2629 alvherre 6288 GIC 68 : printf("transaction type: %s\n",
6289 : num_scripts == 1 ? sql_script[0].desc : "multiple scripts");
6052 ishii 6290 CBC 68 : printf("scaling factor: %d\n", scale);
6291 : /* only print partitioning information if some partitioning was detected */
1286 akapila 6292 GBC 68 : if (partition_method != PART_NONE)
1286 akapila 6293 GIC 6 : printf("partition method: %s\npartitions: %d\n",
6294 : PARTITION_METHOD[partition_method], partitions);
5499 ishii 6295 GBC 68 : printf("query mode: %s\n", QUERYMODE[querymode]);
8397 bruce 6296 GIC 68 : printf("number of clients: %d\n", nclients);
4997 ishii 6297 68 : printf("number of threads: %d\n", nthreads);
6298 :
382 6299 68 : if (max_tries)
354 peter 6300 68 : printf("maximum number of tries: %u\n", max_tries);
382 ishii 6301 ECB :
5323 tgl 6302 GIC 68 : if (duration <= 0)
5323 tgl 6303 ECB : {
5323 tgl 6304 GIC 68 : printf("number of transactions per client: %d\n", nxacts);
2627 alvherre 6305 CBC 68 : printf("number of transactions actually processed: " INT64_FORMAT "/%d\n",
6306 : total->cnt, nxacts * nclients);
6307 : }
6308 : else
5323 tgl 6309 ECB : {
5323 tgl 6310 LBC 0 : printf("duration: %d s\n", duration);
3241 tgl 6311 UIC 0 : printf("number of transactions actually processed: " INT64_FORMAT "\n",
382 ishii 6312 ECB : total->cnt);
6313 : }
6314 :
382 ishii 6315 GIC 68 : printf("number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
382 ishii 6316 ECB : failures, 100.0 * failures / total_cnt);
6317 :
382 ishii 6318 GIC 68 : if (failures_detailed)
6319 : {
382 ishii 6320 UIC 0 : printf("number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
382 ishii 6321 ECB : total->serialization_failures,
6322 : 100.0 * total->serialization_failures / total_cnt);
382 ishii 6323 UIC 0 : printf("number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6324 : total->deadlock_failures,
6325 : 100.0 * total->deadlock_failures / total_cnt);
382 ishii 6326 ECB : }
6327 :
6328 : /* it can be non-zero only if max_tries is not equal to one */
382 ishii 6329 GIC 68 : if (max_tries != 1)
6330 : {
382 ishii 6331 CBC 2 : printf("number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6332 : total->retried, 100.0 * total->retried / total_cnt);
382 ishii 6333 GIC 2 : printf("total number of retries: " INT64_FORMAT "\n", total->retries);
6334 : }
6335 :
6336 : /* Remaining stats are nonsensical if we failed to execute any xacts */
6337 68 : if (total->cnt + total->skipped <= 0)
3036 tgl 6338 43 : return;
3036 tgl 6339 ECB :
3100 heikki.linnakangas 6340 GIC 25 : if (throttle_delay && latency_limit)
403 ishii 6341 2 : printf("number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6342 : total->skipped, 100.0 * total->skipped / total_cnt);
6343 :
3100 heikki.linnakangas 6344 25 : if (latency_limit)
403 ishii 6345 2 : printf("number of transactions above the %.1f ms latency limit: " INT64_FORMAT "/" INT64_FORMAT " (%.3f%%)\n",
6346 : latency_limit / 1000.0, latency_late, total->cnt,
6347 : (total->cnt > 0) ? 100.0 * latency_late / total->cnt : 0.0);
6348 :
3100 heikki.linnakangas 6349 25 : if (throttle_delay || progress || latency_limit)
2627 alvherre 6350 2 : printSimpleStats("latency", &total->latency);
6351 : else
2391 heikki.linnakangas 6352 ECB : {
6353 : /* no measurement, show average latency computed from run time */
382 ishii 6354 CBC 23 : printf("latency average = %.3f ms%s\n",
382 ishii 6355 ECB : 0.001 * total_duration * nclients / total_cnt,
6356 : failures > 0 ? " (including failures)" : "");
6357 : }
6358 :
3547 ishii 6359 CBC 25 : if (throttle_delay)
3547 ishii 6360 ECB : {
6361 : /*
6362 : * Report average transaction lag under rate limit throttling. This
6363 : * is the delay between scheduled and actual start times for the
6364 : * transaction. The measured lag may be caused by thread/client load,
6365 : * the database load, or the Poisson throttling process.
6366 : */
3473 noah 6367 GIC 2 : printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
2627 alvherre 6368 ECB : 0.001 * total->lag.sum / total->cnt, 0.001 * total->lag.max);
6369 : }
3547 ishii 6370 :
6371 : /*
760 tmunro 6372 : * Under -C/--connect, each transaction incurs a significant connection
6373 : * cost, it would not make much sense to ignore it in tps, and it would
6374 : * not be tps anyway.
6375 : *
6376 : * Otherwise connections are made just once at the beginning of the run
6377 : * and should not impact performance but for very short run, so they are
6378 : * (right)fully ignored in tps.
6379 : */
760 tmunro 6380 GIC 25 : if (is_connect)
6381 : {
382 ishii 6382 2 : printf("average connection time = %.3f ms\n", 0.001 * conn_total_duration / (total->cnt + failures));
760 tmunro 6383 2 : printf("tps = %f (including reconnection times)\n", tps);
6384 : }
6385 : else
6386 : {
760 tmunro 6387 CBC 23 : printf("initial connection time = %.3f ms\n", 0.001 * conn_elapsed_duration);
760 tmunro 6388 GIC 23 : printf("tps = %f (without initial connection time)\n", tps);
6389 : }
6390 :
2577 alvherre 6391 ECB : /* Report per-script/command statistics */
1600 alvherre 6392 GIC 25 : if (per_script_stats || report_per_command)
4623 tgl 6393 EUB : {
6394 : int i;
6395 :
2629 alvherre 6396 GIC 16 : for (i = 0; i < num_scripts; i++)
4623 tgl 6397 EUB : {
1965 tgl 6398 GIC 11 : if (per_script_stats)
6399 : {
6400 9 : StatsData *sstats = &sql_script[i].stats;
382 ishii 6401 9 : int64 script_failures = getFailures(sstats);
6402 9 : int64 script_total_cnt =
332 tgl 6403 9 : sstats->cnt + sstats->skipped + script_failures;
1965 tgl 6404 ECB :
2577 alvherre 6405 GIC 9 : printf("SQL script %d: %s\n"
2391 heikki.linnakangas 6406 EUB : " - weight: %d (targets %.1f%% of total)\n"
6407 : " - " INT64_FORMAT " transactions (%.1f%% of total, tps = %f)\n",
6408 : i + 1, sql_script[i].desc,
2577 alvherre 6409 : sql_script[i].weight,
6410 : 100.0 * sql_script[i].weight / total_weight,
6411 : sstats->cnt,
6412 : 100.0 * sstats->cnt / total->cnt,
382 ishii 6413 ECB : sstats->cnt / bench_duration);
382 ishii 6414 EUB :
382 ishii 6415 GIC 9 : printf(" - number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6416 : script_failures,
6417 : 100.0 * script_failures / script_total_cnt);
382 ishii 6418 ECB :
382 ishii 6419 GIC 9 : if (failures_detailed)
6420 : {
382 ishii 6421 UIC 0 : printf(" - number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6422 : sstats->serialization_failures,
6423 : (100.0 * sstats->serialization_failures /
6424 : script_total_cnt));
382 ishii 6425 LBC 0 : printf(" - number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6426 : sstats->deadlock_failures,
6427 : (100.0 * sstats->deadlock_failures /
6428 : script_total_cnt));
382 ishii 6429 ECB : }
6430 :
6431 : /* it can be non-zero only if max_tries is not equal to one */
382 ishii 6432 GIC 9 : if (max_tries != 1)
6433 : {
382 ishii 6434 UIC 0 : printf(" - number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
382 ishii 6435 ECB : sstats->retried,
6436 : 100.0 * sstats->retried / script_total_cnt);
382 ishii 6437 LBC 0 : printf(" - total number of retries: " INT64_FORMAT "\n",
6438 : sstats->retries);
382 ishii 6439 ECB : }
6440 :
382 ishii 6441 CBC 9 : if (throttle_delay && latency_limit && script_total_cnt > 0)
1965 tgl 6442 LBC 0 : printf(" - number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6443 : sstats->skipped,
6444 : 100.0 * sstats->skipped / script_total_cnt);
6445 :
1965 tgl 6446 GIC 9 : printSimpleStats(" - latency", &sstats->latency);
6447 : }
2624 alvherre 6448 EUB :
6449 : /*
6450 : * Report per-command statistics: latencies, retries after errors,
6451 : * failures (errors without retrying).
6452 : */
1600 alvherre 6453 GIC 11 : if (report_per_command)
6454 : {
6455 : Command **commands;
6456 :
382 ishii 6457 2 : printf("%sstatement latencies in milliseconds%s:\n",
6458 : per_script_stats ? " - " : "",
6459 : (max_tries == 1 ?
6460 : " and failures" :
6461 : ", failures and retries"));
6462 :
2624 alvherre 6463 2 : for (commands = sql_script[i].commands;
6464 5 : *commands != NULL;
2624 alvherre 6465 CBC 3 : commands++)
6466 : {
1965 tgl 6467 GIC 3 : SimpleStats *cstats = &(*commands)->stats;
6468 :
382 ishii 6469 CBC 3 : if (max_tries == 1)
382 ishii 6470 GIC 3 : printf(" %11.3f %10" INT64_MODIFIER "d %s\n",
6471 : (cstats->count > 0) ?
382 ishii 6472 ECB : 1000.0 * cstats->sum / cstats->count : 0.0,
6473 : (*commands)->failures,
6474 : (*commands)->first_line);
6475 : else
382 ishii 6476 UIC 0 : printf(" %11.3f %10" INT64_MODIFIER "d %10" INT64_MODIFIER "d %s\n",
382 ishii 6477 EUB : (cstats->count > 0) ?
6478 : 1000.0 * cstats->sum / cstats->count : 0.0,
6479 : (*commands)->failures,
6480 : (*commands)->retries,
6481 : (*commands)->first_line);
6482 : }
6483 : }
6484 : }
6485 : }
6486 : }
6487 :
6488 : /*
6489 : * Set up a random seed according to seed parameter (NULL means default),
1536 tgl 6490 ECB : * and initialize base_random_sequence for use in initializing other sequences.
6491 : */
1835 6492 : static bool
1835 tgl 6493 CBC 161 : set_random_seed(const char *seed)
1840 teodor 6494 ECB : {
6495 : uint64 iseed;
6496 :
1840 teodor 6497 GIC 161 : if (seed == NULL || strcmp(seed, "time") == 0)
6498 : {
1840 teodor 6499 ECB : /* rely on current time */
760 tmunro 6500 CBC 157 : iseed = pg_time_now();
6501 : }
1840 teodor 6502 4 : else if (strcmp(seed, "rand") == 0)
6503 : {
6504 : /* use some "strong" random source */
1840 teodor 6505 LBC 0 : if (!pg_strong_random(&iseed, sizeof(iseed)))
6506 : {
1187 peter 6507 0 : pg_log_error("could not generate random seed");
1835 tgl 6508 UIC 0 : return false;
6509 : }
6510 : }
1840 teodor 6511 ECB : else
6512 : {
6513 : /* parse unsigned-int seed value */
6514 : unsigned long ulseed;
6515 : char garbage;
6516 :
6517 : /* Don't try to use UINT64_FORMAT here; it might not work for sscanf */
1453 tgl 6518 GIC 4 : if (sscanf(seed, "%lu%c", &ulseed, &garbage) != 1)
6519 : {
1187 peter 6520 1 : pg_log_error("unrecognized random seed option \"%s\"", seed);
366 tgl 6521 1 : pg_log_error_detail("Expecting an unsigned integer, \"time\" or \"rand\".");
1835 6522 1 : return false;
6523 : }
1453 6524 3 : iseed = (uint64) ulseed;
6525 : }
6526 :
1840 teodor 6527 160 : if (seed != NULL)
716 michael 6528 3 : pg_log_info("setting random seed to %llu", (unsigned long long) iseed);
6529 :
1840 teodor 6530 160 : random_seed = iseed;
6531 :
6532 : /* Initialize base_random_sequence using seed */
497 tgl 6533 160 : pg_prng_seed(&base_random_sequence, (uint64) iseed);
6534 :
1835 6535 160 : return true;
6536 : }
6537 :
6538 : int
8397 bruce 6539 159 : main(int argc, char **argv)
6540 : {
6541 : static struct option long_options[] = {
6542 : /* systematic long/short named options */
6543 : {"builtin", required_argument, NULL, 'b'},
6544 : {"client", required_argument, NULL, 'c'},
6545 : {"connect", no_argument, NULL, 'C'},
6546 : {"debug", no_argument, NULL, 'd'},
6547 : {"define", required_argument, NULL, 'D'},
6548 : {"file", required_argument, NULL, 'f'},
6549 : {"fillfactor", required_argument, NULL, 'F'},
6550 : {"host", required_argument, NULL, 'h'},
6551 : {"initialize", no_argument, NULL, 'i'},
6552 : {"init-steps", required_argument, NULL, 'I'},
6553 : {"jobs", required_argument, NULL, 'j'},
6554 : {"log", no_argument, NULL, 'l'},
6555 : {"latency-limit", required_argument, NULL, 'L'},
6556 : {"no-vacuum", no_argument, NULL, 'n'},
6557 : {"port", required_argument, NULL, 'p'},
6558 : {"progress", required_argument, NULL, 'P'},
6559 : {"protocol", required_argument, NULL, 'M'},
6560 : {"quiet", no_argument, NULL, 'q'},
6561 : {"report-per-command", no_argument, NULL, 'r'},
2629 alvherre 6562 ECB : {"rate", required_argument, NULL, 'R'},
3573 rhaas 6563 : {"scale", required_argument, NULL, 's'},
6564 : {"select-only", no_argument, NULL, 'S'},
6565 : {"skip-some-updates", no_argument, NULL, 'N'},
6566 : {"time", required_argument, NULL, 'T'},
6567 : {"transactions", required_argument, NULL, 't'},
6568 : {"username", required_argument, NULL, 'U'},
6569 : {"vacuum-all", no_argument, NULL, 'v'},
6570 : /* long-named only options */
1973 tgl 6571 : {"unlogged-tables", no_argument, NULL, 1},
3782 bruce 6572 : {"tablespace", required_argument, NULL, 2},
6573 : {"index-tablespace", required_argument, NULL, 3},
6574 : {"sampling-rate", required_argument, NULL, 4},
6575 : {"aggregate-interval", required_argument, NULL, 5},
6576 : {"progress-timestamp", no_argument, NULL, 6},
6577 : {"log-prefix", required_argument, NULL, 7},
6578 : {"foreign-keys", no_argument, NULL, 8},
1840 teodor 6579 : {"random-seed", required_argument, NULL, 9},
6580 : {"show-script", required_argument, NULL, 10},
6581 : {"partitions", required_argument, NULL, 11},
1286 akapila 6582 : {"partition-method", required_argument, NULL, 12},
6583 : {"failures-detailed", no_argument, NULL, 13},
6584 : {"max-tries", required_argument, NULL, 14},
6585 : {"verbose-errors", no_argument, NULL, 15},
6586 : {NULL, 0, NULL, 0}
6587 : };
6588 :
6589 : int c;
1973 tgl 6590 GIC 159 : bool is_init_mode = false; /* initialize mode? */
6591 159 : char *initialize_steps = NULL;
6592 159 : bool foreign_keys = false;
6593 159 : bool is_no_vacuum = false;
6594 159 : bool do_vacuum_accounts = false; /* vacuum accounts table? */
6595 : int optindex;
5448 tgl 6596 CBC 159 : bool scale_given = false;
6597 :
3162 ishii 6598 GIC 159 : bool benchmarking_option_set = false;
6599 159 : bool initialization_option_set = false;
2629 alvherre 6600 159 : bool internal_script_used = false;
6601 :
6602 : CState *state; /* status of clients */
4997 ishii 6603 ECB : TState *threads; /* array of thread */
8397 bruce 6604 :
6605 : pg_time_usec_t
760 tmunro 6606 : start_time, /* start up time */
760 tmunro 6607 CBC 159 : bench_start = 0, /* first recorded benchmarking time */
6608 : conn_total_duration; /* cumulated connection time in
760 tmunro 6609 ECB : * threads */
3100 heikki.linnakangas 6610 GIC 159 : int64 latency_late = 0;
2627 alvherre 6611 ECB : StatsData stats;
6612 : int weight;
8397 bruce 6613 :
6614 : int i;
6615 : int nclients_dealt;
6616 :
6617 : #ifdef HAVE_GETRLIMIT
6618 : struct rlimit rlim;
8485 ishii 6619 : #endif
6620 :
6621 : PGconn *con;
6622 : char *env;
7243 6623 :
1643 peter_e 6624 GIC 159 : int exit_code = 0;
6625 : struct timeval tv;
637 tmunro 6626 ECB :
637 tmunro 6627 EUB : /*
6628 : * Record difference between Unix time and instr_time time. We'll use
637 tmunro 6629 ECB : * this for logging and aggregation.
6630 : */
637 tmunro 6631 GIC 159 : gettimeofday(&tv, NULL);
6632 159 : epoch_shift = tv.tv_sec * INT64CONST(1000000) + tv.tv_usec - pg_time_now();
1643 peter_e 6633 ECB :
1469 peter 6634 GIC 159 : pg_logging_init(argv[0]);
5154 peter_e 6635 CBC 159 : progname = get_progname(argv[0]);
5154 peter_e 6636 ECB :
5154 peter_e 6637 GIC 159 : if (argc > 1)
5154 peter_e 6638 ECB : {
5154 peter_e 6639 CBC 159 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
6640 : {
3931 rhaas 6641 1 : usage();
5154 peter_e 6642 1 : exit(0);
5154 peter_e 6643 ECB : }
5154 peter_e 6644 CBC 158 : if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
5154 peter_e 6645 ECB : {
5154 peter_e 6646 CBC 1 : puts("pgbench (PostgreSQL) " PG_VERSION);
6647 1 : exit(0);
5154 peter_e 6648 ECB : }
6649 : }
6650 :
1474 michael 6651 CBC 157 : state = (CState *) pg_malloc0(sizeof(CState));
6652 :
6653 : /* set random seed early, because it may be used while parsing scripts. */
1835 tgl 6654 157 : if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
366 tgl 6655 UBC 0 : pg_fatal("error while setting random seed from PGBENCH_RANDOM_SEED environment variable");
1840 teodor 6656 ECB :
118 peter 6657 GNC 1144 : while ((c = getopt_long(argc, argv, "b:c:CdD:f:F:h:iI:j:lL:M:nNp:P:qrR:s:St:T:U:v", long_options, &optindex)) != -1)
8397 bruce 6658 EUB : {
6659 : char *script;
2577 alvherre 6660 :
8397 bruce 6661 GBC 1055 : switch (c)
6662 : {
118 peter 6663 GNC 12 : case 'b':
6664 12 : if (strcmp(optarg, "list") == 0)
6665 : {
6666 1 : listAvailableScripts();
6667 1 : exit(0);
6668 : }
6669 11 : weight = parseScriptWeight(optarg, &script);
6670 9 : process_builtin(findBuiltin(script), weight);
1973 tgl 6671 GIC 7 : benchmarking_option_set = true;
118 peter 6672 GNC 7 : internal_script_used = true;
8397 bruce 6673 CBC 7 : break;
6674 21 : case 'c':
3162 ishii 6675 21 : benchmarking_option_set = true;
624 michael 6676 21 : if (!option_parse_int(optarg, "-c/--clients", 1, INT_MAX,
624 michael 6677 ECB : &nclients))
8397 bruce 6678 : {
8397 bruce 6679 GIC 1 : exit(1);
8397 bruce 6680 ECB : }
6028 tgl 6681 : #ifdef HAVE_GETRLIMIT
8397 bruce 6682 CBC 20 : if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
366 tgl 6683 LBC 0 : pg_fatal("getrlimit failed: %m");
2835 tgl 6684 CBC 20 : if (rlim.rlim_cur < nclients + 3)
8397 bruce 6685 ECB : {
366 tgl 6686 LBC 0 : pg_log_error("need at least %d open files, but system limit is %ld",
1187 peter 6687 ECB : nclients + 3, (long) rlim.rlim_cur);
366 tgl 6688 LBC 0 : pg_log_error_hint("Reduce number of clients, or use limit/ulimit to increase the system limit.");
8397 bruce 6689 0 : exit(1);
8397 bruce 6690 ECB : }
2118 tgl 6691 : #endif /* HAVE_GETRLIMIT */
8397 bruce 6692 CBC 20 : break;
7836 bruce 6693 GNC 2 : case 'C':
3162 ishii 6694 2 : benchmarking_option_set = true;
4765 itagaki.takahiro 6695 2 : is_connect = true;
7836 bruce 6696 2 : break;
118 peter 6697 3 : case 'd':
6698 3 : pg_logging_increase_verbosity();
6401 ishii 6699 3 : break;
6101 6700 433 : case 'D':
6701 : {
6702 : char *p;
6703 :
3162 6704 433 : benchmarking_option_set = true;
6705 :
6101 6706 433 : if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
366 tgl 6707 1 : pg_fatal("invalid variable definition: \"%s\"", optarg);
6708 :
6101 ishii 6709 432 : *p++ = '\0';
382 6710 432 : if (!putVariable(&state[0].variables, "option", optarg, p))
6101 ishii 6711 UNC 0 : exit(1);
6712 : }
6101 ishii 6713 GNC 432 : break;
118 peter 6714 110 : case 'f':
6715 110 : weight = parseScriptWeight(optarg, &script);
6716 110 : process_file(script, weight);
6717 69 : benchmarking_option_set = true;
6718 69 : break;
5845 ishii 6719 3 : case 'F':
3162 6720 3 : initialization_option_set = true;
624 michael 6721 3 : if (!option_parse_int(optarg, "-F/--fillfactor", 10, 100,
6722 : &fillfactor))
5845 ishii 6723 1 : exit(1);
6724 2 : break;
118 peter 6725 1 : case 'h':
6726 1 : pghost = pg_strdup(optarg);
6727 1 : break;
6728 9 : case 'i':
6729 9 : is_init_mode = true;
6730 9 : break;
6731 4 : case 'I':
6732 4 : pg_free(initialize_steps);
6733 4 : initialize_steps = pg_strdup(optarg);
6734 4 : checkInitSteps(initialize_steps);
6735 3 : initialization_option_set = true;
6736 3 : break;
118 peter 6737 GIC 4 : case 'j': /* jobs */
6738 4 : benchmarking_option_set = true;
118 peter 6739 CBC 4 : if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
6740 : &nthreads))
6741 : {
118 peter 6742 GIC 1 : exit(1);
6743 : }
6744 : #ifndef ENABLE_THREAD_SAFETY
118 peter 6745 ECB : if (nthreads != 1)
6746 : pg_fatal("threads are not supported on this platform; use -j1");
6747 : #endif /* !ENABLE_THREAD_SAFETY */
118 peter 6748 CBC 3 : break;
118 peter 6749 GNC 7 : case 'l':
118 peter 6750 CBC 7 : benchmarking_option_set = true;
118 peter 6751 GNC 7 : use_log = true;
6752 7 : break;
6753 3 : case 'L':
6754 : {
6755 3 : double limit_ms = atof(optarg);
6756 :
6757 3 : if (limit_ms <= 0.0)
6758 1 : pg_fatal("invalid latency limit: \"%s\"", optarg);
6759 2 : benchmarking_option_set = true;
6760 2 : latency_limit = (int64) (limit_ms * 1000);
6761 : }
6762 2 : break;
5499 ishii 6763 73 : case 'M':
3162 6764 73 : benchmarking_option_set = true;
5499 6765 210 : for (querymode = 0; querymode < NUM_QUERYMODE; querymode++)
6766 209 : if (strcmp(optarg, QUERYMODE[querymode]) == 0)
6767 72 : break;
6768 73 : if (querymode >= NUM_QUERYMODE)
366 tgl 6769 1 : pg_fatal("invalid query mode (-M): \"%s\"", optarg);
5499 ishii 6770 72 : break;
118 peter 6771 82 : case 'n':
6772 82 : is_no_vacuum = true;
6773 82 : break;
6774 1 : case 'N':
6775 1 : process_builtin(findBuiltin("simple-update"), 1);
6776 1 : benchmarking_option_set = true;
6777 1 : internal_script_used = true;
6778 1 : break;
6779 1 : case 'p':
6780 1 : pgport = pg_strdup(optarg);
6781 1 : break;
3553 ishii 6782 2 : case 'P':
3162 6783 2 : benchmarking_option_set = true;
624 michael 6784 2 : if (!option_parse_int(optarg, "-P/--progress", 1, INT_MAX,
6785 : &progress))
3553 ishii 6786 1 : exit(1);
6787 1 : break;
118 peter 6788 1 : case 'q':
6789 1 : initialization_option_set = true;
6790 1 : use_quiet = true;
118 peter 6791 CBC 1 : break;
118 peter 6792 GIC 2 : case 'r':
118 peter 6793 CBC 2 : benchmarking_option_set = true;
6794 2 : report_per_command = true;
6795 2 : break;
3547 ishii 6796 GNC 3 : case 'R':
6797 : {
6798 : /* get a double from the beginning of option value */
3260 bruce 6799 3 : double throttle_value = atof(optarg);
6800 :
3162 ishii 6801 3 : benchmarking_option_set = true;
6802 :
3260 bruce 6803 3 : if (throttle_value <= 0.0)
366 tgl 6804 1 : pg_fatal("invalid rate limit: \"%s\"", optarg);
6805 : /* Invert rate limit into per-transaction delay in usec */
1657 6806 2 : throttle_delay = 1000000.0 / throttle_value;
6807 : }
3547 ishii 6808 2 : break;
118 peter 6809 CBC 3 : case 's':
118 peter 6810 GIC 3 : scale_given = true;
118 peter 6811 CBC 3 : if (!option_parse_int(optarg, "-s/--scale", 1, INT_MAX,
118 peter 6812 ECB : &scale))
118 peter 6813 CBC 1 : exit(1);
6814 2 : break;
118 peter 6815 GNC 134 : case 'S':
6816 134 : process_builtin(findBuiltin("select-only"), 1);
6817 133 : benchmarking_option_set = true;
6818 133 : internal_script_used = true;
6819 133 : break;
118 peter 6820 CBC 92 : case 't':
6821 92 : benchmarking_option_set = true;
6822 92 : if (!option_parse_int(optarg, "-t/--transactions", 1, INT_MAX,
118 peter 6823 ECB : &nxacts))
118 peter 6824 CBC 1 : exit(1);
6825 91 : break;
6826 5 : case 'T':
6827 5 : benchmarking_option_set = true;
6828 5 : if (!option_parse_int(optarg, "-T/--time", 1, INT_MAX,
118 peter 6829 ECB : &duration))
118 peter 6830 CBC 1 : exit(1);
6831 4 : break;
6832 1 : case 'U':
6833 1 : username = pg_strdup(optarg);
6834 1 : break;
118 peter 6835 GNC 1 : case 'v':
118 peter 6836 CBC 1 : benchmarking_option_set = true;
118 peter 6837 GNC 1 : do_vacuum_accounts = true;
3100 heikki.linnakangas 6838 CBC 1 : break;
1973 tgl 6839 2 : case 1: /* unlogged-tables */
6840 2 : initialization_option_set = true;
6841 2 : unlogged_tables = true;
4276 rhaas 6842 2 : break;
3955 bruce 6843 1 : case 2: /* tablespace */
3162 ishii 6844 1 : initialization_option_set = true;
3831 bruce 6845 1 : tablespace = pg_strdup(optarg);
4276 rhaas 6846 1 : break;
3955 bruce 6847 1 : case 3: /* index-tablespace */
3162 ishii 6848 GIC 1 : initialization_option_set = true;
3831 bruce 6849 CBC 1 : index_tablespace = pg_strdup(optarg);
4276 rhaas 6850 GIC 1 : break;
1973 tgl 6851 CBC 5 : case 4: /* sampling-rate */
3162 ishii 6852 5 : benchmarking_option_set = true;
3840 heikki.linnakangas 6853 GIC 5 : sample_rate = atof(optarg);
6854 5 : if (sample_rate <= 0.0 || sample_rate > 1.0)
366 tgl 6855 CBC 1 : pg_fatal("invalid sampling rate: \"%s\"", optarg);
3840 heikki.linnakangas 6856 4 : break;
1973 tgl 6857 6 : case 5: /* aggregate-interval */
3162 ishii 6858 GIC 6 : benchmarking_option_set = true;
624 michael 6859 CBC 6 : if (!option_parse_int(optarg, "--aggregate-interval", 1, INT_MAX,
624 michael 6860 ECB : &agg_interval))
3720 ishii 6861 CBC 1 : exit(1);
6862 5 : break;
1973 tgl 6863 2 : case 6: /* progress-timestamp */
2762 teodor 6864 GBC 2 : progress_timestamp = true;
2762 teodor 6865 CBC 2 : benchmarking_option_set = true;
6866 2 : break;
1973 tgl 6867 GIC 4 : case 7: /* log-prefix */
2342 rhaas 6868 CBC 4 : benchmarking_option_set = true;
2342 rhaas 6869 GIC 4 : logfile_prefix = pg_strdup(optarg);
2342 rhaas 6870 CBC 4 : break;
1973 tgl 6871 GBC 2 : case 8: /* foreign-keys */
6872 2 : initialization_option_set = true;
6873 2 : foreign_keys = true;
6874 2 : break;
1840 teodor 6875 CBC 4 : case 9: /* random-seed */
1840 teodor 6876 GIC 4 : benchmarking_option_set = true;
1835 tgl 6877 CBC 4 : if (!set_random_seed(optarg))
366 tgl 6878 GIC 1 : pg_fatal("error while setting random seed from --random-seed option");
1840 teodor 6879 CBC 3 : break;
1363 tmunro 6880 1 : case 10: /* list */
6881 : {
6882 1 : const BuiltinScript *s = findBuiltin(optarg);
1363 tmunro 6883 ECB :
1363 tmunro 6884 GIC 1 : fprintf(stderr, "-- %s: %s\n%s\n", s->name, s->desc, s->script);
1363 tmunro 6885 CBC 1 : exit(0);
1363 tmunro 6886 ECB : }
6887 : break;
1286 akapila 6888 CBC 3 : case 11: /* partitions */
6889 3 : initialization_option_set = true;
326 michael 6890 3 : if (!option_parse_int(optarg, "--partitions", 0, INT_MAX,
6891 : &partitions))
1286 akapila 6892 1 : exit(1);
6893 2 : break;
1286 akapila 6894 GIC 3 : case 12: /* partition-method */
6895 3 : initialization_option_set = true;
6896 3 : if (pg_strcasecmp(optarg, "range") == 0)
1286 akapila 6897 UIC 0 : partition_method = PART_RANGE;
1286 akapila 6898 CBC 3 : else if (pg_strcasecmp(optarg, "hash") == 0)
1286 akapila 6899 GIC 2 : partition_method = PART_HASH;
1286 akapila 6900 ECB : else
366 tgl 6901 CBC 1 : pg_fatal("invalid partition method, expecting \"range\" or \"hash\", got: \"%s\"",
366 tgl 6902 ECB : optarg);
1286 akapila 6903 GIC 2 : break;
382 ishii 6904 UIC 0 : case 13: /* failures-detailed */
6905 0 : benchmarking_option_set = true;
382 ishii 6906 LBC 0 : failures_detailed = true;
382 ishii 6907 UIC 0 : break;
382 ishii 6908 CBC 4 : case 14: /* max-tries */
6909 : {
6910 4 : int32 max_tries_arg = atoi(optarg);
382 ishii 6911 ECB :
382 ishii 6912 CBC 4 : if (max_tries_arg < 0)
366 tgl 6913 GIC 1 : pg_fatal("invalid number of maximum tries: \"%s\"", optarg);
6914 :
382 ishii 6915 CBC 3 : benchmarking_option_set = true;
382 ishii 6916 GIC 3 : max_tries = (uint32) max_tries_arg;
6917 : }
382 ishii 6918 CBC 3 : break;
6919 2 : case 15: /* verbose-errors */
382 ishii 6920 GIC 2 : benchmarking_option_set = true;
6921 2 : verbose_errors = true;
382 ishii 6922 CBC 2 : break;
8397 bruce 6923 2 : default:
6924 : /* getopt_long already emitted a complaint */
366 tgl 6925 GIC 2 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
8397 bruce 6926 2 : exit(1);
6927 : }
6928 : }
6929 :
2629 alvherre 6930 ECB : /* set default script if none */
2629 alvherre 6931 CBC 89 : if (num_scripts == 0 && !is_init_mode)
6932 : {
2576 tgl 6933 GIC 11 : process_builtin(findBuiltin("tpcb-like"), 1);
2629 alvherre 6934 11 : benchmarking_option_set = true;
6935 11 : internal_script_used = true;
6936 : }
6937 :
1550 alvherre 6938 ECB : /* complete SQL command initialization and compute total weight */
1550 alvherre 6939 GIC 181 : for (i = 0; i < num_scripts; i++)
2067 tgl 6940 ECB : {
1550 alvherre 6941 CBC 93 : Command **commands = sql_script[i].commands;
6942 :
1550 alvherre 6943 GIC 591 : for (int j = 0; commands[j] != NULL; j++)
1550 alvherre 6944 CBC 499 : if (commands[j]->type == SQL_COMMAND)
6945 238 : postprocess_sql_command(commands[j]);
2067 tgl 6946 ECB :
2577 alvherre 6947 EUB : /* cannot overflow: weight is 32b, total_weight 64b */
2577 alvherre 6948 GIC 92 : total_weight += sql_script[i].weight;
1550 alvherre 6949 ECB : }
6950 :
2567 alvherre 6951 GIC 88 : if (total_weight == 0 && !is_init_mode)
366 tgl 6952 CBC 1 : pg_fatal("total script weight must not be zero");
6953 :
2624 alvherre 6954 EUB : /* show per script stats if several scripts are used */
2624 alvherre 6955 GIC 87 : if (num_scripts > 1)
2624 alvherre 6956 GBC 3 : per_script_stats = true;
2624 alvherre 6957 EUB :
6958 : /*
6959 : * Don't need more threads than there are clients. (This is not merely an
2837 heikki.linnakangas 6960 ECB : * optimization; throttle_delay is calculated incorrectly below if some
6961 : * threads have no clients assigned to them.)
6962 : */
2837 heikki.linnakangas 6963 CBC 87 : if (nthreads > nclients)
2837 heikki.linnakangas 6964 GIC 1 : nthreads = nclients;
2837 heikki.linnakangas 6965 ECB :
1657 tgl 6966 : /*
6967 : * Convert throttle_delay to a per-thread delay time. Note that this
6968 : * might be a fractional number of usec, but that's OK, since it's just
6969 : * the center of a Poisson distribution of delays.
6970 : */
3547 ishii 6971 GIC 87 : throttle_delay *= nthreads;
3547 ishii 6972 ECB :
8397 bruce 6973 CBC 87 : if (argc > optind)
1319 peter 6974 GIC 1 : dbName = argv[optind++];
8397 bruce 6975 ECB : else
6976 : {
7243 ishii 6977 GIC 86 : if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
6978 72 : dbName = env;
764 michael 6979 14 : else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
764 michael 6980 LBC 0 : dbName = env;
7243 ishii 6981 ECB : else
764 michael 6982 GIC 14 : dbName = get_user_name_or_exit(progname);
6983 : }
8397 bruce 6984 ECB :
1319 peter 6985 GIC 87 : if (optind < argc)
6986 : {
366 tgl 6987 LBC 0 : pg_log_error("too many command-line arguments (first is \"%s\")",
6988 : argv[optind]);
366 tgl 6989 UIC 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
1319 peter 6990 LBC 0 : exit(1);
1319 peter 6991 ECB : }
6992 :
8397 bruce 6993 GIC 87 : if (is_init_mode)
6994 : {
3162 ishii 6995 5 : if (benchmarking_option_set)
366 tgl 6996 CBC 1 : pg_fatal("some of the specified options cannot be used in initialization (-i) mode");
3162 ishii 6997 ECB :
1286 akapila 6998 GIC 4 : if (partitions == 0 && partition_method != PART_NONE)
366 tgl 6999 1 : pg_fatal("--partition-method requires greater than zero --partitions");
7000 :
1286 akapila 7001 ECB : /* set default method */
1286 akapila 7002 CBC 3 : if (partitions > 0 && partition_method == PART_NONE)
1286 akapila 7003 GIC 1 : partition_method = PART_RANGE;
7004 :
1973 tgl 7005 CBC 3 : if (initialize_steps == NULL)
7006 1 : initialize_steps = pg_strdup(DEFAULT_INIT_STEPS);
7007 :
1973 tgl 7008 GIC 3 : if (is_no_vacuum)
1973 tgl 7009 ECB : {
7010 : /* Remove any vacuum step in initialize_steps */
7011 : char *p;
7012 :
1973 tgl 7013 CBC 4 : while ((p = strchr(initialize_steps, 'v')) != NULL)
7014 3 : *p = ' ';
7015 : }
7016 :
7017 3 : if (foreign_keys)
1973 tgl 7018 ECB : {
7019 : /* Add 'f' to end of initialize_steps, if not already there */
1973 tgl 7020 CBC 2 : if (strchr(initialize_steps, 'f') == NULL)
1973 tgl 7021 ECB : {
7022 : initialize_steps = (char *)
1973 tgl 7023 CBC 2 : pg_realloc(initialize_steps,
7024 2 : strlen(initialize_steps) + 2);
1973 tgl 7025 GIC 2 : strcat(initialize_steps, "f");
1973 tgl 7026 ECB : }
7027 : }
7028 :
1973 tgl 7029 CBC 3 : runInitSteps(initialize_steps);
8397 bruce 7030 3 : exit(0);
7031 : }
3162 ishii 7032 ECB : else
7033 : {
3162 ishii 7034 GIC 82 : if (initialization_option_set)
366 tgl 7035 CBC 2 : pg_fatal("some of the specified options cannot be used in benchmarking mode");
7036 : }
8397 bruce 7037 ECB :
1973 tgl 7038 CBC 80 : if (nxacts > 0 && duration > 0)
366 tgl 7039 GIC 2 : pg_fatal("specify either a number of transactions (-t) or a duration (-T), not both");
7040 :
7041 : /* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
5323 7042 78 : if (nxacts <= 0 && duration <= 0)
7043 8 : nxacts = DEFAULT_NXACTS;
7044 :
3840 heikki.linnakangas 7045 ECB : /* --sampling-rate may be used only with -l */
3840 heikki.linnakangas 7046 GIC 78 : if (sample_rate > 0.0 && !use_log)
366 tgl 7047 CBC 1 : pg_fatal("log sampling (--sampling-rate) is allowed only when logging transactions (-l)");
7048 :
2613 alvherre 7049 ECB : /* --sampling-rate may not be used with --aggregate-interval */
3720 ishii 7050 CBC 77 : if (sample_rate > 0.0 && agg_interval > 0)
366 tgl 7051 GIC 1 : pg_fatal("log sampling (--sampling-rate) and aggregation (--aggregate-interval) cannot be used at the same time");
7052 :
2835 tgl 7053 CBC 76 : if (agg_interval > 0 && !use_log)
366 tgl 7054 GIC 1 : pg_fatal("log aggregation is allowed only when actually logging transactions");
7055 :
2342 rhaas 7056 75 : if (!use_log && logfile_prefix)
366 tgl 7057 CBC 1 : pg_fatal("log file prefix (--log-prefix) is allowed only when logging transactions (-l)");
2342 rhaas 7058 ECB :
2835 tgl 7059 GIC 74 : if (duration > 0 && agg_interval > duration)
366 tgl 7060 CBC 1 : pg_fatal("number of seconds for aggregation (%d) must not be higher than test duration (%d)", agg_interval, duration);
7061 :
2835 7062 73 : if (duration > 0 && agg_interval > 0 && duration % agg_interval != 0)
366 tgl 7063 GIC 1 : pg_fatal("duration (%d) must be a multiple of aggregation interval (%d)", duration, agg_interval);
3720 ishii 7064 EUB :
2043 tgl 7065 GBC 72 : if (progress_timestamp && progress == 0)
366 7066 1 : pg_fatal("--progress-timestamp is allowed only under --progress");
7067 :
382 ishii 7068 GIC 71 : if (!max_tries)
7069 : {
382 ishii 7070 CBC 1 : if (!latency_limit && duration <= 0)
366 tgl 7071 1 : pg_fatal("an unlimited number of transaction tries can only be used with --latency-limit or a duration (-T)");
382 ishii 7072 EUB : }
7073 :
7074 : /*
7075 : * save main process id in the global variable because process id will be
7076 : * changed after fork.
7077 : */
4765 itagaki.takahiro 7078 GIC 70 : main_pid = (int) getpid();
4765 itagaki.takahiro 7079 ECB :
6101 ishii 7080 GIC 70 : if (nclients > 1)
6101 ishii 7081 ECB : {
3841 tgl 7082 CBC 12 : state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
4623 tgl 7083 GIC 12 : memset(state + 1, 0, sizeof(CState) * (nclients - 1));
7084 :
7085 : /* copy any -D switch values to all clients */
6101 ishii 7086 CBC 43 : for (i = 1; i < nclients; i++)
6101 ishii 7087 ECB : {
7088 : int j;
7089 :
4997 ishii 7090 GIC 31 : state[i].id = i;
382 ishii 7091 CBC 32 : for (j = 0; j < state[0].variables.nvars; j++)
7092 : {
7093 1 : Variable *var = &state[0].variables.vars[j];
7094 :
1916 teodor 7095 GIC 1 : if (var->value.type != PGBT_NO_VALUE)
7096 : {
382 ishii 7097 UIC 0 : if (!putVariableValue(&state[i].variables, "startup",
1809 tgl 7098 LBC 0 : var->name, &var->value))
2529 7099 0 : exit(1);
7100 : }
7101 : else
7102 : {
382 ishii 7103 GIC 1 : if (!putVariable(&state[i].variables, "startup",
1916 teodor 7104 1 : var->name, var->svalue))
2529 tgl 7105 LBC 0 : exit(1);
7106 : }
6101 ishii 7107 ECB : }
7108 : }
7109 : }
7568 ishii 7110 EUB :
7111 : /* other CState initializations */
1844 teodor 7112 GIC 171 : for (i = 0; i < nclients; i++)
7113 : {
7114 101 : state[i].cstack = conditional_stack_create();
1605 alvherre 7115 101 : initRandomState(&state[i].cs_func_rs);
7116 : }
7117 :
8397 bruce 7118 ECB : /* opening connection... */
7882 ishii 7119 GIC 70 : con = doConnect();
7882 ishii 7120 CBC 70 : if (con == NULL)
366 tgl 7121 1 : pg_fatal("could not create connection for setup");
7882 ishii 7122 EUB :
7123 : /* report pgbench and server versions */
660 tgl 7124 GIC 69 : printVersion(con);
7125 :
764 michael 7126 CBC 69 : pg_log_debug("pghost: %s pgport: %s nclients: %d %s: %d dbName: %s",
7127 : PQhost(con), PQport(con), nclients,
764 michael 7128 ECB : duration <= 0 ? "nxacts" : "duration",
7129 : duration <= 0 ? nxacts : duration, PQdb(con));
7130 :
2629 alvherre 7131 CBC 69 : if (internal_script_used)
1286 akapila 7132 GIC 7 : GetTableInfo(con, scale_given);
6014 ishii 7133 EUB :
7134 : /*
7135 : * :scale variables normally get -s or database scale, but don't override
7136 : * an explicit -D switch
5448 tgl 7137 ECB : */
382 ishii 7138 GIC 68 : if (lookupVariable(&state[0].variables, "scale") == NULL)
5448 tgl 7139 ECB : {
5448 tgl 7140 CBC 167 : for (i = 0; i < nclients; i++)
7141 : {
382 ishii 7142 GBC 99 : if (!putVariableInt(&state[i].variables, "startup", "scale", scale))
5448 tgl 7143 UIC 0 : exit(1);
7144 : }
6396 ishii 7145 ECB : }
7146 :
3586 heikki.linnakangas 7147 : /*
7148 : * Define a :client_id variable that is unique per connection. But don't
7149 : * override an explicit -D switch.
7150 : */
382 ishii 7151 CBC 68 : if (lookupVariable(&state[0].variables, "client_id") == NULL)
7152 : {
3586 heikki.linnakangas 7153 167 : for (i = 0; i < nclients; i++)
382 ishii 7154 GIC 99 : if (!putVariableInt(&state[i].variables, "startup", "client_id", i))
3586 heikki.linnakangas 7155 UBC 0 : exit(1);
3586 heikki.linnakangas 7156 EUB : }
7157 :
7158 : /* set default seed for hash functions */
382 ishii 7159 GIC 68 : if (lookupVariable(&state[0].variables, "default_seed") == NULL)
1845 teodor 7160 ECB : {
497 tgl 7161 GIC 68 : uint64 seed = pg_prng_uint64(&base_random_sequence);
7162 :
1845 teodor 7163 CBC 167 : for (i = 0; i < nclients; i++)
382 ishii 7164 99 : if (!putVariableInt(&state[i].variables, "startup", "default_seed",
7165 : (int64) seed))
1845 teodor 7166 LBC 0 : exit(1);
7167 : }
1845 teodor 7168 ECB :
7169 : /* set random seed unless overwritten */
382 ishii 7170 CBC 68 : if (lookupVariable(&state[0].variables, "random_seed") == NULL)
1840 teodor 7171 ECB : {
1840 teodor 7172 CBC 167 : for (i = 0; i < nclients; i++)
382 ishii 7173 99 : if (!putVariableInt(&state[i].variables, "startup", "random_seed",
382 ishii 7174 ECB : random_seed))
1840 teodor 7175 LBC 0 : exit(1);
1840 teodor 7176 ECB : }
7177 :
6396 ishii 7178 CBC 68 : if (!is_no_vacuum)
6396 ishii 7179 ECB : {
6396 ishii 7180 GIC 9 : fprintf(stderr, "starting vacuum...");
2889 sfrost 7181 CBC 9 : tryExecuteStatement(con, "vacuum pgbench_branches");
2889 sfrost 7182 GIC 9 : tryExecuteStatement(con, "vacuum pgbench_tellers");
7183 9 : tryExecuteStatement(con, "truncate pgbench_history");
6396 ishii 7184 9 : fprintf(stderr, "end.\n");
6396 ishii 7185 ECB :
5847 ishii 7186 GIC 9 : if (do_vacuum_accounts)
7187 : {
5085 tgl 7188 LBC 0 : fprintf(stderr, "starting vacuum pgbench_accounts...");
2889 sfrost 7189 UIC 0 : tryExecuteStatement(con, "vacuum analyze pgbench_accounts");
8397 bruce 7190 0 : fprintf(stderr, "end.\n");
8397 bruce 7191 ECB : }
8397 bruce 7192 EUB : }
6396 ishii 7193 GIC 68 : PQfinish(con);
8397 bruce 7194 ECB :
4623 tgl 7195 : /* set up thread data structures */
3841 tgl 7196 GBC 68 : threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
2837 heikki.linnakangas 7197 GIC 68 : nclients_dealt = 0;
7198 :
4623 tgl 7199 137 : for (i = 0; i < nthreads; i++)
4623 tgl 7200 ECB : {
4382 bruce 7201 GIC 69 : TState *thread = &threads[i];
4623 tgl 7202 ECB :
4623 tgl 7203 GIC 69 : thread->tid = i;
2837 heikki.linnakangas 7204 CBC 69 : thread->state = &state[nclients_dealt];
7205 69 : thread->nstate =
2837 heikki.linnakangas 7206 GIC 69 : (nclients - nclients_dealt + nthreads - i - 1) / (nthreads - i);
1605 alvherre 7207 CBC 69 : initRandomState(&thread->ts_choose_rs);
1605 alvherre 7208 GBC 69 : initRandomState(&thread->ts_throttle_rs);
1605 alvherre 7209 GIC 69 : initRandomState(&thread->ts_sample_rs);
2495 rhaas 7210 69 : thread->logfile = NULL; /* filled in later */
3100 heikki.linnakangas 7211 69 : thread->latency_late = 0;
2288 tgl 7212 69 : initStats(&thread->stats, 0);
7213 :
2837 heikki.linnakangas 7214 69 : nclients_dealt += thread->nstate;
4623 tgl 7215 ECB : }
7216 :
2837 heikki.linnakangas 7217 EUB : /* all clients must be assigned to a thread */
2837 heikki.linnakangas 7218 GIC 68 : Assert(nclients_dealt == nclients);
7219 :
760 tmunro 7220 ECB : /* get start up time for the whole computation */
760 tmunro 7221 GIC 68 : start_time = pg_time_now();
7222 :
4997 ishii 7223 ECB : /* set alarm if duration is specified. */
4997 ishii 7224 CBC 68 : if (duration > 0)
4997 ishii 7225 UIC 0 : setalarm(duration);
4997 ishii 7226 ECB :
760 tmunro 7227 GIC 68 : errno = THREAD_BARRIER_INIT(&barrier, nthreads);
760 tmunro 7228 CBC 68 : if (errno != 0)
366 tgl 7229 UIC 0 : pg_fatal("could not initialize barrier: %m");
7230 :
2837 heikki.linnakangas 7231 ECB : #ifdef ENABLE_THREAD_SAFETY
760 tmunro 7232 : /* start all threads but thread 0 which is executed directly later */
760 tmunro 7233 GIC 69 : for (i = 1; i < nthreads; i++)
7234 : {
4382 bruce 7235 CBC 1 : TState *thread = &threads[i];
4623 tgl 7236 ECB :
760 tmunro 7237 CBC 1 : thread->create_time = pg_time_now();
760 tmunro 7238 GIC 1 : errno = THREAD_CREATE(&thread->thread, threadRun, thread);
7239 :
760 tmunro 7240 CBC 1 : if (errno != 0)
366 tgl 7241 LBC 0 : pg_fatal("could not create thread: %m");
4997 ishii 7242 ECB : }
2837 heikki.linnakangas 7243 : #else
760 tmunro 7244 : Assert(nthreads == 1);
7245 : #endif /* ENABLE_THREAD_SAFETY */
7246 :
2587 rhaas 7247 : /* compute when to stop */
760 tmunro 7248 CBC 68 : threads[0].create_time = pg_time_now();
2587 rhaas 7249 68 : if (duration > 0)
760 tmunro 7250 UIC 0 : end_time = threads[0].create_time + (int64) 1000000 * duration;
7251 :
760 tmunro 7252 ECB : /* run thread 0 directly */
760 tmunro 7253 CBC 68 : (void) threadRun(&threads[0]);
7254 :
7255 : /* wait for other threads and accumulate results */
2288 tgl 7256 GIC 68 : initStats(&stats, 0);
760 tmunro 7257 68 : conn_total_duration = 0;
7258 :
4997 ishii 7259 137 : for (i = 0; i < nthreads; i++)
7260 : {
2837 heikki.linnakangas 7261 CBC 69 : TState *thread = &threads[i];
7262 :
7263 : #ifdef ENABLE_THREAD_SAFETY
760 tmunro 7264 GIC 69 : if (i > 0)
7265 1 : THREAD_JOIN(thread->thread);
7266 : #endif /* ENABLE_THREAD_SAFETY */
7267 :
1643 peter_e 7268 168 : for (int j = 0; j < thread->nstate; j++)
557 fujii 7269 99 : if (thread->state[j].state != CSTATE_FINISHED)
1643 peter_e 7270 CBC 44 : exit_code = 2;
7271 :
7272 : /* aggregate thread level stats */
2627 alvherre 7273 69 : mergeSimpleStats(&stats.latency, &thread->stats.latency);
2627 alvherre 7274 GIC 69 : mergeSimpleStats(&stats.lag, &thread->stats.lag);
2627 alvherre 7275 CBC 69 : stats.cnt += thread->stats.cnt;
7276 69 : stats.skipped += thread->stats.skipped;
382 ishii 7277 GIC 69 : stats.retries += thread->stats.retries;
382 ishii 7278 CBC 69 : stats.retried += thread->stats.retried;
382 ishii 7279 GIC 69 : stats.serialization_failures += thread->stats.serialization_failures;
7280 69 : stats.deadlock_failures += thread->stats.deadlock_failures;
2792 heikki.linnakangas 7281 69 : latency_late += thread->latency_late;
760 tmunro 7282 CBC 69 : conn_total_duration += thread->conn_duration;
7283 :
760 tmunro 7284 ECB : /* first recorded benchmarking start time */
760 tmunro 7285 CBC 69 : if (bench_start == 0 || thread->bench_start < bench_start)
760 tmunro 7286 GIC 68 : bench_start = thread->bench_start;
4997 ishii 7287 ECB : }
760 tmunro 7288 :
585 fujii 7289 : /*
7290 : * All connections should be already closed in threadRun(), so this
7291 : * disconnect_all() will be a no-op, but clean up the connections just to
7292 : * be sure. We don't need to measure the disconnection delays here.
7293 : */
4997 ishii 7294 GIC 68 : disconnect_all(state, nclients);
7295 :
7296 : /*
760 tmunro 7297 ECB : * Beware that performance of short benchmarks with many threads and
7298 : * possibly long transactions can be deceptive because threads do not
7299 : * start and finish at the exact same time. The total duration computed
7300 : * here encompasses all transactions so that tps shown is somehow slightly
7301 : * underestimated.
3472 noah 7302 : */
760 tmunro 7303 CBC 68 : printResults(&stats, pg_time_now() - bench_start, conn_total_duration,
7304 : bench_start - start_time, latency_late);
4997 ishii 7305 EUB :
760 tmunro 7306 GIC 68 : THREAD_BARRIER_DESTROY(&barrier);
760 tmunro 7307 ECB :
1643 peter_e 7308 GIC 68 : if (exit_code != 0)
366 tgl 7309 CBC 44 : pg_log_error("Run was aborted; the above results are incomplete.");
1643 peter_e 7310 EUB :
1643 peter_e 7311 GIC 68 : return exit_code;
7312 : }
7313 :
760 tmunro 7314 ECB : static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC
4997 ishii 7315 CBC 69 : threadRun(void *arg)
7316 : {
4997 ishii 7317 GIC 69 : TState *thread = (TState *) arg;
4997 ishii 7318 CBC 69 : CState *state = thread->state;
7319 : pg_time_usec_t start;
7320 69 : int nstate = thread->nstate;
2118 tgl 7321 69 : int remains = nstate; /* number of remaining clients */
1658 7322 69 : socket_set *sockets = alloc_socket_set(nstate);
760 tmunro 7323 ECB : int64 thread_start,
7324 : last_report,
7325 : next_report;
7326 : StatsData last,
2627 alvherre 7327 : aggs;
7328 :
7329 : /* open log file if requested */
4765 itagaki.takahiro 7330 CBC 69 : if (use_log)
7331 : {
2336 rhaas 7332 ECB : char logpath[MAXPGPATH];
2289 tgl 7333 GIC 2 : char *prefix = logfile_prefix ? logfile_prefix : "pgbench_log";
7334 :
4765 itagaki.takahiro 7335 GBC 2 : if (thread->tid == 0)
2342 rhaas 7336 GIC 2 : snprintf(logpath, sizeof(logpath), "%s.%d", prefix, main_pid);
7337 : else
2342 rhaas 7338 UIC 0 : snprintf(logpath, sizeof(logpath), "%s.%d.%d", prefix, main_pid, thread->tid);
7339 :
2613 alvherre 7340 GIC 2 : thread->logfile = fopen(logpath, "w");
7341 :
2613 alvherre 7342 CBC 2 : if (thread->logfile == NULL)
366 tgl 7343 UIC 0 : pg_fatal("could not open logfile \"%s\": %m", logpath);
4765 itagaki.takahiro 7344 ECB : }
7345 :
760 tmunro 7346 : /* explicitly initialize the state machines */
760 tmunro 7347 GIC 168 : for (int i = 0; i < nstate; i++)
7348 99 : state[i].state = CSTATE_CHOOSE_SCRIPT;
7349 :
7350 : /* READY */
7351 69 : THREAD_BARRIER_WAIT(&barrier);
7352 :
7353 69 : thread_start = pg_time_now();
7354 69 : thread->started_time = thread_start;
587 fujii 7355 CBC 69 : thread->conn_duration = 0;
760 tmunro 7356 69 : last_report = thread_start;
760 tmunro 7357 GIC 69 : next_report = last_report + (int64) 1000000 * progress;
7358 :
760 tmunro 7359 ECB : /* STEADY */
4765 itagaki.takahiro 7360 GIC 69 : if (!is_connect)
7361 : {
7362 : /* make connections to the database before starting */
760 tmunro 7363 CBC 159 : for (int i = 0; i < nstate; i++)
7364 : {
4997 ishii 7365 GIC 92 : if ((state[i].con = doConnect()) == NULL)
7366 : {
7367 : /* coldly abort on initial connection failure */
366 tgl 7368 UIC 0 : pg_fatal("could not create connection for client %d",
366 tgl 7369 ECB : state[i].id);
760 tmunro 7370 : }
4997 ishii 7371 : }
8397 bruce 7372 : }
7373 :
760 tmunro 7374 : /* GO */
760 tmunro 7375 GIC 69 : THREAD_BARRIER_WAIT(&barrier);
760 tmunro 7376 ECB :
760 tmunro 7377 CBC 69 : start = pg_time_now();
760 tmunro 7378 GIC 69 : thread->bench_start = start;
7379 69 : thread->throttle_trigger = start;
7380 :
7381 : /*
637 tmunro 7382 ECB : * The log format currently has Unix epoch timestamps with whole numbers
7383 : * of seconds. Round the first aggregate's start time down to the nearest
7384 : * Unix epoch second (the very first aggregate might really have started a
7385 : * fraction of a second later, but later aggregates are measured from the
7386 : * whole number time that is actually logged).
7387 : */
637 tmunro 7388 CBC 69 : initStats(&aggs, (start + epoch_shift) / 1000000 * 1000000);
760 tmunro 7389 GIC 69 : last = aggs;
760 tmunro 7390 ECB :
2386 tgl 7391 : /* loop till all clients have terminated */
4997 ishii 7392 CBC 7236 : while (remains > 0)
7393 : {
7394 : int nsocks; /* number of sockets to be waited for */
7395 : pg_time_usec_t min_usec;
760 tmunro 7396 GIC 7167 : pg_time_usec_t now = 0; /* set this only if needed */
8397 bruce 7397 ECB :
7398 : /*
1658 tgl 7399 : * identify which client sockets should be checked for input, and
7400 : * compute the nearest time (if any) at which we need to wake up.
1658 tgl 7401 EUB : */
1658 tgl 7402 GBC 7167 : clear_socket_set(sockets);
1658 tgl 7403 GIC 7167 : nsocks = 0;
2929 andres 7404 7167 : min_usec = PG_INT64_MAX;
760 tmunro 7405 CBC 34078 : for (int i = 0; i < nstate; i++)
7406 : {
4997 ishii 7407 29307 : CState *st = &state[i];
6396 ishii 7408 ECB :
1600 alvherre 7409 GIC 29307 : if (st->state == CSTATE_SLEEP || st->state == CSTATE_THROTTLE)
3547 ishii 7410 3 : {
7411 : /* a nap from the script, or under throttling */
7412 : pg_time_usec_t this_usec;
7413 :
2386 tgl 7414 ECB : /* get current time if needed */
760 tmunro 7415 CBC 3 : pg_time_now_lazy(&now);
7416 :
7417 : /* min_usec should be the minimum delay across all clients */
2386 heikki.linnakangas 7418 GIC 6 : this_usec = (st->state == CSTATE_SLEEP ?
760 tmunro 7419 3 : st->sleep_until : st->txn_scheduled) - now;
2386 heikki.linnakangas 7420 CBC 3 : if (min_usec > this_usec)
2386 heikki.linnakangas 7421 GIC 3 : min_usec = this_usec;
4997 ishii 7422 EUB : }
382 ishii 7423 GIC 29304 : else if (st->state == CSTATE_WAIT_RESULT ||
382 ishii 7424 GBC 4650 : st->state == CSTATE_WAIT_ROLLBACK_RESULT)
4997 7425 24655 : {
2386 heikki.linnakangas 7426 EUB : /*
7427 : * waiting for result from server - nothing to do unless the
7428 : * socket is readable
7429 : */
2386 tgl 7430 GIC 24655 : int sock = PQsocket(st->con);
7431 :
heikki.linnakangas 7432 24655 : if (sock < 0)
7433 : {
1187 peter 7434 LBC 0 : pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
2386 heikki.linnakangas 7435 UIC 0 : goto done;
2386 heikki.linnakangas 7436 ECB : }
7437 :
1658 tgl 7438 CBC 24655 : add_socket_to_set(sockets, sock, nsocks++);
7439 : }
2386 7440 4649 : else if (st->state != CSTATE_ABORTED &&
2386 tgl 7441 GIC 4649 : st->state != CSTATE_FINISHED)
4997 ishii 7442 EUB : {
7443 : /*
7444 : * This client thread is ready to do something, so we don't
7445 : * want to wait. No need to examine additional clients.
2386 tgl 7446 ECB : */
2386 heikki.linnakangas 7447 GIC 2396 : min_usec = 0;
7448 2396 : break;
7449 : }
7450 : }
8397 bruce 7451 ECB :
7452 : /* also wake up to print the next progress report on time */
2801 andres 7453 GIC 7167 : if (progress && min_usec > 0 && thread->tid == 0)
2837 heikki.linnakangas 7454 ECB : {
760 tmunro 7455 UIC 0 : pg_time_now_lazy(&now);
2837 heikki.linnakangas 7456 EUB :
760 tmunro 7457 UIC 0 : if (now >= next_report)
2837 heikki.linnakangas 7458 0 : min_usec = 0;
760 tmunro 7459 UBC 0 : else if ((next_report - now) < min_usec)
760 tmunro 7460 UIC 0 : min_usec = next_report - now;
7461 : }
2837 heikki.linnakangas 7462 EUB :
7463 : /*
7464 : * If no clients are ready to execute actions, sleep until we receive
7465 : * data on some client socket or the timeout (if any) elapses.
7466 : */
2016 heikki.linnakangas 7467 GIC 7167 : if (min_usec > 0)
7468 : {
1658 tgl 7469 4771 : int rc = 0;
7470 :
2929 andres 7471 CBC 4771 : if (min_usec != PG_INT64_MAX)
7472 : {
1658 tgl 7473 GIC 3 : if (nsocks > 0)
7474 : {
1658 tgl 7475 LBC 0 : rc = wait_on_socket_set(sockets, min_usec);
2016 heikki.linnakangas 7476 ECB : }
7477 : else /* nothing active, simple sleep */
7478 : {
2016 heikki.linnakangas 7479 GIC 3 : pg_usleep(min_usec);
2016 heikki.linnakangas 7480 ECB : }
5756 JanWieck 7481 : }
1658 tgl 7482 : else /* no explicit delay, wait without timeout */
7483 : {
1658 tgl 7484 CBC 4768 : rc = wait_on_socket_set(sockets, 0);
7485 : }
2016 heikki.linnakangas 7486 ECB :
1658 tgl 7487 GIC 4771 : if (rc < 0)
8397 bruce 7488 EUB : {
6401 ishii 7489 UBC 0 : if (errno == EINTR)
7490 : {
7491 : /* On EINTR, go back to top of loop */
6401 ishii 7492 LBC 0 : continue;
2386 tgl 7493 ECB : }
7494 : /* must be something wrong */
557 fujii 7495 LBC 0 : pg_log_error("%s() failed: %m", SOCKET_WAIT_METHOD);
4997 ishii 7496 0 : goto done;
7497 : }
7498 : }
1984 tgl 7499 ECB : else
7500 : {
7501 : /* min_usec <= 0, i.e. something needs to be executed now */
7502 :
7503 : /* If we didn't wait, don't try to read any data */
1658 tgl 7504 GIC 2396 : clear_socket_set(sockets);
7505 : }
7506 :
7507 : /* ok, advance the state machine of each connection */
1658 tgl 7508 CBC 7167 : nsocks = 0;
760 tmunro 7509 41079 : for (int i = 0; i < nstate; i++)
7510 : {
4997 ishii 7511 GIC 33912 : CState *st = &state[i];
7512 :
382 ishii 7513 CBC 33912 : if (st->state == CSTATE_WAIT_RESULT ||
382 ishii 7514 GIC 4944 : st->state == CSTATE_WAIT_ROLLBACK_RESULT)
8397 bruce 7515 GBC 5148 : {
7516 : /* don't call advanceConnectionState unless data is available */
2610 alvherre 7517 28969 : int sock = PQsocket(st->con);
7518 :
2610 alvherre 7519 GIC 28969 : if (sock < 0)
7520 : {
1187 peter 7521 UIC 0 : pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
2610 alvherre 7522 0 : goto done;
7523 : }
7524 :
1658 tgl 7525 GBC 28969 : if (!socket_has_input(sockets, sock, nsocks++))
2386 tgl 7526 GIC 23821 : continue;
7527 : }
7528 4943 : else if (st->state == CSTATE_FINISHED ||
7529 2476 : st->state == CSTATE_ABORTED)
7530 : {
7531 : /* this client is done, no need to consider it anymore */
7532 2467 : continue;
7533 : }
2386 tgl 7534 EUB :
1600 alvherre 7535 GBC 7624 : advanceConnectionState(thread, st, &aggs);
7536 :
7537 : /*
7538 : * If advanceConnectionState changed client to finished state,
7539 : * that's one fewer client that remains.
1600 alvherre 7540 ECB : */
2386 tgl 7541 CBC 7624 : if (st->state == CSTATE_FINISHED || st->state == CSTATE_ABORTED)
2386 tgl 7542 GIC 99 : remains--;
8397 bruce 7543 ECB : }
7544 :
2386 tgl 7545 : /* progress report is made by thread 0 for all threads */
3553 ishii 7546 GIC 7167 : if (progress && thread->tid == 0)
7547 : {
185 drowley 7548 UNC 0 : pg_time_usec_t now2 = pg_time_now();
7549 :
7550 0 : if (now2 >= next_report)
3553 ishii 7551 ECB : {
7552 : /*
1467 tgl 7553 : * Horrible hack: this relies on the thread pointer we are
7554 : * passed to be equivalent to threads[0], that is the first
7555 : * entry of the threads array. That is why this MUST be done
7556 : * by thread 0 and not any other.
7557 : */
185 drowley 7558 UNC 0 : printProgressReport(thread, thread_start, now2,
7559 : &last, &last_report);
2837 heikki.linnakangas 7560 ECB :
7561 : /*
7562 : * Ensure that the next report is in the future, in case
7563 : * pgbench/postgres got stuck somewhere.
7564 : */
7565 : do
7566 : {
760 tmunro 7567 UIC 0 : next_report += (int64) 1000000 * progress;
185 drowley 7568 UNC 0 : } while (now2 >= next_report);
7569 : }
7570 : }
7571 : }
7572 :
4997 ishii 7573 GIC 69 : done:
4997 ishii 7574 GBC 69 : disconnect_all(state, nstate);
7575 :
2613 alvherre 7576 69 : if (thread->logfile)
2627 alvherre 7577 EUB : {
2288 tgl 7578 GIC 2 : if (agg_interval > 0)
7579 : {
2627 alvherre 7580 EUB : /* log aggregated but not yet reported transactions */
2288 tgl 7581 UIC 0 : doLog(thread, state, &aggs, false, 0, 0);
2627 alvherre 7582 EUB : }
2613 alvherre 7583 GBC 2 : fclose(thread->logfile);
2288 tgl 7584 2 : thread->logfile = NULL;
7585 : }
1658 tgl 7586 GIC 69 : free_socket_set(sockets);
760 tmunro 7587 69 : THREAD_FUNC_RETURN;
7588 : }
7589 :
7590 : static void
1865 andres 7591 407 : finishCon(CState *st)
7592 : {
7593 407 : if (st->con != NULL)
7594 : {
7595 202 : PQfinish(st->con);
7596 202 : st->con = NULL;
7597 : }
7598 407 : }
7599 :
7600 : /*
7601 : * Support for duration option: set timer_exceeded after so many seconds.
7602 : */
7603 :
7604 : #ifndef WIN32
7605 :
7606 : static void
5323 tgl 7607 UIC 0 : handle_sig_alarm(SIGNAL_ARGS)
7608 : {
7609 0 : timer_exceeded = true;
7610 0 : }
7611 :
7612 : static void
7613 0 : setalarm(int seconds)
7614 : {
7615 0 : pqsignal(SIGALRM, handle_sig_alarm);
7616 0 : alarm(seconds);
7617 0 : }
7618 :
7619 : #else /* WIN32 */
7620 :
7621 : static VOID CALLBACK
7622 : win32_timer_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
7623 : {
7624 : timer_exceeded = true;
7625 : }
7626 :
7627 : static void
7628 : setalarm(int seconds)
7629 : {
7630 : HANDLE queue;
7631 : HANDLE timer;
7632 :
7633 : /* This function will be called at most once, so we can cheat a bit. */
7634 : queue = CreateTimerQueue();
7635 : if (seconds > ((DWORD) -1) / 1000 ||
7636 : !CreateTimerQueueTimer(&timer, queue,
7637 : win32_timer_callback, NULL, seconds * 1000, 0,
7638 : WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE))
7639 : pg_fatal("failed to set timer");
7640 : }
7641 :
7642 : #endif /* WIN32 */
7643 :
7644 :
7645 : /*
7646 : * These functions provide an abstraction layer that hides the syscall
7647 : * we use to wait for input on a set of sockets.
7648 : *
7649 : * Currently there are two implementations, based on ppoll(2) and select(2).
1658 tgl 7650 ECB : * ppoll() is preferred where available due to its typically higher ceiling
7651 : * on the number of usable sockets. We do not use the more-widely-available
7652 : * poll(2) because it only offers millisecond timeout resolution, which could
7653 : * be problematic with high --rate settings.
7654 : *
7655 : * Function APIs:
7656 : *
7657 : * alloc_socket_set: allocate an empty socket set with room for up to
7658 : * "count" sockets.
7659 : *
7660 : * free_socket_set: deallocate a socket set.
7661 : *
7662 : * clear_socket_set: reset a socket set to empty.
7663 : *
7664 : * add_socket_to_set: add socket with indicated FD to slot "idx" in the
7665 : * socket set. Slots must be filled in order, starting with 0.
7666 : *
7667 : * wait_on_socket_set: wait for input on any socket in set, or for timeout
7668 : * to expire. timeout is measured in microseconds; 0 means wait forever.
7669 : * Returns result code of underlying syscall (>=0 if OK, else see errno).
7670 : *
7671 : * socket_has_input: after waiting, call this to see if given socket has
7672 : * input. fd and idx parameters should match some previous call to
7673 : * add_socket_to_set.
7674 : *
7675 : * Note that wait_on_socket_set destructively modifies the state of the
7676 : * socket set. After checking for input, caller must apply clear_socket_set
7677 : * and add_socket_to_set again before waiting again.
7678 : */
7679 :
7680 : #ifdef POLL_USING_PPOLL
7681 :
7682 : static socket_set *
1658 tgl 7683 GIC 69 : alloc_socket_set(int count)
1658 tgl 7684 ECB : {
7685 : socket_set *sa;
7686 :
1658 tgl 7687 GIC 69 : sa = (socket_set *) pg_malloc0(offsetof(socket_set, pollfds) +
7688 : sizeof(struct pollfd) * count);
7689 69 : sa->maxfds = count;
1658 tgl 7690 GBC 69 : sa->curfds = 0;
7691 69 : return sa;
1658 tgl 7692 EUB : }
7693 :
7694 : static void
1658 tgl 7695 GIC 69 : free_socket_set(socket_set *sa)
1658 tgl 7696 ECB : {
1658 tgl 7697 GIC 69 : pg_free(sa);
7698 69 : }
7699 :
7700 : static void
1658 tgl 7701 CBC 9563 : clear_socket_set(socket_set *sa)
7702 : {
1658 tgl 7703 GIC 9563 : sa->curfds = 0;
7704 9563 : }
7705 :
7706 : static void
7707 24655 : add_socket_to_set(socket_set *sa, int fd, int idx)
7708 : {
7709 24655 : Assert(idx < sa->maxfds && idx == sa->curfds);
7710 24655 : sa->pollfds[idx].fd = fd;
1658 tgl 7711 CBC 24655 : sa->pollfds[idx].events = POLLIN;
7712 24655 : sa->pollfds[idx].revents = 0;
1658 tgl 7713 GIC 24655 : sa->curfds++;
1658 tgl 7714 CBC 24655 : }
1658 tgl 7715 ECB :
7716 : static int
1658 tgl 7717 GIC 4768 : wait_on_socket_set(socket_set *sa, int64 usecs)
7718 : {
7719 4768 : if (usecs > 0)
7720 : {
7721 : struct timespec timeout;
7722 :
1658 tgl 7723 UIC 0 : timeout.tv_sec = usecs / 1000000;
7724 0 : timeout.tv_nsec = (usecs % 1000000) * 1000;
7725 0 : return ppoll(sa->pollfds, sa->curfds, &timeout, NULL);
7726 : }
7727 : else
7728 : {
1658 tgl 7729 GIC 4768 : return ppoll(sa->pollfds, sa->curfds, NULL, NULL);
7730 : }
7731 : }
7732 :
7733 : static bool
7734 28969 : socket_has_input(socket_set *sa, int fd, int idx)
7735 : {
7736 : /*
7737 : * In some cases, threadRun will apply clear_socket_set and then try to
7738 : * apply socket_has_input anyway with arguments that it used before that,
7739 : * or might've used before that except that it exited its setup loop
7740 : * early. Hence, if the socket set is empty, silently return false
7741 : * regardless of the parameters. If it's not empty, we can Assert that
7742 : * the parameters match a previous call.
7743 : */
7744 28969 : if (sa->curfds == 0)
7745 8258 : return false;
7746 :
7747 20711 : Assert(idx < sa->curfds && sa->pollfds[idx].fd == fd);
7748 20711 : return (sa->pollfds[idx].revents & POLLIN) != 0;
7749 : }
7750 :
7751 : #endif /* POLL_USING_PPOLL */
7752 :
7753 : #ifdef POLL_USING_SELECT
7754 :
7755 : static socket_set *
7756 : alloc_socket_set(int count)
7757 : {
7758 : return (socket_set *) pg_malloc0(sizeof(socket_set));
7759 : }
7760 :
7761 : static void
7762 : free_socket_set(socket_set *sa)
7763 : {
7764 : pg_free(sa);
7765 : }
7766 :
7767 : static void
7768 : clear_socket_set(socket_set *sa)
7769 : {
7770 : FD_ZERO(&sa->fds);
7771 : sa->maxfd = -1;
7772 : }
7773 :
7774 : static void
7775 : add_socket_to_set(socket_set *sa, int fd, int idx)
7776 : {
7777 : if (fd < 0 || fd >= FD_SETSIZE)
7778 : {
7779 : /*
7780 : * Doing a hard exit here is a bit grotty, but it doesn't seem worth
7781 : * complicating the API to make it less grotty.
7782 : */
7783 : pg_fatal("too many client connections for select()");
7784 : }
7785 : FD_SET(fd, &sa->fds);
7786 : if (fd > sa->maxfd)
7787 : sa->maxfd = fd;
7788 : }
7789 :
7790 : static int
7791 : wait_on_socket_set(socket_set *sa, int64 usecs)
7792 : {
7793 : if (usecs > 0)
7794 : {
7795 : struct timeval timeout;
7796 :
7797 : timeout.tv_sec = usecs / 1000000;
7798 : timeout.tv_usec = usecs % 1000000;
7799 : return select(sa->maxfd + 1, &sa->fds, NULL, NULL, &timeout);
7800 : }
7801 : else
7802 : {
7803 : return select(sa->maxfd + 1, &sa->fds, NULL, NULL, NULL);
7804 : }
7805 : }
7806 :
7807 : static bool
7808 : socket_has_input(socket_set *sa, int fd, int idx)
7809 : {
7810 : return (FD_ISSET(fd, &sa->fds) != 0);
7811 : }
7812 :
7813 : #endif /* POLL_USING_SELECT */
|