PostgreSQL Source Code  git master
pgbench.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include "common/int.h"
#include "common/logging.h"
#include "common/pg_prng.h"
#include "common/string.h"
#include "common/username.h"
#include "fe_utils/cancel.h"
#include "fe_utils/conditional.h"
#include "fe_utils/option_utils.h"
#include "fe_utils/string_utils.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "pgbench.h"
#include "port/pg_bitutils.h"
#include "portability/instr_time.h"
Include dependency graph for pgbench.c:

Go to the source code of this file.

Data Structures

struct  socket_set
 
struct  Variable
 
struct  SimpleStats
 
struct  StatsData
 
struct  CState
 
struct  TState
 
struct  Command
 
struct  ParsedScript
 
struct  BuiltinScript
 

Macros

#define POLL_USING_SELECT
 
#define M_PI   3.14159265358979323846
 
#define ERRCODE_UNDEFINED_TABLE   "42P01"
 
#define FNV_PRIME   UINT64CONST(0x100000001b3)
 
#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)
 
#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)
 
#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)
 
#define MM2_ROT   47
 
#define SOCKET_WAIT_METHOD   "select"
 
#define THREAD_T   void *
 
#define THREAD_FUNC_RETURN_TYPE   void *
 
#define THREAD_FUNC_RETURN   return NULL
 
#define THREAD_FUNC_CC
 
#define THREAD_BARRIER_T   int
 
#define THREAD_BARRIER_INIT(barrier, n)   (*(barrier) = 0)
 
#define THREAD_BARRIER_WAIT(barrier)
 
#define THREAD_BARRIER_DESTROY(barrier)
 
#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */
 
#define ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */
 
#define LOG_STEP_SECONDS   5 /* seconds between log messages */
 
#define DEFAULT_NXACTS   10 /* default nxacts */
 
#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */
 
#define MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */
 
#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */
 
#define nbranches
 
#define ntellers   10
 
#define naccounts   100000
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define WSEP   '@' /* weight separator */
 
#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */
 
#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */
 
#define SQL_COMMAND   1
 
#define META_COMMAND   2
 
#define MAX_ARGS   256
 
#define PG_TIME_GET_DOUBLE(t)   (0.000001 * (t))
 
#define PARAMS_ARRAY_SIZE   7
 
#define MAX_FARGS   16
 
#define MAX_PREPARE_NAME   32
 
#define COMMANDS_ALLOC_NUM   128
 

Typedefs

typedef struct socket_set socket_set
 
typedef struct SimpleStats SimpleStats
 
typedef int64 pg_time_usec_t
 
typedef struct StatsData StatsData
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct Command Command
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 

Enumerations

enum  partition_method_t { PART_NONE , PART_RANGE , PART_HASH }
 
enum  ConnectionStateEnum {
  CSTATE_CHOOSE_SCRIPT , CSTATE_START_TX , CSTATE_PREPARE_THROTTLE , CSTATE_THROTTLE ,
  CSTATE_START_COMMAND , CSTATE_WAIT_RESULT , CSTATE_SLEEP , CSTATE_END_COMMAND ,
  CSTATE_SKIP_COMMAND , CSTATE_END_TX , CSTATE_ABORTED , CSTATE_FINISHED
}
 
enum  MetaCommand {
  META_NONE , META_SET , META_SETSHELL , META_SHELL ,
  META_SLEEP , META_GSET , META_ASET , META_IF ,
  META_ELIF , META_ELSE , META_ENDIF , META_STARTPIPELINE ,
  META_ENDPIPELINE
}
 
enum  QueryMode { QUERY_SIMPLE , QUERY_EXTENDED , QUERY_PREPARED , NUM_QUERYMODE }
 

Functions

static void setNullValue (PgBenchValue *pv)
 
static void setBoolValue (PgBenchValue *pv, bool bval)
 
static void setIntValue (PgBenchValue *pv, int64 ival)
 
static void setDoubleValue (PgBenchValue *pv, double dval)
 
static bool evaluateExpr (CState *st, PgBenchExpr *expr, PgBenchValue *retval)
 
static ConnectionStateEnum executeMetaCommand (CState *st, pg_time_usec_t *now)
 
static void doLog (TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
 
static void processXactStats (TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg)
 
static void addScript (ParsedScript script)
 
static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun (void *arg)
 
static void finishCon (CState *st)
 
static void setalarm (int seconds)
 
static socket_setalloc_socket_set (int count)
 
static void free_socket_set (socket_set *sa)
 
static void clear_socket_set (socket_set *sa)
 
static void add_socket_to_set (socket_set *sa, int fd, int idx)
 
static int wait_on_socket_set (socket_set *sa, int64 usecs)
 
static bool socket_has_input (socket_set *sa, int fd, int idx)
 
static pg_time_usec_t pg_time_now (void)
 
static void pg_time_now_lazy (pg_time_usec_t *now)
 
static void usage (void)
 
static bool is_an_int (const char *str)
 
bool strtoint64 (const char *str, bool errorOK, int64 *result)
 
bool strtodouble (const char *str, bool errorOK, double *dv)
 
static void initRandomState (pg_prng_state *state)
 
static int64 getrand (pg_prng_state *state, int64 min, int64 max)
 
static int64 getExponentialRand (pg_prng_state *state, int64 min, int64 max, double parameter)
 
static int64 getGaussianRand (pg_prng_state *state, int64 min, int64 max, double parameter)
 
static int64 getPoissonRand (pg_prng_state *state, double center)
 
static int64 computeIterativeZipfian (pg_prng_state *state, int64 n, double s)
 
static int64 getZipfianRand (pg_prng_state *state, int64 min, int64 max, double s)
 
static int64 getHashFnv1a (int64 val, uint64 seed)
 
static int64 getHashMurmur2 (int64 val, uint64 seed)
 
static int64 permute (const int64 val, const int64 isize, const int64 seed)
 
static void initSimpleStats (SimpleStats *ss)
 
static void addToSimpleStats (SimpleStats *ss, double val)
 
static void mergeSimpleStats (SimpleStats *acc, SimpleStats *ss)
 
static void initStats (StatsData *sd, pg_time_usec_t start)
 
static void accumStats (StatsData *stats, bool skipped, double lat, double lag)
 
static void executeStatement (PGconn *con, const char *sql)
 
static void tryExecuteStatement (PGconn *con, const char *sql)
 
static PGconndoConnect (void)
 
static int compareVariableNames (const void *v1, const void *v2)
 
static VariablelookupVariable (CState *st, char *name)
 
static char * getVariable (CState *st, char *name)
 
static bool makeVariableValue (Variable *var)
 
static bool valid_variable_name (const char *name)
 
static VariablelookupCreateVariable (CState *st, const char *context, char *name)
 
static bool putVariable (CState *st, const char *context, char *name, const char *value)
 
static bool putVariableValue (CState *st, const char *context, char *name, const PgBenchValue *value)
 
static bool putVariableInt (CState *st, const char *context, char *name, int64 value)
 
static char * parseVariable (const char *sql, int *eaten)
 
static char * replaceVariable (char **sql, char *param, int len, char *value)
 
static char * assignVariables (CState *st, char *sql)
 
static void getQueryParams (CState *st, const Command *command, const char **params)
 
static char * valueTypeName (PgBenchValue *pval)
 
static bool coerceToBool (PgBenchValue *pval, bool *bval)
 
static bool valueTruth (PgBenchValue *pval)
 
static bool coerceToInt (PgBenchValue *pval, int64 *ival)
 
static bool coerceToDouble (PgBenchValue *pval, double *dval)
 
static bool isLazyFunc (PgBenchFunction func)
 
static bool evalLazyFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static bool evalStandardFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static bool evalFunc (CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
 
static MetaCommand getMetaCommand (const char *cmd)
 
static bool runShellCommand (CState *st, char *variable, char **argv, int argc)
 
static void preparedStatementName (char *buffer, int file, int state)
 
static void commandFailed (CState *st, const char *cmd, const char *message)
 
static int chooseScript (TState *thread)
 
static bool sendCommand (CState *st, Command *command)
 
static bool readCommandResponse (CState *st, MetaCommand meta, char *varprefix)
 
static bool evaluateSleep (CState *st, int argc, char **argv, int *usecs)
 
static void advanceConnectionState (TState *thread, CState *st, StatsData *agg)
 
static void disconnect_all (CState *state, int length)
 
static void initDropTables (PGconn *con)
 
static void createPartitions (PGconn *con)
 
static void initCreateTables (PGconn *con)
 
static void initTruncateTables (PGconn *con)
 
static void initGenerateDataClientSide (PGconn *con)
 
static void initGenerateDataServerSide (PGconn *con)
 
static void initVacuum (PGconn *con)
 
static void initCreatePKeys (PGconn *con)
 
static void initCreateFKeys (PGconn *con)
 
static void checkInitSteps (const char *initialize_steps)
 
static void runInitSteps (const char *initialize_steps)
 
static void GetTableInfo (PGconn *con, bool scale_given)
 
static bool parseQuery (Command *cmd)
 
void syntax_error (const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
 
static char * skip_sql_comments (char *sql_command)
 
static Commandcreate_sql_command (PQExpBuffer buf, const char *source)
 
static void free_command (Command *command)
 
static void postprocess_sql_command (Command *my_command)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source)
 
static void ConditionError (const char *desc, int cmdn, const char *msg)
 
static void CheckConditional (ParsedScript ps)
 
static void ParseScript (const char *script, const char *desc, int weight)
 
static char * read_file_contents (FILE *fd)
 
static void process_file (const char *filename, int weight)
 
static void process_builtin (const BuiltinScript *bi, int weight)
 
static void listAvailableScripts (void)
 
static const BuiltinScriptfindBuiltin (const char *name)
 
static int parseScriptWeight (const char *option, char **script)
 
static void printProgressReport (TState *threads, int64 test_start, pg_time_usec_t now, StatsData *last, int64 *last_report)
 
static void printSimpleStats (const char *prefix, SimpleStats *ss)
 
static void printVersion (PGconn *con)
 
static void printResults (StatsData *total, pg_time_usec_t total_duration, pg_time_usec_t conn_total_duration, pg_time_usec_t conn_elapsed_duration, int64 latency_late)
 
static bool set_random_seed (const char *seed)
 
int main (int argc, char **argv)
 
static void handle_sig_alarm (SIGNAL_ARGS)
 

Variables

int nxacts = 0
 
int duration = 0
 
int64 end_time = 0
 
int scale = 1
 
int fillfactor = 100
 
bool unlogged_tables = false
 
double sample_rate = 0.0
 
double throttle_delay = 0
 
int64 latency_limit = 0
 
char * tablespace = NULL
 
char * index_tablespace = NULL
 
static int partitions = 0
 
static partition_method_t partition_method = PART_NONE
 
static const char * PARTITION_METHOD [] = {"none", "range", "hash"}
 
int64 random_seed = -1
 
bool use_log
 
bool use_quiet
 
int agg_interval
 
bool per_script_stats = false
 
int progress = 0
 
bool progress_timestamp = false
 
int nclients = 1
 
int nthreads = 1
 
bool is_connect
 
bool report_per_command
 
int main_pid
 
const char * pghost = NULL
 
const char * pgport = NULL
 
const char * username = NULL
 
const char * dbName = NULL
 
char * logfile_prefix = NULL
 
const char * progname
 
volatile bool timer_exceeded = false
 
pg_time_usec_t epoch_shift
 
static pg_prng_state base_random_sequence
 
static THREAD_BARRIER_T barrier
 
static QueryMode querymode = QUERY_SIMPLE
 
static const char * QUERYMODE [] = {"simple", "extended", "prepared"}
 
static ParsedScript sql_script [MAX_SCRIPTS]
 
static int num_scripts
 
static int64 total_weight = 0
 
static const BuiltinScript builtin_script []
 
static const PsqlScanCallbacks pgbench_callbacks
 

Macro Definition Documentation

◆ ALL_INIT_STEPS

#define ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */

Definition at line 174 of file pgbench.c.

◆ COMMANDS_ALLOC_NUM

#define COMMANDS_ALLOC_NUM   128

◆ DEFAULT_INIT_STEPS

#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */

Definition at line 173 of file pgbench.c.

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 177 of file pgbench.c.

◆ ERRCODE_UNDEFINED_TABLE

#define ERRCODE_UNDEFINED_TABLE   "42P01"

Definition at line 79 of file pgbench.c.

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 85 of file pgbench.c.

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 84 of file pgbench.c.

◆ LOG_STEP_SECONDS

#define LOG_STEP_SECONDS   5 /* seconds between log messages */

Definition at line 176 of file pgbench.c.

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 76 of file pgbench.c.

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 521 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2027 of file pgbench.c.

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 2801 of file pgbench.c.

◆ MAX_SCRIPTS

#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */

Definition at line 308 of file pgbench.c.

◆ MAX_ZIPFIAN_PARAM

#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */

Definition at line 182 of file pgbench.c.

◆ META_COMMAND

#define META_COMMAND   2

Definition at line 515 of file pgbench.c.

◆ MIN_GAUSSIAN_PARAM

#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */

Definition at line 179 of file pgbench.c.

◆ MIN_ZIPFIAN_PARAM

#define MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */

Definition at line 181 of file pgbench.c.

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 86 of file pgbench.c.

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 87 of file pgbench.c.

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 88 of file pgbench.c.

◆ naccounts

#define naccounts   100000

Definition at line 256 of file pgbench.c.

◆ nbranches

#define nbranches
Value:
1 /* Makes little sense to change this. Change
* -s instead */

Definition at line 254 of file pgbench.c.

◆ ntellers

#define ntellers   10

Definition at line 255 of file pgbench.c.

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

◆ PG_TIME_GET_DOUBLE

#define PG_TIME_GET_DOUBLE (   t)    (0.000001 * (t))

Definition at line 689 of file pgbench.c.

◆ POLL_USING_SELECT

#define POLL_USING_SELECT

Definition at line 54 of file pgbench.c.

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 265 of file pgbench.c.

◆ SHELL_COMMAND_SIZE

#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */

Definition at line 309 of file pgbench.c.

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 107 of file pgbench.c.

◆ SQL_COMMAND

#define SQL_COMMAND   1

Definition at line 514 of file pgbench.c.

◆ THREAD_BARRIER_DESTROY

#define THREAD_BARRIER_DESTROY (   barrier)

Definition at line 166 of file pgbench.c.

◆ THREAD_BARRIER_INIT

#define THREAD_BARRIER_INIT (   barrier,
 
)    (*(barrier) = 0)

Definition at line 164 of file pgbench.c.

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   int

Definition at line 163 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

#define THREAD_BARRIER_WAIT (   barrier)

Definition at line 165 of file pgbench.c.

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 162 of file pgbench.c.

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 161 of file pgbench.c.

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 160 of file pgbench.c.

◆ THREAD_T

#define THREAD_T   void *

Definition at line 159 of file pgbench.c.

◆ WSEP

#define WSEP   '@' /* weight separator */

Definition at line 287 of file pgbench.c.

Typedef Documentation

◆ BuiltinScript

typedef struct BuiltinScript BuiltinScript

◆ Command

typedef struct Command Command

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ pg_time_usec_t

typedef int64 pg_time_usec_t

Definition at line 331 of file pgbench.c.

◆ QueryMode

typedef enum QueryMode QueryMode

◆ SimpleStats

typedef struct SimpleStats SimpleStats

◆ socket_set

typedef struct socket_set socket_set

◆ StatsData

typedef struct StatsData StatsData

Enumeration Type Documentation

◆ ConnectionStateEnum

Enumerator
CSTATE_CHOOSE_SCRIPT 
CSTATE_START_TX 
CSTATE_PREPARE_THROTTLE 
CSTATE_THROTTLE 
CSTATE_START_COMMAND 
CSTATE_WAIT_RESULT 
CSTATE_SLEEP 
CSTATE_END_COMMAND 
CSTATE_SKIP_COMMAND 
CSTATE_END_TX 
CSTATE_ABORTED 
CSTATE_FINISHED 

Definition at line 362 of file pgbench.c.

364 {
365  /*
366  * The client must first choose a script to execute. Once chosen, it can
367  * either be throttled (state CSTATE_PREPARE_THROTTLE under --rate), start
368  * right away (state CSTATE_START_TX) or not start at all if the timer was
369  * exceeded (state CSTATE_FINISHED).
370  */
372 
373  /*
374  * CSTATE_START_TX performs start-of-transaction processing. Establishes
375  * a new connection for the transaction in --connect mode, records the
376  * transaction start time, and proceed to the first command.
377  *
378  * Note: once a script is started, it will either error or run till its
379  * end, where it may be interrupted. It is not interrupted while running,
380  * so pgbench --time is to be understood as tx are allowed to start in
381  * that time, and will finish when their work is completed.
382  */
384 
385  /*
386  * In CSTATE_PREPARE_THROTTLE state, we calculate when to begin the next
387  * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
388  * sleeps until that moment, then advances to CSTATE_START_TX, or
389  * CSTATE_FINISHED if the next transaction would start beyond the end of
390  * the run.
391  */
394 
395  /*
396  * We loop through these states, to process each command in the script:
397  *
398  * CSTATE_START_COMMAND starts the execution of a command. On a SQL
399  * command, the command is sent to the server, and we move to
400  * CSTATE_WAIT_RESULT state unless in pipeline mode. On a \sleep
401  * meta-command, the timer is set, and we enter the CSTATE_SLEEP state to
402  * wait for it to expire. Other meta-commands are executed immediately. If
403  * the command about to start is actually beyond the end of the script,
404  * advance to CSTATE_END_TX.
405  *
406  * CSTATE_WAIT_RESULT waits until we get a result set back from the server
407  * for the current command.
408  *
409  * CSTATE_SLEEP waits until the end of \sleep.
410  *
411  * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
412  * command counter, and loops back to CSTATE_START_COMMAND state.
413  *
414  * CSTATE_SKIP_COMMAND is used by conditional branches which are not
415  * executed. It quickly skip commands that do not need any evaluation.
416  * This state can move forward several commands, till there is something
417  * to do or the end of the script.
418  */
421  CSTATE_SLEEP,
424 
425  /*
426  * CSTATE_END_TX performs end-of-transaction processing. It calculates
427  * latency, and logs the transaction. In --connect mode, it closes the
428  * current connection.
429  *
430  * Then either starts over in CSTATE_CHOOSE_SCRIPT, or enters
431  * CSTATE_FINISHED if we have no more work to do.
432  */
434 
435  /*
436  * Final states. CSTATE_ABORTED means that the script execution was
437  * aborted because a command failed, CSTATE_FINISHED means success.
438  */
@ CSTATE_START_TX
Definition: pgbench.c:382
@ CSTATE_END_TX
Definition: pgbench.c:432
@ CSTATE_FINISHED
Definition: pgbench.c:439
@ CSTATE_SKIP_COMMAND
Definition: pgbench.c:422
@ CSTATE_THROTTLE
Definition: pgbench.c:392
@ CSTATE_START_COMMAND
Definition: pgbench.c:418
@ CSTATE_END_COMMAND
Definition: pgbench.c:421
@ CSTATE_WAIT_RESULT
Definition: pgbench.c:419
@ CSTATE_CHOOSE_SCRIPT
Definition: pgbench.c:370
@ CSTATE_ABORTED
Definition: pgbench.c:438
@ CSTATE_PREPARE_THROTTLE
Definition: pgbench.c:391
@ CSTATE_SLEEP
Definition: pgbench.c:420

◆ MetaCommand

Enumerator
META_NONE 
META_SET 
META_SETSHELL 
META_SHELL 
META_SLEEP 
META_GSET 
META_ASET 
META_IF 
META_ELIF 
META_ELSE 
META_ENDIF 
META_STARTPIPELINE 
META_ENDPIPELINE 

Definition at line 523 of file pgbench.c.

525 {
526  META_NONE, /* not a known meta-command */
527  META_SET, /* \set */
528  META_SETSHELL, /* \setshell */
529  META_SHELL, /* \shell */
530  META_SLEEP, /* \sleep */
531  META_GSET, /* \gset */
532  META_ASET, /* \aset */
533  META_IF, /* \if */
534  META_ELIF, /* \elif */
535  META_ELSE, /* \else */
536  META_ENDIF, /* \endif */
537  META_STARTPIPELINE, /* \startpipeline */
538  META_ENDPIPELINE /* \endpipeline */
@ META_ELSE
Definition: pgbench.c:534
@ META_SETSHELL
Definition: pgbench.c:527
@ META_ENDIF
Definition: pgbench.c:535
@ META_SHELL
Definition: pgbench.c:528
@ META_STARTPIPELINE
Definition: pgbench.c:536
@ META_SET
Definition: pgbench.c:526
@ META_ELIF
Definition: pgbench.c:533
@ META_SLEEP
Definition: pgbench.c:529
@ META_NONE
Definition: pgbench.c:525
@ META_IF
Definition: pgbench.c:532
@ META_ENDPIPELINE
Definition: pgbench.c:537
@ META_ASET
Definition: pgbench.c:531
@ META_GSET
Definition: pgbench.c:530

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 237 of file pgbench.c.

238 {
239  PART_NONE, /* no partitioning */
240  PART_RANGE, /* range partitioning */
241  PART_HASH /* hash partitioning */
partition_method_t
Definition: pgbench.c:238
@ PART_NONE
Definition: pgbench.c:239
@ PART_RANGE
Definition: pgbench.c:240
@ PART_HASH
Definition: pgbench.c:241

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 540 of file pgbench.c.

542 {
543  QUERY_SIMPLE, /* simple query */
544  QUERY_EXTENDED, /* extended query */
545  QUERY_PREPARED, /* extended query with prepared statements */
@ QUERY_PREPARED
Definition: pgbench.c:544
@ NUM_QUERYMODE
Definition: pgbench.c:545
@ QUERY_SIMPLE
Definition: pgbench.c:542
@ QUERY_EXTENDED
Definition: pgbench.c:543

Function Documentation

◆ accumStats()

static void accumStats ( StatsData stats,
bool  skipped,
double  lat,
double  lag 
)
static

Definition at line 1275 of file pgbench.c.

1277 {
1278  stats->cnt++;
1279 
1280  if (skipped)
1281  {
1282  /* no latency to record on skipped transactions */
1283  stats->skipped++;
1284  }
1285  else
1286  {
1287  addToSimpleStats(&stats->latency, lat);
1288 
1289  /* and possibly the same for schedule lag */
1290  if (throttle_delay)
1291  addToSimpleStats(&stats->lag, lag);
1292  }
double throttle_delay
Definition: pgbench.c:214
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1231
int64 cnt
Definition: pgbench.c:340
int64 skipped
Definition: pgbench.c:341
SimpleStats lag
Definition: pgbench.c:344
SimpleStats latency
Definition: pgbench.c:343

References addToSimpleStats(), StatsData::cnt, StatsData::lag, StatsData::latency, StatsData::skipped, and throttle_delay.

Referenced by doLog(), and processXactStats().

◆ add_socket_to_set()

static void add_socket_to_set ( socket_set sa,
int  fd,
int  idx 
)
static

Definition at line 7042 of file pgbench.c.

7044 {
7045  if (fd < 0 || fd >= FD_SETSIZE)
7046  {
7047  /*
7048  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
7049  * complicating the API to make it less grotty.
7050  */
7051  pg_log_fatal("too many client connections for select()");
7052  exit(1);
7053  }
7054  FD_SET(fd, &sa->fds);
7055  if (fd > sa->maxfd)
7056  sa->maxfd = fd;
exit(1)
#define pg_log_fatal(...)
Definition: logging.h:76
static int fd(const char *x, int i)
Definition: preproc-init.c:105

References exit(), fd(), and pg_log_fatal.

Referenced by threadRun().

◆ addScript()

static void addScript ( ParsedScript  script)
static

Definition at line 5409 of file pgbench.c.

5411 {
5412  if (script.commands == NULL || script.commands[0] == NULL)
5413  {
5414  pg_log_fatal("empty command list for script \"%s\"", script.desc);
5415  exit(1);
5416  }
5417 
5418  if (num_scripts >= MAX_SCRIPTS)
5419  {
5420  pg_log_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
5421  exit(1);
5422  }
5423 
5424  CheckConditional(script);
5425 
5426  sql_script[num_scripts] = script;
5427  num_scripts++;
static void CheckConditional(ParsedScript ps)
Definition: pgbench.c:5059
#define MAX_SCRIPTS
Definition: pgbench.c:308
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:592
static int num_scripts
Definition: pgbench.c:593
const char * desc
Definition: pgbench.c:586
Command ** commands
Definition: pgbench.c:588

References CheckConditional(), ParsedScript::commands, ParsedScript::desc, exit(), MAX_SCRIPTS, num_scripts, pg_log_fatal, and sql_script.

Referenced by ParseScript().

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1231 of file pgbench.c.

1233 {
1234  if (ss->count == 0 || val < ss->min)
1235  ss->min = val;
1236  if (ss->count == 0 || val > ss->max)
1237  ss->max = val;
1238  ss->count++;
1239  ss->sum += val;
1240  ss->sum2 += val * val;
long val
Definition: informix.c:664
int64 count
Definition: pgbench.c:319
double sum
Definition: pgbench.c:322
double min
Definition: pgbench.c:320
double max
Definition: pgbench.c:321
double sum2
Definition: pgbench.c:323

References SimpleStats::count, SimpleStats::max, SimpleStats::min, SimpleStats::sum, SimpleStats::sum2, and val.

Referenced by accumStats(), and advanceConnectionState().

◆ advanceConnectionState()

static void advanceConnectionState ( TState thread,
CState st,
StatsData agg 
)
static

Definition at line 3101 of file pgbench.c.

3103 {
3104 
3105  /*
3106  * gettimeofday() isn't free, so we get the current timestamp lazily the
3107  * first time it's needed, and reuse the same value throughout this
3108  * function after that. This also ensures that e.g. the calculated
3109  * latency reported in the log file and in the totals are the same. Zero
3110  * means "not set yet". Reset "now" when we execute shell commands or
3111  * expressions, which might take a non-negligible amount of time, though.
3112  */
3113  pg_time_usec_t now = 0;
3114 
3115  /*
3116  * Loop in the state machine, until we have to wait for a result from the
3117  * server or have to sleep for throttling or \sleep.
3118  *
3119  * Note: In the switch-statement below, 'break' will loop back here,
3120  * meaning "continue in the state machine". Return is used to return to
3121  * the caller, giving the thread the opportunity to advance another
3122  * client.
3123  */
3124  for (;;)
3125  {
3126  Command *command;
3127 
3128  switch (st->state)
3129  {
3130  /* Select transaction (script) to run. */
3131  case CSTATE_CHOOSE_SCRIPT:
3132  st->use_file = chooseScript(thread);
3134 
3135  pg_log_debug("client %d executing script \"%s\"",
3136  st->id, sql_script[st->use_file].desc);
3137 
3138  /*
3139  * If time is over, we're done; otherwise, get ready to start
3140  * a new transaction, or to get throttled if that's requested.
3141  */
3144  break;
3145 
3146  /* Start new transaction (script) */
3147  case CSTATE_START_TX:
3149 
3150  /* establish connection if needed, i.e. under --connect */
3151  if (st->con == NULL)
3152  {
3153  pg_time_usec_t start = now;
3154 
3155  if ((st->con = doConnect()) == NULL)
3156  {
3157  /*
3158  * as the bench is already running, we do not abort
3159  * the process
3160  */
3161  pg_log_error("client %d aborted while establishing connection", st->id);
3162  st->state = CSTATE_ABORTED;
3163  break;
3164  }
3165 
3166  /* reset now after connection */
3167  now = pg_time_now();
3168 
3169  thread->conn_duration += now - start;
3170 
3171  /* Reset session-local state */
3172  memset(st->prepared, 0, sizeof(st->prepared));
3173  }
3174 
3175  /* record transaction start time */
3176  st->txn_begin = now;
3177 
3178  /*
3179  * When not throttling, this is also the transaction's
3180  * scheduled start time.
3181  */
3182  if (!throttle_delay)
3183  st->txn_scheduled = now;
3184 
3185  /* Begin with the first command */
3187  st->command = 0;
3188  break;
3189 
3190  /*
3191  * Handle throttling once per transaction by sleeping.
3192  */
3194 
3195  /*
3196  * Generate a delay such that the series of delays will
3197  * approximate a Poisson distribution centered on the
3198  * throttle_delay time.
3199  *
3200  * If transactions are too slow or a given wait is shorter
3201  * than a transaction, the next transaction will start right
3202  * away.
3203  */
3204  Assert(throttle_delay > 0);
3205 
3206  thread->throttle_trigger +=
3208  st->txn_scheduled = thread->throttle_trigger;
3209 
3210  /*
3211  * If --latency-limit is used, and this slot is already late
3212  * so that the transaction will miss the latency limit even if
3213  * it completed immediately, skip this time slot and loop to
3214  * reschedule.
3215  */
3216  if (latency_limit)
3217  {
3219 
3220  if (thread->throttle_trigger < now - latency_limit)
3221  {
3222  processXactStats(thread, st, &now, true, agg);
3223 
3224  /*
3225  * Finish client if -T or -t was exceeded.
3226  *
3227  * Stop counting skipped transactions under -T as soon
3228  * as the timer is exceeded. Because otherwise it can
3229  * take a very long time to count all of them
3230  * especially when quite a lot of them happen with
3231  * unrealistically high rate setting in -R, which
3232  * would prevent pgbench from ending immediately.
3233  * Because of this behavior, note that there is no
3234  * guarantee that all skipped transactions are counted
3235  * under -T though there is under -t. This is OK in
3236  * practice because it's very unlikely to happen with
3237  * realistic setting.
3238  */
3239  if (timer_exceeded || (nxacts > 0 && st->cnt >= nxacts))
3240  st->state = CSTATE_FINISHED;
3241 
3242  /* Go back to top of loop with CSTATE_PREPARE_THROTTLE */
3243  break;
3244  }
3245  }
3246 
3247  /*
3248  * stop client if next transaction is beyond pgbench end of
3249  * execution; otherwise, throttle it.
3250  */
3251  st->state = end_time > 0 && st->txn_scheduled > end_time ?
3253  break;
3254 
3255  /*
3256  * Wait until it's time to start next transaction.
3257  */
3258  case CSTATE_THROTTLE:
3260 
3261  if (now < st->txn_scheduled)
3262  return; /* still sleeping, nothing to do here */
3263 
3264  /* done sleeping, but don't start transaction if we're done */
3266  break;
3267 
3268  /*
3269  * Send a command to server (or execute a meta-command)
3270  */
3271  case CSTATE_START_COMMAND:
3272  command = sql_script[st->use_file].commands[st->command];
3273 
3274  /* Transition to script end processing if done */
3275  if (command == NULL)
3276  {
3277  st->state = CSTATE_END_TX;
3278  break;
3279  }
3280 
3281  /* record begin time of next command, and initiate it */
3282  if (report_per_command)
3283  {
3285  st->stmt_begin = now;
3286  }
3287 
3288  /* Execute the command */
3289  if (command->type == SQL_COMMAND)
3290  {
3291  /* disallow \aset and \gset in pipeline mode */
3292  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
3293  {
3294  if (command->meta == META_GSET)
3295  {
3296  commandFailed(st, "gset", "\\gset is not allowed in pipeline mode");
3297  st->state = CSTATE_ABORTED;
3298  break;
3299  }
3300  else if (command->meta == META_ASET)
3301  {
3302  commandFailed(st, "aset", "\\aset is not allowed in pipeline mode");
3303  st->state = CSTATE_ABORTED;
3304  break;
3305  }
3306  }
3307 
3308  if (!sendCommand(st, command))
3309  {
3310  commandFailed(st, "SQL", "SQL command send failed");
3311  st->state = CSTATE_ABORTED;
3312  }
3313  else
3314  {
3315  /* Wait for results, unless in pipeline mode */
3316  if (PQpipelineStatus(st->con) == PQ_PIPELINE_OFF)
3317  st->state = CSTATE_WAIT_RESULT;
3318  else
3319  st->state = CSTATE_END_COMMAND;
3320  }
3321  }
3322  else if (command->type == META_COMMAND)
3323  {
3324  /*-----
3325  * Possible state changes when executing meta commands:
3326  * - on errors CSTATE_ABORTED
3327  * - on sleep CSTATE_SLEEP
3328  * - else CSTATE_END_COMMAND
3329  */
3330  st->state = executeMetaCommand(st, &now);
3331  }
3332 
3333  /*
3334  * We're now waiting for an SQL command to complete, or
3335  * finished processing a metacommand, or need to sleep, or
3336  * something bad happened.
3337  */
3338  Assert(st->state == CSTATE_WAIT_RESULT ||
3339  st->state == CSTATE_END_COMMAND ||
3340  st->state == CSTATE_SLEEP ||
3341  st->state == CSTATE_ABORTED);
3342  break;
3343 
3344  /*
3345  * non executed conditional branch
3346  */
3347  case CSTATE_SKIP_COMMAND:
3349  /* quickly skip commands until something to do... */
3350  while (true)
3351  {
3352  Command *command;
3353 
3354  command = sql_script[st->use_file].commands[st->command];
3355 
3356  /* cannot reach end of script in that state */
3357  Assert(command != NULL);
3358 
3359  /*
3360  * if this is conditional related, update conditional
3361  * state
3362  */
3363  if (command->type == META_COMMAND &&
3364  (command->meta == META_IF ||
3365  command->meta == META_ELIF ||
3366  command->meta == META_ELSE ||
3367  command->meta == META_ENDIF))
3368  {
3369  switch (conditional_stack_peek(st->cstack))
3370  {
3371  case IFSTATE_FALSE:
3372  if (command->meta == META_IF ||
3373  command->meta == META_ELIF)
3374  {
3375  /* we must evaluate the condition */
3377  }
3378  else if (command->meta == META_ELSE)
3379  {
3380  /* we must execute next command */
3384  st->command++;
3385  }
3386  else if (command->meta == META_ENDIF)
3387  {
3390  if (conditional_active(st->cstack))
3392 
3393  /*
3394  * else state remains in
3395  * CSTATE_SKIP_COMMAND
3396  */
3397  st->command++;
3398  }
3399  break;
3400 
3401  case IFSTATE_IGNORED:
3402  case IFSTATE_ELSE_FALSE:
3403  if (command->meta == META_IF)
3405  IFSTATE_IGNORED);
3406  else if (command->meta == META_ENDIF)
3407  {
3410  if (conditional_active(st->cstack))
3412  }
3413  /* could detect "else" & "elif" after "else" */
3414  st->command++;
3415  break;
3416 
3417  case IFSTATE_NONE:
3418  case IFSTATE_TRUE:
3419  case IFSTATE_ELSE_TRUE:
3420  default:
3421 
3422  /*
3423  * inconsistent if inactive, unreachable dead
3424  * code
3425  */
3426  Assert(false);
3427  }
3428  }
3429  else
3430  {
3431  /* skip and consider next */
3432  st->command++;
3433  }
3434 
3435  if (st->state != CSTATE_SKIP_COMMAND)
3436  /* out of quick skip command loop */
3437  break;
3438  }
3439  break;
3440 
3441  /*
3442  * Wait for the current SQL command to complete
3443  */
3444  case CSTATE_WAIT_RESULT:
3445  pg_log_debug("client %d receiving", st->id);
3446 
3447  /*
3448  * Only check for new network data if we processed all data
3449  * fetched prior. Otherwise we end up doing a syscall for each
3450  * individual pipelined query, which has a measurable
3451  * performance impact.
3452  */
3453  if (PQisBusy(st->con) && !PQconsumeInput(st->con))
3454  {
3455  /* there's something wrong */
3456  commandFailed(st, "SQL", "perhaps the backend died while processing");
3457  st->state = CSTATE_ABORTED;
3458  break;
3459  }
3460  if (PQisBusy(st->con))
3461  return; /* don't have the whole result yet */
3462 
3463  /* store or discard the query results */
3464  if (readCommandResponse(st,
3467  {
3468  /*
3469  * outside of pipeline mode: stop reading results.
3470  * pipeline mode: continue reading results until an
3471  * end-of-pipeline response.
3472  */
3473  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
3474  st->state = CSTATE_END_COMMAND;
3475  }
3476  else
3477  st->state = CSTATE_ABORTED;
3478  break;
3479 
3480  /*
3481  * Wait until sleep is done. This state is entered after a
3482  * \sleep metacommand. The behavior is similar to
3483  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3484  * instead of CSTATE_START_TX.
3485  */
3486  case CSTATE_SLEEP:
3488  if (now < st->sleep_until)
3489  return; /* still sleeping, nothing to do here */
3490  /* Else done sleeping. */
3491  st->state = CSTATE_END_COMMAND;
3492  break;
3493 
3494  /*
3495  * End of command: record stats and proceed to next command.
3496  */
3497  case CSTATE_END_COMMAND:
3498 
3499  /*
3500  * command completed: accumulate per-command execution times
3501  * in thread-local data structure, if per-command latencies
3502  * are requested.
3503  */
3504  if (report_per_command)
3505  {
3506  Command *command;
3507 
3509 
3510  command = sql_script[st->use_file].commands[st->command];
3511  /* XXX could use a mutex here, but we choose not to */
3512  addToSimpleStats(&command->stats,
3514  }
3515 
3516  /* Go ahead with next command, to be executed or skipped */
3517  st->command++;
3518  st->state = conditional_active(st->cstack) ?
3520  break;
3521 
3522  /*
3523  * End of transaction (end of script, really).
3524  */
3525  case CSTATE_END_TX:
3526 
3527  /* transaction finished: calculate latency and do log */
3528  processXactStats(thread, st, &now, false, agg);
3529 
3530  /*
3531  * missing \endif... cannot happen if CheckConditional was
3532  * okay
3533  */
3535 
3536  if (is_connect)
3537  {
3538  pg_time_usec_t start = now;
3539 
3540  pg_time_now_lazy(&start);
3541  finishCon(st);
3542  now = pg_time_now();
3543  thread->conn_duration += now - start;
3544  }
3545 
3546  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
3547  {
3548  /* script completed */
3549  st->state = CSTATE_FINISHED;
3550  break;
3551  }
3552 
3553  /* next transaction (script) */
3555 
3556  /*
3557  * Ensure that we always return on this point, so as to avoid
3558  * an infinite loop if the script only contains meta commands.
3559  */
3560  return;
3561 
3562  /*
3563  * Final states. Close the connection if it's still open.
3564  */
3565  case CSTATE_ABORTED:
3566  case CSTATE_FINISHED:
3567 
3568  /*
3569  * Don't measure the disconnection delays here even if in
3570  * CSTATE_FINISHED and -C/--connect option is specified.
3571  * Because in this case all the connections that this thread
3572  * established are closed at the end of transactions and the
3573  * disconnection delays should have already been measured at
3574  * that moment.
3575  *
3576  * In CSTATE_ABORTED state, the measurement is no longer
3577  * necessary because we cannot report complete results anyways
3578  * in this case.
3579  */
3580  finishCon(st);
3581  return;
3582  }
3583  }
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1544
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:128
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:118
@ IFSTATE_FALSE
Definition: conditional.h:34
@ IFSTATE_ELSE_TRUE
Definition: conditional.h:40
@ IFSTATE_IGNORED
Definition: conditional.h:37
@ IFSTATE_TRUE
Definition: conditional.h:32
@ IFSTATE_NONE
Definition: conditional.h:31
@ IFSTATE_ELSE_FALSE
Definition: conditional.h:42
PGpipelineStatus PQpipelineStatus(const PGconn *conn)
Definition: fe-connect.c:6812
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1904
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:1951
@ PQ_PIPELINE_OFF
Definition: libpq-fe.h:156
@ PQ_PIPELINE_ON
Definition: libpq-fe.h:157
Assert(fmt[strlen(fmt) - 1] !='\n')
#define pg_log_error(...)
Definition: logging.h:80
#define pg_log_debug(...)
Definition: logging.h:92
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:673
int64 latency_limit
Definition: pgbench.c:222
int64 end_time
Definition: pgbench.c:186
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:2836
static void finishCon(CState *st)
Definition: pgbench.c:6855
int64 pg_time_usec_t
Definition: pgbench.c:331
bool is_connect
Definition: pgbench.c:276
int nxacts
Definition: pgbench.c:184
bool report_per_command
Definition: pgbench.c:277
#define PG_TIME_GET_DOUBLE(t)
Definition: pgbench.c:689
static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:3593
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:2809
static int chooseScript(TState *thread)
Definition: pgbench.c:2817
#define SQL_COMMAND
Definition: pgbench.c:514
static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg)
Definition: pgbench.c:3874
int duration
Definition: pgbench.c:185
static void pg_time_now_lazy(pg_time_usec_t *now)
Definition: pgbench.c:683
static int64 getPoissonRand(pg_prng_state *state, double center)
Definition: pgbench.c:1007
static PGconn * doConnect(void)
Definition: pgbench.c:1327
volatile bool timer_exceeded
Definition: pgbench.c:289
#define META_COMMAND
Definition: pgbench.c:515
static bool readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
Definition: pgbench.c:2932
int64 cnt
Definition: pgbench.c:475
int id
Definition: pgbench.c:448
pg_time_usec_t txn_scheduled
Definition: pgbench.c:467
bool prepared[MAX_SCRIPTS]
Definition: pgbench.c:472
pg_time_usec_t stmt_begin
Definition: pgbench.c:470
int command
Definition: pgbench.c:459
int use_file
Definition: pgbench.c:458
ConditionalStack cstack
Definition: pgbench.c:450
pg_time_usec_t txn_begin
Definition: pgbench.c:469
PGconn * con
Definition: pgbench.c:447
ConnectionStateEnum state
Definition: pgbench.c:449
char * varprefix
Definition: pgbench.c:579
int type
Definition: pgbench.c:575
MetaCommand meta
Definition: pgbench.c:576
SimpleStats stats
Definition: pgbench.c:581
int64 throttle_trigger
Definition: pgbench.c:497
pg_prng_state ts_throttle_rs
Definition: pgbench.c:494
pg_time_usec_t conn_duration
Definition: pgbench.c:504

References addToSimpleStats(), Assert(), chooseScript(), CState::cnt, CState::command, commandFailed(), ParsedScript::commands, CState::con, conditional_active(), conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), TState::conn_duration, CState::cstack, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_END_COMMAND, CSTATE_END_TX, CSTATE_FINISHED, CSTATE_PREPARE_THROTTLE, CSTATE_SKIP_COMMAND, CSTATE_SLEEP, CSTATE_START_COMMAND, CSTATE_START_TX, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, ParsedScript::desc, doConnect(), duration, end_time, executeMetaCommand(), finishCon(), getPoissonRand(), CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, is_connect, latency_limit, Command::meta, META_ASET, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_GSET, META_IF, now(), nxacts, pg_log_debug, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), pg_time_now_lazy(), PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQconsumeInput(), PQisBusy(), PQpipelineStatus(), CState::prepared, processXactStats(), readCommandResponse(), report_per_command, sendCommand(), SQL_COMMAND, sql_script, CState::state, Command::stats, CState::stmt_begin, throttle_delay, TState::throttle_trigger, timer_exceeded, TState::ts_throttle_rs, CState::txn_begin, CState::txn_scheduled, Command::type, CState::use_file, and Command::varprefix.

Referenced by threadRun().

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 7023 of file pgbench.c.

7025 {
7026  return (socket_set *) pg_malloc0(sizeof(socket_set));
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

References pg_malloc0().

Referenced by threadRun().

◆ assignVariables()

static char* assignVariables ( CState st,
char *  sql 
)
static

Definition at line 1722 of file pgbench.c.

1724 {
1725  char *p,
1726  *name,
1727  *val;
1728 
1729  p = sql;
1730  while ((p = strchr(p, ':')) != NULL)
1731  {
1732  int eaten;
1733 
1734  name = parseVariable(p, &eaten);
1735  if (name == NULL)
1736  {
1737  while (*p == ':')
1738  {
1739  p++;
1740  }
1741  continue;
1742  }
1743 
1744  val = getVariable(st, name);
1745  free(name);
1746  if (val == NULL)
1747  {
1748  p++;
1749  continue;
1750  }
1751 
1752  p = replaceVariable(&sql, p, eaten, val);
1753  }
1754 
1755  return sql;
const char * name
Definition: encode.c:561
#define free(a)
Definition: header.h:65
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1427
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1675
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1702

References free, getVariable(), name, parseVariable(), replaceVariable(), and val.

Referenced by sendCommand().

◆ CheckConditional()

static void CheckConditional ( ParsedScript  ps)
static

Definition at line 5059 of file pgbench.c.

5061 {
5062  /* statically check conditional structure */
5064  int i;
5065 
5066  for (i = 0; ps.commands[i] != NULL; i++)
5067  {
5068  Command *cmd = ps.commands[i];
5069 
5070  if (cmd->type == META_COMMAND)
5071  {
5072  switch (cmd->meta)
5073  {
5074  case META_IF:
5076  break;
5077  case META_ELIF:
5078  if (conditional_stack_empty(cs))
5079  ConditionError(ps.desc, i + 1, "\\elif without matching \\if");
5081  ConditionError(ps.desc, i + 1, "\\elif after \\else");
5082  break;
5083  case META_ELSE:
5084  if (conditional_stack_empty(cs))
5085  ConditionError(ps.desc, i + 1, "\\else without matching \\if");
5087  ConditionError(ps.desc, i + 1, "\\else after \\else");
5089  break;
5090  case META_ENDIF:
5091  if (!conditional_stack_pop(cs))
5092  ConditionError(ps.desc, i + 1, "\\endif without matching \\if");
5093  break;
5094  default:
5095  /* ignore anything else... */
5096  break;
5097  }
5098  }
5099  }
5100  if (!conditional_stack_empty(cs))
5101  ConditionError(ps.desc, i + 1, "\\if without matching \\endif");
ConditionalStack conditional_stack_create(void)
Definition: conditional.c:18
void conditional_stack_destroy(ConditionalStack cstack)
Definition: conditional.c:30
int i
Definition: isn.c:73
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:5048

References ParsedScript::commands, conditional_stack_create(), conditional_stack_destroy(), conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), ConditionError(), ParsedScript::desc, i, IFSTATE_ELSE_FALSE, IFSTATE_FALSE, Command::meta, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_IF, and Command::type.

Referenced by addScript().

◆ checkInitSteps()

static void checkInitSteps ( const char *  initialize_steps)
static

Definition at line 4401 of file pgbench.c.

4403 {
4404  if (initialize_steps[0] == '\0')
4405  {
4406  pg_log_fatal("no initialization steps specified");
4407  exit(1);
4408  }
4409 
4410  for (const char *step = initialize_steps; *step != '\0'; step++)
4411  {
4412  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
4413  {
4414  pg_log_fatal("unrecognized initialization step \"%c\"", *step);
4415  pg_log_info("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
4416  exit(1);
4417  }
4418  }
#define pg_log_info(...)
Definition: logging.h:88
#define ALL_INIT_STEPS
Definition: pgbench.c:174

References ALL_INIT_STEPS, exit(), pg_log_fatal, and pg_log_info.

Referenced by main().

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 2817 of file pgbench.c.

2819 {
2820  int i = 0;
2821  int64 w;
2822 
2823  if (num_scripts == 1)
2824  return 0;
2825 
2826  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
2827  do
2828  {
2829  w -= sql_script[i++].weight;
2830  } while (w >= 0);
2831 
2832  return i - 1;
static int64 total_weight
Definition: pgbench.c:594
static int64 getrand(pg_prng_state *state, int64 min, int64 max)
Definition: pgbench.c:912
int weight
Definition: pgbench.c:587
pg_prng_state ts_choose_rs
Definition: pgbench.c:493

References getrand(), i, num_scripts, sql_script, total_weight, TState::ts_choose_rs, and ParsedScript::weight.

Referenced by advanceConnectionState().

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 7035 of file pgbench.c.

7037 {
7038  FD_ZERO(&sa->fds);
7039  sa->maxfd = -1;

Referenced by threadRun().

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 1789 of file pgbench.c.

1791 {
1792  if (pval->type == PGBT_BOOLEAN)
1793  {
1794  *bval = pval->u.bval;
1795  return true;
1796  }
1797  else /* NULL, INT or DOUBLE */
1798  {
1799  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
1800  *bval = false; /* suppress uninitialized-variable warnings */
1801  return false;
1802  }
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1767
@ PGBT_BOOLEAN
Definition: pgbench.h:40
PgBenchValueType type
Definition: pgbench.h:46
bool bval
Definition: pgbench.h:51
union PgBenchValue::@30 u

References PgBenchValue::bval, pg_log_error, PGBT_BOOLEAN, PgBenchValue::type, PgBenchValue::u, and valueTypeName().

Referenced by evalLazyFunc(), and evalStandardFunc().

◆ coerceToDouble()

static bool coerceToDouble ( PgBenchValue pval,
double *  dval 
)
static

Definition at line 1858 of file pgbench.c.

1860 {
1861  if (pval->type == PGBT_DOUBLE)
1862  {
1863  *dval = pval->u.dval;
1864  return true;
1865  }
1866  else if (pval->type == PGBT_INT)
1867  {
1868  *dval = (double) pval->u.ival;
1869  return true;
1870  }
1871  else /* BOOLEAN or NULL */
1872  {
1873  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
1874  return false;
1875  }
@ PGBT_INT
Definition: pgbench.h:38
@ PGBT_DOUBLE
Definition: pgbench.h:39
int64 ival
Definition: pgbench.h:49
double dval
Definition: pgbench.h:50

References PgBenchValue::dval, PgBenchValue::ival, pg_log_error, PGBT_DOUBLE, PGBT_INT, PgBenchValue::type, PgBenchValue::u, and valueTypeName().

Referenced by evalStandardFunc().

◆ coerceToInt()

static bool coerceToInt ( PgBenchValue pval,
int64 *  ival 
)
static

Definition at line 1830 of file pgbench.c.

1832 {
1833  if (pval->type == PGBT_INT)
1834  {
1835  *ival = pval->u.ival;
1836  return true;
1837  }
1838  else if (pval->type == PGBT_DOUBLE)
1839  {
1840  double dval = rint(pval->u.dval);
1841 
1842  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
1843  {
1844  pg_log_error("double to int overflow for %f", dval);
1845  return false;
1846  }
1847  *ival = (int64) dval;
1848  return true;
1849  }
1850  else /* BOOLEAN or NULL */
1851  {
1852  pg_log_error("cannot coerce %s to int", valueTypeName(pval));
1853  return false;
1854  }
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1104

References PgBenchValue::dval, FLOAT8_FITS_IN_INT64, PgBenchValue::ival, pg_log_error, PGBT_DOUBLE, PGBT_INT, PgBenchValue::type, PgBenchValue::u, and valueTypeName().

Referenced by evalStandardFunc().

◆ commandFailed()

static void commandFailed ( CState st,
const char *  cmd,
const char *  message 
)
static

Definition at line 2809 of file pgbench.c.

2811 {
2812  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
2813  st->id, st->command, cmd, st->use_file, message);

References CState::command, CState::id, pg_log_error, and CState::use_file.

Referenced by advanceConnectionState(), and executeMetaCommand().

◆ compareVariableNames()

static int compareVariableNames ( const void *  v1,
const void *  v2 
)
static

Definition at line 1392 of file pgbench.c.

1394 {
1395  return strcmp(((const Variable *) v1)->name,
1396  ((const Variable *) v2)->name);

References name.

Referenced by lookupVariable().

◆ computeIterativeZipfian()

static int64 computeIterativeZipfian ( pg_prng_state state,
int64  n,
double  s 
)
static

Definition at line 1029 of file pgbench.c.

1031 {
1032  double b = pow(2.0, s - 1.0);
1033  double x,
1034  t,
1035  u,
1036  v;
1037 
1038  /* Ensure n is sane */
1039  if (n <= 1)
1040  return 1;
1041 
1042  while (true)
1043  {
1044  /* random variates */
1045  u = pg_prng_double(state);
1046  v = pg_prng_double(state);
1047 
1048  x = floor(pow(u, -1.0 / (s - 1.0)));
1049 
1050  t = pow(1.0 + 1.0 / x, s - 1.0);
1051  /* reject if too large or out of bound */
1052  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1053  break;
1054  }
1055  return (int64) x;
int b
Definition: isn.c:70
int x
Definition: isn.c:71
double pg_prng_double(pg_prng_state *state)
Definition: pg_prng.c:226
Definition: regguts.h:318

References b, pg_prng_double(), and x.

Referenced by getZipfianRand().

◆ ConditionError()

static void ConditionError ( const char *  desc,
int  cmdn,
const char *  msg 
)
static

Definition at line 5048 of file pgbench.c.

5050 {
5051  pg_log_fatal("condition error in script \"%s\" command %d: %s",
5052  desc, cmdn, msg);
5053  exit(1);

References exit(), and pg_log_fatal.

Referenced by CheckConditional().

◆ create_sql_command()

static Command* create_sql_command ( PQExpBuffer  buf,
const char *  source 
)
static

Definition at line 4757 of file pgbench.c.

4759 {
4760  Command *my_command;
4761  char *p = skip_sql_comments(buf->data);
4762 
4763  if (p == NULL)
4764  return NULL;
4765 
4766  /* Allocate and initialize Command structure */
4767  my_command = (Command *) pg_malloc(sizeof(Command));
4768  initPQExpBuffer(&my_command->lines);
4769  appendPQExpBufferStr(&my_command->lines, p);
4770  my_command->first_line = NULL; /* this is set later */
4771  my_command->type = SQL_COMMAND;
4772  my_command->meta = META_NONE;
4773  my_command->argc = 0;
4774  memset(my_command->argv, 0, sizeof(my_command->argv));
4775  my_command->varprefix = NULL; /* allocated later, if needed */
4776  my_command->expr = NULL;
4777  initSimpleStats(&my_command->stats);
4778 
4779  return my_command;
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static char * buf
Definition: pg_test_fsync.c:70
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:4722
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1222
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
PQExpBufferData lines
Definition: pgbench.c:573
PgBenchExpr * expr
Definition: pgbench.c:580
char * argv[MAX_ARGS]
Definition: pgbench.c:578
char * first_line
Definition: pgbench.c:574
int argc
Definition: pgbench.c:577

References appendPQExpBufferStr(), Command::argc, Command::argv, buf, Command::expr, Command::first_line, initPQExpBuffer(), initSimpleStats(), Command::lines, Command::meta, META_NONE, pg_malloc(), skip_sql_comments(), SQL_COMMAND, Command::stats, Command::type, and Command::varprefix.

Referenced by ParseScript().

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 3954 of file pgbench.c.

3956 {
3957  PQExpBufferData query;
3958 
3959  /* we must have to create some partitions */
3960  Assert(partitions > 0);
3961 
3962  fprintf(stderr, "creating %d partitions...\n", partitions);
3963 
3964  initPQExpBuffer(&query);
3965 
3966  for (int p = 1; p <= partitions; p++)
3967  {
3969  {
3970  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
3971 
3972  printfPQExpBuffer(&query,
3973  "create%s table pgbench_accounts_%d\n"
3974  " partition of pgbench_accounts\n"
3975  " for values from (",
3976  unlogged_tables ? " unlogged" : "", p);
3977 
3978  /*
3979  * For RANGE, we use open-ended partitions at the beginning and
3980  * end to allow any valid value for the primary key. Although the
3981  * actual minimum and maximum values can be derived from the
3982  * scale, it is more generic and the performance is better.
3983  */
3984  if (p == 1)
3985  appendPQExpBufferStr(&query, "minvalue");
3986  else
3987  appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
3988 
3989  appendPQExpBufferStr(&query, ") to (");
3990 
3991  if (p < partitions)
3992  appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
3993  else
3994  appendPQExpBufferStr(&query, "maxvalue");
3995 
3996  appendPQExpBufferChar(&query, ')');
3997  }
3998  else if (partition_method == PART_HASH)
3999  printfPQExpBuffer(&query,
4000  "create%s table pgbench_accounts_%d\n"
4001  " partition of pgbench_accounts\n"
4002  " for values with (modulus %d, remainder %d)",
4003  unlogged_tables ? " unlogged" : "", p,
4004  partitions, p - 1);
4005  else /* cannot get there */
4006  Assert(0);
4007 
4008  /*
4009  * Per ddlinfo in initCreateTables, fillfactor is needed on table
4010  * pgbench_accounts.
4011  */
4012  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4013 
4014  executeStatement(con, query.data);
4015  }
4016 
4017  termPQExpBuffer(&query);
#define INT64_FORMAT
Definition: c.h:483
int scale
Definition: pgbench.c:192
static int partitions
Definition: pgbench.c:234
int fillfactor
Definition: pgbench.c:198
static partition_method_t partition_method
Definition: pgbench.c:244
bool unlogged_tables
Definition: pgbench.c:203
#define naccounts
Definition: pgbench.c:256
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1296
#define fprintf
Definition: port.h:226
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:380
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131

References appendPQExpBuffer(), appendPQExpBufferChar(), appendPQExpBufferStr(), Assert(), PQExpBufferData::data, executeStatement(), fillfactor, fprintf, initPQExpBuffer(), INT64_FORMAT, naccounts, PART_HASH, PART_RANGE, partition_method, partitions, printfPQExpBuffer(), scale, termPQExpBuffer(), and unlogged_tables.

Referenced by initCreateTables().

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 3920 of file pgbench.c.

3922 {
3923  int i;
3924 
3925  for (i = 0; i < length; i++)
3926  finishCon(&state[i]);

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1327 of file pgbench.c.

1329 {
1330  PGconn *conn;
1331  bool new_pass;
1332  static char *password = NULL;
1333 
1334  /*
1335  * Start the connection. Loop until we have a password if requested by
1336  * backend.
1337  */
1338  do
1339  {
1340 #define PARAMS_ARRAY_SIZE 7
1341 
1342  const char *keywords[PARAMS_ARRAY_SIZE];
1343  const char *values[PARAMS_ARRAY_SIZE];
1344 
1345  keywords[0] = "host";
1346  values[0] = pghost;
1347  keywords[1] = "port";
1348  values[1] = pgport;
1349  keywords[2] = "user";
1350  values[2] = username;
1351  keywords[3] = "password";
1352  values[3] = password;
1353  keywords[4] = "dbname";
1354  values[4] = dbName;
1355  keywords[5] = "fallback_application_name";
1356  values[5] = progname;
1357  keywords[6] = NULL;
1358  values[6] = NULL;
1359 
1360  new_pass = false;
1361 
1362  conn = PQconnectdbParams(keywords, values, true);
1363 
1364  if (!conn)
1365  {
1366  pg_log_error("connection to database \"%s\" failed", dbName);
1367  return NULL;
1368  }
1369 
1370  if (PQstatus(conn) == CONNECTION_BAD &&
1372  !password)
1373  {
1374  PQfinish(conn);
1375  password = simple_prompt("Password: ", false);
1376  new_pass = true;
1377  }
1378  } while (new_pass);
1379 
1380  /* check to see that the backend connection was successfully made */
1381  if (PQstatus(conn) == CONNECTION_BAD)
1382  {
1384  PQfinish(conn);
1385  return NULL;
1386  }
1387 
1388  return conn;
static Datum values[MAXATTR]
Definition: bootstrap.c:156
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:657
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6821
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6770
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6717
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4257
@ CONNECTION_BAD
Definition: libpq-fe.h:59
#define PARAMS_ARRAY_SIZE
const char * pghost
Definition: pgbench.c:280
const char * username
Definition: pgbench.c:282
const char * progname
Definition: pgbench.c:285
const char * pgport
Definition: pgbench.c:281
const char * dbName
Definition: pgbench.c:283
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
static char * password
Definition: streamutil.c:53
PGconn * conn
Definition: streamutil.c:54

References conn, CONNECTION_BAD, dbName, PARAMS_ARRAY_SIZE, password, pg_log_error, pghost, pgport, PQconnectdbParams(), PQconnectionNeedsPassword(), PQerrorMessage(), PQfinish(), PQstatus(), progname, simple_prompt(), username, and values.

Referenced by advanceConnectionState(), main(), runInitSteps(), and threadRun().

◆ doLog()

static void doLog ( TState thread,
CState st,
StatsData agg,
bool  skipped,
double  latency,
double  lag 
)
static

Definition at line 3793 of file pgbench.c.

3796 {
3797  FILE *logfile = thread->logfile;
3799 
3800  Assert(use_log);
3801 
3802  /*
3803  * Skip the log entry if sampling is enabled and this row doesn't belong
3804  * to the random sample.
3805  */
3806  if (sample_rate != 0.0 &&
3808  return;
3809 
3810  /* should we aggregate the results or not? */
3811  if (agg_interval > 0)
3812  {
3814 
3815  /*
3816  * Loop until we reach the interval of the current moment, and print
3817  * any empty intervals in between (this may happen with very low tps,
3818  * e.g. --rate=0.1).
3819  */
3820 
3821  while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
3822  {
3823  /* print aggregated report to logfile */
3824  fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
3825  agg->start_time / 1000000, /* seconds since Unix epoch */
3826  agg->cnt,
3827  agg->latency.sum,
3828  agg->latency.sum2,
3829  agg->latency.min,
3830  agg->latency.max);
3831  if (throttle_delay)
3832  {
3833  fprintf(logfile, " %.0f %.0f %.0f %.0f",
3834  agg->lag.sum,
3835  agg->lag.sum2,
3836  agg->lag.min,
3837  agg->lag.max);
3838  if (latency_limit)
3839  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
3840  }
3841  fputc('\n', logfile);
3842 
3843  /* reset data and move to next interval */
3844  initStats(agg, next);
3845  }
3846 
3847  /* accumulate the current transaction */
3848  accumStats(agg, skipped, latency, lag);
3849  }
3850  else
3851  {
3852  /* no, print raw transactions */
3853  if (skipped)
3854  fprintf(logfile, "%d " INT64_FORMAT " skipped %d " INT64_FORMAT " "
3855  INT64_FORMAT,
3856  st->id, st->cnt, st->use_file, now / 1000000, now % 1000000);
3857  else
3858  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
3859  INT64_FORMAT,
3860  st->id, st->cnt, latency, st->use_file,
3861  now / 1000000, now % 1000000);
3862  if (throttle_delay)
3863  fprintf(logfile, " %.0f", lag);
3864  fputc('\n', logfile);
3865  }
static int32 next
Definition: blutils.c:219
static FILE * logfile
Definition: pg_regress.c:102
bool use_log
Definition: pgbench.c:267
int agg_interval
Definition: pgbench.c:269
static void initStats(StatsData *sd, pg_time_usec_t start)
Definition: pgbench.c:1262
double sample_rate
Definition: pgbench.c:208
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:1275
pg_time_usec_t epoch_shift
Definition: pgbench.c:351
pg_time_usec_t start_time
Definition: pgbench.c:339
FILE * logfile
Definition: pgbench.c:498
pg_prng_state ts_sample_rs
Definition: pgbench.c:495

References accumStats(), agg_interval, Assert(), StatsData::cnt, CState::cnt, epoch_shift, fprintf, CState::id, initStats(), INT64_FORMAT, StatsData::lag, StatsData::latency, latency_limit, TState::logfile, logfile, SimpleStats::max, SimpleStats::min, next, now(), pg_prng_double(), pg_time_now(), sample_rate, StatsData::skipped, StatsData::start_time, SimpleStats::sum, SimpleStats::sum2, throttle_delay, TState::ts_sample_rs, CState::use_file, and use_log.

Referenced by processXactStats(), and threadRun().

◆ evalFunc()

static bool evalFunc ( CState st,
PgBenchFunction  func,
PgBenchExprLink args,
PgBenchValue retval 
)
static

Definition at line 2601 of file pgbench.c.

2604 {
2605  if (isLazyFunc(func))
2606  return evalLazyFunc(st, func, args, retval);
2607  else
2608  return evalStandardFunc(st, func, args, retval);
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1910
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1917
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2034

References generate_unaccent_rules::args, evalLazyFunc(), evalStandardFunc(), and isLazyFunc().

Referenced by evaluateExpr().

◆ evalLazyFunc()

static bool evalLazyFunc ( CState st,
PgBenchFunction  func,
PgBenchExprLink args,
PgBenchValue retval 
)
static

Definition at line 1917 of file pgbench.c.

1920 {
1921  PgBenchValue a1,
1922  a2;
1923  bool ba1,
1924  ba2;
1925 
1926  Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
1927 
1928  /* args points to first condition */
1929  if (!evaluateExpr(st, args->expr, &a1))
1930  return false;
1931 
1932  /* second condition for AND/OR and corresponding branch for CASE */
1933  args = args->next;
1934 
1935  switch (func)
1936  {
1937  case PGBENCH_AND:
1938  if (a1.type == PGBT_NULL)
1939  {
1940  setNullValue(retval);
1941  return true;
1942  }
1943 
1944  if (!coerceToBool(&a1, &ba1))
1945  return false;
1946 
1947  if (!ba1)
1948  {
1949  setBoolValue(retval, false);
1950  return true;
1951  }
1952 
1953  if (!evaluateExpr(st, args->expr, &a2))
1954  return false;
1955 
1956  if (a2.type == PGBT_NULL)
1957  {
1958  setNullValue(retval);
1959  return true;
1960  }
1961  else if (!coerceToBool(&a2, &ba2))
1962  return false;
1963  else
1964  {
1965  setBoolValue(retval, ba2);
1966  return true;
1967  }
1968 
1969  return true;
1970 
1971  case PGBENCH_OR:
1972 
1973  if (a1.type == PGBT_NULL)
1974  {
1975  setNullValue(retval);
1976  return true;
1977  }
1978 
1979  if (!coerceToBool(&a1, &ba1))
1980  return false;
1981 
1982  if (ba1)
1983  {
1984  setBoolValue(retval, true);
1985  return true;
1986  }
1987 
1988  if (!evaluateExpr(st, args->expr, &a2))
1989  return false;
1990 
1991  if (a2.type == PGBT_NULL)
1992  {
1993  setNullValue(retval);
1994  return true;
1995  }
1996  else if (!coerceToBool(&a2, &ba2))
1997  return false;
1998  else
1999  {
2000  setBoolValue(retval, ba2);
2001  return true;
2002  }
2003 
2004  case PGBENCH_CASE:
2005  /* when true, execute branch */
2006  if (valueTruth(&a1))
2007  return evaluateExpr(st, args->expr, retval);
2008 
2009  /* now args contains next condition or final else expression */
2010  args = args->next;
2011 
2012  /* final else case? */
2013  if (args->next == NULL)
2014  return evaluateExpr(st, args->expr, retval);
2015 
2016  /* no, another when, proceed */
2017  return evalLazyFunc(st, PGBENCH_CASE, args, retval);
2018 
2019  default:
2020  /* internal error, cannot get here */
2021  Assert(0);
2022  break;
2023  }
2024  return false;
static const FormData_pg_attribute a1
Definition: heap.c:153
static const FormData_pg_attribute a2
Definition: heap.c:167
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:1879
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2617
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:1887
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1809
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:1789
@ PGBT_NULL
Definition: pgbench.h:37
@ PGBENCH_AND
Definition: pgbench.h:87
@ PGBENCH_OR
Definition: pgbench.h:88
@ PGBENCH_CASE
Definition: pgbench.h:100

References a1, a2, generate_unaccent_rules::args, Assert(), coerceToBool(), evaluateExpr(), isLazyFunc(), PGBENCH_AND, PGBENCH_CASE, PGBENCH_OR, PGBT_NULL, setBoolValue(), setNullValue(), and valueTruth().

Referenced by evalFunc().

◆ evalStandardFunc()

static bool evalStandardFunc ( CState st,
PgBenchFunction  func,
PgBenchExprLink args,
PgBenchValue retval 
)
static

Definition at line 2034 of file pgbench.c.

2038 {
2039  /* evaluate all function arguments */
2040  int nargs = 0;
2041  PgBenchValue vargs[MAX_FARGS];
2042  PgBenchExprLink *l = args;
2043  bool has_null = false;
2044 
2045  for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
2046  {
2047  if (!evaluateExpr(st, l->expr, &vargs[nargs]))
2048  return false;
2049  has_null |= vargs[nargs].type == PGBT_NULL;
2050  }
2051 
2052  if (l != NULL)
2053  {
2054  pg_log_error("too many function arguments, maximum is %d", MAX_FARGS);
2055  return false;
2056  }
2057 
2058  /* NULL arguments */
2059  if (has_null && func != PGBENCH_IS && func != PGBENCH_DEBUG)
2060  {
2061  setNullValue(retval);
2062  return true;
2063  }
2064 
2065  /* then evaluate function */
2066  switch (func)
2067  {
2068  /* overloaded operators */
2069  case PGBENCH_ADD:
2070  case PGBENCH_SUB:
2071  case PGBENCH_MUL:
2072  case PGBENCH_DIV:
2073  case PGBENCH_MOD:
2074  case PGBENCH_EQ:
2075  case PGBENCH_NE:
2076  case PGBENCH_LE:
2077  case PGBENCH_LT:
2078  {
2079  PgBenchValue *lval = &vargs[0],
2080  *rval = &vargs[1];
2081 
2082  Assert(nargs == 2);
2083 
2084  /* overloaded type management, double if some double */
2085  if ((lval->type == PGBT_DOUBLE ||
2086  rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
2087  {
2088  double ld,
2089  rd;
2090 
2091  if (!coerceToDouble(lval, &ld) ||
2092  !coerceToDouble(rval, &rd))
2093  return false;
2094 
2095  switch (func)
2096  {
2097  case PGBENCH_ADD:
2098  setDoubleValue(retval, ld + rd);
2099  return true;
2100 
2101  case PGBENCH_SUB:
2102  setDoubleValue(retval, ld - rd);
2103  return true;
2104 
2105  case PGBENCH_MUL:
2106  setDoubleValue(retval, ld * rd);
2107  return true;
2108 
2109  case PGBENCH_DIV:
2110  setDoubleValue(retval, ld / rd);
2111  return true;
2112 
2113  case PGBENCH_EQ:
2114  setBoolValue(retval, ld == rd);
2115  return true;
2116 
2117  case PGBENCH_NE:
2118  setBoolValue(retval, ld != rd);
2119  return true;
2120 
2121  case PGBENCH_LE:
2122  setBoolValue(retval, ld <= rd);
2123  return true;
2124 
2125  case PGBENCH_LT:
2126  setBoolValue(retval, ld < rd);
2127  return true;
2128 
2129  default:
2130  /* cannot get here */
2131  Assert(0);
2132  }
2133  }
2134  else /* we have integer operands, or % */
2135  {
2136  int64 li,
2137  ri,
2138  res;
2139 
2140  if (!coerceToInt(lval, &li) ||
2141  !coerceToInt(rval, &ri))
2142  return false;
2143 
2144  switch (func)
2145  {
2146  case PGBENCH_ADD:
2147  if (pg_add_s64_overflow(li, ri, &res))
2148  {
2149  pg_log_error("bigint add out of range");
2150  return false;
2151  }
2152  setIntValue(retval, res);
2153  return true;
2154 
2155  case PGBENCH_SUB:
2156  if (pg_sub_s64_overflow(li, ri, &res))
2157  {
2158  pg_log_error("bigint sub out of range");
2159  return false;
2160  }
2161  setIntValue(retval, res);
2162  return true;
2163 
2164  case PGBENCH_MUL:
2165  if (pg_mul_s64_overflow(li, ri, &res))
2166  {
2167  pg_log_error("bigint mul out of range");
2168  return false;
2169  }
2170  setIntValue(retval, res);
2171  return true;
2172 
2173  case PGBENCH_EQ:
2174  setBoolValue(retval, li == ri);
2175  return true;
2176 
2177  case PGBENCH_NE:
2178  setBoolValue(retval, li != ri);
2179  return true;
2180 
2181  case PGBENCH_LE:
2182  setBoolValue(retval, li <= ri);
2183  return true;
2184 
2185  case PGBENCH_LT:
2186  setBoolValue(retval, li < ri);
2187  return true;
2188 
2189  case PGBENCH_DIV:
2190  case PGBENCH_MOD:
2191  if (ri == 0)
2192  {
2193  pg_log_error("division by zero");
2194  return false;
2195  }
2196  /* special handling of -1 divisor */
2197  if (ri == -1)
2198  {
2199  if (func == PGBENCH_DIV)
2200  {
2201  /* overflow check (needed for INT64_MIN) */
2202  if (li == PG_INT64_MIN)
2203  {
2204  pg_log_error("bigint div out of range");
2205  return false;
2206  }
2207  else
2208  setIntValue(retval, -li);
2209  }
2210  else
2211  setIntValue(retval, 0);
2212  return true;
2213  }
2214  /* else divisor is not -1 */
2215  if (func == PGBENCH_DIV)
2216  setIntValue(retval, li / ri);
2217  else /* func == PGBENCH_MOD */
2218  setIntValue(retval, li % ri);
2219 
2220  return true;
2221 
2222  default:
2223  /* cannot get here */
2224  Assert(0);
2225  }
2226  }
2227 
2228  Assert(0);
2229  return false; /* NOTREACHED */
2230  }
2231 
2232  /* integer bitwise operators */
2233  case PGBENCH_BITAND:
2234  case PGBENCH_BITOR:
2235  case PGBENCH_BITXOR:
2236  case PGBENCH_LSHIFT:
2237  case PGBENCH_RSHIFT:
2238  {
2239  int64 li,
2240  ri;
2241 
2242  if (!coerceToInt(&vargs[0], &li) || !coerceToInt(&vargs[1], &ri))
2243  return false;
2244 
2245  if (func == PGBENCH_BITAND)
2246  setIntValue(retval, li & ri);
2247  else if (func == PGBENCH_BITOR)
2248  setIntValue(retval, li | ri);
2249  else if (func == PGBENCH_BITXOR)
2250  setIntValue(retval, li ^ ri);
2251  else if (func == PGBENCH_LSHIFT)
2252  setIntValue(retval, li << ri);
2253  else if (func == PGBENCH_RSHIFT)
2254  setIntValue(retval, li >> ri);
2255  else /* cannot get here */
2256  Assert(0);
2257 
2258  return true;
2259  }
2260 
2261  /* logical operators */
2262  case PGBENCH_NOT:
2263  {
2264  bool b;
2265 
2266  if (!coerceToBool(&vargs[0], &b))
2267  return false;
2268 
2269  setBoolValue(retval, !b);
2270  return true;
2271  }
2272 
2273  /* no arguments */
2274  case PGBENCH_PI:
2275  setDoubleValue(retval, M_PI);
2276  return true;
2277 
2278  /* 1 overloaded argument */
2279  case PGBENCH_ABS:
2280  {
2281  PgBenchValue *varg = &vargs[0];
2282 
2283  Assert(nargs == 1);
2284 
2285  if (varg->type == PGBT_INT)
2286  {
2287  int64 i = varg->u.ival;
2288 
2289  setIntValue(retval, i < 0 ? -i : i);
2290  }
2291  else
2292  {
2293  double d = varg->u.dval;
2294 
2295  Assert(varg->type == PGBT_DOUBLE);
2296  setDoubleValue(retval, d < 0.0 ? -d : d);
2297  }
2298 
2299  return true;
2300  }
2301 
2302  case PGBENCH_DEBUG:
2303  {
2304  PgBenchValue *varg = &vargs[0];
2305 
2306  Assert(nargs == 1);
2307 
2308  fprintf(stderr, "debug(script=%d,command=%d): ",
2309  st->use_file, st->command + 1);
2310 
2311  if (varg->type == PGBT_NULL)
2312  fprintf(stderr, "null\n");
2313  else if (varg->type == PGBT_BOOLEAN)
2314  fprintf(stderr, "boolean %s\n", varg->u.bval ? "true" : "false");
2315  else if (varg->type == PGBT_INT)
2316  fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
2317  else if (varg->type == PGBT_DOUBLE)
2318  fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
2319  else /* internal error, unexpected type */
2320  Assert(0);
2321 
2322  *retval = *varg;
2323 
2324  return true;
2325  }
2326 
2327  /* 1 double argument */
2328  case PGBENCH_DOUBLE:
2329  case PGBENCH_SQRT:
2330  case PGBENCH_LN:
2331  case PGBENCH_EXP:
2332  {
2333  double dval;
2334 
2335  Assert(nargs == 1);
2336 
2337  if (!coerceToDouble(&vargs[0], &dval))
2338  return false;
2339 
2340  if (func == PGBENCH_SQRT)
2341  dval = sqrt(dval);
2342  else if (func == PGBENCH_LN)
2343  dval = log(dval);
2344  else if (func == PGBENCH_EXP)
2345  dval = exp(dval);
2346  /* else is cast: do nothing */
2347 
2348  setDoubleValue(retval, dval);
2349  return true;
2350  }
2351 
2352  /* 1 int argument */
2353  case PGBENCH_INT:
2354  {
2355  int64 ival;
2356 
2357  Assert(nargs == 1);
2358 
2359  if (!coerceToInt(&vargs[0], &ival))
2360  return false;
2361 
2362  setIntValue(retval, ival);
2363  return true;
2364  }
2365 
2366  /* variable number of arguments */
2367  case PGBENCH_LEAST:
2368  case PGBENCH_GREATEST:
2369  {
2370  bool havedouble;
2371  int i;
2372 
2373  Assert(nargs >= 1);
2374 
2375  /* need double result if any input is double */
2376  havedouble = false;
2377  for (i = 0; i < nargs; i++)
2378  {
2379  if (vargs[i].type == PGBT_DOUBLE)
2380  {
2381  havedouble = true;
2382  break;
2383  }
2384  }
2385  if (havedouble)
2386  {
2387  double extremum;
2388 
2389  if (!coerceToDouble(&vargs[0], &extremum))
2390  return false;
2391  for (i = 1; i < nargs; i++)
2392  {
2393  double dval;
2394 
2395  if (!coerceToDouble(&vargs[i], &dval))
2396  return false;
2397  if (func == PGBENCH_LEAST)
2398  extremum = Min(extremum, dval);
2399  else
2400  extremum = Max(extremum, dval);
2401  }
2402  setDoubleValue(retval, extremum);
2403  }
2404  else
2405  {
2406  int64 extremum;
2407 
2408  if (!coerceToInt(&vargs[0], &extremum))
2409  return false;
2410  for (i = 1; i < nargs; i++)
2411  {
2412  int64 ival;
2413 
2414  if (!coerceToInt(&vargs[i], &ival))
2415  return false;
2416  if (func == PGBENCH_LEAST)
2417  extremum = Min(extremum, ival);
2418  else
2419  extremum = Max(extremum, ival);
2420  }
2421  setIntValue(retval, extremum);
2422  }
2423  return true;
2424  }
2425 
2426  /* random functions */
2427  case PGBENCH_RANDOM:
2431  {
2432  int64 imin,
2433  imax,
2434  delta;
2435 
2436  Assert(nargs >= 2);
2437 
2438  if (!coerceToInt(&vargs[0], &imin) ||
2439  !coerceToInt(&vargs[1], &imax))
2440  return false;
2441 
2442  /* check random range */
2443  if (unlikely(imin > imax))
2444  {
2445  pg_log_error("empty range given to random");
2446  return false;
2447  }
2448  else if (unlikely(pg_sub_s64_overflow(imax, imin, &delta) ||
2449  pg_add_s64_overflow(delta, 1, &delta)))
2450  {
2451  /* prevent int overflows in random functions */
2452  pg_log_error("random range is too large");
2453  return false;
2454  }
2455 
2456  if (func == PGBENCH_RANDOM)
2457  {
2458  Assert(nargs == 2);
2459  setIntValue(retval, getrand(&st->cs_func_rs, imin, imax));
2460  }
2461  else /* gaussian & exponential */
2462  {
2463  double param;
2464 
2465  Assert(nargs == 3);
2466 
2467  if (!coerceToDouble(&vargs[2], &param))
2468  return false;
2469 
2470  if (func == PGBENCH_RANDOM_GAUSSIAN)
2471  {
2472  if (param < MIN_GAUSSIAN_PARAM)
2473  {
2474  pg_log_error("gaussian parameter must be at least %f (not %f)",
2475  MIN_GAUSSIAN_PARAM, param);
2476  return false;
2477  }
2478 
2479  setIntValue(retval,
2481  imin, imax, param));
2482  }
2483  else if (func == PGBENCH_RANDOM_ZIPFIAN)
2484  {
2485  if (param < MIN_ZIPFIAN_PARAM || param > MAX_ZIPFIAN_PARAM)
2486  {
2487  pg_log_error("zipfian parameter must be in range [%.3f, %.0f] (not %f)",
2489  return false;
2490  }
2491 
2492  setIntValue(retval,
2493  getZipfianRand(&st->cs_func_rs, imin, imax, param));
2494  }
2495  else /* exponential */
2496  {
2497  if (param <= 0.0)
2498  {
2499  pg_log_error("exponential parameter must be greater than zero (not %f)",
2500  param);
2501  return false;
2502  }
2503 
2504  setIntValue(retval,
2506  imin, imax, param));
2507  }
2508  }
2509 
2510  return true;
2511  }
2512 
2513  case PGBENCH_POW:
2514  {
2515  PgBenchValue *lval = &vargs[0];
2516  PgBenchValue *rval = &vargs[1];
2517  double ld,
2518  rd;
2519 
2520  Assert(nargs == 2);
2521 
2522  if (!coerceToDouble(lval, &ld) ||
2523  !coerceToDouble(rval, &rd))
2524  return false;
2525 
2526  setDoubleValue(retval, pow(ld, rd));
2527 
2528  return true;
2529  }
2530 
2531  case PGBENCH_IS:
2532  {
2533  Assert(nargs == 2);
2534 
2535  /*
2536  * note: this simple implementation is more permissive than
2537  * SQL
2538  */
2539  setBoolValue(retval,
2540  vargs[0].type == vargs[1].type &&
2541  vargs[0].u.bval == vargs[1].u.bval);
2542  return true;
2543  }
2544 
2545  /* hashing */
2546  case PGBENCH_HASH_FNV1A:
2547  case PGBENCH_HASH_MURMUR2:
2548  {
2549  int64 val,
2550  seed;
2551 
2552  Assert(nargs == 2);
2553 
2554  if (!coerceToInt(&vargs[0], &val) ||
2555  !coerceToInt(&vargs[1], &seed))
2556  return false;
2557 
2558  if (func == PGBENCH_HASH_MURMUR2)
2559  setIntValue(retval, getHashMurmur2(val, seed));
2560  else if (func == PGBENCH_HASH_FNV1A)
2561  setIntValue(retval, getHashFnv1a(val, seed));
2562  else
2563  /* cannot get here */
2564  Assert(0);
2565 
2566  return true;
2567  }
2568 
2569  case PGBENCH_PERMUTE:
2570  {
2571  int64 val,
2572  size,
2573  seed;
2574 
2575  Assert(nargs == 3);
2576 
2577  if (!coerceToInt(&vargs[0], &val) ||
2578  !coerceToInt(&vargs[1], &size) ||
2579  !coerceToInt(&vargs[2], &seed))
2580  return false;
2581 
2582  if (size <= 0)
2583  {
2584  pg_log_error("permute size parameter must be greater than zero");
2585  return false;
2586  }
2587 
2588  setIntValue(retval, permute(val, size, seed));
2589  return true;
2590  }
2591 
2592  default:
2593  /* cannot get here */
2594  Assert(0);
2595  /* dead code to avoid a compiler warning */
2596  return false;
2597  }
#define Min(x, y)
Definition: c.h:986
#define Max(x, y)
Definition: c.h:980
#define PG_INT64_MIN
Definition: c.h:526
#define unlikely(x)
Definition: c.h:273
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:215
static bool pg_sub_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:188
static bool pg_add_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:161
static int64 getZipfianRand(pg_prng_state *state, int64 min, int64 max, double s)
Definition: pgbench.c:1059
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:1895
static bool coerceToInt(PgBenchValue *pval, int64 *ival)
Definition: pgbench.c:1830
static int64 getExponentialRand(pg_prng_state *state, int64 min, int64 max, double parameter)
Definition: pgbench.c:923
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:1903
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:181
static int64 permute(const int64 val, const int64 isize, const int64 seed)
Definition: pgbench.c:1131
#define MAX_FARGS
Definition: pgbench.c:2027
static int64 getHashMurmur2(int64 val, uint64 seed)
Definition: pgbench.c:1098
static int64 getGaussianRand(pg_prng_state *state, int64 min, int64 max, double parameter)
Definition: pgbench.c:947
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:179
#define M_PI
Definition: pgbench.c:76
static int64 getHashFnv1a(int64 val, uint64 seed)
Definition: pgbench.c:1073
static bool coerceToDouble(PgBenchValue *pval, double *dval)
Definition: pgbench.c:1858
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:182
@ PGBENCH_DIV
Definition: pgbench.h:70
@ PGBENCH_DOUBLE
Definition: pgbench.h:77
@ PGBENCH_LT
Definition: pgbench.h:98
@ PGBENCH_LN
Definition: pgbench.h:80
@ PGBENCH_RANDOM_EXPONENTIAL
Definition: pgbench.h:84
@ PGBENCH_RSHIFT
Definition: pgbench.h:94
@ PGBENCH_DEBUG
Definition: pgbench.h:72
@ PGBENCH_MOD
Definition: pgbench.h:71
@ PGBENCH_GREATEST
Definition: pgbench.h:75
@ PGBENCH_BITXOR
Definition: pgbench.h:92
@ PGBENCH_RANDOM_ZIPFIAN
Definition: pgbench.h:85
@ PGBENCH_INT
Definition: pgbench.h:76
@ PGBENCH_NE
Definition: pgbench.h:96
@ PGBENCH_LE
Definition: pgbench.h:97
@ PGBENCH_EXP
Definition: pgbench.h:81
@ PGBENCH_PI
Definition: pgbench.h:78
@ PGBENCH_ADD
Definition: pgbench.h:67
@ PGBENCH_EQ
Definition: pgbench.h:95
@ PGBENCH_LSHIFT
Definition: pgbench.h:93
@ PGBENCH_RANDOM
Definition: pgbench.h:82
@ PGBENCH_POW
Definition: pgbench.h:86
@ PGBENCH_IS
Definition: pgbench.h:99
@ PGBENCH_SUB
Definition: pgbench.h:68
@ PGBENCH_HASH_MURMUR2
Definition: pgbench.h:102
@ PGBENCH_ABS
Definition: pgbench.h:73
@ PGBENCH_BITOR
Definition: pgbench.h:91
@ PGBENCH_SQRT
Definition: pgbench.h:79
@ PGBENCH_LEAST
Definition: pgbench.h:74
@ PGBENCH_PERMUTE
Definition: pgbench.h:103
@ PGBENCH_HASH_FNV1A
Definition: pgbench.h:101
@ PGBENCH_NOT
Definition: pgbench.h:89
@ PGBENCH_BITAND
Definition: pgbench.h:90
@ PGBENCH_RANDOM_GAUSSIAN
Definition: pgbench.h:83
@ PGBENCH_MUL
Definition: pgbench.h:69
pg_prng_state cs_func_rs
Definition: pgbench.c:456

References generate_unaccent_rules::args, Assert(), b, PgBenchValue::bval, coerceToBool(), coerceToDouble(), coerceToInt(), CState::command, CState::cs_func_rs, PgBenchValue::dval, evaluateExpr(), PgBenchExprLink::expr, fprintf, getExponentialRand(), getGaussianRand(), getHashFnv1a(), getHashMurmur2(), getrand(), getZipfianRand(), i, INT64_FORMAT, PgBenchValue::ival, M_PI, Max, MAX_FARGS, MAX_ZIPFIAN_PARAM, Min, MIN_GAUSSIAN_PARAM, MIN_ZIPFIAN_PARAM, PgBenchExprLink::next, permute(), pg_add_s64_overflow(), PG_INT64_MIN, pg_log_error, pg_mul_s64_overflow(), pg_sub_s64_overflow(), PGBENCH_ABS, PGBENCH_ADD, PGBENCH_BITAND, PGBENCH_BITOR, PGBENCH_BITXOR, PGBENCH_DEBUG, PGBENCH_DIV, PGBENCH_DOUBLE, PGBENCH_EQ, PGBENCH_EXP, PGBENCH_GREATEST, PGBENCH_HASH_FNV1A, PGBENCH_HASH_MURMUR2, PGBENCH_INT, PGBENCH_IS, PGBENCH_LE, PGBENCH_LEAST, PGBENCH_LN, PGBENCH_LSHIFT, PGBENCH_LT, PGBENCH_MOD, PGBENCH_MUL, PGBENCH_NE, PGBENCH_NOT, PGBENCH_PERMUTE, PGBENCH_PI, PGBENCH_POW, PGBENCH_RANDOM, PGBENCH_RANDOM_EXPONENTIAL, PGBENCH_RANDOM_GAUSSIAN, PGBENCH_RANDOM_ZIPFIAN, PGBENCH_RSHIFT, PGBENCH_SQRT, PGBENCH_SUB, PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NULL, res, setBoolValue(), setDoubleValue(), setIntValue(), setNullValue(), generate_unaccent_rules::type, PgBenchValue::type, PgBenchValue::u, unlikely, CState::use_file, and val.

Referenced by evalFunc().

◆ evaluateExpr()

static bool evaluateExpr ( CState st,
PgBenchExpr expr,
PgBenchValue retval 
)
static

Definition at line 2617 of file pgbench.c.

2619 {
2620  switch (expr->etype)
2621  {
2622  case ENODE_CONSTANT:
2623  {
2624  *retval = expr->u.constant;
2625  return true;
2626  }
2627 
2628  case ENODE_VARIABLE:
2629  {
2630  Variable *var;
2631 
2632  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
2633  {
2634  pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2635  return false;
2636  }
2637 
2638  if (!makeVariableValue(var))
2639  return false;
2640 
2641  *retval = var->value;
2642  return true;
2643  }
2644 
2645  case ENODE_FUNCTION:
2646  return evalFunc(st,
2647  expr->u.function.function,
2648  expr->u.function.args,
2649  retval);
2650 
2651  default:
2652  /* internal error which should never occur */
2653  pg_log_fatal("unexpected enode type in evaluation: %d", expr->etype);
2654  exit(1);
2655  }
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2601
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1460
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1400
@ ENODE_VARIABLE
Definition: pgbench.h:60
@ ENODE_CONSTANT
Definition: pgbench.h:59
@ ENODE_FUNCTION
Definition: pgbench.h:61
PgBenchValue constant
Definition: pgbench.h:115
PgBenchFunction function
Definition: pgbench.h:122
union PgBenchExpr::@31 u
PgBenchExprType etype
Definition: pgbench.h:112
struct PgBenchExpr::@31::@32 variable
PgBenchValue value
Definition: pgbench.c:305

References PgBenchExpr::constant, ENODE_CONSTANT, ENODE_FUNCTION, ENODE_VARIABLE, PgBenchExpr::etype, evalFunc(), exit(), PgBenchExpr::function, lookupVariable(), makeVariableValue(), pg_log_error, pg_log_fatal, PgBenchExpr::u, Variable::value, and PgBenchExpr::variable.

Referenced by evalLazyFunc(), evalStandardFunc(), and executeMetaCommand().

◆ evaluateSleep()

static bool evaluateSleep ( CState st,
int  argc,
char **  argv,
int *  usecs 
)
static

Definition at line 3057 of file pgbench.c.

3059 {
3060  char *var;
3061  int usec;
3062 
3063  if (*argv[1] == ':')
3064  {
3065  if ((var = getVariable(st, argv[1] + 1)) == NULL)
3066  {
3067  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3068  return false;
3069  }
3070 
3071  usec = atoi(var);
3072 
3073  /* Raise an error if the value of a variable is not a number */
3074  if (usec == 0 && !isdigit((unsigned char) *var))
3075  {
3076  pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3077  argv[0], var, argv[1] + 1);
3078  return false;
3079  }
3080  }
3081  else
3082  usec = atoi(argv[1]);
3083 
3084  if (argc > 2)
3085  {
3086  if (pg_strcasecmp(argv[2], "ms") == 0)
3087  usec *= 1000;
3088  else if (pg_strcasecmp(argv[2], "s") == 0)
3089  usec *= 1000000;
3090  }
3091  else
3092  usec *= 1000000;
3093 
3094  *usecs = usec;
3095  return true;
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

References getVariable(), pg_log_error, and pg_strcasecmp().

Referenced by executeMetaCommand().

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
pg_time_usec_t now 
)
static

Definition at line 3593 of file pgbench.c.

3595 {
3596  Command *command = sql_script[st->use_file].commands[st->command];
3597  int argc;
3598  char **argv;
3599 
3600  Assert(command != NULL && command->type == META_COMMAND);
3601 
3602  argc = command->argc;
3603  argv = command->argv;
3604 
3606  {
3608 
3609  initPQExpBuffer(&buf);
3610 
3611  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
3612  for (int i = 1; i < argc; i++)
3613  appendPQExpBuffer(&buf, " %s", argv[i]);
3614 
3615  pg_log_debug("%s", buf.data);
3616 
3617  termPQExpBuffer(&buf);
3618  }
3619 
3620  if (command->meta == META_SLEEP)
3621  {
3622  int usec;
3623 
3624  /*
3625  * A \sleep doesn't execute anything, we just get the delay from the
3626  * argument, and enter the CSTATE_SLEEP state. (The per-command
3627  * latency will be recorded in CSTATE_SLEEP state, not here, after the
3628  * delay has elapsed.)
3629  */
3630  if (!evaluateSleep(st, argc, argv, &usec))
3631  {
3632  commandFailed(st, "sleep", "execution of meta-command failed");
3633  return CSTATE_ABORTED;
3634  }
3635 
3637  st->sleep_until = (*now) + usec;
3638  return CSTATE_SLEEP;
3639  }
3640  else if (command->meta == META_SET)
3641  {
3642  PgBenchExpr *expr = command->expr;
3643  PgBenchValue result;
3644 
3645  if (!evaluateExpr(st, expr, &result))
3646  {
3647  commandFailed(st, argv[0], "evaluation of meta-command failed");
3648  return CSTATE_ABORTED;
3649  }
3650 
3651  if (!putVariableValue(st, argv[0], argv[1], &result))
3652  {
3653  commandFailed(st, "set", "assignment of meta-command failed");
3654  return CSTATE_ABORTED;
3655  }
3656  }
3657  else if (command->meta == META_IF)
3658  {
3659  /* backslash commands with an expression to evaluate */
3660  PgBenchExpr *expr = command->expr;
3661  PgBenchValue result;
3662  bool cond;
3663 
3664  if (!evaluateExpr(st, expr, &result))
3665  {
3666  commandFailed(st, argv[0], "evaluation of meta-command failed");
3667  return CSTATE_ABORTED;
3668  }
3669 
3670  cond = valueTruth(&result);
3672  }
3673  else if (command->meta == META_ELIF)
3674  {
3675  /* backslash commands with an expression to evaluate */
3676  PgBenchExpr *expr = command->expr;
3677  PgBenchValue result;
3678  bool cond;
3679 
3681  {
3682  /* elif after executed block, skip eval and wait for endif. */
3684  return CSTATE_END_COMMAND;
3685  }
3686 
3687  if (!evaluateExpr(st, expr, &result))
3688  {
3689  commandFailed(st, argv[0], "evaluation of meta-command failed");
3690  return CSTATE_ABORTED;
3691  }
3692 
3693  cond = valueTruth(&result);
3696  }
3697  else if (command->meta == META_ELSE)
3698  {
3699  switch (conditional_stack_peek(st->cstack))
3700  {
3701  case IFSTATE_TRUE:
3703  break;
3704  case IFSTATE_FALSE: /* inconsistent if active */
3705  case IFSTATE_IGNORED: /* inconsistent if active */
3706  case IFSTATE_NONE: /* else without if */
3707  case IFSTATE_ELSE_TRUE: /* else after else */
3708  case IFSTATE_ELSE_FALSE: /* else after else */
3709  default:
3710  /* dead code if conditional check is ok */
3711  Assert(false);
3712  }
3713  }
3714  else if (command->meta == META_ENDIF)
3715  {
3718  }
3719  else if (command->meta == META_SETSHELL)
3720  {
3721  if (!runShellCommand(st, argv[1], argv + 2, argc - 2))
3722  {
3723  commandFailed(st, "setshell", "execution of meta-command failed");
3724  return CSTATE_ABORTED;
3725  }
3726  }
3727  else if (command->meta == META_SHELL)
3728  {
3729  if (!runShellCommand(st, NULL, argv + 1, argc - 1))
3730  {
3731  commandFailed(st, "shell", "execution of meta-command failed");
3732  return CSTATE_ABORTED;
3733  }
3734  }
3735  else if (command->meta == META_STARTPIPELINE)
3736  {
3737  /*
3738  * In pipeline mode, we use a workflow based on libpq pipeline
3739  * functions.
3740  */
3741  if (querymode == QUERY_SIMPLE)
3742  {
3743  commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
3744  return CSTATE_ABORTED;
3745  }
3746 
3747  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
3748  {
3749  commandFailed(st, "startpipeline", "already in pipeline mode");
3750  return CSTATE_ABORTED;
3751  }
3752  if (PQenterPipelineMode(st->con) == 0)
3753  {
3754  commandFailed(st, "startpipeline", "failed to enter pipeline mode");
3755  return CSTATE_ABORTED;
3756  }
3757  }
3758  else if (command->meta == META_ENDPIPELINE)
3759  {
3760  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
3761  {
3762  commandFailed(st, "endpipeline", "not in pipeline mode");
3763  return CSTATE_ABORTED;
3764  }
3765  if (!PQpipelineSync(st->con))
3766  {
3767  commandFailed(st, "endpipeline", "failed to send a pipeline sync");
3768  return CSTATE_ABORTED;
3769  }
3770  /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
3771  /* collect pending results before getting out of pipeline mode */
3772  return CSTATE_WAIT_RESULT;
3773  }
3774 
3775  /*
3776  * executing the expression or shell command might have taken a
3777  * non-negligible amount of time, so reset 'now'
3778  */
3779  *now = 0;
3780 
3781  return CSTATE_END_COMMAND;
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:2894
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3077
enum pg_log_level __pg_log_level
Definition: logging.c:21
@ PG_LOG_DEBUG
Definition: logging.h:26
static QueryMode querymode
Definition: pgbench.c:548
static bool putVariableValue(CState *st, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1638
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:2701
static bool evaluateSleep(CState *st, int argc, char **argv, int *usecs)
Definition: pgbench.c:3057
pg_time_usec_t sleep_until
Definition: pgbench.c:468

References __pg_log_level, appendPQExpBuffer(), Command::argc, Command::argv, Assert(), buf, CState::command, commandFailed(), ParsedScript::commands, CState::con, conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), CState::cstack, CSTATE_ABORTED, CSTATE_END_COMMAND, CSTATE_SLEEP, CSTATE_WAIT_RESULT, evaluateExpr(), evaluateSleep(), Command::expr, i, CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, initPQExpBuffer(), Command::meta, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_ENDPIPELINE, META_IF, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, META_STARTPIPELINE, now(), PG_LOG_DEBUG, pg_log_debug, pg_time_now_lazy(), PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQenterPipelineMode(), PQpipelineStatus(), PQpipelineSync(), printfPQExpBuffer(), putVariableValue(), QUERY_SIMPLE, querymode, runShellCommand(), CState::sleep_until, sql_script, termPQExpBuffer(), Command::type, unlikely, CState::use_file, and valueTruth().

Referenced by advanceConnectionState().

◆ executeStatement()

static void executeStatement ( PGconn con,
const char *  sql 
)
static

Definition at line 1296 of file pgbench.c.

1298 {
1299  PGresult *res;
1300 
1301  res = PQexec(con, sql);
1303  {
1304  pg_log_fatal("query failed: %s", PQerrorMessage(con));
1305  pg_log_info("query was: %s", sql);
1306  exit(1);
1307  }
1308  PQclear(res);
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3178
void PQclear(PGresult *res)
Definition: fe-exec.c:694
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2193
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:95

References exit(), pg_log_fatal, pg_log_info, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), PQresultStatus(), and res.

Referenced by createPartitions(), initCreateFKeys(), initCreatePKeys(), initCreateTables(), initDropTables(), initGenerateDataClientSide(), initGenerateDataServerSide(), initTruncateTables(), and initVacuum().

◆ findBuiltin()

static const BuiltinScript* findBuiltin ( const char *  name)
static

Definition at line 5330 of file pgbench.c.

5332 {
5333  int i,
5334  found = 0,
5335  len = strlen(name);
5336  const BuiltinScript *result = NULL;
5337 
5338  for (i = 0; i < lengthof(builtin_script); i++)
5339  {
5340  if (strncmp(builtin_script[i].name, name, len) == 0)
5341  {
5342  result = &builtin_script[i];
5343  found++;
5344  }
5345  }
5346 
5347  /* ok, unambiguous result */
5348  if (found == 1)
5349  return result;
5350 
5351  /* error cases */
5352  if (found == 0)
5353  pg_log_fatal("no builtin script found for name \"%s\"", name);
5354  else /* found > 1 */
5355  pg_log_fatal("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
5356 
5358  exit(1);
#define lengthof(array)
Definition: c.h:734
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:5318
static const BuiltinScript builtin_script[]
Definition: pgbench.c:604

References builtin_script, exit(), i, len, lengthof, listAvailableScripts(), name, and pg_log_fatal.

Referenced by main().

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 6855 of file pgbench.c.

6857 {
6858  if (st->con != NULL)
6859  {
6860  PQfinish(st->con);
6861  st->con = NULL;
6862  }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 4783 of file pgbench.c.

4785 {
4786  termPQExpBuffer(&command->lines);
4787  if (command->first_line)
4788  pg_free(command->first_line);
4789  for (int i = 0; i < command->argc; i++)
4790  pg_free(command->argv[i]);
4791  if (command->varprefix)
4792  pg_free(command->varprefix);
4793 
4794  /*
4795  * It should also free expr recursively, but this is currently not needed
4796  * as only gset commands (which do not have an expression) are freed.
4797  */
4798  pg_free(command);
void pg_free(void *ptr)
Definition: fe_memutils.c:105

References Command::argc, Command::argv, Command::first_line, i, Command::lines, pg_free(), termPQExpBuffer(), and Command::varprefix.

Referenced by ParseScript().

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 7029 of file pgbench.c.

7031 {
7032  pg_free(sa);

References pg_free().

Referenced by threadRun().

◆ getExponentialRand()

static int64 getExponentialRand ( pg_prng_state state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 923 of file pgbench.c.

926 {
927  double cut,
928  uniform,
929  rand;
930 
931  /* abort if wrong parameter, but must really be checked beforehand */
932  Assert(parameter > 0.0);
933  cut = exp(-parameter);
934  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
935  uniform = 1.0 - pg_prng_double(state);
936 
937  /*
938  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
939  */
940  Assert((1.0 - cut) != 0.0);
941  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
942  /* return int64 random number within between min and max */
943  return min + (int64) ((max - min + 1) * rand);

References Assert(), and pg_prng_double().

Referenced by evalStandardFunc().

◆ getGaussianRand()

static int64 getGaussianRand ( pg_prng_state state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 947 of file pgbench.c.

950 {
951  double stdev;
952  double rand;
953 
954  /* abort if parameter is too low, but must really be checked beforehand */
955  Assert(parameter >= MIN_GAUSSIAN_PARAM);
956 
957  /*
958  * Get user specified random number from this loop, with -parameter <
959  * stdev <= parameter
960  *
961  * This loop is executed until the number is in the expected range.
962  *
963  * As the minimum parameter is 2.0, the probability of looping is low:
964  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
965  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
966  * the worst case. For a parameter value of 5.0, the looping probability
967  * is about e^{-5} * 2 / pi ~ 0.43%.
968  */
969  do
970  {
971  /*
972  * pg_prng_double generates [0, 1), but for the basic version of the
973  * Box-Muller transform the two uniformly distributed random numbers
974  * are expected to be in (0, 1] (see
975  * https://en.wikipedia.org/wiki/Box-Muller_transform)
976  */
977  double rand1 = 1.0 - pg_prng_double(state);
978  double rand2 = 1.0 - pg_prng_double(state);
979 
980  /* Box-Muller basic form transform */
981  double var_sqrt = sqrt(-2.0 * log(rand1));
982 
983  stdev = var_sqrt * sin(2.0 * M_PI * rand2);
984 
985  /*
986  * we may try with cos, but there may be a bias induced if the
987  * previous value fails the test. To be on the safe side, let us try
988  * over.
989  */
990  }
991  while (stdev < -parameter || stdev >= parameter);
992 
993  /* stdev is in [-parameter, parameter), normalization to [0,1) */
994  rand = (stdev + parameter) / (parameter * 2.0);
995 
996  /* return int64 random number within between min and max */
997  return min + (int64) ((max - min + 1) * rand);

References Assert(), M_PI, MIN_GAUSSIAN_PARAM, and pg_prng_double().

Referenced by evalStandardFunc().

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1073 of file pgbench.c.

1075 {
1076  int64 result;
1077  int i;
1078 
1079  result = FNV_OFFSET_BASIS ^ seed;
1080  for (i = 0; i < 8; ++i)
1081  {
1082  int32 octet = val & 0xff;
1083 
1084  val = val >> 8;
1085  result = result ^ octet;
1086  result = result * FNV_PRIME;
1087  }
1088 
1089  return result;
signed int int32
Definition: c.h:429
#define FNV_OFFSET_BASIS
Definition: pgbench.c:85
#define FNV_PRIME
Definition: pgbench.c:84

References FNV_OFFSET_BASIS, FNV_PRIME, i, and val.

Referenced by evalStandardFunc().

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1098 of file pgbench.c.

1100 {
1101  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1102  uint64 k = (uint64) val;
1103 
1104  k *= MM2_MUL;
1105  k ^= k >> MM2_ROT;
1106  k *= MM2_MUL;
1107 
1108  result ^= k;
1109  result *= MM2_MUL;
1110 
1111  result ^= result >> MM2_ROT;
1112  result *= MM2_MUL;
1113  result ^= result >> MM2_ROT;
1114 
1115  return (int64) result;
#define MM2_MUL_TIMES_8
Definition: pgbench.c:87
#define MM2_ROT
Definition: pgbench.c:88
#define MM2_MUL
Definition: pgbench.c:86

References MM2_MUL, MM2_MUL_TIMES_8, MM2_ROT, and val.

Referenced by evalStandardFunc().

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2661 of file pgbench.c.

2663 {
2664  MetaCommand mc;
2665 
2666  if (cmd == NULL)
2667  mc = META_NONE;
2668  else if (pg_strcasecmp(cmd, "set") == 0)
2669  mc = META_SET;
2670  else if (pg_strcasecmp(cmd, "setshell") == 0)
2671  mc = META_SETSHELL;
2672  else if (pg_strcasecmp(cmd, "shell") == 0)
2673  mc = META_SHELL;
2674  else if (pg_strcasecmp(cmd, "sleep") == 0)
2675  mc = META_SLEEP;
2676  else if (pg_strcasecmp(cmd, "if") == 0)
2677  mc = META_IF;
2678  else if (pg_strcasecmp(cmd, "elif") == 0)
2679  mc = META_ELIF;
2680  else if (pg_strcasecmp(cmd, "else") == 0)
2681  mc = META_ELSE;
2682  else if (pg_strcasecmp(cmd, "endif") == 0)
2683  mc = META_ENDIF;
2684  else if (pg_strcasecmp(cmd, "gset") == 0)
2685  mc = META_GSET;
2686  else if (pg_strcasecmp(cmd, "aset") == 0)
2687  mc = META_ASET;
2688  else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2689  mc = META_STARTPIPELINE;
2690  else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2691  mc = META_ENDPIPELINE;
2692  else
2693  mc = META_NONE;
2694  return mc;
MetaCommand
Definition: pgbench.c:524

References META_ASET, META_ELIF, META_ELSE, META_ENDIF, META_ENDPIPELINE, META_GSET, META_IF, META_NONE, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, META_STARTPIPELINE, and pg_strcasecmp().

Referenced by process_backslash_command().

◆ getPoissonRand()

static int64 getPoissonRand ( pg_prng_state state,
double  center 
)
static

Definition at line 1007 of file pgbench.c.

1009 {
1010  /*
1011  * Use inverse transform sampling to generate a value > 0, such that the
1012  * expected (i.e. average) value is the given argument.
1013  */
1014  double uniform;
1015 
1016  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1017  uniform = 1.0 - pg_prng_double(state);
1018 
1019  return (int64) (-log(uniform) * center + 0.5);

References pg_prng_double().

Referenced by advanceConnectionState().

◆ getQueryParams()

static void getQueryParams ( CState st,
const Command command,
const char **  params 
)
static

Definition at line 1758 of file pgbench.c.

1760 {
1761  int i;
1762 
1763  for (i = 0; i < command->argc - 1; i++)
1764  params[i] = getVariable(st, command->argv[i + 1]);

References Command::argc, Command::argv, getVariable(), and i.

Referenced by sendCommand().

◆ getrand()

static int64 getrand ( pg_prng_state state,
int64  min,
int64  max 
)
static

Definition at line 912 of file pgbench.c.

914 {
915  return min + (int64) pg_prng_uint64_range(state, 0, max - min);
uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax)
Definition: pg_prng.c:138

References pg_prng_uint64_range().

Referenced by chooseScript(), and evalStandardFunc().

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 4512 of file pgbench.c.

4514 {
4515  PGresult *res;
4516 
4517  /*
4518  * get the scaling factor that should be same as count(*) from
4519  * pgbench_branches if this is not a custom query
4520  */
4521  res = PQexec(con, "select count(*) from pgbench_branches");
4523  {
4524  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
4525 
4526  pg_log_fatal("could not count number of branches: %s", PQerrorMessage(con));
4527 
4528  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
4529  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\"",
4530  PQdb(con));
4531 
4532  exit(1);
4533  }
4534  scale = atoi(PQgetvalue(res, 0, 0));
4535  if (scale < 0)
4536  {
4537  pg_log_fatal("invalid count(*) from pgbench_branches: \"%s\"",
4538  PQgetvalue(res, 0, 0));
4539  exit(1);
4540  }
4541  PQclear(res);
4542 
4543  /* warn if we override user-given -s switch */
4544  if (scale_given)
4545  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
4546  scale);
4547 
4548  /*
4549  * Get the partition information for the first "pgbench_accounts" table
4550  * found in search_path.
4551  *
4552  * The result is empty if no "pgbench_accounts" is found.
4553  *
4554  * Otherwise, it always returns one row even if the table is not
4555  * partitioned (in which case the partition strategy is NULL).
4556  *
4557  * The number of partitions can be 0 even for partitioned tables, if no
4558  * partition is attached.
4559  *
4560  * We assume no partitioning on any failure, so as to avoid failing on an
4561  * old version without "pg_partitioned_table".
4562  */
4563  res = PQexec(con,
4564  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
4565  "from pg_catalog.pg_class as c "
4566  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
4567  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
4568  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
4569  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
4570  "where c.relname = 'pgbench_accounts' and o.n is not null "
4571  "group by 1, 2 "
4572  "order by 1 asc "
4573  "limit 1");
4574 
4576  {
4577  /* probably an older version, coldly assume no partitioning */
4579  partitions = 0;
4580  }
4581  else if (PQntuples(res) == 0)
4582  {
4583  /*
4584  * This case is unlikely as pgbench already found "pgbench_branches"
4585  * above to compute the scale.
4586  */
4587  pg_log_fatal("no pgbench_accounts table found in search_path");
4588  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
4589  exit(1);
4590  }
4591  else /* PQntupes(res) == 1 */
4592  {
4593  /* normal case, extract partition information */
4594  if (PQgetisnull(res, 0, 1))
4596  else
4597  {
4598  char *ps = PQgetvalue(res, 0, 1);
4599 
4600  /* column must be there */
4601  Assert(ps != NULL);
4602 
4603  if (strcmp(ps, "r") == 0)
4605  else if (strcmp(ps, "h") == 0)
4607  else
4608  {
4609  /* possibly a newer version with new partition method */
4610  pg_log_fatal("unexpected partition method: \"%s\"", ps);
4611  exit(1);
4612  }
4613  }
4614 
4615  partitions = atoi(PQgetvalue(res, 0, 2));
4616  }
4617 
4618  PQclear(res);
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6616
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3248
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3642
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3667
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:3233
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:98
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:79
#define pg_log_warning(...)
Definition: pgfnames.c:24
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57

References Assert(), ERRCODE_UNDEFINED_TABLE, exit(), PART_HASH, PART_NONE, PART_RANGE, partition_method, partitions, PG_DIAG_SQLSTATE, pg_log_fatal, pg_log_info, pg_log_warning, PGRES_TUPLES_OK, PQclear(), PQdb(), PQerrorMessage(), PQexec(), PQgetisnull(), PQgetvalue(), PQntuples(), PQresultErrorField(), PQresultStatus(), res, and scale.

Referenced by main().

◆ getVariable()

static char* getVariable ( CState st,
char *  name 
)
static

Definition at line 1427 of file pgbench.c.

1429 {
1430  Variable *var;
1431  char stringform[64];
1432 
1433  var = lookupVariable(st, name);
1434  if (var == NULL)
1435  return NULL; /* not found */
1436 
1437  if (var->svalue)
1438  return var->svalue; /* we have it in string form */
1439 
1440  /* We need to produce a string equivalent of the value */
1441  Assert(var->value.type != PGBT_NO_VALUE);
1442  if (var->value.type == PGBT_NULL)
1443  snprintf(stringform, sizeof(stringform), "NULL");
1444  else if (var->value.type == PGBT_BOOLEAN)
1445  snprintf(stringform, sizeof(stringform),
1446  "%s", var->value.u.bval ? "true" : "false");
1447  else if (var->value.type == PGBT_INT)
1448  snprintf(stringform, sizeof(stringform),
1449  INT64_FORMAT, var->value.u.ival);
1450  else if (var->value.type == PGBT_DOUBLE)
1451  snprintf(stringform, sizeof(stringform),
1452  "%.*g", DBL_DIG, var->value.u.dval);
1453  else /* internal error, unexpected type */
1454  Assert(0);
1455  var->svalue = pg_strdup(stringform);
1456  return var->svalue;
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
@ PGBT_NO_VALUE
Definition: pgbench.h:36
#define snprintf
Definition: port.h:222
char * svalue
Definition: pgbench.c:304

References Assert(), PgBenchValue::bval, PgBenchValue::dval, INT64_FORMAT, PgBenchValue::ival, lookupVariable(), name, pg_strdup(), PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NO_VALUE, PGBT_NULL, snprintf, Variable::svalue, PgBenchValue::type, PgBenchValue::u, and Variable::value.

Referenced by assignVariables(), evaluateSleep(), getQueryParams(), and runShellCommand().

◆ getZipfianRand()

static int64 getZipfianRand ( pg_prng_state state,
int64  min,
int64  max,
double  s 
)
static

Definition at line 1059 of file pgbench.c.

1061 {
1062  int64 n = max - min + 1;
1063 
1064  /* abort if parameter is invalid */
1066 
1067  return min - 1 + computeIterativeZipfian(state, n, s);
static int64 computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
Definition: pgbench.c:1029

References Assert(), computeIterativeZipfian(), MAX_ZIPFIAN_PARAM, and MIN_ZIPFIAN_PARAM.

Referenced by evalStandardFunc().

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 6871 of file pgbench.c.

6873 {
6874  timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 4375 of file pgbench.c.

4377 {
4378  static const char *const DDLKEYs[] = {
4379  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
4380  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
4381  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
4382  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
4383  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
4384  };
4385  int i;
4386 
4387  fprintf(stderr, "creating foreign keys...\n");
4388  for (i = 0; i < lengthof(DDLKEYs); i++)
4389  {
4390  executeStatement(con, DDLKEYs[i]);
4391  }

References executeStatement(), fprintf, i, and lengthof.

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 4337 of file pgbench.c.

4339 {
4340  static const char *const DDLINDEXes[] = {
4341  "alter table pgbench_branches add primary key (bid)",
4342  "alter table pgbench_tellers add primary key (tid)",
4343  "alter table pgbench_accounts add primary key (aid)"
4344  };
4345  int i;
4346  PQExpBufferData query;
4347 
4348  fprintf(stderr, "creating primary keys...\n");
4349  initPQExpBuffer(&query);
4350 
4351  for (i = 0; i < lengthof(DDLINDEXes); i++)
4352  {
4353  resetPQExpBuffer(&query);
4354  appendPQExpBufferStr(&query, DDLINDEXes[i]);
4355 
4356  if (index_tablespace != NULL)
4357  {
4358  char *escape_tablespace;
4359 
4360  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
4361  strlen(index_tablespace));
4362  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
4363  PQfreemem(escape_tablespace);
4364  }
4365 
4366  executeStatement(con, query.data);
4367  }
4368 
4369  termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:3796
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4075
char * index_tablespace
Definition: pgbench.c:228
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:148

References appendPQExpBuffer(), appendPQExpBufferStr(), PQExpBufferData::data, executeStatement(), fprintf, i, index_tablespace, initPQExpBuffer(), lengthof, PQescapeIdentifier(), PQfreemem(), resetPQExpBuffer(), and termPQExpBuffer().

Referenced by runInitSteps().

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 4023 of file pgbench.c.

4025 {
4026  /*
4027  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4028  * fields in these table declarations were intended to comply with that.
4029  * The pgbench_accounts table complies with that because the "filler"
4030  * column is set to blank-padded empty string. But for all other tables
4031  * the columns default to NULL and so don't actually take any space. We
4032  * could fix that by giving them non-null default values. However, that
4033  * would completely break comparability of pgbench results with prior
4034  * versions. Since pgbench has never pretended to be fully TPC-B compliant
4035  * anyway, we stick with the historical behavior.
4036  */
4037  struct ddlinfo
4038  {
4039  const char *table; /* table name */
4040  const char *smcols; /* column decls if accountIDs are 32 bits */
4041  const char *bigcols; /* column decls if accountIDs are 64 bits */
4042  int declare_fillfactor;
4043  };
4044  static const struct ddlinfo DDLs[] = {
4045  {
4046  "pgbench_history",
4047  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4048  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4049  0
4050  },
4051  {
4052  "pgbench_tellers",
4053  "tid int not null,bid int,tbalance int,filler char(84)",
4054  "tid int not null,bid int,tbalance int,filler char(84)",
4055  1
4056  },
4057  {
4058  "pgbench_accounts",
4059  "aid int not null,bid int,abalance int,filler char(84)",
4060  "aid bigint not null,bid int,abalance int,filler char(84)",
4061  1
4062  },
4063  {
4064  "pgbench_branches",
4065  "bid int not null,bbalance int,filler char(88)",
4066  "bid int not null,bbalance int,filler char(88)",
4067  1
4068  }
4069  };
4070  int i;
4071  PQExpBufferData query;
4072 
4073  fprintf(stderr, "creating tables...\n");
4074 
4075  initPQExpBuffer(&query);
4076 
4077  for (i = 0; i < lengthof(DDLs); i++)
4078  {
4079  const struct ddlinfo *ddl = &DDLs[i];
4080 
4081  /* Construct new create table statement. */
4082  printfPQExpBuffer(&query, "create%s table %s(%s)",
4083  unlogged_tables ? " unlogged" : "",
4084  ddl->table,
4085  (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4086 
4087  /* Partition pgbench_accounts table */
4088  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4089  appendPQExpBuffer(&query,
4090  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4091  else if (ddl->declare_fillfactor)
4092  {
4093  /* fillfactor is only expected on actual tables */
4094  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4095  }
4096 
4097  if (tablespace != NULL)
4098  {
4099  char *escape_tablespace;
4100 
4101  escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4102  appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4103  PQfreemem(escape_tablespace);
4104  }
4105 
4106  executeStatement(con, query.data);
4107  }
4108 
4109  termPQExpBuffer(&query);
4110 
4111  if (partition_method != PART_NONE)
4112  createPartitions(con);
static void createPartitions(PGconn *con)
Definition: pgbench.c:3954
static const char * PARTITION_METHOD[]
Definition: pgbench.c:245
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:265
char * tablespace
Definition: pgbench.c:227

References appendPQExpBuffer(), createPartitions(), PQExpBufferData::data, executeStatement(), fillfactor, fprintf, i, initPQExpBuffer(), lengthof, PART_NONE, partition_method, PARTITION_METHOD, PQescapeIdentifier(), PQfreemem(), printfPQExpBuffer(), scale, SCALE_32BIT_THRESHOLD, tablespace, termPQExpBuffer(), and unlogged_tables.

Referenced by runInitSteps().

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 3932 of file pgbench.c.

3934 {
3935  fprintf(stderr, "dropping old tables...\n");
3936 
3937  /*
3938  * We drop all the tables in one command, so that whether there are
3939  * foreign key dependencies or not doesn't matter.
3940  */
3941  executeStatement(con, "drop table if exists "
3942  "pgbench_accounts, "
3943  "pgbench_branches, "
3944  "pgbench_history, "
3945  "pgbench_tellers");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 4131 of file pgbench.c.

4133 {
4134  PQExpBufferData sql;
4135  PGresult *res;
4136  int i;
4137  int64 k;
4138  char *copy_statement;
4139 
4140  /* used to track elapsed time and estimate of the remaining time */
4141  pg_time_usec_t start;
4142  int log_interval = 1;
4143 
4144  /* Stay on the same line if reporting to a terminal */
4145  char eol = isatty(fileno(stderr)) ? '\r' : '\n';
4146 
4147  fprintf(stderr, "generating data (client-side)...\n");
4148 
4149  /*
4150  * we do all of this in one transaction to enable the backend's
4151  * data-loading optimizations
4152  */
4153  executeStatement(con, "begin");
4154 
4155  /* truncate away any old data */
4156  initTruncateTables(con);
4157 
4158  initPQExpBuffer(&sql);
4159 
4160  /*
4161  * fill branches, tellers, accounts in that order in case foreign keys
4162  * already exist
4163  */
4164  for (i = 0; i < nbranches * scale; i++)
4165  {
4166  /* "filler" column defaults to NULL */
4167  printfPQExpBuffer(&sql,
4168  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
4169  i + 1);
4170  executeStatement(con, sql.data);
4171  }
4172 
4173  for (i = 0; i < ntellers * scale; i++)
4174  {
4175  /* "filler" column defaults to NULL */
4176  printfPQExpBuffer(&sql,
4177  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
4178  i + 1, i / ntellers + 1);
4179  executeStatement(con, sql.data);
4180  }
4181 
4182  /*
4183  * accounts is big enough to be worth using COPY and tracking runtime
4184  */
4185 
4186  /* use COPY with FREEZE on v14 and later without partioning */
4187  if (partitions == 0 && PQserverVersion(con) >= 140000)
4188  copy_statement = "copy pgbench_accounts from stdin with (freeze on)";
4189  else
4190  copy_statement = "copy pgbench_accounts from stdin";
4191 
4192  res = PQexec(con, copy_statement);
4193 
4195  {
4196  pg_log_fatal("unexpected copy in result: %s", PQerrorMessage(con));
4197  exit(1);
4198  }
4199  PQclear(res);
4200 
4201  start = pg_time_now();
4202 
4203  for (k = 0; k < (int64) naccounts * scale; k++)
4204  {
4205  int64 j = k + 1;
4206 
4207  /* "filler" column defaults to blank padded empty string */
4208  printfPQExpBuffer(&sql,
4209  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
4210  j, k / naccounts + 1, 0);
4211  if (PQputline(con, sql.data))
4212  {
4213  pg_log_fatal("PQputline failed");
4214  exit(1);
4215  }
4216 
4217  if (CancelRequested)
4218  break;
4219 
4220  /*
4221  * If we want to stick with the original logging, print a message each
4222  * 100k inserted rows.
4223  */
4224  if ((!use_quiet) && (j % 100000 == 0))
4225  {
4226  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4227  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4228 
4229  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4230  j, (int64) naccounts * scale,
4231  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
4232  elapsed_sec, remaining_sec, eol);
4233  }
4234  /* let's not call the timing for each row, but only each 100 rows */
4235  else if (use_quiet && (j % 100 == 0))
4236  {
4237  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4238  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4239 
4240  /* have we reached the next interval (or end)? */
4241  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
4242  {
4243  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4244  j, (int64) naccounts * scale,
4245  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
4246 
4247  /* skip to the next interval */
4248  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
4249  }
4250  }
4251  }
4252 
4253  if (eol != '\n')
4254  fputc('\n', stderr); /* Need to move to next line */
4255 
4256  if (PQputline(con, "\\.\n"))
4257  {
4258  pg_log_fatal("very last PQputline failed");
4259  exit(1);
4260  }
4261  if (PQendcopy(con))
4262  {
4263  pg_log_fatal("PQendcopy failed");
4264  exit(1);
4265  }
4266 
4267  termPQExpBuffer(&sql);
4268 
4269  executeStatement(con, "commit");
volatile sig_atomic_t CancelRequested
Definition: cancel.c:52
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6760
int PQputline(PGconn *conn, const char *s)
Definition: fe-exec.c:2771
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2802
int j
Definition: isn.c:74
@ PGRES_COPY_IN
Definition: libpq-fe.h:102
#define ntellers
Definition: pgbench.c:255
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4118
#define LOG_STEP_SECONDS
Definition: pgbench.c:176
#define nbranches
Definition: pgbench.c:254
bool use_quiet
Definition: pgbench.c:268

References CancelRequested, PQExpBufferData::data, executeStatement(), exit(), fprintf, i, initPQExpBuffer(), initTruncateTables(), INT64_FORMAT, j, LOG_STEP_SECONDS, naccounts, nbranches, ntellers, partitions, pg_log_fatal, PG_TIME_GET_DOUBLE, pg_time_now(), PGRES_COPY_IN, PQclear(), PQendcopy(), PQerrorMessage(), PQexec(), PQputline(), PQresultStatus(), PQserverVersion(), printfPQExpBuffer(), res, scale, termPQExpBuffer(), and use_quiet.

Referenced by runInitSteps().

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 4279 of file pgbench.c.

4281 {
4282  PQExpBufferData sql;
4283 
4284  fprintf(stderr, "generating data (server-side)...\n");
4285 
4286  /*
4287  * we do all of this in one transaction to enable the backend's
4288  * data-loading optimizations
4289  */
4290  executeStatement(con, "begin");
4291 
4292  /* truncate away any old data */
4293  initTruncateTables(con);
4294 
4295  initPQExpBuffer(&sql);
4296 
4297  printfPQExpBuffer(&sql,
4298  "insert into pgbench_branches(bid,bbalance) "
4299  "select bid, 0 "
4300  "from generate_series(1, %d) as bid", nbranches * scale);
4301  executeStatement(con, sql.data);
4302 
4303  printfPQExpBuffer(&sql,
4304  "insert into pgbench_tellers(tid,bid,tbalance) "
4305  "select tid, (tid - 1) / %d + 1, 0 "
4306  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
4307  executeStatement(con, sql.data);
4308 
4309  printfPQExpBuffer(&sql,
4310  "insert into pgbench_accounts(aid,bid,abalance,filler) "
4311  "select aid, (aid - 1) / %d + 1, 0, '' "
4312  "from generate_series(1, " INT64_FORMAT ") as aid",
4313  naccounts, (int64) naccounts * scale);
4314  executeStatement(con, sql.data);
4315 
4316  termPQExpBuffer(&sql);
4317 
4318  executeStatement(con, "commit");

References PQExpBufferData::data, executeStatement(), fprintf, initPQExpBuffer(), initTruncateTables(), INT64_FORMAT, naccounts, nbranches, ntellers, printfPQExpBuffer(), scale, and termPQExpBuffer().

Referenced by runInitSteps().

◆ initRandomState()

static void initRandomState ( pg_prng_state state)
static

Definition at line 898 of file pgbench.c.

900 {
uint64 pg_prng_uint64(pg_prng_state *state)
Definition: pg_prng.c:128
void pg_prng_seed(pg_prng_state *state, uint64 seed)
Definition: pg_prng.c:83
static pg_prng_state base_random_sequence
Definition: pgbench.c:354

References base_random_sequence, pg_prng_seed(), and pg_prng_uint64().

Referenced by main().

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1222 of file pgbench.c.

1224 {
1225  memset(ss, 0, sizeof(SimpleStats));

Referenced by create_sql_command(), initStats(), and process_backslash_command().

◆ initStats()

static void initStats ( StatsData sd,
pg_time_usec_t  start 
)
static

Definition at line 1262 of file pgbench.c.

1264 {
1265  sd->start_time = start;
1266  sd->cnt = 0;
1267  sd->skipped = 0;
1268  initSimpleStats(&sd->latency);
1269  initSimpleStats(&sd->lag);

References StatsData::cnt, initSimpleStats(), StatsData::lag, StatsData::latency, StatsData::skipped, and StatsData::start_time.

Referenced by doLog(), main(), ParseScript(), printProgressReport(), and threadRun().

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 4118 of file pgbench.c.

4120 {
4121  executeStatement(con, "truncate table "
4122  "pgbench_accounts, "
4123  "pgbench_branches, "
4124  "pgbench_history, "
4125  "pgbench_tellers");

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 4324 of file pgbench.c.

4326 {
4327  fprintf(stderr, "vacuuming...\n");
4328  executeStatement(con, "vacuum analyze pgbench_branches");
4329  executeStatement(con, "vacuum analyze pgbench_tellers");
4330  executeStatement(con, "vacuum analyze pgbench_accounts");
4331  executeStatement(con, "vacuum analyze pgbench_history");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 761 of file pgbench.c.

763 {
764  const char *ptr = str;
765 
766  /* skip leading spaces; cast is consistent with strtoint64 */
767  while (*ptr && isspace((unsigned char) *ptr))
768  ptr++;
769 
770  /* skip sign */
771  if (*ptr == '+' || *ptr == '-')
772  ptr++;
773 
774  /* at least one digit */
775  if (*ptr && !isdigit((unsigned char) *ptr))
776  return false;
777 
778  /* eat all digits */
779  while (*ptr && isdigit((unsigned char) *ptr))
780  ptr++;
781 
782  /* must have reached end of string */
783  return *ptr == '\0';

References generate_unaccent_rules::str.

Referenced by makeVariableValue().

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 1910 of file pgbench.c.

1912 {
1913  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 5318 of file pgbench.c.

5320 {
5321  int i;
5322 
5323  fprintf(stderr, "Available builtin scripts:\n");
5324  for (i = 0; i < lengthof(builtin_script); i++)
5325  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
5326  fprintf(stderr, "\n");

References builtin_script, fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

◆ lookupCreateVariable()

static Variable* lookupCreateVariable ( CState st,
const char *  context,
char *  name 
)
static

Definition at line 1570 of file pgbench.c.

1572 {
1573  Variable *var;
1574 
1575  var = lookupVariable(st, name);
1576  if (var == NULL)
1577  {
1578  Variable *newvars;
1579 
1580  /*
1581  * Check for the name only when declaring a new variable to avoid
1582  * overhead.
1583  */
1584  if (!valid_variable_name(name))
1585  {
1586  pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1587  return NULL;
1588  }
1589 
1590  /* Create variable at the end of the array */
1591  if (st->variables)
1592  newvars = (Variable *) pg_realloc(st->variables,
1593  (st->nvariables + 1) * sizeof(Variable));
1594  else
1595  newvars = (Variable *) pg_malloc(sizeof(Variable));
1596 
1597  st->variables = newvars;
1598 
1599  var = &newvars[st->nvariables];
1600 
1601  var->name = pg_strdup(name);
1602  var->svalue = NULL;
1603  /* caller is expected to initialize remaining fields */
1604 
1605  st->nvariables++;
1606  /* we don't re-sort the array till we have to */
1607  st->vars_sorted = false;
1608  }
1609 
1610  return var;
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1534
int nvariables
Definition: pgbench.c:463
bool vars_sorted
Definition: pgbench.c:464
Variable * variables
Definition: pgbench.c:462
char * name
Definition: pgbench.c:303

References lookupVariable(), name, Variable::name, CState::nvariables, pg_log_error, pg_malloc(), pg_realloc(), pg_strdup(), Variable::svalue, valid_variable_name(), CState::variables, and CState::vars_sorted.

Referenced by putVariable(), and putVariableValue().

◆ lookupVariable()

static Variable* lookupVariable ( CState st,
char *  name 
)
static

Definition at line 1400 of file pgbench.c.

1402 {
1403  Variable key;
1404 
1405  /* On some versions of Solaris, bsearch of zero items dumps core */
1406  if (st->nvariables <= 0)
1407  return NULL;
1408 
1409  /* Sort if we have to */
1410  if (!st->vars_sorted)
1411  {
1412  qsort((void *) st->variables, st->nvariables, sizeof(Variable),
1414  st->vars_sorted = true;
1415  }
1416 
1417  /* Now we can search */
1418  key.name = name;
1419  return (Variable *) bsearch((void *) &key,
1420  (void *) st->variables,
1421  st->nvariables,
1422  sizeof(Variable),
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:1392
#define qsort(a, b, c, d)
Definition: port.h:497

References compareVariableNames(), sort-test::key, name, CState::nvariables, qsort, CState::variables, and CState::vars_sorted.

Referenced by evaluateExpr(), getVariable(), lookupCreateVariable(), and main().

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 5755 of file pgbench.c.

5757 {
5758  static struct option long_options[] = {
5759  /* systematic long/short named options */
5760  {"builtin", required_argument, NULL, 'b'},
5761  {"client", required_argument, NULL, 'c'},
5762  {"connect", no_argument, NULL, 'C'},
5763  {"debug", no_argument, NULL, 'd'},
5764  {"define", required_argument, NULL, 'D'},
5765  {"file", required_argument, NULL, 'f'},
5766  {"fillfactor", required_argument, NULL, 'F'},
5767  {"host", required_argument, NULL, 'h'},
5768  {"initialize", no_argument, NULL, 'i'},
5769  {"init-steps", required_argument, NULL, 'I'},
5770  {"jobs", required_argument, NULL, 'j'},
5771  {"log", no_argument, NULL, 'l'},
5772  {"latency-limit", required_argument, NULL, 'L'},
5773  {"no-vacuum", no_argument, NULL, 'n'},
5774  {"port", required_argument, NULL, 'p'},
5775  {"progress", required_argument, NULL, 'P'},
5776  {"protocol", required_argument, NULL, 'M'},
5777  {"quiet", no_argument, NULL, 'q'},
5778  {"report-latencies", no_argument, NULL, 'r'},
5779  {"rate", required_argument, NULL, 'R'},
5780  {"scale", required_argument, NULL, 's'},
5781  {"select-only", no_argument, NULL, 'S'},
5782  {"skip-some-updates", no_argument, NULL, 'N'},
5783  {"time", required_argument, NULL, 'T'},
5784  {"transactions", required_argument, NULL, 't'},
5785  {"username", required_argument, NULL, 'U'},
5786  {"vacuum-all", no_argument, NULL, 'v'},
5787  /* long-named only options */
5788  {"unlogged-tables", no_argument, NULL, 1},
5789  {"tablespace", required_argument, NULL, 2},
5790  {"index-tablespace", required_argument, NULL, 3},
5791  {"sampling-rate", required_argument, NULL, 4},
5792  {"aggregate-interval", required_argument, NULL, 5},
5793  {"progress-timestamp", no_argument, NULL, 6},
5794  {"log-prefix", required_argument, NULL, 7},
5795  {"foreign-keys", no_argument, NULL, 8},
5796  {"random-seed", required_argument, NULL, 9},
5797  {"show-script", required_argument, NULL, 10},
5798  {"partitions", required_argument, NULL, 11},
5799  {"partition-method", required_argument, NULL, 12},
5800  {NULL, 0, NULL, 0}
5801  };
5802 
5803  int c;
5804  bool is_init_mode = false; /* initialize mode? */
5805  char *initialize_steps = NULL;
5806  bool foreign_keys = false;
5807  bool is_no_vacuum = false;
5808  bool do_vacuum_accounts = false; /* vacuum accounts table? */
5809  int optindex;
5810  bool scale_given = false;
5811 
5812  bool benchmarking_option_set = false;
5813  bool initialization_option_set = false;
5814  bool internal_script_used = false;
5815 
5816  CState *state; /* status of clients */
5817  TState *threads; /* array of thread */
5818 
5820  start_time, /* start up time */
5821  bench_start = 0, /* first recorded benchmarking time */
5822  conn_total_duration; /* cumulated connection time in
5823  * threads */
5824  int64 latency_late = 0;
5825  StatsData stats;
5826  int weight;
5827 
5828  int i;
5829  int nclients_dealt;
5830 
5831 #ifdef HAVE_GETRLIMIT
5832  struct rlimit rlim;
5833 #endif
5834 
5835  PGconn *con;
5836  char *env;
5837 
5838  int exit_code = 0;
5839  struct timeval tv;
5840 
5841  /*
5842  * Record difference between Unix time and instr_time time. We'll use
5843  * this for logging and aggregation.
5844  */
5845  gettimeofday(&tv, NULL);
5846  epoch_shift = tv.tv_sec * INT64CONST(1000000) + tv.tv_usec - pg_time_now();
5847 
5848  pg_logging_init(argv[0]);
5849  progname = get_progname(argv[0]);
5850 
5851  if (argc > 1)
5852  {
5853  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
5854  {
5855  usage();
5856  exit(0);
5857  }
5858  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
5859  {
5860  puts("pgbench (PostgreSQL) " PG_VERSION);
5861  exit(0);
5862  }
5863  }
5864 
5865  state = (CState *) pg_malloc0(sizeof(CState));
5866 
5867  /* set random seed early, because it may be used while parsing scripts. */
5868  if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
5869  {
5870  pg_log_fatal("error while setting random seed from PGBENCH_RANDOM_SEED environment variable");
5871  exit(1);
5872  }
5873 
5874  while ((c = getopt_long(argc, argv, "iI:h:nvp:dqb:SNc:j:Crs:t:T:U:lf:D:F:M:P:R:L:", long_options, &optindex)) != -1)
5875  {
5876  char *script;
5877 
5878  switch (c)
5879  {
5880  case 'i':
5881  is_init_mode = true;
5882  break;
5883  case 'I':
5884  if (initialize_steps)
5885  pg_free(initialize_steps);
5886  initialize_steps = pg_strdup(optarg);
5887  checkInitSteps(initialize_steps);
5888  initialization_option_set = true;
5889  break;
5890  case 'h':
5891  pghost = pg_strdup(optarg);
5892  break;
5893  case 'n':
5894  is_no_vacuum = true;
5895  break;
5896  case 'v':
5897  benchmarking_option_set = true;
5898  do_vacuum_accounts = true;
5899  break;
5900  case 'p':
5901  pgport = pg_strdup(optarg);
5902  break;
5903  case 'd':
5905  break;
5906  case 'c':
5907  benchmarking_option_set = true;
5908  if (!option_parse_int(optarg, "-c/--clients", 1, INT_MAX,
5909  &nclients))
5910  {
5911  exit(1);
5912  }
5913 #ifdef HAVE_GETRLIMIT
5914 #ifdef RLIMIT_NOFILE /* most platforms use RLIMIT_NOFILE */
5915  if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
5916 #else /* but BSD doesn't ... */
5917  if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
5918 #endif /* RLIMIT_NOFILE */
5919  {
5920  pg_log_fatal("getrlimit failed: %m");
5921  exit(1);
5922  }
5923  if (rlim.rlim_cur < nclients + 3)
5924  {
5925  pg_log_fatal("need at least %d open files, but system limit is %ld",
5926  nclients + 3, (long) rlim.rlim_cur);
5927  pg_log_info("Reduce number of clients, or use limit/ulimit to increase the system limit.");
5928  exit(1);
5929  }
5930 #endif /* HAVE_GETRLIMIT */
5931  break;
5932  case 'j': /* jobs */
5933  benchmarking_option_set = true;
5934  if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
5935  &nthreads))
5936  {
5937  exit(1);
5938  }
5939 #ifndef ENABLE_THREAD_SAFETY
5940  if (nthreads != 1)
5941  {
5942  pg_log_fatal("threads are not supported on this platform; use -j1");
5943  exit(1);
5944  }
5945 #endif /* !ENABLE_THREAD_SAFETY */
5946  break;
5947  case 'C':
5948  benchmarking_option_set = true;
5949  is_connect = true;
5950  break;
5951  case 'r':
5952  benchmarking_option_set = true;
5953  report_per_command = true;
5954  break;
5955  case 's':
5956  scale_given = true;
5957  if (!option_parse_int(optarg, "-s/--scale", 1, INT_MAX,
5958  &scale))
5959  exit(1);
5960  break;
5961  case 't':
5962  benchmarking_option_set = true;
5963  if (!option_parse_int(optarg, "-t/--transactions", 1, INT_MAX,
5964  &nxacts))
5965  exit(1);
5966  break;
5967  case 'T':
5968  benchmarking_option_set = true;
5969  if (!option_parse_int(optarg, "-T/--time", 1, INT_MAX,
5970  &duration))
5971  exit(1);
5972  break;
5973  case 'U':
5975  break;
5976  case 'l':
5977  benchmarking_option_set = true;
5978  use_log = true;
5979  break;
5980  case 'q':
5981  initialization_option_set = true;
5982  use_quiet = true;
5983  break;
5984  case 'b':
5985  if (strcmp(optarg, "list") == 0)
5986  {
5988  exit(0);
5989  }
5990  weight = parseScriptWeight(optarg, &script);
5991  process_builtin(findBuiltin(script), weight);
5992  benchmarking_option_set = true;
5993  internal_script_used = true;
5994  break;
5995  case 'S':
5996  process_builtin(findBuiltin("select-only"), 1);
5997  benchmarking_option_set = true;
5998  internal_script_used = true;
5999  break;
6000  case 'N':
6001  process_builtin(findBuiltin("simple-update"), 1);
6002  benchmarking_option_set = true;
6003  internal_script_used = true;
6004  break;
6005  case 'f':
6006  weight = parseScriptWeight(optarg, &script);
6007  process_file(script, weight);
6008  benchmarking_option_set = true;
6009  break;
6010  case 'D':
6011  {
6012  char *p;
6013 
6014  benchmarking_option_set = true;
6015 
6016  if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
6017  {
6018  pg_log_fatal("invalid variable definition: \"%s\"", optarg);
6019  exit(1);
6020  }
6021 
6022  *p++ = '\0';
6023  if (!putVariable(&state[0], "option", optarg, p))
6024  exit(1);
6025  }
6026  break;
6027  case 'F':
6028  initialization_option_set = true;
6029  if (!option_parse_int(optarg, "-F/--fillfactor", 10, 100,
6030  &fillfactor))
6031  exit(1);
6032  break;
6033  case 'M':
6034  benchmarking_option_set = true;
6035  for (querymode = 0; querymode < NUM_QUERYMODE; querymode++)
6036  if (strcmp(optarg, QUERYMODE[querymode]) == 0)
6037  break;
6038  if (querymode >= NUM_QUERYMODE)
6039  {
6040  pg_log_fatal("invalid query mode (-M): \"%s\"", optarg);
6041  exit(1);
6042  }
6043  break;
6044  case 'P':
6045  benchmarking_option_set = true;
6046  if (!option_parse_int(optarg, "-P/--progress", 1, INT_MAX,
6047  &progress))
6048  exit(1);
6049  break;
6050  case 'R':
6051  {
6052  /* get a double from the beginning of option value */
6053  double throttle_value = atof(optarg);
6054 
6055  benchmarking_option_set = true;
6056 
6057  if (throttle_value <= 0.0)
6058  {
6059  pg_log_fatal("invalid rate limit: \"%s\"", optarg);
6060  exit(1);
6061  }
6062  /* Invert rate limit into per-transaction delay in usec */
6063  throttle_delay = 1000000.0 / throttle_value;
6064  }
6065  break;
6066  case 'L':
6067  {
6068  double limit_ms = atof(optarg);
6069 
6070  if (limit_ms <= 0.0)
6071  {
6072  pg_log_fatal("invalid latency limit: \"%s\"", optarg);
6073  exit(1);
6074  }
6075  benchmarking_option_set = true;
6076  latency_limit = (int64) (limit_ms * 1000);
6077  }
6078  break;
6079  case 1: /* unlogged-tables */
6080  initialization_option_set = true;
6081  unlogged_tables = true;
6082  break;
6083  case 2: /* tablespace */
6084  initialization_option_set = true;
6086  break;
6087  case 3: /* index-tablespace */
6088  initialization_option_set = true;
6090  break;
6091  case 4: /* sampling-rate */
6092  benchmarking_option_set = true;
6093  sample_rate = atof(optarg);
6094  if (sample_rate <= 0.0 || sample_rate > 1.0)
6095  {
6096  pg_log_fatal("invalid sampling rate: \"%s\"", optarg);
6097  exit(1);
6098  }
6099  break;
6100  case 5: /* aggregate-interval */
6101  benchmarking_option_set = true;
6102  if (!option_parse_int(optarg, "--aggregate-interval", 1, INT_MAX,
6103  &agg_interval))
6104  exit(1);
6105  break;
6106  case 6: /* progress-timestamp */
6107  progress_timestamp = true;
6108  benchmarking_option_set = true;
6109  break;
6110  case 7: /* log-prefix */
6111  benchmarking_option_set = true;
6113  break;
6114  case 8: /* foreign-keys */
6115  initialization_option_set = true;
6116  foreign_keys = true;
6117  break;
6118  case 9: /* random-seed */
6119  benchmarking_option_set = true;
6120  if (!set_random_seed(optarg))
6121  {
6122  pg_log_fatal("error while setting random seed from --random-seed option");
6123  exit(1);
6124  }
6125  break;
6126  case 10: /* list */
6127  {
6128  const BuiltinScript *s = findBuiltin(optarg);
6129 
6130  fprintf(stderr, "-- %s: %s\n%s\n", s->name, s->desc, s->script);
6131  exit(0);
6132  }
6133  break;
6134  case 11: /* partitions */
6135  initialization_option_set = true;
6136  if (!option_parse_int(optarg, "--partitions", 1, INT_MAX,
6137  &partitions))
6138  exit(1);
6139  break;
6140  case 12: /* partition-method */
6141  initialization_option_set = true;
6142  if (pg_strcasecmp(optarg, "range") == 0)
6144  else if (pg_strcasecmp(optarg, "hash") == 0)
6146  else
6147  {
6148  pg_log_fatal("invalid partition method, expecting \"range\" or \"hash\", got: \"%s\"",
6149  optarg);
6150  exit(1);
6151  }
6152  break;
6153  default:
6154  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
6155  exit(1);
6156  break;
6157  }
6158  }
6159 
6160  /* set default script if none */
6161  if (num_scripts == 0 && !is_init_mode)
6162  {
6163  process_builtin(findBuiltin("tpcb-like"), 1);
6164  benchmarking_option_set = true;
6165  internal_script_used = true;
6166  }
6167 
6168  /* complete SQL command initialization and compute total weight */
6169  for (i = 0; i < num_scripts; i++)
6170  {
6171  Command **commands = sql_script[i].commands;
6172 
6173  for (int j = 0; commands[j] != NULL; j++)
6174  if (commands[j]->type == SQL_COMMAND)
6175  postprocess_sql_command(commands[j]);
6176 
6177  /* cannot overflow: weight is 32b, total_weight 64b */
6179  }
6180 
6181  if (total_weight == 0 && !is_init_mode)
6182  {
6183  pg_log_fatal("total script weight must not be zero");
6184  exit(1);
6185  }
6186 
6187  /* show per script stats if several scripts are used */
6188  if (num_scripts > 1)
6189  per_script_stats = true;
6190 
6191  /*
6192  * Don't need more threads than there are clients. (This is not merely an
6193  * optimization; throttle_delay is calculated incorrectly below if some
6194  * threads have no clients assigned to them.)
6195  */
6196  if (nthreads > nclients)
6197  nthreads = nclients;
6198 
6199  /*
6200  * Convert throttle_delay to a per-thread delay time. Note that this
6201  * might be a fractional number of usec, but that's OK, since it's just
6202  * the center of a Poisson distribution of delays.
6203  */
6205 
6206  if (argc > optind)
6207  dbName = argv[optind++];
6208  else
6209  {
6210  if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
6211  dbName = env;
6212  else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
6213  dbName = env;
6214  else
6216  }
6217 
6218  if (optind < argc)
6219  {
6220  pg_log_fatal("too many command-line arguments (first is \"%s\")",
6221  argv[optind]);
6222  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
6223  exit(1);
6224  }
6225 
6226  if (is_init_mode)
6227  {
6228  if (benchmarking_option_set)
6229  {
6230  pg_log_fatal("some of the specified options cannot be used in initialization (-i) mode");
6231  exit(1);
6232  }
6233 
6234  if (partitions == 0 && partition_method != PART_NONE)
6235  {
6236  pg_log_fatal("--partition-method requires greater than zero --partitions");
6237  exit(1);
6238  }
6239 
6240  /* set default method */
6241  if (partitions > 0 && partition_method == PART_NONE)
6243 
6244  if (initialize_steps == NULL)
6245  initialize_steps = pg_strdup(DEFAULT_INIT_STEPS);
6246 
6247  if (is_no_vacuum)
6248  {
6249  /* Remove any vacuum step in initialize_steps */
6250  char *p;
6251 
6252  while ((p = strchr(initialize_steps, 'v')) != NULL)
6253  *p = ' ';
6254  }
6255 
6256  if (foreign_keys)
6257  {
6258  /* Add 'f' to end of initialize_steps, if not already there */
6259  if (strchr(initialize_steps, 'f') == NULL)
6260  {
6261  initialize_steps = (char *)
6262  pg_realloc(initialize_steps,
6263  strlen(initialize_steps) + 2);
6264  strcat(initialize_steps, "f");
6265  }
6266  }
6267 
6268  runInitSteps(initialize_steps);
6269