PostgreSQL Source Code  git master
pgbench.c File Reference
#include "postgres_fe.h"
#include "common/int.h"
#include "common/logging.h"
#include "fe_utils/conditional.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "portability/instr_time.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include "pgbench.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  RandomState
 
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 pthread_t   void *
 
#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */
 
#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 INVALID_THREAD   ((pthread_t) 0)
 
#define SQL_COMMAND   1
 
#define META_COMMAND   2
 
#define MAX_ARGS   256
 
#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 struct StatsData StatsData
 
typedef struct RandomState RandomState
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct Command Command
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 

Enumerations

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_IF, META_ELIF,
  META_ELSE, META_ENDIF
}
 
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, instr_time *now)
 
static void doLog (TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
 
static void processXactStats (TState *thread, CState *st, instr_time *now, bool skipped, StatsData *agg)
 
static void addScript (ParsedScript script)
 
static void * 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 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 (RandomState *random_state)
 
static int64 getrand (RandomState *random_state, int64 min, int64 max)
 
static int64 getExponentialRand (RandomState *random_state, int64 min, int64 max, double parameter)
 
static int64 getGaussianRand (RandomState *random_state, int64 min, int64 max, double parameter)
 
static int64 getPoissonRand (RandomState *random_state, double center)
 
static int64 computeIterativeZipfian (RandomState *random_state, int64 n, double s)
 
static int64 getZipfianRand (RandomState *random_state, int64 min, int64 max, double s)
 
static int64 getHashFnv1a (int64 val, uint64 seed)
 
static int64 getHashMurmur2 (int64 val, uint64 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, time_t start_time)
 
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, 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 initCreateTables (PGconn *con)
 
static void initGenerateData (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 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, int64 now, StatsData *last, int64 *last_report)
 
static void printSimpleStats (const char *prefix, SimpleStats *ss)
 
static void printResults (StatsData *total, instr_time total_time, instr_time conn_total_time, 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
 
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
 
char * pghost = ""
 
char * pgport = ""
 
char * login = NULL
 
char * dbName
 
char * logfile_prefix = NULL
 
const char * progname
 
volatile bool timer_exceeded = false
 
static RandomState base_random_sequence
 
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 int debug = 0
 
static const BuiltinScript builtin_script []
 
static const PsqlScanCallbacks pgbench_callbacks
 

Macro Definition Documentation

◆ COMMANDS_ALLOC_NUM

#define COMMANDS_ALLOC_NUM   128

Referenced by ParseScript().

◆ DEFAULT_INIT_STEPS

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

Definition at line 133 of file pgbench.c.

Referenced by main().

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 136 of file pgbench.c.

Referenced by main().

◆ ERRCODE_UNDEFINED_TABLE

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 78 of file pgbench.c.

Referenced by getHashFnv1a().

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 77 of file pgbench.c.

Referenced by getHashFnv1a().

◆ INVALID_THREAD

#define INVALID_THREAD   ((pthread_t) 0)

Definition at line 442 of file pgbench.c.

Referenced by main().

◆ LOG_STEP_SECONDS

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

Definition at line 135 of file pgbench.c.

Referenced by initGenerateData().

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 67 of file pgbench.c.

Referenced by evalStandardFunc(), and getGaussianRand().

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 454 of file pgbench.c.

Referenced by parseQuery(), process_backslash_command(), and sendCommand().

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 1843 of file pgbench.c.

Referenced by evalStandardFunc().

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 2596 of file pgbench.c.

Referenced by sendCommand().

◆ MAX_SCRIPTS

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

Definition at line 251 of file pgbench.c.

Referenced by addScript().

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 141 of file pgbench.c.

Referenced by evalStandardFunc(), and getZipfianRand().

◆ META_COMMAND

#define META_COMMAND   2

◆ MIN_GAUSSIAN_PARAM

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

Definition at line 138 of file pgbench.c.

Referenced by evalStandardFunc(), and getGaussianRand().

◆ MIN_ZIPFIAN_PARAM

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

Definition at line 140 of file pgbench.c.

Referenced by evalStandardFunc(), and getZipfianRand().

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 79 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 80 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 81 of file pgbench.c.

Referenced by getHashMurmur2().

◆ naccounts

#define naccounts   100000

Definition at line 199 of file pgbench.c.

Referenced by initGenerateData().

◆ nbranches

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

Definition at line 196 of file pgbench.c.

Referenced by initGenerateData().

◆ ntellers

#define ntellers   10

Definition at line 198 of file pgbench.c.

Referenced by initGenerateData().

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

Referenced by doConnect().

◆ POLL_USING_SELECT

#define POLL_USING_SELECT

Definition at line 60 of file pgbench.c.

◆ pthread_t

#define pthread_t   void *

Definition at line 126 of file pgbench.c.

Referenced by main(), and socket_has_input().

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 208 of file pgbench.c.

Referenced by initCreateTables().

◆ SHELL_COMMAND_SIZE

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

Definition at line 252 of file pgbench.c.

Referenced by runShellCommand().

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 100 of file pgbench.c.

Referenced by threadRun().

◆ SQL_COMMAND

#define SQL_COMMAND   1

◆ WSEP

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

Definition at line 230 of file pgbench.c.

Referenced by parseScriptWeight().

Typedef Documentation

◆ BuiltinScript

typedef struct BuiltinScript BuiltinScript

◆ Command

typedef struct Command Command

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ QueryMode

typedef enum QueryMode QueryMode

◆ RandomState

typedef struct RandomState RandomState

◆ 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 297 of file pgbench.c.

298 {
299  /*
300  * The client must first choose a script to execute. Once chosen, it can
301  * either be throttled (state CSTATE_PREPARE_THROTTLE under --rate), start
302  * right away (state CSTATE_START_TX) or not start at all if the timer was
303  * exceeded (state CSTATE_FINISHED).
304  */
306 
307  /*
308  * CSTATE_START_TX performs start-of-transaction processing. Establishes
309  * a new connection for the transaction in --connect mode, records the
310  * transaction start time, and proceed to the first command.
311  *
312  * Note: once a script is started, it will either error or run till its
313  * end, where it may be interrupted. It is not interrupted while running,
314  * so pgbench --time is to be understood as tx are allowed to start in
315  * that time, and will finish when their work is completed.
316  */
318 
319  /*
320  * In CSTATE_PREPARE_THROTTLE state, we calculate when to begin the next
321  * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
322  * sleeps until that moment, then advances to CSTATE_START_TX, or
323  * CSTATE_FINISHED if the next transaction would start beyond the end of
324  * the run.
325  */
328 
329  /*
330  * We loop through these states, to process each command in the script:
331  *
332  * CSTATE_START_COMMAND starts the execution of a command. On a SQL
333  * command, the command is sent to the server, and we move to
334  * CSTATE_WAIT_RESULT state. On a \sleep meta-command, the timer is set,
335  * and we enter the CSTATE_SLEEP state to wait for it to expire. Other
336  * meta-commands are executed immediately. If the command about to start
337  * is actually beyond the end of the script, advance to CSTATE_END_TX.
338  *
339  * CSTATE_WAIT_RESULT waits until we get a result set back from the server
340  * for the current command.
341  *
342  * CSTATE_SLEEP waits until the end of \sleep.
343  *
344  * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
345  * command counter, and loops back to CSTATE_START_COMMAND state.
346  *
347  * CSTATE_SKIP_COMMAND is used by conditional branches which are not
348  * executed. It quickly skip commands that do not need any evaluation.
349  * This state can move forward several commands, till there is something
350  * to do or the end of the script.
351  */
354  CSTATE_SLEEP,
357 
358  /*
359  * CSTATE_END_TX performs end-of-transaction processing. It calculates
360  * latency, and logs the transaction. In --connect mode, it closes the
361  * current connection.
362  *
363  * Then either starts over in CSTATE_CHOOSE_SCRIPT, or enters
364  * CSTATE_FINISHED if we have no more work to do.
365  */
367 
368  /*
369  * Final states. CSTATE_ABORTED means that the script execution was
370  * aborted because a command failed, CSTATE_FINISHED means success.
371  */
ConnectionStateEnum
Definition: pgbench.c:297

◆ MetaCommand

Enumerator
META_NONE 
META_SET 
META_SETSHELL 
META_SHELL 
META_SLEEP 
META_GSET 
META_IF 
META_ELIF 
META_ELSE 
META_ENDIF 

Definition at line 456 of file pgbench.c.

457 {
458  META_NONE, /* not a known meta-command */
459  META_SET, /* \set */
460  META_SETSHELL, /* \setshell */
461  META_SHELL, /* \shell */
462  META_SLEEP, /* \sleep */
463  META_GSET, /* \gset */
464  META_IF, /* \if */
465  META_ELIF, /* \elif */
466  META_ELSE, /* \else */
467  META_ENDIF /* \endif */
468 } MetaCommand;
MetaCommand
Definition: pgbench.c:456

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 470 of file pgbench.c.

471 {
472  QUERY_SIMPLE, /* simple query */
473  QUERY_EXTENDED, /* extended query */
474  QUERY_PREPARED, /* extended query with prepared statements */
476 } QueryMode;
QueryMode
Definition: pgbench.c:470

Function Documentation

◆ accumStats()

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

Definition at line 1100 of file pgbench.c.

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

Referenced by doLog(), and processXactStats().

1101 {
1102  stats->cnt++;
1103 
1104  if (skipped)
1105  {
1106  /* no latency to record on skipped transactions */
1107  stats->skipped++;
1108  }
1109  else
1110  {
1111  addToSimpleStats(&stats->latency, lat);
1112 
1113  /* and possibly the same for schedule lag */
1114  if (throttle_delay)
1115  addToSimpleStats(&stats->lag, lag);
1116  }
1117 }
SimpleStats lag
Definition: pgbench.c:280
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1056
SimpleStats latency
Definition: pgbench.c:279
double throttle_delay
Definition: pgbench.c:173
int64 cnt
Definition: pgbench.c:276
int64 skipped
Definition: pgbench.c:277

◆ add_socket_to_set()

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

Definition at line 6423 of file pgbench.c.

References fd(), socket_set::fds, fprintf, and socket_set::maxfd.

Referenced by setalarm(), and threadRun().

6424 {
6425  if (fd < 0 || fd >= FD_SETSIZE)
6426  {
6427  /*
6428  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
6429  * complicating the API to make it less grotty.
6430  */
6431  fprintf(stderr, "too many client connections for select()\n");
6432  exit(1);
6433  }
6434  FD_SET(fd, &sa->fds);
6435  if (fd > sa->maxfd)
6436  sa->maxfd = fd;
6437 }
#define fprintf
Definition: port.h:196
static int fd(const char *x, int i)
Definition: preproc-init.c:105
fd_set fds
Definition: pgbench.c:105
int maxfd
Definition: pgbench.c:104

◆ addScript()

static void addScript ( ParsedScript  script)
static

Definition at line 4775 of file pgbench.c.

References CheckConditional(), ParsedScript::commands, ParsedScript::desc, fprintf, MAX_SCRIPTS, and num_scripts.

Referenced by ParseScript().

4776 {
4777  if (script.commands == NULL || script.commands[0] == NULL)
4778  {
4779  fprintf(stderr, "empty command list for script \"%s\"\n", script.desc);
4780  exit(1);
4781  }
4782 
4783  if (num_scripts >= MAX_SCRIPTS)
4784  {
4785  fprintf(stderr, "at most %d SQL scripts are allowed\n", MAX_SCRIPTS);
4786  exit(1);
4787  }
4788 
4789  CheckConditional(script);
4790 
4791  sql_script[num_scripts] = script;
4792  num_scripts++;
4793 }
static int num_scripts
Definition: pgbench.c:521
#define MAX_SCRIPTS
Definition: pgbench.c:251
#define fprintf
Definition: port.h:196
static void CheckConditional(ParsedScript ps)
Definition: pgbench.c:4424
const char * desc
Definition: pgbench.c:514
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:520
Command ** commands
Definition: pgbench.c:516

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1056 of file pgbench.c.

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

Referenced by accumStats(), and advanceConnectionState().

1057 {
1058  if (ss->count == 0 || val < ss->min)
1059  ss->min = val;
1060  if (ss->count == 0 || val > ss->max)
1061  ss->max = val;
1062  ss->count++;
1063  ss->sum += val;
1064  ss->sum2 += val * val;
1065 }
double sum
Definition: pgbench.c:265
int64 count
Definition: pgbench.c:262
double max
Definition: pgbench.c:264
double sum2
Definition: pgbench.c:266
long val
Definition: informix.c:684
double min
Definition: pgbench.c:263

◆ advanceConnectionState()

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

Definition at line 2864 of file pgbench.c.

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_time, 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(), executeMetaCommand(), finishCon(), fprintf, getPoissonRand(), CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, INSTR_TIME_ACCUM_DIFF, INSTR_TIME_GET_DOUBLE, INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SET_CURRENT_LAZY, INSTR_TIME_SET_ZERO, Command::meta, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_IF, now(), PQconsumeInput(), PQisBusy(), CState::prepared, processXactStats(), readCommandResponse(), sendCommand(), CState::sleep_until, SQL_COMMAND, CState::state, Command::stats, CState::stmt_begin, TState::throttle_trigger, TState::ts_throttle_rs, CState::txn_begin, CState::txn_scheduled, Command::type, CState::use_file, and Command::varprefix.

Referenced by threadRun().

2865 {
2866  instr_time now;
2867 
2868  /*
2869  * gettimeofday() isn't free, so we get the current timestamp lazily the
2870  * first time it's needed, and reuse the same value throughout this
2871  * function after that. This also ensures that e.g. the calculated
2872  * latency reported in the log file and in the totals are the same. Zero
2873  * means "not set yet". Reset "now" when we execute shell commands or
2874  * expressions, which might take a non-negligible amount of time, though.
2875  */
2876  INSTR_TIME_SET_ZERO(now);
2877 
2878  /*
2879  * Loop in the state machine, until we have to wait for a result from the
2880  * server or have to sleep for throttling or \sleep.
2881  *
2882  * Note: In the switch-statement below, 'break' will loop back here,
2883  * meaning "continue in the state machine". Return is used to return to
2884  * the caller, giving the thread the opportunity to advance another
2885  * client.
2886  */
2887  for (;;)
2888  {
2889  Command *command;
2890 
2891  switch (st->state)
2892  {
2893  /* Select transaction (script) to run. */
2894  case CSTATE_CHOOSE_SCRIPT:
2895  st->use_file = chooseScript(thread);
2897 
2898  if (debug)
2899  fprintf(stderr, "client %d executing script \"%s\"\n", st->id,
2900  sql_script[st->use_file].desc);
2901 
2902  /*
2903  * If time is over, we're done; otherwise, get ready to start
2904  * a new transaction, or to get throttled if that's requested.
2905  */
2908  break;
2909 
2910  /* Start new transaction (script) */
2911  case CSTATE_START_TX:
2912 
2913  /* establish connection if needed, i.e. under --connect */
2914  if (st->con == NULL)
2915  {
2916  instr_time start;
2917 
2919  start = now;
2920  if ((st->con = doConnect()) == NULL)
2921  {
2922  fprintf(stderr, "client %d aborted while establishing connection\n",
2923  st->id);
2924  st->state = CSTATE_ABORTED;
2925  break;
2926  }
2928  INSTR_TIME_ACCUM_DIFF(thread->conn_time, now, start);
2929 
2930  /* Reset session-local state */
2931  memset(st->prepared, 0, sizeof(st->prepared));
2932  }
2933 
2934  /* record transaction start time */
2936  st->txn_begin = now;
2937 
2938  /*
2939  * When not throttling, this is also the transaction's
2940  * scheduled start time.
2941  */
2942  if (!throttle_delay)
2944 
2945  /* Begin with the first command */
2947  st->command = 0;
2948  break;
2949 
2950  /*
2951  * Handle throttling once per transaction by sleeping.
2952  */
2954 
2955  /*
2956  * Generate a delay such that the series of delays will
2957  * approximate a Poisson distribution centered on the
2958  * throttle_delay time.
2959  *
2960  * If transactions are too slow or a given wait is shorter
2961  * than a transaction, the next transaction will start right
2962  * away.
2963  */
2964  Assert(throttle_delay > 0);
2965 
2966  thread->throttle_trigger +=
2968  st->txn_scheduled = thread->throttle_trigger;
2969 
2970  /*
2971  * If --latency-limit is used, and this slot is already late
2972  * so that the transaction will miss the latency limit even if
2973  * it completed immediately, skip this time slot and schedule
2974  * to continue running on the next slot that isn't late yet.
2975  * But don't iterate beyond the -t limit, if one is given.
2976  */
2977  if (latency_limit)
2978  {
2979  int64 now_us;
2980 
2982  now_us = INSTR_TIME_GET_MICROSEC(now);
2983 
2984  while (thread->throttle_trigger < now_us - latency_limit &&
2985  (nxacts <= 0 || st->cnt < nxacts))
2986  {
2987  processXactStats(thread, st, &now, true, agg);
2988  /* next rendez-vous */
2989  thread->throttle_trigger +=
2991  st->txn_scheduled = thread->throttle_trigger;
2992  }
2993 
2994  /*
2995  * stop client if -t was exceeded in the previous skip
2996  * loop
2997  */
2998  if (nxacts > 0 && st->cnt >= nxacts)
2999  {
3000  st->state = CSTATE_FINISHED;
3001  break;
3002  }
3003  }
3004 
3005  /*
3006  * stop client if next transaction is beyond pgbench end of
3007  * execution; otherwise, throttle it.
3008  */
3009  st->state = end_time > 0 && st->txn_scheduled > end_time ?
3011  break;
3012 
3013  /*
3014  * Wait until it's time to start next transaction.
3015  */
3016  case CSTATE_THROTTLE:
3018 
3019  if (INSTR_TIME_GET_MICROSEC(now) < st->txn_scheduled)
3020  return; /* still sleeping, nothing to do here */
3021 
3022  /* done sleeping, but don't start transaction if we're done */
3024  break;
3025 
3026  /*
3027  * Send a command to server (or execute a meta-command)
3028  */
3029  case CSTATE_START_COMMAND:
3030  command = sql_script[st->use_file].commands[st->command];
3031 
3032  /* Transition to script end processing if done */
3033  if (command == NULL)
3034  {
3035  st->state = CSTATE_END_TX;
3036  break;
3037  }
3038 
3039  /* record begin time of next command, and initiate it */
3040  if (report_per_command)
3041  {
3043  st->stmt_begin = now;
3044  }
3045 
3046  /* Execute the command */
3047  if (command->type == SQL_COMMAND)
3048  {
3049  if (!sendCommand(st, command))
3050  {
3051  commandFailed(st, "SQL", "SQL command send failed");
3052  st->state = CSTATE_ABORTED;
3053  }
3054  else
3055  st->state = CSTATE_WAIT_RESULT;
3056  }
3057  else if (command->type == META_COMMAND)
3058  {
3059  /*-----
3060  * Possible state changes when executing meta commands:
3061  * - on errors CSTATE_ABORTED
3062  * - on sleep CSTATE_SLEEP
3063  * - else CSTATE_END_COMMAND
3064  */
3065  st->state = executeMetaCommand(st, &now);
3066  }
3067 
3068  /*
3069  * We're now waiting for an SQL command to complete, or
3070  * finished processing a metacommand, or need to sleep, or
3071  * something bad happened.
3072  */
3073  Assert(st->state == CSTATE_WAIT_RESULT ||
3074  st->state == CSTATE_END_COMMAND ||
3075  st->state == CSTATE_SLEEP ||
3076  st->state == CSTATE_ABORTED);
3077  break;
3078 
3079  /*
3080  * non executed conditional branch
3081  */
3082  case CSTATE_SKIP_COMMAND:
3084  /* quickly skip commands until something to do... */
3085  while (true)
3086  {
3087  Command *command;
3088 
3089  command = sql_script[st->use_file].commands[st->command];
3090 
3091  /* cannot reach end of script in that state */
3092  Assert(command != NULL);
3093 
3094  /*
3095  * if this is conditional related, update conditional
3096  * state
3097  */
3098  if (command->type == META_COMMAND &&
3099  (command->meta == META_IF ||
3100  command->meta == META_ELIF ||
3101  command->meta == META_ELSE ||
3102  command->meta == META_ENDIF))
3103  {
3104  switch (conditional_stack_peek(st->cstack))
3105  {
3106  case IFSTATE_FALSE:
3107  if (command->meta == META_IF ||
3108  command->meta == META_ELIF)
3109  {
3110  /* we must evaluate the condition */
3112  }
3113  else if (command->meta == META_ELSE)
3114  {
3115  /* we must execute next command */
3119  st->command++;
3120  }
3121  else if (command->meta == META_ENDIF)
3122  {
3125  if (conditional_active(st->cstack))
3127 
3128  /*
3129  * else state remains in
3130  * CSTATE_SKIP_COMMAND
3131  */
3132  st->command++;
3133  }
3134  break;
3135 
3136  case IFSTATE_IGNORED:
3137  case IFSTATE_ELSE_FALSE:
3138  if (command->meta == META_IF)
3140  IFSTATE_IGNORED);
3141  else if (command->meta == META_ENDIF)
3142  {
3145  if (conditional_active(st->cstack))
3147  }
3148  /* could detect "else" & "elif" after "else" */
3149  st->command++;
3150  break;
3151 
3152  case IFSTATE_NONE:
3153  case IFSTATE_TRUE:
3154  case IFSTATE_ELSE_TRUE:
3155  default:
3156 
3157  /*
3158  * inconsistent if inactive, unreachable dead
3159  * code
3160  */
3161  Assert(false);
3162  }
3163  }
3164  else
3165  {
3166  /* skip and consider next */
3167  st->command++;
3168  }
3169 
3170  if (st->state != CSTATE_SKIP_COMMAND)
3171  /* out of quick skip command loop */
3172  break;
3173  }
3174  break;
3175 
3176  /*
3177  * Wait for the current SQL command to complete
3178  */
3179  case CSTATE_WAIT_RESULT:
3180  if (debug)
3181  fprintf(stderr, "client %d receiving\n", st->id);
3182  if (!PQconsumeInput(st->con))
3183  {
3184  /* there's something wrong */
3185  commandFailed(st, "SQL", "perhaps the backend died while processing");
3186  st->state = CSTATE_ABORTED;
3187  break;
3188  }
3189  if (PQisBusy(st->con))
3190  return; /* don't have the whole result yet */
3191 
3192  /* store or discard the query results */
3194  st->state = CSTATE_END_COMMAND;
3195  else
3196  st->state = CSTATE_ABORTED;
3197  break;
3198 
3199  /*
3200  * Wait until sleep is done. This state is entered after a
3201  * \sleep metacommand. The behavior is similar to
3202  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3203  * instead of CSTATE_START_TX.
3204  */
3205  case CSTATE_SLEEP:
3207  if (INSTR_TIME_GET_MICROSEC(now) < st->sleep_until)
3208  return; /* still sleeping, nothing to do here */
3209  /* Else done sleeping. */
3210  st->state = CSTATE_END_COMMAND;
3211  break;
3212 
3213  /*
3214  * End of command: record stats and proceed to next command.
3215  */
3216  case CSTATE_END_COMMAND:
3217 
3218  /*
3219  * command completed: accumulate per-command execution times
3220  * in thread-local data structure, if per-command latencies
3221  * are requested.
3222  */
3223  if (report_per_command)
3224  {
3225  Command *command;
3226 
3228 
3229  command = sql_script[st->use_file].commands[st->command];
3230  /* XXX could use a mutex here, but we choose not to */
3231  addToSimpleStats(&command->stats,
3232  INSTR_TIME_GET_DOUBLE(now) -
3234  }
3235 
3236  /* Go ahead with next command, to be executed or skipped */
3237  st->command++;
3238  st->state = conditional_active(st->cstack) ?
3240  break;
3241 
3242  /*
3243  * End of transaction (end of script, really).
3244  */
3245  case CSTATE_END_TX:
3246 
3247  /* transaction finished: calculate latency and do log */
3248  processXactStats(thread, st, &now, false, agg);
3249 
3250  /*
3251  * missing \endif... cannot happen if CheckConditional was
3252  * okay
3253  */
3255 
3256  if (is_connect)
3257  {
3258  finishCon(st);
3259  INSTR_TIME_SET_ZERO(now);
3260  }
3261 
3262  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
3263  {
3264  /* script completed */
3265  st->state = CSTATE_FINISHED;
3266  break;
3267  }
3268 
3269  /* next transaction (script) */
3271 
3272  /*
3273  * Ensure that we always return on this point, so as to avoid
3274  * an infinite loop if the script only contains meta commands.
3275  */
3276  return;
3277 
3278  /*
3279  * Final states. Close the connection if it's still open.
3280  */
3281  case CSTATE_ABORTED:
3282  case CSTATE_FINISHED:
3283  finishCon(st);
3284  return;
3285  }
3286  }
3287 }
int64 throttle_trigger
Definition: pgbench.c:432
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:128
int type
Definition: pgbench.c:503
int id
Definition: pgbench.c:382
static int chooseScript(TState *thread)
Definition: pgbench.c:2613
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static bool readCommandResponse(CState *st, char *varprefix)
Definition: pgbench.c:2719
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:2604
struct timeval instr_time
Definition: instr_time.h:150
#define INSTR_TIME_ACCUM_DIFF(x, y, z)
Definition: instr_time.h:182
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1056
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
#define fprintf
Definition: port.h:196
int duration
Definition: pgbench.c:144
ConditionalStack cstack
Definition: pgbench.c:384
static void finishCon(CState *st)
Definition: pgbench.c:6236
bool is_connect
Definition: pgbench.c:219
double throttle_delay
Definition: pgbench.c:173
int64 end_time
Definition: pgbench.c:145
instr_time stmt_begin
Definition: pgbench.c:404
static ConnectionStateEnum executeMetaCommand(CState *st, instr_time *now)
Definition: pgbench.c:3297
#define META_COMMAND
Definition: pgbench.c:448
static int debug
Definition: pgbench.c:524
int nxacts
Definition: pgbench.c:143
const char * desc
Definition: pgbench.c:514
int64 cnt
Definition: pgbench.c:409
MetaCommand meta
Definition: pgbench.c:504
int64 txn_scheduled
Definition: pgbench.c:401
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:520
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:2632
RandomState ts_throttle_rs
Definition: pgbench.c:429
instr_time txn_begin
Definition: pgbench.c:403
#define SQL_COMMAND
Definition: pgbench.c:447
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1705
int command
Definition: pgbench.c:393
SimpleStats stats
Definition: pgbench.c:509
ConnectionStateEnum state
Definition: pgbench.c:383
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
int64 sleep_until
Definition: pgbench.c:402
PGconn * con
Definition: pgbench.c:381
#define INSTR_TIME_SET_CURRENT_LAZY(t)
Definition: instr_time.h:253
static PGconn * doConnect(void)
Definition: pgbench.c:1151
#define Assert(condition)
Definition: c.h:732
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:1755
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:205
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
char * varprefix
Definition: pgbench.c:507
volatile bool timer_exceeded
Definition: pgbench.c:232
Command ** commands
Definition: pgbench.c:516
int64 latency_limit
Definition: pgbench.c:181
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
bool report_per_command
Definition: pgbench.c:220
static int64 getPoissonRand(RandomState *random_state, double center)
Definition: pgbench.c:933
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:118
instr_time conn_time
Definition: pgbench.c:437
bool prepared[MAX_SCRIPTS]
Definition: pgbench.c:406
static void processXactStats(TState *thread, CState *st, instr_time *now, bool skipped, StatsData *agg)
Definition: pgbench.c:3531
int use_file
Definition: pgbench.c:392
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1532

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 6404 of file pgbench.c.

References pg_malloc0().

Referenced by setalarm(), and threadRun().

6405 {
6406  return (socket_set *) pg_malloc0(sizeof(socket_set));
6407 }
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

◆ assignVariables()

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

Definition at line 1538 of file pgbench.c.

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

Referenced by sendCommand().

1539 {
1540  char *p,
1541  *name,
1542  *val;
1543 
1544  p = sql;
1545  while ((p = strchr(p, ':')) != NULL)
1546  {
1547  int eaten;
1548 
1549  name = parseVariable(p, &eaten);
1550  if (name == NULL)
1551  {
1552  while (*p == ':')
1553  {
1554  p++;
1555  }
1556  continue;
1557  }
1558 
1559  val = getVariable(st, name);
1560  free(name);
1561  if (val == NULL)
1562  {
1563  p++;
1564  continue;
1565  }
1566 
1567  p = replaceVariable(&sql, p, eaten, val);
1568  }
1569 
1570  return sql;
1571 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1255
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1518
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1495
const char * name
Definition: encode.c:521
long val
Definition: informix.c:684

◆ CheckConditional()

static void CheckConditional ( ParsedScript  ps)
static

Definition at line 4424 of file pgbench.c.

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().

4425 {
4426  /* statically check conditional structure */
4428  int i;
4429 
4430  for (i = 0; ps.commands[i] != NULL; i++)
4431  {
4432  Command *cmd = ps.commands[i];
4433 
4434  if (cmd->type == META_COMMAND)
4435  {
4436  switch (cmd->meta)
4437  {
4438  case META_IF:
4440  break;
4441  case META_ELIF:
4442  if (conditional_stack_empty(cs))
4443  ConditionError(ps.desc, i + 1, "\\elif without matching \\if");
4445  ConditionError(ps.desc, i + 1, "\\elif after \\else");
4446  break;
4447  case META_ELSE:
4448  if (conditional_stack_empty(cs))
4449  ConditionError(ps.desc, i + 1, "\\else without matching \\if");
4451  ConditionError(ps.desc, i + 1, "\\else after \\else");
4453  break;
4454  case META_ENDIF:
4455  if (!conditional_stack_pop(cs))
4456  ConditionError(ps.desc, i + 1, "\\endif without matching \\if");
4457  break;
4458  default:
4459  /* ignore anything else... */
4460  break;
4461  }
4462  }
4463  }
4464  if (!conditional_stack_empty(cs))
4465  ConditionError(ps.desc, i + 1, "\\if without matching \\endif");
4467 }
int type
Definition: pgbench.c:503
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:4412
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
#define META_COMMAND
Definition: pgbench.c:448
const char * desc
Definition: pgbench.c:514
MetaCommand meta
Definition: pgbench.c:504
ConditionalStack conditional_stack_create(void)
Definition: conditional.c:18
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
Command ** commands
Definition: pgbench.c:516
void conditional_stack_destroy(ConditionalStack cstack)
Definition: conditional.c:30
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:118
int i

◆ checkInitSteps()

static void checkInitSteps ( const char *  initialize_steps)
static

Definition at line 3907 of file pgbench.c.

References fprintf.

Referenced by main().

3908 {
3909  const char *step;
3910 
3911  if (initialize_steps[0] == '\0')
3912  {
3913  fprintf(stderr, "no initialization steps specified\n");
3914  exit(1);
3915  }
3916 
3917  for (step = initialize_steps; *step != '\0'; step++)
3918  {
3919  if (strchr("dtgvpf ", *step) == NULL)
3920  {
3921  fprintf(stderr, "unrecognized initialization step \"%c\"\n",
3922  *step);
3923  fprintf(stderr, "allowed steps are: \"d\", \"t\", \"g\", \"v\", \"p\", \"f\"\n");
3924  exit(1);
3925  }
3926  }
3927 }
#define fprintf
Definition: port.h:196

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 2613 of file pgbench.c.

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

Referenced by advanceConnectionState().

2614 {
2615  int i = 0;
2616  int64 w;
2617 
2618  if (num_scripts == 1)
2619  return 0;
2620 
2621  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
2622  do
2623  {
2624  w -= sql_script[i++].weight;
2625  } while (w >= 0);
2626 
2627  return i - 1;
2628 }
static int num_scripts
Definition: pgbench.c:521
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:829
int weight
Definition: pgbench.c:515
RandomState ts_choose_rs
Definition: pgbench.c:428
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:520
static int64 total_weight
Definition: pgbench.c:522
int i

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 6416 of file pgbench.c.

References socket_set::fds, and socket_set::maxfd.

Referenced by setalarm(), and threadRun().

6417 {
6418  FD_ZERO(&sa->fds);
6419  sa->maxfd = -1;
6420 }
fd_set fds
Definition: pgbench.c:105
int maxfd
Definition: pgbench.c:104

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 1605 of file pgbench.c.

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

Referenced by evalLazyFunc(), and evalStandardFunc().

1606 {
1607  if (pval->type == PGBT_BOOLEAN)
1608  {
1609  *bval = pval->u.bval;
1610  return true;
1611  }
1612  else /* NULL, INT or DOUBLE */
1613  {
1614  fprintf(stderr, "cannot coerce %s to boolean\n", valueTypeName(pval));
1615  *bval = false; /* suppress uninitialized-variable warnings */
1616  return false;
1617  }
1618 }
union PgBenchValue::@39 u
#define fprintf
Definition: port.h:196
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1583
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46

◆ coerceToDouble()

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

Definition at line 1674 of file pgbench.c.

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

Referenced by evalStandardFunc().

1675 {
1676  if (pval->type == PGBT_DOUBLE)
1677  {
1678  *dval = pval->u.dval;
1679  return true;
1680  }
1681  else if (pval->type == PGBT_INT)
1682  {
1683  *dval = (double) pval->u.ival;
1684  return true;
1685  }
1686  else /* BOOLEAN or NULL */
1687  {
1688  fprintf(stderr, "cannot coerce %s to double\n", valueTypeName(pval));
1689  return false;
1690  }
1691 }
union PgBenchValue::@39 u
#define fprintf
Definition: port.h:196
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1583
double dval
Definition: pgbench.h:50
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49

◆ coerceToInt()

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

Definition at line 1646 of file pgbench.c.

References PgBenchValue::dval, fprintf, PgBenchValue::ival, PG_INT64_MAX, PG_INT64_MIN, PGBT_DOUBLE, PGBT_INT, PgBenchValue::type, PgBenchValue::u, and valueTypeName().

Referenced by evalStandardFunc().

1647 {
1648  if (pval->type == PGBT_INT)
1649  {
1650  *ival = pval->u.ival;
1651  return true;
1652  }
1653  else if (pval->type == PGBT_DOUBLE)
1654  {
1655  double dval = pval->u.dval;
1656 
1657  if (dval < PG_INT64_MIN || PG_INT64_MAX < dval)
1658  {
1659  fprintf(stderr, "double to int overflow for %f\n", dval);
1660  return false;
1661  }
1662  *ival = (int64) dval;
1663  return true;
1664  }
1665  else /* BOOLEAN or NULL */
1666  {
1667  fprintf(stderr, "cannot coerce %s to int\n", valueTypeName(pval));
1668  return false;
1669  }
1670 }
#define PG_INT64_MAX
Definition: c.h:444
union PgBenchValue::@39 u
#define fprintf
Definition: port.h:196
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1583
#define PG_INT64_MIN
Definition: c.h:443
double dval
Definition: pgbench.h:50
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49

◆ commandFailed()

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

Definition at line 2604 of file pgbench.c.

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

Referenced by advanceConnectionState(), and executeMetaCommand().

2605 {
2606  fprintf(stderr,
2607  "client %d aborted in command %d (%s) of script %d; %s\n",
2608  st->id, st->command, cmd, st->use_file, message);
2609 }
int id
Definition: pgbench.c:382
#define fprintf
Definition: port.h:196
int command
Definition: pgbench.c:393
int use_file
Definition: pgbench.c:392

◆ compareVariableNames()

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

Definition at line 1220 of file pgbench.c.

References name.

Referenced by lookupVariable().

1221 {
1222  return strcmp(((const Variable *) v1)->name,
1223  ((const Variable *) v2)->name);
1224 }
const char * name
Definition: encode.c:521

◆ computeIterativeZipfian()

static int64 computeIterativeZipfian ( RandomState random_state,
int64  n,
double  s 
)
static

Definition at line 955 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by getZipfianRand().

956 {
957  double b = pow(2.0, s - 1.0);
958  double x,
959  t,
960  u,
961  v;
962 
963  /* Ensure n is sane */
964  if (n <= 1)
965  return 1;
966 
967  while (true)
968  {
969  /* random variates */
970  u = pg_erand48(random_state->xseed);
971  v = pg_erand48(random_state->xseed);
972 
973  x = floor(pow(u, -1.0 / (s - 1.0)));
974 
975  t = pow(1.0 + 1.0 / x, s - 1.0);
976  /* reject if too large or out of bound */
977  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
978  break;
979  }
980  return (int64) x;
981 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:288

◆ ConditionError()

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

Definition at line 4412 of file pgbench.c.

References fprintf.

Referenced by CheckConditional().

4413 {
4414  fprintf(stderr,
4415  "condition error in script \"%s\" command %d: %s\n",
4416  desc, cmdn, msg);
4417  exit(1);
4418 }
#define fprintf
Definition: port.h:196

◆ create_sql_command()

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

Definition at line 4147 of file pgbench.c.

References appendPQExpBufferStr(), Command::argc, Command::argv, PQExpBufferData::data, 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().

4148 {
4149  Command *my_command;
4150  char *p = skip_sql_comments(buf->data);
4151 
4152  if (p == NULL)
4153  return NULL;
4154 
4155  /* Allocate and initialize Command structure */
4156  my_command = (Command *) pg_malloc(sizeof(Command));
4157  initPQExpBuffer(&my_command->lines);
4158  appendPQExpBufferStr(&my_command->lines, p);
4159  my_command->first_line = NULL; /* this is set later */
4160  my_command->type = SQL_COMMAND;
4161  my_command->meta = META_NONE;
4162  my_command->argc = 0;
4163  memset(my_command->argv, 0, sizeof(my_command->argv));
4164  my_command->varprefix = NULL; /* allocated later, if needed */
4165  my_command->expr = NULL;
4166  initSimpleStats(&my_command->stats);
4167 
4168  return my_command;
4169 }
int type
Definition: pgbench.c:503
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
PgBenchExpr * expr
Definition: pgbench.c:508
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:4112
char * argv[MAX_ARGS]
Definition: pgbench.c:506
MetaCommand meta
Definition: pgbench.c:504
PQExpBufferData lines
Definition: pgbench.c:501
int argc
Definition: pgbench.c:505
#define SQL_COMMAND
Definition: pgbench.c:447
SimpleStats stats
Definition: pgbench.c:509
char * varprefix
Definition: pgbench.c:507
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1047
char * first_line
Definition: pgbench.c:502
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 3577 of file pgbench.c.

References finishCon(), and i.

Referenced by main(), and threadRun().

3578 {
3579  int i;
3580 
3581  for (i = 0; i < length; i++)
3582  finishCon(&state[i]);
3583 }
static void finishCon(CState *st)
Definition: pgbench.c:6236
int i

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1151 of file pgbench.c.

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

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

1152 {
1153  PGconn *conn;
1154  bool new_pass;
1155  static bool have_password = false;
1156  static char password[100];
1157 
1158  /*
1159  * Start the connection. Loop until we have a password if requested by
1160  * backend.
1161  */
1162  do
1163  {
1164 #define PARAMS_ARRAY_SIZE 7
1165 
1166  const char *keywords[PARAMS_ARRAY_SIZE];
1167  const char *values[PARAMS_ARRAY_SIZE];
1168 
1169  keywords[0] = "host";
1170  values[0] = pghost;
1171  keywords[1] = "port";
1172  values[1] = pgport;
1173  keywords[2] = "user";
1174  values[2] = login;
1175  keywords[3] = "password";
1176  values[3] = have_password ? password : NULL;
1177  keywords[4] = "dbname";
1178  values[4] = dbName;
1179  keywords[5] = "fallback_application_name";
1180  values[5] = progname;
1181  keywords[6] = NULL;
1182  values[6] = NULL;
1183 
1184  new_pass = false;
1185 
1186  conn = PQconnectdbParams(keywords, values, true);
1187 
1188  if (!conn)
1189  {
1190  fprintf(stderr, "connection to database \"%s\" failed\n",
1191  dbName);
1192  return NULL;
1193  }
1194 
1195  if (PQstatus(conn) == CONNECTION_BAD &&
1196  PQconnectionNeedsPassword(conn) &&
1197  !have_password)
1198  {
1199  PQfinish(conn);
1200  simple_prompt("Password: ", password, sizeof(password), false);
1201  have_password = true;
1202  new_pass = true;
1203  }
1204  } while (new_pass);
1205 
1206  /* check to see that the backend connection was successfully made */
1207  if (PQstatus(conn) == CONNECTION_BAD)
1208  {
1209  fprintf(stderr, "connection to database \"%s\" failed:\n%s",
1210  dbName, PQerrorMessage(conn));
1211  PQfinish(conn);
1212  return NULL;
1213  }
1214 
1215  return conn;
1216 }
static char password[100]
Definition: streamutil.c:55
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6561
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4063
#define fprintf
Definition: port.h:196
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:613
PGconn * conn
Definition: streamutil.c:56
void simple_prompt(const char *prompt, char *destination, size_t destlen, bool echo)
Definition: sprompt.c:37
#define PARAMS_ARRAY_SIZE
char * pghost
Definition: pgbench.c:223
static bool have_password
Definition: streamutil.c:54
const char * progname
Definition: pgbench.c:228
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6595
char * dbName
Definition: pgbench.c:226
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6508
char * pgport
Definition: pgbench.c:224
char * login
Definition: pgbench.c:225

◆ doLog()

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

Definition at line 3450 of file pgbench.c.

References accumStats(), Assert, StatsData::cnt, CState::cnt, fprintf, gettimeofday(), CState::id, initStats(), INT64_FORMAT, StatsData::lag, StatsData::latency, logfile, TState::logfile, SimpleStats::max, SimpleStats::min, pg_erand48(), StatsData::skipped, StatsData::start_time, SimpleStats::sum, SimpleStats::sum2, TState::ts_sample_rs, CState::use_file, and RandomState::xseed.

Referenced by processXactStats(), and threadRun().

3452 {
3453  FILE *logfile = thread->logfile;
3454 
3455  Assert(use_log);
3456 
3457  /*
3458  * Skip the log entry if sampling is enabled and this row doesn't belong
3459  * to the random sample.
3460  */
3461  if (sample_rate != 0.0 &&
3463  return;
3464 
3465  /* should we aggregate the results or not? */
3466  if (agg_interval > 0)
3467  {
3468  /*
3469  * Loop until we reach the interval of the current moment, and print
3470  * any empty intervals in between (this may happen with very low tps,
3471  * e.g. --rate=0.1).
3472  */
3473  time_t now = time(NULL);
3474 
3475  while (agg->start_time + agg_interval <= now)
3476  {
3477  /* print aggregated report to logfile */
3478  fprintf(logfile, "%ld " INT64_FORMAT " %.0f %.0f %.0f %.0f",
3479  (long) agg->start_time,
3480  agg->cnt,
3481  agg->latency.sum,
3482  agg->latency.sum2,
3483  agg->latency.min,
3484  agg->latency.max);
3485  if (throttle_delay)
3486  {
3487  fprintf(logfile, " %.0f %.0f %.0f %.0f",
3488  agg->lag.sum,
3489  agg->lag.sum2,
3490  agg->lag.min,
3491  agg->lag.max);
3492  if (latency_limit)
3493  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
3494  }
3495  fputc('\n', logfile);
3496 
3497  /* reset data and move to next interval */
3498  initStats(agg, agg->start_time + agg_interval);
3499  }
3500 
3501  /* accumulate the current transaction */
3502  accumStats(agg, skipped, latency, lag);
3503  }
3504  else
3505  {
3506  /* no, print raw transactions */
3507  struct timeval tv;
3508 
3509  gettimeofday(&tv, NULL);
3510  if (skipped)
3511  fprintf(logfile, "%d " INT64_FORMAT " skipped %d %ld %ld",
3512  st->id, st->cnt, st->use_file,
3513  (long) tv.tv_sec, (long) tv.tv_usec);
3514  else
3515  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d %ld %ld",
3516  st->id, st->cnt, latency, st->use_file,
3517  (long) tv.tv_sec, (long) tv.tv_usec);
3518  if (throttle_delay)
3519  fprintf(logfile, " %.0f", lag);
3520  fputc('\n', logfile);
3521  }
3522 }
time_t start_time
Definition: pgbench.c:275
int gettimeofday(struct timeval *tp, struct timezone *tzp)
Definition: gettimeofday.c:105
double sample_rate
Definition: pgbench.c:167
int id
Definition: pgbench.c:382
SimpleStats lag
Definition: pgbench.c:280
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:1087
double sum
Definition: pgbench.c:265
RandomState ts_sample_rs
Definition: pgbench.c:430
bool use_log
Definition: pgbench.c:210
static FILE * logfile
Definition: pg_regress.c:102
SimpleStats latency
Definition: pgbench.c:279
#define fprintf
Definition: port.h:196
double throttle_delay
Definition: pgbench.c:173
FILE * logfile
Definition: pgbench.c:433
int64 cnt
Definition: pgbench.c:276
int64 cnt
Definition: pgbench.c:409
int64 skipped
Definition: pgbench.c:277
double max
Definition: pgbench.c:264
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:1100
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:732
double sum2
Definition: pgbench.c:266
unsigned short xseed[3]
Definition: pgbench.c:288
int64 latency_limit
Definition: pgbench.c:181
#define INT64_FORMAT
Definition: c.h:400
int use_file
Definition: pgbench.c:392
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1532
double min
Definition: pgbench.c:263
int agg_interval
Definition: pgbench.c:212

◆ evalFunc()

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

Definition at line 2397 of file pgbench.c.

References evalLazyFunc(), evalStandardFunc(), and isLazyFunc().

Referenced by evaluateExpr().

2399 {
2400  if (isLazyFunc(func))
2401  return evalLazyFunc(st, func, args, retval);
2402  else
2403  return evalStandardFunc(st, func, args, retval);
2404 }
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1733
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1850
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1726

◆ evalLazyFunc()

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

Definition at line 1733 of file pgbench.c.

References a1, a2, Assert, coerceToBool(), evaluateExpr(), PgBenchExprLink::expr, isLazyFunc(), PgBenchExprLink::next, PGBENCH_AND, PGBENCH_CASE, PGBENCH_OR, PGBT_NULL, setBoolValue(), setNullValue(), PgBenchValue::type, and valueTruth().

Referenced by evalFunc().

1735 {
1736  PgBenchValue a1,
1737  a2;
1738  bool ba1,
1739  ba2;
1740 
1741  Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
1742 
1743  /* args points to first condition */
1744  if (!evaluateExpr(st, args->expr, &a1))
1745  return false;
1746 
1747  /* second condition for AND/OR and corresponding branch for CASE */
1748  args = args->next;
1749 
1750  switch (func)
1751  {
1752  case PGBENCH_AND:
1753  if (a1.type == PGBT_NULL)
1754  {
1755  setNullValue(retval);
1756  return true;
1757  }
1758 
1759  if (!coerceToBool(&a1, &ba1))
1760  return false;
1761 
1762  if (!ba1)
1763  {
1764  setBoolValue(retval, false);
1765  return true;
1766  }
1767 
1768  if (!evaluateExpr(st, args->expr, &a2))
1769  return false;
1770 
1771  if (a2.type == PGBT_NULL)
1772  {
1773  setNullValue(retval);
1774  return true;
1775  }
1776  else if (!coerceToBool(&a2, &ba2))
1777  return false;
1778  else
1779  {
1780  setBoolValue(retval, ba2);
1781  return true;
1782  }
1783 
1784  return true;
1785 
1786  case PGBENCH_OR:
1787 
1788  if (a1.type == PGBT_NULL)
1789  {
1790  setNullValue(retval);
1791  return true;
1792  }
1793 
1794  if (!coerceToBool(&a1, &ba1))
1795  return false;
1796 
1797  if (ba1)
1798  {
1799  setBoolValue(retval, true);
1800  return true;
1801  }
1802 
1803  if (!evaluateExpr(st, args->expr, &a2))
1804  return false;
1805 
1806  if (a2.type == PGBT_NULL)
1807  {
1808  setNullValue(retval);
1809  return true;
1810  }
1811  else if (!coerceToBool(&a2, &ba2))
1812  return false;
1813  else
1814  {
1815  setBoolValue(retval, ba2);
1816  return true;
1817  }
1818 
1819  case PGBENCH_CASE:
1820  /* when true, execute branch */
1821  if (valueTruth(&a1))
1822  return evaluateExpr(st, args->expr, retval);
1823 
1824  /* now args contains next condition or final else expression */
1825  args = args->next;
1826 
1827  /* final else case? */
1828  if (args->next == NULL)
1829  return evaluateExpr(st, args->expr, retval);
1830 
1831  /* no, another when, proceed */
1832  return evalLazyFunc(st, PGBENCH_CASE, args, retval);
1833 
1834  default:
1835  /* internal error, cannot get here */
1836  Assert(0);
1837  break;
1838  }
1839  return false;
1840 }
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:1605
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1733
static const FormData_pg_attribute a2
Definition: heap.c:166
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2413
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:1703
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:1695
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1726
#define Assert(condition)
Definition: c.h:732
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1625
PgBenchValueType type
Definition: pgbench.h:46
static const FormData_pg_attribute a1
Definition: heap.c:152

◆ evalStandardFunc()

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

Definition at line 1850 of file pgbench.c.

References generate_unaccent_rules::args, Assert, PgBenchValue::bval, coerceToBool(), coerceToDouble(), coerceToInt(), CState::command, CState::cs_func_rs, PgBenchValue::dval, evaluateExpr(), 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, pg_add_s64_overflow(), PG_INT64_MIN, 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_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, setBoolValue(), setDoubleValue(), setIntValue(), setNullValue(), PgBenchValue::type, generate_unaccent_rules::type, PgBenchValue::u, CState::use_file, and val.

Referenced by evalFunc().

1853 {
1854  /* evaluate all function arguments */
1855  int nargs = 0;
1856  PgBenchValue vargs[MAX_FARGS];
1857  PgBenchExprLink *l = args;
1858  bool has_null = false;
1859 
1860  for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
1861  {
1862  if (!evaluateExpr(st, l->expr, &vargs[nargs]))
1863  return false;
1864  has_null |= vargs[nargs].type == PGBT_NULL;
1865  }
1866 
1867  if (l != NULL)
1868  {
1869  fprintf(stderr,
1870  "too many function arguments, maximum is %d\n", MAX_FARGS);
1871  return false;
1872  }
1873 
1874  /* NULL arguments */
1875  if (has_null && func != PGBENCH_IS && func != PGBENCH_DEBUG)
1876  {
1877  setNullValue(retval);
1878  return true;
1879  }
1880 
1881  /* then evaluate function */
1882  switch (func)
1883  {
1884  /* overloaded operators */
1885  case PGBENCH_ADD:
1886  case PGBENCH_SUB:
1887  case PGBENCH_MUL:
1888  case PGBENCH_DIV:
1889  case PGBENCH_MOD:
1890  case PGBENCH_EQ:
1891  case PGBENCH_NE:
1892  case PGBENCH_LE:
1893  case PGBENCH_LT:
1894  {
1895  PgBenchValue *lval = &vargs[0],
1896  *rval = &vargs[1];
1897 
1898  Assert(nargs == 2);
1899 
1900  /* overloaded type management, double if some double */
1901  if ((lval->type == PGBT_DOUBLE ||
1902  rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
1903  {
1904  double ld,
1905  rd;
1906 
1907  if (!coerceToDouble(lval, &ld) ||
1908  !coerceToDouble(rval, &rd))
1909  return false;
1910 
1911  switch (func)
1912  {
1913  case PGBENCH_ADD:
1914  setDoubleValue(retval, ld + rd);
1915  return true;
1916 
1917  case PGBENCH_SUB:
1918  setDoubleValue(retval, ld - rd);
1919  return true;
1920 
1921  case PGBENCH_MUL:
1922  setDoubleValue(retval, ld * rd);
1923  return true;
1924 
1925  case PGBENCH_DIV:
1926  setDoubleValue(retval, ld / rd);
1927  return true;
1928 
1929  case PGBENCH_EQ:
1930  setBoolValue(retval, ld == rd);
1931  return true;
1932 
1933  case PGBENCH_NE:
1934  setBoolValue(retval, ld != rd);
1935  return true;
1936 
1937  case PGBENCH_LE:
1938  setBoolValue(retval, ld <= rd);
1939  return true;
1940 
1941  case PGBENCH_LT:
1942  setBoolValue(retval, ld < rd);
1943  return true;
1944 
1945  default:
1946  /* cannot get here */
1947  Assert(0);
1948  }
1949  }
1950  else /* we have integer operands, or % */
1951  {
1952  int64 li,
1953  ri,
1954  res;
1955 
1956  if (!coerceToInt(lval, &li) ||
1957  !coerceToInt(rval, &ri))
1958  return false;
1959 
1960  switch (func)
1961  {
1962  case PGBENCH_ADD:
1963  if (pg_add_s64_overflow(li, ri, &res))
1964  {
1965  fprintf(stderr, "bigint add out of range\n");
1966  return false;
1967  }
1968  setIntValue(retval, res);
1969  return true;
1970 
1971  case PGBENCH_SUB:
1972  if (pg_sub_s64_overflow(li, ri, &res))
1973  {
1974  fprintf(stderr, "bigint sub out of range\n");
1975  return false;
1976  }
1977  setIntValue(retval, res);
1978  return true;
1979 
1980  case PGBENCH_MUL:
1981  if (pg_mul_s64_overflow(li, ri, &res))
1982  {
1983  fprintf(stderr, "bigint mul out of range\n");
1984  return false;
1985  }
1986  setIntValue(retval, res);
1987  return true;
1988 
1989  case PGBENCH_EQ:
1990  setBoolValue(retval, li == ri);
1991  return true;
1992 
1993  case PGBENCH_NE:
1994  setBoolValue(retval, li != ri);
1995  return true;
1996 
1997  case PGBENCH_LE:
1998  setBoolValue(retval, li <= ri);
1999  return true;
2000 
2001  case PGBENCH_LT:
2002  setBoolValue(retval, li < ri);
2003  return true;
2004 
2005  case PGBENCH_DIV:
2006  case PGBENCH_MOD:
2007  if (ri == 0)
2008  {
2009  fprintf(stderr, "division by zero\n");
2010  return false;
2011  }
2012  /* special handling of -1 divisor */
2013  if (ri == -1)
2014  {
2015  if (func == PGBENCH_DIV)
2016  {
2017  /* overflow check (needed for INT64_MIN) */
2018  if (li == PG_INT64_MIN)
2019  {
2020  fprintf(stderr, "bigint div out of range\n");
2021  return false;
2022  }
2023  else
2024  setIntValue(retval, -li);
2025  }
2026  else
2027  setIntValue(retval, 0);
2028  return true;
2029  }
2030  /* else divisor is not -1 */
2031  if (func == PGBENCH_DIV)
2032  setIntValue(retval, li / ri);
2033  else /* func == PGBENCH_MOD */
2034  setIntValue(retval, li % ri);
2035 
2036  return true;
2037 
2038  default:
2039  /* cannot get here */
2040  Assert(0);
2041  }
2042  }
2043 
2044  Assert(0);
2045  return false; /* NOTREACHED */
2046  }
2047 
2048  /* integer bitwise operators */
2049  case PGBENCH_BITAND:
2050  case PGBENCH_BITOR:
2051  case PGBENCH_BITXOR:
2052  case PGBENCH_LSHIFT:
2053  case PGBENCH_RSHIFT:
2054  {
2055  int64 li,
2056  ri;
2057 
2058  if (!coerceToInt(&vargs[0], &li) || !coerceToInt(&vargs[1], &ri))
2059  return false;
2060 
2061  if (func == PGBENCH_BITAND)
2062  setIntValue(retval, li & ri);
2063  else if (func == PGBENCH_BITOR)
2064  setIntValue(retval, li | ri);
2065  else if (func == PGBENCH_BITXOR)
2066  setIntValue(retval, li ^ ri);
2067  else if (func == PGBENCH_LSHIFT)
2068  setIntValue(retval, li << ri);
2069  else if (func == PGBENCH_RSHIFT)
2070  setIntValue(retval, li >> ri);
2071  else /* cannot get here */
2072  Assert(0);
2073 
2074  return true;
2075  }
2076 
2077  /* logical operators */
2078  case PGBENCH_NOT:
2079  {
2080  bool b;
2081 
2082  if (!coerceToBool(&vargs[0], &b))
2083  return false;
2084 
2085  setBoolValue(retval, !b);
2086  return true;
2087  }
2088 
2089  /* no arguments */
2090  case PGBENCH_PI:
2091  setDoubleValue(retval, M_PI);
2092  return true;
2093 
2094  /* 1 overloaded argument */
2095  case PGBENCH_ABS:
2096  {
2097  PgBenchValue *varg = &vargs[0];
2098 
2099  Assert(nargs == 1);
2100 
2101  if (varg->type == PGBT_INT)
2102  {
2103  int64 i = varg->u.ival;
2104 
2105  setIntValue(retval, i < 0 ? -i : i);
2106  }
2107  else
2108  {
2109  double d = varg->u.dval;
2110 
2111  Assert(varg->type == PGBT_DOUBLE);
2112  setDoubleValue(retval, d < 0.0 ? -d : d);
2113  }
2114 
2115  return true;
2116  }
2117 
2118  case PGBENCH_DEBUG:
2119  {
2120  PgBenchValue *varg = &vargs[0];
2121 
2122  Assert(nargs == 1);
2123 
2124  fprintf(stderr, "debug(script=%d,command=%d): ",
2125  st->use_file, st->command + 1);
2126 
2127  if (varg->type == PGBT_NULL)
2128  fprintf(stderr, "null\n");
2129  else if (varg->type == PGBT_BOOLEAN)
2130  fprintf(stderr, "boolean %s\n", varg->u.bval ? "true" : "false");
2131  else if (varg->type == PGBT_INT)
2132  fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
2133  else if (varg->type == PGBT_DOUBLE)
2134  fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
2135  else /* internal error, unexpected type */
2136  Assert(0);
2137 
2138  *retval = *varg;
2139 
2140  return true;
2141  }
2142 
2143  /* 1 double argument */
2144  case PGBENCH_DOUBLE:
2145  case PGBENCH_SQRT:
2146  case PGBENCH_LN:
2147  case PGBENCH_EXP:
2148  {
2149  double dval;
2150 
2151  Assert(nargs == 1);
2152 
2153  if (!coerceToDouble(&vargs[0], &dval))
2154  return false;
2155 
2156  if (func == PGBENCH_SQRT)
2157  dval = sqrt(dval);
2158  else if (func == PGBENCH_LN)
2159  dval = log(dval);
2160  else if (func == PGBENCH_EXP)
2161  dval = exp(dval);
2162  /* else is cast: do nothing */
2163 
2164  setDoubleValue(retval, dval);
2165  return true;
2166  }
2167 
2168  /* 1 int argument */
2169  case PGBENCH_INT:
2170  {
2171  int64 ival;
2172 
2173  Assert(nargs == 1);
2174 
2175  if (!coerceToInt(&vargs[0], &ival))
2176  return false;
2177 
2178  setIntValue(retval, ival);
2179  return true;
2180  }
2181 
2182  /* variable number of arguments */
2183  case PGBENCH_LEAST:
2184  case PGBENCH_GREATEST:
2185  {
2186  bool havedouble;
2187  int i;
2188 
2189  Assert(nargs >= 1);
2190 
2191  /* need double result if any input is double */
2192  havedouble = false;
2193  for (i = 0; i < nargs; i++)
2194  {
2195  if (vargs[i].type == PGBT_DOUBLE)
2196  {
2197  havedouble = true;
2198  break;
2199  }
2200  }
2201  if (havedouble)
2202  {
2203  double extremum;
2204 
2205  if (!coerceToDouble(&vargs[0], &extremum))
2206  return false;
2207  for (i = 1; i < nargs; i++)
2208  {
2209  double dval;
2210 
2211  if (!coerceToDouble(&vargs[i], &dval))
2212  return false;
2213  if (func == PGBENCH_LEAST)
2214  extremum = Min(extremum, dval);
2215  else
2216  extremum = Max(extremum, dval);
2217  }
2218  setDoubleValue(retval, extremum);
2219  }
2220  else
2221  {
2222  int64 extremum;
2223 
2224  if (!coerceToInt(&vargs[0], &extremum))
2225  return false;
2226  for (i = 1; i < nargs; i++)
2227  {
2228  int64 ival;
2229 
2230  if (!coerceToInt(&vargs[i], &ival))
2231  return false;
2232  if (func == PGBENCH_LEAST)
2233  extremum = Min(extremum, ival);
2234  else
2235  extremum = Max(extremum, ival);
2236  }
2237  setIntValue(retval, extremum);
2238  }
2239  return true;
2240  }
2241 
2242  /* random functions */
2243  case PGBENCH_RANDOM:
2247  {
2248  int64 imin,
2249  imax;
2250 
2251  Assert(nargs >= 2);
2252 
2253  if (!coerceToInt(&vargs[0], &imin) ||
2254  !coerceToInt(&vargs[1], &imax))
2255  return false;
2256 
2257  /* check random range */
2258  if (imin > imax)
2259  {
2260  fprintf(stderr, "empty range given to random\n");
2261  return false;
2262  }
2263  else if (imax - imin < 0 || (imax - imin) + 1 < 0)
2264  {
2265  /* prevent int overflows in random functions */
2266  fprintf(stderr, "random range is too large\n");
2267  return false;
2268  }
2269 
2270  if (func == PGBENCH_RANDOM)
2271  {
2272  Assert(nargs == 2);
2273  setIntValue(retval, getrand(&st->cs_func_rs, imin, imax));
2274  }
2275  else /* gaussian & exponential */
2276  {
2277  double param;
2278 
2279  Assert(nargs == 3);
2280 
2281  if (!coerceToDouble(&vargs[2], &param))
2282  return false;
2283 
2284  if (func == PGBENCH_RANDOM_GAUSSIAN)
2285  {
2286  if (param < MIN_GAUSSIAN_PARAM)
2287  {
2288  fprintf(stderr,
2289  "gaussian parameter must be at least %f "
2290  "(not %f)\n", MIN_GAUSSIAN_PARAM, param);
2291  return false;
2292  }
2293 
2294  setIntValue(retval,
2296  imin, imax, param));
2297  }
2298  else if (func == PGBENCH_RANDOM_ZIPFIAN)
2299  {
2300  if (param < MIN_ZIPFIAN_PARAM || param > MAX_ZIPFIAN_PARAM)
2301  {
2302  fprintf(stderr,
2303  "zipfian parameter must be in range [%.3f, %.0f]"
2304  " (not %f)\n",
2305  MIN_ZIPFIAN_PARAM, MAX_ZIPFIAN_PARAM, param);
2306  return false;
2307  }
2308 
2309  setIntValue(retval,
2310  getZipfianRand(&st->cs_func_rs, imin, imax, param));
2311  }
2312  else /* exponential */
2313  {
2314  if (param <= 0.0)
2315  {
2316  fprintf(stderr,
2317  "exponential parameter must be greater than zero"
2318  " (not %f)\n", param);
2319  return false;
2320  }
2321 
2322  setIntValue(retval,
2324  imin, imax, param));
2325  }
2326  }
2327 
2328  return true;
2329  }
2330 
2331  case PGBENCH_POW:
2332  {
2333  PgBenchValue *lval = &vargs[0];
2334  PgBenchValue *rval = &vargs[1];
2335  double ld,
2336  rd;
2337 
2338  Assert(nargs == 2);
2339 
2340  if (!coerceToDouble(lval, &ld) ||
2341  !coerceToDouble(rval, &rd))
2342  return false;
2343 
2344  setDoubleValue(retval, pow(ld, rd));
2345 
2346  return true;
2347  }
2348 
2349  case PGBENCH_IS:
2350  {
2351  Assert(nargs == 2);
2352 
2353  /*
2354  * note: this simple implementation is more permissive than
2355  * SQL
2356  */
2357  setBoolValue(retval,
2358  vargs[0].type == vargs[1].type &&
2359  vargs[0].u.bval == vargs[1].u.bval);
2360  return true;
2361  }
2362 
2363  /* hashing */
2364  case PGBENCH_HASH_FNV1A:
2365  case PGBENCH_HASH_MURMUR2:
2366  {
2367  int64 val,
2368  seed;
2369 
2370  Assert(nargs == 2);
2371 
2372  if (!coerceToInt(&vargs[0], &val) ||
2373  !coerceToInt(&vargs[1], &seed))
2374  return false;
2375 
2376  if (func == PGBENCH_HASH_MURMUR2)
2377  setIntValue(retval, getHashMurmur2(val, seed));
2378  else if (func == PGBENCH_HASH_FNV1A)
2379  setIntValue(retval, getHashFnv1a(val, seed));
2380  else
2381  /* cannot get here */
2382  Assert(0);
2383 
2384  return true;
2385  }
2386 
2387  default:
2388  /* cannot get here */
2389  Assert(0);
2390  /* dead code to avoid a compiler warning */
2391  return false;
2392  }
2393 }
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:1605
static bool pg_sub_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:188
static int64 getHashMurmur2(int64 val, uint64 seed)
Definition: pgbench.c:1024
static int64 getHashFnv1a(int64 val, uint64 seed)
Definition: pgbench.c:999
#define Min(x, y)
Definition: c.h:904
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:829
union PgBenchValue::@39 u
RandomState cs_func_rs
Definition: pgbench.c:390
static bool coerceToDouble(PgBenchValue *pval, double *dval)
Definition: pgbench.c:1674
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:1719
#define fprintf
Definition: port.h:196
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:138
static int64 getExponentialRand(RandomState *random_state, int64 min, int64 max, double parameter)
Definition: pgbench.c:849
#define MAX_FARGS
Definition: pgbench.c:1843
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2413
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:1703
static int64 getZipfianRand(RandomState *random_state, int64 min, int64 max, double s)
Definition: pgbench.c:985
#define M_PI
Definition: pgbench.c:67
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:1695
#define PG_INT64_MIN
Definition: c.h:443
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:141
int command
Definition: pgbench.c:393
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:140
double dval
Definition: pgbench.h:50
static bool pg_add_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:161
#define Max(x, y)
Definition: c.h:898
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:215
#define Assert(condition)
Definition: c.h:732
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:1711
#define INT64_FORMAT
Definition: c.h:400
static int64 getGaussianRand(RandomState *random_state, int64 min, int64 max, double parameter)
Definition: pgbench.c:873
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
int i
static bool coerceToInt(PgBenchValue *pval, int64 *ival)
Definition: pgbench.c:1646
int64 ival
Definition: pgbench.h:49
int use_file
Definition: pgbench.c:392
long val
Definition: informix.c:684

◆ evaluateExpr()

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

Definition at line 2413 of file pgbench.c.

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

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

2414 {
2415  switch (expr->etype)
2416  {
2417  case ENODE_CONSTANT:
2418  {
2419  *retval = expr->u.constant;
2420  return true;
2421  }
2422 
2423  case ENODE_VARIABLE:
2424  {
2425  Variable *var;
2426 
2427  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
2428  {
2429  fprintf(stderr, "undefined variable \"%s\"\n",
2430  expr->u.variable.varname);
2431  return false;
2432  }
2433 
2434  if (!makeVariableValue(var))
2435  return false;
2436 
2437  *retval = var->value;
2438  return true;
2439  }
2440 
2441  case ENODE_FUNCTION:
2442  return evalFunc(st,
2443  expr->u.function.function,
2444  expr->u.function.args,
2445  retval);
2446 
2447  default:
2448  /* internal error which should never occur */
2449  fprintf(stderr, "unexpected enode type in evaluation: %d\n",
2450  expr->etype);
2451  exit(1);
2452  }
2453 }
PgBenchValue constant
Definition: pgbench.h:114
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1228
struct PgBenchExpr::@40::@41 variable
#define fprintf
Definition: port.h:196
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2397
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1288
PgBenchValue value
Definition: pgbench.c:248
PgBenchFunction function
Definition: pgbench.h:121
union PgBenchExpr::@40 u
PgBenchExprType etype
Definition: pgbench.h:111

◆ evaluateSleep()

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

Definition at line 2828 of file pgbench.c.

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

Referenced by executeMetaCommand().

2829 {
2830  char *var;
2831  int usec;
2832 
2833  if (*argv[1] == ':')
2834  {
2835  if ((var = getVariable(st, argv[1] + 1)) == NULL)
2836  {
2837  fprintf(stderr, "%s: undefined variable \"%s\"\n",
2838  argv[0], argv[1]);
2839  return false;
2840  }
2841  usec = atoi(var);
2842  }
2843  else
2844  usec = atoi(argv[1]);
2845 
2846  if (argc > 2)
2847  {
2848  if (pg_strcasecmp(argv[2], "ms") == 0)
2849  usec *= 1000;
2850  else if (pg_strcasecmp(argv[2], "s") == 0)
2851  usec *= 1000000;
2852  }
2853  else
2854  usec *= 1000000;
2855 
2856  *usecs = usec;
2857  return true;
2858 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1255
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define fprintf
Definition: port.h:196

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
instr_time now 
)
static

Definition at line 3297 of file pgbench.c.

References Command::argc, Command::argv, Assert, CState::command, commandFailed(), ParsedScript::commands, conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), CState::cstack, CSTATE_ABORTED, CSTATE_END_COMMAND, CSTATE_SLEEP, evaluateExpr(), evaluateSleep(), Command::expr, fprintf, i, CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT_LAZY, INSTR_TIME_SET_ZERO, Command::meta, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_IF, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, putVariableValue(), runShellCommand(), CState::sleep_until, Command::type, CState::use_file, and valueTruth().

Referenced by advanceConnectionState().

3298 {
3299  Command *command = sql_script[st->use_file].commands[st->command];
3300  int argc;
3301  char **argv;
3302 
3303  Assert(command != NULL && command->type == META_COMMAND);
3304 
3305  argc = command->argc;
3306  argv = command->argv;
3307 
3308  if (debug)
3309  {
3310  fprintf(stderr, "client %d executing \\%s", st->id, argv[0]);
3311  for (int i = 1; i < argc; i++)
3312  fprintf(stderr, " %s", argv[i]);
3313  fprintf(stderr, "\n");
3314  }
3315 
3316  if (command->meta == META_SLEEP)
3317  {
3318  int usec;
3319 
3320  /*
3321  * A \sleep doesn't execute anything, we just get the delay from the
3322  * argument, and enter the CSTATE_SLEEP state. (The per-command
3323  * latency will be recorded in CSTATE_SLEEP state, not here, after the
3324  * delay has elapsed.)
3325  */
3326  if (!evaluateSleep(st, argc, argv, &usec))
3327  {
3328  commandFailed(st, "sleep", "execution of meta-command failed");
3329  return CSTATE_ABORTED;
3330  }
3331 
3333  st->sleep_until = INSTR_TIME_GET_MICROSEC(*now) + usec;
3334  return CSTATE_SLEEP;
3335  }
3336  else if (command->meta == META_SET)
3337  {
3338  PgBenchExpr *expr = command->expr;
3339  PgBenchValue result;
3340 
3341  if (!evaluateExpr(st, expr, &result))
3342  {
3343  commandFailed(st, argv[0], "evaluation of meta-command failed");
3344  return CSTATE_ABORTED;
3345  }
3346 
3347  if (!putVariableValue(st, argv[0], argv[1], &result))
3348  {
3349  commandFailed(st, "set", "assignment of meta-command failed");
3350  return CSTATE_ABORTED;
3351  }
3352  }
3353  else if (command->meta == META_IF)
3354  {
3355  /* backslash commands with an expression to evaluate */
3356  PgBenchExpr *expr = command->expr;
3357  PgBenchValue result;
3358  bool cond;
3359 
3360  if (!evaluateExpr(st, expr, &result))
3361  {
3362  commandFailed(st, argv[0], "evaluation of meta-command failed");
3363  return CSTATE_ABORTED;
3364  }
3365 
3366  cond = valueTruth(&result);
3368  }
3369  else if (command->meta == META_ELIF)
3370  {
3371  /* backslash commands with an expression to evaluate */
3372  PgBenchExpr *expr = command->expr;
3373  PgBenchValue result;
3374  bool cond;
3375 
3377  {
3378  /* elif after executed block, skip eval and wait for endif. */
3380  return CSTATE_END_COMMAND;
3381  }
3382 
3383  if (!evaluateExpr(st, expr, &result))
3384  {
3385  commandFailed(st, argv[0], "evaluation of meta-command failed");
3386  return CSTATE_ABORTED;
3387  }
3388 
3389  cond = valueTruth(&result);
3392  }
3393  else if (command->meta == META_ELSE)
3394  {
3395  switch (conditional_stack_peek(st->cstack))
3396  {
3397  case IFSTATE_TRUE:
3399  break;
3400  case IFSTATE_FALSE: /* inconsistent if active */
3401  case IFSTATE_IGNORED: /* inconsistent if active */
3402  case IFSTATE_NONE: /* else without if */
3403  case IFSTATE_ELSE_TRUE: /* else after else */
3404  case IFSTATE_ELSE_FALSE: /* else after else */
3405  default:
3406  /* dead code if conditional check is ok */
3407  Assert(false);
3408  }
3409  }
3410  else if (command->meta == META_ENDIF)
3411  {
3414  }
3415  else if (command->meta == META_SETSHELL)
3416  {
3417  if (!runShellCommand(st, argv[1], argv + 2, argc - 2))
3418  {
3419  commandFailed(st, "setshell", "execution of meta-command failed");
3420  return CSTATE_ABORTED;
3421  }
3422  }
3423  else if (command->meta == META_SHELL)
3424  {
3425  if (!runShellCommand(st, NULL, argv + 1, argc - 1))
3426  {
3427  commandFailed(st, "shell", "execution of meta-command failed");
3428  return CSTATE_ABORTED;
3429  }
3430  }
3431 
3432  /*
3433  * executing the expression or shell command might have taken a
3434  * non-negligible amount of time, so reset 'now'
3435  */
3437 
3438  return CSTATE_END_COMMAND;
3439 }
int type
Definition: pgbench.c:503
int id
Definition: pgbench.c:382
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:2604
PgBenchExpr * expr
Definition: pgbench.c:508
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
#define fprintf
Definition: port.h:196
char * argv[MAX_ARGS]
Definition: pgbench.c:506
ConditionalStack cstack
Definition: pgbench.c:384
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2413
#define META_COMMAND
Definition: pgbench.c:448
static int debug
Definition: pgbench.c:524
MetaCommand meta
Definition: pgbench.c:504
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:520
int argc
Definition: pgbench.c:505
int command
Definition: pgbench.c:393
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:2493
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
int64 sleep_until
Definition: pgbench.c:402
static bool evaluateSleep(CState *st, int argc, char **argv, int *usecs)
Definition: pgbench.c:2828
#define INSTR_TIME_SET_CURRENT_LAZY(t)
Definition: instr_time.h:253
#define Assert(condition)
Definition: c.h:732
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:205
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1625
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
Command ** commands
Definition: pgbench.c:516
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:118
int i
static bool putVariableValue(CState *st, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1458
int use_file
Definition: pgbench.c:392
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1532

◆ executeStatement()

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

Definition at line 1121 of file pgbench.c.

References fprintf, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), and PQresultStatus().

Referenced by initCreateFKeys(), initCreatePKeys(), initCreateTables(), initDropTables(), initGenerateData(), and initVacuum().

1122 {
1123  PGresult *res;
1124 
1125  res = PQexec(con, sql);
1126  if (PQresultStatus(res) != PGRES_COMMAND_OK)
1127  {
1128  fprintf(stderr, "%s", PQerrorMessage(con));
1129  exit(1);
1130  }
1131  PQclear(res);
1132 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6561
#define fprintf
Definition: port.h:196
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2693
void PQclear(PGresult *res)
Definition: fe-exec.c:695
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1940

◆ findBuiltin()

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

Definition at line 4694 of file pgbench.c.

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

Referenced by main().

4695 {
4696  int i,
4697  found = 0,
4698  len = strlen(name);
4699  const BuiltinScript *result = NULL;
4700 
4701  for (i = 0; i < lengthof(builtin_script); i++)
4702  {
4703  if (strncmp(builtin_script[i].name, name, len) == 0)
4704  {
4705  result = &builtin_script[i];
4706  found++;
4707  }
4708  }
4709 
4710  /* ok, unambiguous result */
4711  if (found == 1)
4712  return result;
4713 
4714  /* error cases */
4715  if (found == 0)
4716  fprintf(stderr, "no builtin script found for name \"%s\"\n", name);
4717  else /* found > 1 */
4718  fprintf(stderr,
4719  "ambiguous builtin name: %d builtin scripts found for prefix \"%s\"\n", found, name);
4720 
4722  exit(1);
4723 }
static void listAvailableScripts(void)
Definition: pgbench.c:4682
#define lengthof(array)
Definition: c.h:662
#define fprintf
Definition: port.h:196
static const BuiltinScript builtin_script[]
Definition: pgbench.c:534
const char * name
Definition: encode.c:521
int i

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 6236 of file pgbench.c.

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

6237 {
6238  if (st->con != NULL)
6239  {
6240  PQfinish(st->con);
6241  st->con = NULL;
6242  }
6243 }
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4063
PGconn * con
Definition: pgbench.c:381

◆ free_command()

static void free_command ( Command command)
static

Definition at line 4173 of file pgbench.c.

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

Referenced by ParseScript().

4174 {
4175  termPQExpBuffer(&command->lines);
4176  if (command->first_line)
4177  pg_free(command->first_line);
4178  for (int i = 0; i < command->argc; i++)
4179  pg_free(command->argv[i]);
4180  if (command->varprefix)
4181  pg_free(command->varprefix);
4182 
4183  /*
4184  * It should also free expr recursively, but this is currently not needed
4185  * as only gset commands (which do not have an expression) are freed.
4186  */
4187  pg_free(command);
4188 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
char * argv[MAX_ARGS]
Definition: pgbench.c:506
PQExpBufferData lines
Definition: pgbench.c:501
int argc
Definition: pgbench.c:505
char * varprefix
Definition: pgbench.c:507
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
char * first_line
Definition: pgbench.c:502

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 6410 of file pgbench.c.

References pg_free().

Referenced by setalarm(), and threadRun().

6411 {
6412  pg_free(sa);
6413 }
void pg_free(void *ptr)
Definition: fe_memutils.c:105

◆ getExponentialRand()

static int64 getExponentialRand ( RandomState random_state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 849 of file pgbench.c.

References Assert, pg_erand48(), and RandomState::xseed.

Referenced by evalStandardFunc().

851 {
852  double cut,
853  uniform,
854  rand;
855 
856  /* abort if wrong parameter, but must really be checked beforehand */
857  Assert(parameter > 0.0);
858  cut = exp(-parameter);
859  /* erand in [0, 1), uniform in (0, 1] */
860  uniform = 1.0 - pg_erand48(random_state->xseed);
861 
862  /*
863  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
864  */
865  Assert((1.0 - cut) != 0.0);
866  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
867  /* return int64 random number within between min and max */
868  return min + (int64) ((max - min + 1) * rand);
869 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:732
unsigned short xseed[3]
Definition: pgbench.c:288

◆ getGaussianRand()

static int64 getGaussianRand ( RandomState random_state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 873 of file pgbench.c.

References Assert, M_PI, MIN_GAUSSIAN_PARAM, pg_erand48(), and RandomState::xseed.

Referenced by evalStandardFunc().

875 {
876  double stdev;
877  double rand;
878 
879  /* abort if parameter is too low, but must really be checked beforehand */
880  Assert(parameter >= MIN_GAUSSIAN_PARAM);
881 
882  /*
883  * Get user specified random number from this loop, with -parameter <
884  * stdev <= parameter
885  *
886  * This loop is executed until the number is in the expected range.
887  *
888  * As the minimum parameter is 2.0, the probability of looping is low:
889  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
890  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
891  * the worst case. For a parameter value of 5.0, the looping probability
892  * is about e^{-5} * 2 / pi ~ 0.43%.
893  */
894  do
895  {
896  /*
897  * pg_erand48 generates [0,1), but for the basic version of the
898  * Box-Muller transform the two uniformly distributed random numbers
899  * are expected in (0, 1] (see
900  * https://en.wikipedia.org/wiki/Box-Muller_transform)
901  */
902  double rand1 = 1.0 - pg_erand48(random_state->xseed);
903  double rand2 = 1.0 - pg_erand48(random_state->xseed);
904 
905  /* Box-Muller basic form transform */
906  double var_sqrt = sqrt(-2.0 * log(rand1));
907 
908  stdev = var_sqrt * sin(2.0 * M_PI * rand2);
909 
910  /*
911  * we may try with cos, but there may be a bias induced if the
912  * previous value fails the test. To be on the safe side, let us try
913  * over.
914  */
915  }
916  while (stdev < -parameter || stdev >= parameter);
917 
918  /* stdev is in [-parameter, parameter), normalization to [0,1) */
919  rand = (stdev + parameter) / (parameter * 2.0);
920 
921  /* return int64 random number within between min and max */
922  return min + (int64) ((max - min + 1) * rand);
923 }
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:138
#define M_PI
Definition: pgbench.c:67
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:732
unsigned short xseed[3]
Definition: pgbench.c:288

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 999 of file pgbench.c.

References FNV_OFFSET_BASIS, FNV_PRIME, and i.

Referenced by evalStandardFunc().

1000 {
1001  int64 result;
1002  int i;
1003 
1004  result = FNV_OFFSET_BASIS ^ seed;
1005  for (i = 0; i < 8; ++i)
1006  {
1007  int32 octet = val & 0xff;
1008 
1009  val = val >> 8;
1010  result = result ^ octet;
1011  result = result * FNV_PRIME;
1012  }
1013 
1014  return result;
1015 }
#define FNV_PRIME
Definition: pgbench.c:77
#define FNV_OFFSET_BASIS
Definition: pgbench.c:78
signed int int32
Definition: c.h:346
int i
long val
Definition: informix.c:684

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1024 of file pgbench.c.

References MM2_MUL, MM2_MUL_TIMES_8, and MM2_ROT.

Referenced by evalStandardFunc().

1025 {
1026  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1027  uint64 k = (uint64) val;
1028 
1029  k *= MM2_MUL;
1030  k ^= k >> MM2_ROT;
1031  k *= MM2_MUL;
1032 
1033  result ^= k;
1034  result *= MM2_MUL;
1035 
1036  result ^= result >> MM2_ROT;
1037  result *= MM2_MUL;
1038  result ^= result >> MM2_ROT;
1039 
1040  return (int64) result;
1041 }
#define MM2_MUL_TIMES_8
Definition: pgbench.c:80
#define MM2_ROT
Definition: pgbench.c:81
long val
Definition: informix.c:684
#define MM2_MUL
Definition: pgbench.c:79

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2459 of file pgbench.c.

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

Referenced by process_backslash_command().

2460 {
2461  MetaCommand mc;
2462 
2463  if (cmd == NULL)
2464  mc = META_NONE;
2465  else if (pg_strcasecmp(cmd, "set") == 0)
2466  mc = META_SET;
2467  else if (pg_strcasecmp(cmd, "setshell") == 0)
2468  mc = META_SETSHELL;
2469  else if (pg_strcasecmp(cmd, "shell") == 0)
2470  mc = META_SHELL;
2471  else if (pg_strcasecmp(cmd, "sleep") == 0)
2472  mc = META_SLEEP;
2473  else if (pg_strcasecmp(cmd, "if") == 0)
2474  mc = META_IF;
2475  else if (pg_strcasecmp(cmd, "elif") == 0)
2476  mc = META_ELIF;
2477  else if (pg_strcasecmp(cmd, "else") == 0)
2478  mc = META_ELSE;
2479  else if (pg_strcasecmp(cmd, "endif") == 0)
2480  mc = META_ENDIF;
2481  else if (pg_strcasecmp(cmd, "gset") == 0)
2482  mc = META_GSET;
2483  else
2484  mc = META_NONE;
2485  return mc;
2486 }
MetaCommand
Definition: pgbench.c:456
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

◆ getPoissonRand()

static int64 getPoissonRand ( RandomState random_state,
double  center 
)
static

Definition at line 933 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by advanceConnectionState().

934 {
935  /*
936  * Use inverse transform sampling to generate a value > 0, such that the
937  * expected (i.e. average) value is the given argument.
938  */
939  double uniform;
940 
941  /* erand in [0, 1), uniform in (0, 1] */
942  uniform = 1.0 - pg_erand48(random_state->xseed);
943 
944  return (int64) (-log(uniform) * center + 0.5);
945 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:288

◆ getQueryParams()

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

Definition at line 1574 of file pgbench.c.

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

Referenced by sendCommand().

1575 {
1576  int i;
1577 
1578  for (i = 0; i < command->argc - 1; i++)
1579  params[i] = getVariable(st, command->argv[i + 1]);
1580 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1255
char * argv[MAX_ARGS]
Definition: pgbench.c:506
int argc
Definition: pgbench.c:505
int i

◆ getrand()

static int64 getrand ( RandomState random_state,
int64  min,
int64  max 
)
static

Definition at line 829 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by chooseScript(), and evalStandardFunc().

830 {
831  /*
832  * Odd coding is so that min and max have approximately the same chance of
833  * being selected as do numbers between them.
834  *
835  * pg_erand48() is thread-safe and concurrent, which is why we use it
836  * rather than random(), which in glibc is non-reentrant, and therefore
837  * protected by a mutex, and therefore a bottleneck on machines with many
838  * CPUs.
839  */
840  return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
841 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:288

◆ getVariable()

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

Definition at line 1255 of file pgbench.c.

References Assert, PgBenchValue::bval, PgBenchValue::dval, INT64_FORMAT, PgBenchValue::ival, lookupVariable(), 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().

1256 {
1257  Variable *var;
1258  char stringform[64];
1259 
1260  var = lookupVariable(st, name);
1261  if (var == NULL)
1262  return NULL; /* not found */
1263 
1264  if (var->svalue)
1265  return var->svalue; /* we have it in string form */
1266 
1267  /* We need to produce a string equivalent of the value */
1268  Assert(var->value.type != PGBT_NO_VALUE);
1269  if (var->value.type == PGBT_NULL)
1270  snprintf(stringform, sizeof(stringform), "NULL");
1271  else if (var->value.type == PGBT_BOOLEAN)
1272  snprintf(stringform, sizeof(stringform),
1273  "%s", var->value.u.bval ? "true" : "false");
1274  else if (var->value.type == PGBT_INT)
1275  snprintf(stringform, sizeof(stringform),
1276  INT64_FORMAT, var->value.u.ival);
1277  else if (var->value.type == PGBT_DOUBLE)
1278  snprintf(stringform, sizeof(stringform),
1279  "%.*g", DBL_DIG, var->value.u.dval);
1280  else /* internal error, unexpected type */
1281  Assert(0);
1282  var->svalue = pg_strdup(stringform);
1283  return var->svalue;
1284 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1228
union PgBenchValue::@39 u
char * svalue
Definition: pgbench.c:247
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
PgBenchValue value
Definition: pgbench.c:248
double dval
Definition: pgbench.h:50
#define Assert(condition)
Definition: c.h:732
#define INT64_FORMAT
Definition: c.h:400
const char * name
Definition: encode.c:521
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49
#define snprintf
Definition: port.h:192

◆ getZipfianRand()

static int64 getZipfianRand ( RandomState random_state,
int64  min,
int64  max,
double  s 
)
static

Definition at line 985 of file pgbench.c.

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

Referenced by evalStandardFunc().

986 {
987  int64 n = max - min + 1;
988 
989  /* abort if parameter is invalid */
991 
992  return min - 1 + computeIterativeZipfian(random_state, n, s);
993 }
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:141
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:140
#define Assert(condition)
Definition: c.h:732
static int64 computeIterativeZipfian(RandomState *random_state, int64 n, double s)
Definition: pgbench.c:955

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 6252 of file pgbench.c.

Referenced by setalarm().

6253 {
6254  timer_exceeded = true;
6255 }
volatile bool timer_exceeded
Definition: pgbench.c:232

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 3881 of file pgbench.c.

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

Referenced by runInitSteps().

3882 {
3883  static const char *const DDLKEYs[] = {
3884  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
3885  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
3886  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
3887  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
3888  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
3889  };
3890  int i;
3891 
3892  fprintf(stderr, "creating foreign keys...\n");
3893  for (i = 0; i < lengthof(DDLKEYs); i++)
3894  {
3895  executeStatement(con, DDLKEYs[i]);
3896  }
3897 }
#define lengthof(array)
Definition: c.h:662
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1121
int i

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 3846 of file pgbench.c.

References executeStatement(), fprintf, i, lengthof, PQescapeIdentifier(), PQfreemem(), snprintf, and strlcpy().

Referenced by runInitSteps().

3847 {
3848  static const char *const DDLINDEXes[] = {
3849  "alter table pgbench_branches add primary key (bid)",
3850  "alter table pgbench_tellers add primary key (tid)",
3851  "alter table pgbench_accounts add primary key (aid)"
3852  };
3853  int i;
3854 
3855  fprintf(stderr, "creating primary keys...\n");
3856  for (i = 0; i < lengthof(DDLINDEXes); i++)
3857  {
3858  char buffer[256];
3859 
3860  strlcpy(buffer, DDLINDEXes[i], sizeof(buffer));
3861 
3862  if (index_tablespace != NULL)
3863  {
3864  char *escape_tablespace;
3865 
3866  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
3867  strlen(index_tablespace));
3868  snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer),
3869  " using index tablespace %s", escape_tablespace);
3870  PQfreemem(escape_tablespace);
3871  }
3872 
3873  executeStatement(con, buffer);
3874  }
3875 }
#define lengthof(array)
Definition: c.h:662
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1121
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3571
char * index_tablespace
Definition: pgbench.c:187
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
int i
#define snprintf
Definition: port.h:192
void PQfreemem(void *ptr)
Definition: fe-exec.c:3297

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 3608 of file pgbench.c.

References executeStatement(), fprintf, i, lengthof, PQescapeIdentifier(), PQfreemem(), SCALE_32BIT_THRESHOLD, and snprintf.

Referenced by runInitSteps().

3609 {
3610  /*
3611  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
3612  * fields in these table declarations were intended to comply with that.
3613  * The pgbench_accounts table complies with that because the "filler"
3614  * column is set to blank-padded empty string. But for all other tables
3615  * the columns default to NULL and so don't actually take any space. We
3616  * could fix that by giving them non-null default values. However, that
3617  * would completely break comparability of pgbench results with prior
3618  * versions. Since pgbench has never pretended to be fully TPC-B compliant
3619  * anyway, we stick with the historical behavior.
3620  */
3621  struct ddlinfo
3622  {
3623  const char *table; /* table name */
3624  const char *smcols; /* column decls if accountIDs are 32 bits */
3625  const char *bigcols; /* column decls if accountIDs are 64 bits */
3626  int declare_fillfactor;
3627  };
3628  static const struct ddlinfo DDLs[] = {
3629  {
3630  "pgbench_history",
3631  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
3632  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
3633  0
3634  },
3635  {
3636  "pgbench_tellers",
3637  "tid int not null,bid int,tbalance int,filler char(84)",
3638  "tid int not null,bid int,tbalance int,filler char(84)",
3639  1
3640  },
3641  {
3642  "pgbench_accounts",
3643  "aid int not null,bid int,abalance int,filler char(84)",
3644  "aid bigint not null,bid int,abalance int,filler char(84)",
3645  1
3646  },
3647  {
3648  "pgbench_branches",
3649  "bid int not null,bbalance int,filler char(88)",
3650  "bid int not null,bbalance int,filler char(88)",
3651  1
3652  }
3653  };
3654  int i;
3655 
3656  fprintf(stderr, "creating tables...\n");
3657 
3658  for (i = 0; i < lengthof(DDLs); i++)
3659  {
3660  char opts[256];
3661  char buffer[256];
3662  const struct ddlinfo *ddl = &DDLs[i];
3663  const char *cols;
3664 
3665  /* Construct new create table statement. */
3666  opts[0] = '\0';
3667  if (ddl->declare_fillfactor)
3668  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
3669  " with (fillfactor=%d)", fillfactor);
3670  if (tablespace != NULL)
3671  {
3672  char *escape_tablespace;
3673 
3674  escape_tablespace = PQescapeIdentifier(con, tablespace,
3675  strlen(tablespace));
3676  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
3677  " tablespace %s", escape_tablespace);
3678  PQfreemem(escape_tablespace);
3679  }
3680 
3681  cols = (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols;
3682 
3683  snprintf(buffer, sizeof(buffer), "create%s table %s(%s)%s",
3684  unlogged_tables ? " unlogged" : "",
3685  ddl->table, cols, opts);
3686 
3687  executeStatement(con, buffer);
3688  }
3689 }
int scale
Definition: pgbench.c:151
#define lengthof(array)
Definition: c.h:662
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1121
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:208
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3571
int fillfactor
Definition: pgbench.c:157
char * tablespace
Definition: pgbench.c:186
bool unlogged_tables
Definition: pgbench.c:162
int i
#define snprintf
Definition: port.h:192
void PQfreemem(void *ptr)
Definition: fe-exec.c:3297

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 3589 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

3590 {
3591  fprintf(stderr, "dropping old tables...\n");
3592 
3593  /*
3594  * We drop all the tables in one command, so that whether there are
3595  * foreign key dependencies or not doesn't matter.
3596  */
3597  executeStatement(con, "drop table if exists "
3598  "pgbench_accounts, "
3599  "pgbench_branches, "
3600  "pgbench_history, "
3601  "pgbench_tellers");
3602 }
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1121

◆ initGenerateData()

static void initGenerateData ( PGconn con)
static

Definition at line 3695 of file pgbench.c.

References executeStatement(), fprintf, i, INSTR_TIME_GET_DOUBLE, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, INT64_FORMAT, LOG_STEP_SECONDS, naccounts, nbranches, ntellers, PGRES_COPY_IN, PQclear(), PQendcopy(), PQerrorMessage(), PQexec(), PQputline(), PQresultStatus(), scale, and snprintf.

Referenced by runInitSteps().

3696 {
3697  char sql[256];
3698  PGresult *res;
3699  int i;
3700  int64 k;
3701 
3702  /* used to track elapsed time and estimate of the remaining time */
3703  instr_time start,
3704  diff;
3705  double elapsed_sec,
3706  remaining_sec;
3707  int log_interval = 1;
3708 
3709  fprintf(stderr, "generating data...\n");
3710 
3711  /*
3712  * we do all of this in one transaction to enable the backend's
3713  * data-loading optimizations
3714  */
3715  executeStatement(con, "begin");
3716 
3717  /*
3718  * truncate away any old data, in one command in case there are foreign
3719  * keys
3720  */
3721  executeStatement(con, "truncate table "
3722  "pgbench_accounts, "
3723  "pgbench_branches, "
3724  "pgbench_history, "
3725  "pgbench_tellers");
3726 
3727  /*
3728  * fill branches, tellers, accounts in that order in case foreign keys
3729  * already exist
3730  */
3731  for (i = 0; i < nbranches * scale; i++)
3732  {
3733  /* "filler" column defaults to NULL */
3734  snprintf(sql, sizeof(sql),
3735  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
3736  i + 1);
3737  executeStatement(con, sql);
3738  }
3739 
3740  for (i = 0; i < ntellers * scale; i++)
3741  {
3742  /* "filler" column defaults to NULL */
3743  snprintf(sql, sizeof(sql),
3744  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
3745  i + 1, i / ntellers + 1);
3746  executeStatement(con, sql);
3747  }
3748 
3749  /*
3750  * accounts is big enough to be worth using COPY and tracking runtime
3751  */
3752  res = PQexec(con, "copy pgbench_accounts from stdin");
3753  if (PQresultStatus(res) != PGRES_COPY_IN)
3754  {
3755  fprintf(stderr, "%s", PQerrorMessage(con));
3756  exit(1);
3757  }
3758  PQclear(res);
3759 
3760  INSTR_TIME_SET_CURRENT(start);
3761 
3762  for (k = 0; k < (int64) naccounts * scale; k++)
3763  {
3764  int64 j = k + 1;
3765 
3766  /* "filler" column defaults to blank padded empty string */
3767  snprintf(sql, sizeof(sql),
3768  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
3769  j, k / naccounts + 1, 0);
3770  if (PQputline(con, sql))
3771  {
3772  fprintf(stderr, "PQputline failed\n");
3773  exit(1);
3774  }
3775 
3776  /*
3777  * If we want to stick with the original logging, print a message each
3778  * 100k inserted rows.
3779  */
3780  if ((!use_quiet) && (j % 100000 == 0))
3781  {
3782  INSTR_TIME_SET_CURRENT(diff);
3783  INSTR_TIME_SUBTRACT(diff, start);
3784 
3785  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
3786  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
3787 
3788  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)\n",
3789  j, (int64) naccounts * scale,
3790  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
3791  elapsed_sec, remaining_sec);
3792  }
3793  /* let's not call the timing for each row, but only each 100 rows */
3794  else if (use_quiet && (j % 100 == 0))
3795  {
3796  INSTR_TIME_SET_CURRENT(diff);
3797  INSTR_TIME_SUBTRACT(diff, start);
3798 
3799  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
3800  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
3801 
3802  /* have we reached the next interval (or end)? */
3803  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
3804  {
3805  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)\n",
3806  j, (int64) naccounts * scale,
3807  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec);
3808 
3809  /* skip to the next interval */
3810  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
3811  }
3812  }
3813 
3814  }
3815  if (PQputline(con, "\\.\n"))
3816  {
3817  fprintf(stderr, "very last PQputline failed\n");
3818  exit(1);
3819  }
3820  if (PQendcopy(con))
3821  {
3822  fprintf(stderr, "PQendcopy failed\n");
3823  exit(1);
3824  }
3825 
3826  executeStatement(con, "commit");
3827 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6561
struct timeval instr_time
Definition: instr_time.h:150
int scale
Definition: pgbench.c:151
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
#define LOG_STEP_SECONDS
Definition: pgbench.c:135
#define fprintf
Definition: port.h:196
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2693
bool use_quiet
Definition: pgbench.c:211
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1121
int PQputline(PGconn *conn, const char *s)
Definition: fe-exec.c:2586
#define nbranches
Definition: pgbench.c:196
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
#define ntellers
Definition: pgbench.c:198
#define naccounts
Definition: pgbench.c:199
void PQclear(PGresult *res)
Definition: fe-exec.c:695
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2619
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
#define INT64_FORMAT
Definition: c.h:400
int i
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1940
#define snprintf
Definition: port.h:192

◆ initRandomState()

static void initRandomState ( RandomState random_state)
static

Definition at line 810 of file pgbench.c.

References pg_jrand48(), and RandomState::xseed.

Referenced by main().

811 {
812  random_state->xseed[0] = (unsigned short)
814  random_state->xseed[1] = (unsigned short)
816  random_state->xseed[2] = (unsigned short)
818 }
static RandomState base_random_sequence
Definition: pgbench.c:292
unsigned short xseed[3]
Definition: pgbench.c:288
long pg_jrand48(unsigned short xseed[3])
Definition: erand48.c:112

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1047 of file pgbench.c.

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

1048 {
1049  memset(ss, 0, sizeof(SimpleStats));
1050 }

◆ initStats()

static void initStats ( StatsData sd,
time_t  start_time 
)
static

Definition at line 1087 of file pgbench.c.

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

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

1088 {
1089  sd->start_time = start_time;
1090  sd->cnt = 0;
1091  sd->skipped = 0;
1092  initSimpleStats(&sd->latency);
1093  initSimpleStats(&sd->lag);
1094 }
time_t start_time
Definition: pgbench.c:275
SimpleStats lag
Definition: pgbench.c:280
SimpleStats latency
Definition: pgbench.c:279
static time_t start_time
Definition: pg_ctl.c:99
int64 cnt
Definition: pgbench.c:276
int64 skipped
Definition: pgbench.c:277
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1047

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 3833 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

3834 {
3835  fprintf(stderr, "vacuuming...\n");
3836  executeStatement(con, "vacuum analyze pgbench_branches");
3837  executeStatement(con, "vacuum analyze pgbench_tellers");
3838  executeStatement(con, "vacuum analyze pgbench_accounts");
3839  executeStatement(con, "vacuum analyze pgbench_history");
3840 }
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1121

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 669 of file pgbench.c.

References generate_unaccent_rules::str.

Referenced by makeVariableValue().

670 {
671  const char *ptr = str;
672 
673  /* skip leading spaces; cast is consistent with strtoint64 */
674  while (*ptr && isspace((unsigned char) *ptr))
675  ptr++;
676 
677  /* skip sign */
678  if (*ptr == '+' || *ptr == '-')
679  ptr++;
680 
681  /* at least one digit */
682  if (*ptr && !isdigit((unsigned char) *ptr))
683  return false;
684 
685  /* eat all digits */
686  while (*ptr && isdigit((unsigned char) *ptr))
687  ptr++;
688 
689  /* must have reached end of string */
690  return *ptr == '\0';
691 }

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 1726 of file pgbench.c.

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

1727 {
1728  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
1729 }

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 4682 of file pgbench.c.

References fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

4683 {
4684  int i;
4685 
4686  fprintf(stderr, "Available builtin scripts:\n");
4687  for (i = 0; i < lengthof(builtin_script); i++)
4688  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
4689  fprintf(stderr, "\n");
4690 }
#define lengthof(array)
Definition: c.h:662
#define fprintf
Definition: port.h:196
static const BuiltinScript builtin_script[]
Definition: pgbench.c:534
const char * name
Definition: encode.c:521
int i

◆ lookupCreateVariable()

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

Definition at line 1389 of file pgbench.c.

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

Referenced by putVariable(), and putVariableValue().

1390 {
1391  Variable *var;
1392 
1393  var = lookupVariable(st, name);
1394  if (var == NULL)
1395  {
1396  Variable *newvars;
1397 
1398  /*
1399  * Check for the name only when declaring a new variable to avoid
1400  * overhead.
1401  */
1402  if (!valid_variable_name(name))
1403  {
1404  fprintf(stderr, "%s: invalid variable name: \"%s\"\n",
1405  context, name);
1406  return NULL;
1407  }
1408 
1409  /* Create variable at the end of the array */
1410  if (st->variables)
1411  newvars = (Variable *) pg_realloc(st->variables,
1412  (st->nvariables + 1) * sizeof(Variable));
1413  else
1414  newvars = (Variable *) pg_malloc(sizeof(Variable));
1415 
1416  st->variables = newvars;
1417 
1418  var = &newvars[st->nvariables];
1419 
1420  var->name = pg_strdup(name);
1421  var->svalue = NULL;
1422  /* caller is expected to initialize remaining fields */
1423 
1424  st->nvariables++;
1425  /* we don't re-sort the array till we have to */
1426  st->vars_sorted = false;
1427  }
1428 
1429  return var;
1430 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1228
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * name
Definition: pgbench.c:246
#define fprintf
Definition: port.h:196
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1362
Variable * variables
Definition: pgbench.c:396
bool vars_sorted
Definition: pgbench.c:398
char * svalue
Definition: pgbench.c:247
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
const char * name
Definition: encode.c:521
int nvariables
Definition: pgbench.c:397

◆ lookupVariable()

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

Definition at line 1228 of file pgbench.c.

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

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

1229 {
1230  Variable key;
1231 
1232  /* On some versions of Solaris, bsearch of zero items dumps core */
1233  if (st->nvariables <= 0)
1234  return NULL;
1235 
1236  /* Sort if we have to */
1237  if (!st->vars_sorted)
1238  {
1239  qsort((void *) st->variables, st->nvariables, sizeof(Variable),
1241  st->vars_sorted = true;
1242  }
1243 
1244  /* Now we can search */
1245  key.name = name;
1246  return (Variable *) bsearch((void *) &key,
1247  (void *) st->variables,
1248  st->nvariables,
1249  sizeof(Variable),
1251 }
char * name
Definition: pgbench.c:246
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:1220
Variable * variables
Definition: pgbench.c:396
bool vars_sorted
Definition: pgbench.c:398
const char * name
Definition: encode.c:521
int nvariables
Definition: pgbench.c:397
#define qsort(a, b, c, d)
Definition: port.h:492

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 5087 of file pgbench.c.

References _, Assert, checkInitSteps(), StatsData::cnt, ParsedScript::commands, conditional_stack_create(), TState::conn_time, CONNECTION_BAD, CState::cstack, CSTATE_ABORTED, DEFAULT_INIT_STEPS, DEFAULT_NXACTS, BuiltinScript::desc, disconnect_all(), doConnect(), ERRCODE_UNDEFINED_TABLE, findBuiltin(), fprintf, get_progname(), getopt_long(), i, CState::id, initRandomState(), initStats(), INSTR_TIME_ADD, INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SET_ZERO, INSTR_TIME_SUBTRACT, INVALID_THREAD, StatsData::lag, StatsData::latency, TState::latency_late, listAvailableScripts(), TState::logfile, login, lookupVariable(), mergeSimpleStats(), Variable::name, BuiltinScript::name, nclients, no_argument, TState::nstate, nthreads, NUM_QUERYMODE, num_scripts, CState::nvariables, optarg, optind, parseScriptWeight(), PG_DIAG_SQLSTATE, pg_free(), pg_jrand48(), pg_logging_init(), pg_malloc(), pg_malloc0(), pg_realloc(), pg_strdup(), PGBT_NO_VALUE, PGRES_TUPLES_OK, postprocess_sql_command(), PQclear(), PQdb(), PQerrorMessage(), PQexec(), PQfinish(), PQgetvalue(), PQresultErrorField(), PQresultStatus(), PQstatus(), printf, printResults(), process_builtin(), process_file(), putVariable(), putVariableInt(), putVariableValue(), required_argument, runInitSteps(), BuiltinScript::script, set_random_seed(), setalarm(), StatsData::skipped, SQL_COMMAND, start_time, TState::start_time, CState::state, TState::state, TState::stats, strerror, Variable::svalue, TState::thread, threadRun(), TState::tid, tryExecuteStatement(), TState::ts_choose_rs, TState::ts_sample_rs, TState::ts_throttle_rs, PgBenchValue::type, generate_unaccent_rules::type, usage(), Variable::value, CState::variables, ParsedScript::weight, and RandomState::xseed.

5088 {
5089  static struct option long_options[] = {
5090  /* systematic long/short named options */
5091  {"builtin", required_argument, NULL, 'b'},
5092  {"client", required_argument, NULL, 'c'},
5093  {"connect", no_argument, NULL, 'C'},
5094  {"debug", no_argument, NULL, 'd'},
5095  {"define", required_argument, NULL, 'D'},
5096  {"file", required_argument, NULL, 'f'},
5097  {"fillfactor", required_argument, NULL, 'F'},
5098  {"host", required_argument, NULL, 'h'},
5099  {"initialize", no_argument, NULL, 'i'},
5100  {"init-steps", required_argument, NULL, 'I'},
5101  {"jobs", required_argument, NULL, 'j'},
5102  {"log", no_argument, NULL, 'l'},
5103  {"latency-limit", required_argument, NULL, 'L'},
5104  {"no-vacuum", no_argument, NULL, 'n'},
5105  {"port", required_argument, NULL, 'p'},
5106  {"progress", required_argument, NULL, 'P'},
5107  {"protocol", required_argument, NULL, 'M'},
5108  {"quiet", no_argument, NULL, 'q'},
5109  {"report-latencies", no_argument, NULL, 'r'},
5110  {"rate", required_argument, NULL, 'R'},
5111  {"scale", required_argument, NULL, 's'},
5112  {"select-only", no_argument, NULL, 'S'},
5113  {"skip-some-updates", no_argument, NULL, 'N'},
5114  {"time", required_argument, NULL, 'T'},
5115  {"transactions", required_argument, NULL, 't'},
5116  {"username", required_argument, NULL, 'U'},
5117  {"vacuum-all", no_argument, NULL, 'v'},
5118  /* long-named only options */
5119  {"unlogged-tables", no_argument, NULL, 1},
5120  {"tablespace", required_argument, NULL, 2},
5121  {"index-tablespace", required_argument, NULL, 3},
5122  {"sampling-rate", required_argument, NULL, 4},
5123  {"aggregate-interval", required_argument, NULL, 5},
5124  {"progress-timestamp", no_argument, NULL, 6},
5125  {"log-prefix", required_argument, NULL, 7},
5126  {"foreign-keys", no_argument, NULL, 8},
5127  {"random-seed", required_argument, NULL, 9},
5128  {"show-script", required_argument, NULL, 10},
5129  {NULL, 0, NULL, 0}
5130  };
5131 
5132  int c;
5133  bool is_init_mode = false; /* initialize mode? */
5134  char *initialize_steps = NULL;
5135  bool foreign_keys = false;
5136  bool is_no_vacuum = false;
5137  bool do_vacuum_accounts = false; /* vacuum accounts table? */
5138  int optindex;
5139  bool scale_given = false;
5140 
5141  bool benchmarking_option_set = false;
5142  bool initialization_option_set = false;
5143  bool internal_script_used = false;
5144 
5145  CState *state; /* status of clients */
5146  TState *threads; /* array of thread */
5147 
5148  instr_time start_time; /* start up time */
5149  instr_time total_time;
5150  instr_time conn_total_time;
5151  int64 latency_late = 0;
5152  StatsData stats;
5153  int weight;
5154 
5155  int i;
5156  int nclients_dealt;
5157 
5158 #ifdef HAVE_GETRLIMIT
5159  struct rlimit rlim;
5160 #endif
5161 
5162  PGconn *con;
5163  PGresult *res;
5164  char *env;
5165 
5166  int exit_code = 0;
5167 
5168  pg_logging_init(argv[0]);
5169  progname = get_progname(argv[0]);
5170 
5171  if (argc > 1)
5172  {
5173  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
5174  {
5175  usage();
5176  exit(0);
5177  }
5178  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
5179  {
5180  puts("pgbench (PostgreSQL) " PG_VERSION);
5181  exit(0);
5182  }
5183  }
5184 
5185  if ((env = getenv("PGHOST")) != NULL && *env != '\0')
5186  pghost = env;
5187  if ((env = getenv("PGPORT")) != NULL && *env != '\0')
5188  pgport = env;
5189  else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
5190  login = env;
5191 
5192  state = (CState *) pg_malloc0(sizeof(CState));
5193 
5194  /* set random seed early, because it may be used while parsing scripts. */
5195  if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
5196  {
5197  fprintf(stderr, "error while setting random seed from PGBENCH_RANDOM_SEED environment variable\n");
5198  exit(1);
5199  }
5200 
5201  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)
5202  {
5203  char *script;
5204 
5205  switch (c)
5206  {
5207  case 'i':
5208  is_init_mode = true;
5209  break;
5210  case 'I':
5211  if (initialize_steps)
5212  pg_free(initialize_steps);
5213  initialize_steps = pg_strdup(optarg);
5214  checkInitSteps(initialize_steps);
5215  initialization_option_set = true;
5216  break;
5217  case 'h':
5218  pghost = pg_strdup(optarg);
5219  break;
5220  case 'n':
5221  is_no_vacuum = true;
5222  break;
5223  case 'v':
5224  benchmarking_option_set = true;
5225  do_vacuum_accounts = true;
5226  break;
5227  case 'p':
5228  pgport = pg_strdup(optarg);
5229  break;
5230  case 'd':
5231  debug++;
5232  break;
5233  case 'c':
5234  benchmarking_option_set = true;
5235  nclients = atoi(optarg);
5236  if (nclients <= 0)
5237  {
5238  fprintf(stderr, "invalid number of clients: \"%s\"\n",
5239  optarg);
5240  exit(1);
5241  }
5242 #ifdef HAVE_GETRLIMIT
5243 #ifdef RLIMIT_NOFILE /* most platforms use RLIMIT_NOFILE */
5244  if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
5245 #else /* but BSD doesn't ... */
5246  if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
5247 #endif /* RLIMIT_NOFILE */
5248  {
5249  fprintf(stderr, "getrlimit failed: %s\n", strerror(errno));
5250  exit(1);
5251  }
5252  if (rlim.rlim_cur < nclients + 3)
5253  {
5254  fprintf(stderr, "need at least %d open files, but system limit is %ld\n",
5255  nclients + 3, (long) rlim.rlim_cur);
5256  fprintf(stderr, "Reduce number of clients, or use limit/ulimit to increase the system limit.\n");
5257  exit(1);
5258  }
5259 #endif /* HAVE_GETRLIMIT */
5260  break;
5261  case 'j': /* jobs */
5262  benchmarking_option_set = true;
5263  nthreads = atoi(optarg);
5264  if (nthreads <= 0)
5265  {
5266  fprintf(stderr, "invalid number of threads: \"%s\"\n",
5267  optarg);
5268  exit(1);
5269  }
5270 #ifndef ENABLE_THREAD_SAFETY
5271  if (nthreads != 1)
5272  {
5273  fprintf(stderr, "threads are not supported on this platform; use -j1\n");
5274  exit(1);
5275  }
5276 #endif /* !ENABLE_THREAD_SAFETY */
5277  break;
5278  case 'C':
5279  benchmarking_option_set = true;
5280  is_connect = true;
5281  break;
5282  case 'r':
5283  benchmarking_option_set = true;
5284  report_per_command = true;
5285  break;
5286  case 's':
5287  scale_given = true;
5288  scale = atoi(optarg);
5289  if (scale <= 0)
5290  {
5291  fprintf(stderr, "invalid scaling factor: \"%s\"\n", optarg);
5292  exit(1);
5293  }
5294  break;
5295  case 't':
5296  benchmarking_option_set = true;
5297  nxacts = atoi(optarg);
5298  if (nxacts <= 0)
5299  {
5300  fprintf(stderr, "invalid number of transactions: \"%s\"\n",
5301  optarg);
5302  exit(1);
5303  }
5304  break;
5305  case 'T':
5306  benchmarking_option_set = true;
5307  duration = atoi(optarg);
5308  if (duration <= 0)
5309  {
5310  fprintf(stderr, "invalid duration: \"%s\"\n", optarg);
5311  exit(1);
5312  }
5313  break;
5314  case 'U':
5315  login = pg_strdup(optarg);
5316  break;
5317  case 'l':
5318  benchmarking_option_set = true;
5319  use_log = true;
5320  break;
5321  case 'q':
5322  initialization_option_set = true;
5323  use_quiet = true;
5324  break;
5325  case 'b':
5326  if (strcmp(optarg, "list") == 0)
5327  {
5329  exit(0);
5330  }
5331  weight = parseScriptWeight(optarg, &script);
5332  process_builtin(findBuiltin(script), weight);
5333  benchmarking_option_set = true;
5334  internal_script_used = true;
5335  break;
5336  case 'S':
5337  process_builtin(findBuiltin("select-only"), 1);
5338  benchmarking_option_set = true;
5339  internal_script_used = true;
5340  break;
5341  case 'N':
5342  process_builtin(findBuiltin("simple-update"), 1);
5343  benchmarking_option_set = true;
5344  internal_script_used = true;
5345  break;
5346  case 'f':
5347  weight = parseScriptWeight(optarg, &script);
5348  process_file(script, weight);
5349  benchmarking_option_set = true;
5350  break;
5351  case 'D':
5352  {
5353  char *p;
5354 
5355  benchmarking_option_set = true;
5356 
5357  if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
5358  {
5359  fprintf(stderr, "invalid variable definition: \"%s\"\n",
5360  optarg);
5361  exit(1);
5362  }
5363 
5364  *p++ = '\0';
5365  if (!putVariable(&state[0], "option", optarg, p))
5366  exit(1);
5367  }
5368  break;
5369  case 'F':
5370  initialization_option_set = true;
5371  fillfactor = atoi(optarg);
5372  if (fillfactor < 10 || fillfactor > 100)
5373  {
5374  fprintf(stderr, "invalid fillfactor: \"%s\"\n", optarg);
5375  exit(1);
5376  }
5377  break;
5378  case 'M':
5379  benchmarking_option_set = true;
5380  for (querymode = 0; querymode < NUM_QUERYMODE; querymode++)
5381  if (strcmp(optarg, QUERYMODE[querymode]) == 0)
5382  break;
5383  if (querymode >= NUM_QUERYMODE)
5384  {
5385  fprintf(stderr, "invalid query mode (-M): \"%s\"\n",
5386  optarg);
5387  exit(1);
5388  }
5389  break;
5390  case 'P':
5391  benchmarking_option_set = true;
5392  progress = atoi(optarg);
5393  if (progress <= 0)
5394  {
5395  fprintf(stderr, "invalid thread progress delay: \"%s\"\n",
5396  optarg);
5397  exit(1);
5398  }
5399  break;
5400  case 'R':
5401  {
5402  /* get a double from the beginning of option value */
5403  double throttle_value = atof(optarg);
5404 
5405  benchmarking_option_set = true;
5406 
5407  if (throttle_value <= 0.0)
5408  {
5409  fprintf(stderr, "invalid rate limit: \"%s\"\n", optarg);
5410  exit(1);
5411  }
5412  /* Invert rate limit into per-transaction delay in usec */
5413  throttle_delay = 1000000.0 / throttle_value;
5414  }
5415  break;
5416  case 'L':
5417  {
5418  double limit_ms = atof(optarg);
5419 
5420  if (limit_ms <= 0.0)
5421  {
5422  fprintf(stderr, "invalid latency limit: \"%s\"\n",
5423  optarg);
5424  exit(1);
5425  }
5426  benchmarking_option_set = true;
5427  latency_limit = (int64) (limit_ms * 1000);
5428  }
5429  break;
5430  case 1: /* unlogged-tables */
5431  initialization_option_set = true;
5432  unlogged_tables = true;
5433  break;
5434  case 2: /* tablespace */
5435  initialization_option_set = true;
5437  break;
5438  case 3: /* index-tablespace */
5439  initialization_option_set = true;
5441  break;
5442  case 4: /* sampling-rate */
5443  benchmarking_option_set = true;
5444  sample_rate = atof(optarg);
5445  if (sample_rate <= 0.0 || sample_rate > 1.0)
5446  {
5447  fprintf(stderr, "invalid sampling rate: \"%s\"\n", optarg);
5448  exit(1);
5449  }
5450  break;
5451  case 5: /* aggregate-interval */
5452  benchmarking_option_set = true;
5453  agg_interval = atoi(optarg);
5454  if (agg_interval <= 0)
5455  {
5456  fprintf(stderr, "invalid number of seconds for aggregation: \"%s\"\n",
5457  optarg);
5458  exit(1);
5459  }
5460  break;
5461  case 6: /* progress-timestamp */
5462  progress_timestamp = true;
5463  benchmarking_option_set = true;
5464  break;
5465  case 7: /* log-prefix */
5466  benchmarking_option_set = true;
5468  break;
5469  case 8: /* foreign-keys */
5470  initialization_option_set = true;
5471  foreign_keys = true;
5472  break;
5473  case 9: /* random-seed */
5474  benchmarking_option_set = true;
5475  if (!set_random_seed(optarg))
5476  {
5477  fprintf(stderr, "error while setting random seed from --random-seed option\n");
5478  exit(1);
5479  }
5480  break;
5481  case 10: /* list */
5482  {
5483  const BuiltinScript *s = findBuiltin(optarg);
5484 
5485  fprintf(stderr, "-- %s: %s\n%s\n", s->name, s->desc, s->script);
5486  exit(0);
5487  }
5488  break;
5489  default:
5490  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
5491  exit(1);
5492  break;
5493  }
5494  }
5495 
5496  /* set default script if none */
5497  if (num_scripts == 0 && !is_init_mode)
5498  {
5499  process_builtin(findBuiltin("tpcb-like"), 1);
5500  benchmarking_option_set = true;
5501  internal_script_used = true;
5502  }
5503 
5504  /* complete SQL command initialization and compute total weight */
5505  for (i = 0; i < num_scripts; i++)
5506  {
5507  Command **commands = sql_script[i].commands;
5508 
5509  for (int j = 0; commands[j] != NULL; j++)
5510  if (commands[j]->type == SQL_COMMAND)
5511  postprocess_sql_command(commands[j]);
5512 
5513  /* cannot overflow: weight is 32b, total_weight 64b */
5515  }
5516 
5517  if (total_weight == 0 && !is_init_mode)
5518  {
5519  fprintf(stderr, "total script weight must not be zero\n");
5520  exit(1);
5521  }
5522 
5523  /* show per script stats if several scripts are used */
5524  if (num_scripts > 1)
5525  per_script_stats = true;
5526 
5527  /*
5528  * Don't need more threads than there are clients. (This is not merely an
5529  * optimization; throttle_delay is calculated incorrectly below if some
5530  * threads have no clients assigned to them.)
5531  */
5532  if (nthreads > nclients)
5533  nthreads = nclients;
5534 
5535  /*
5536  * Convert throttle_delay to a per-thread delay time. Note that this
5537  * might be a fractional number of usec, but that's OK, since it's just
5538  * the center of a Poisson distribution of delays.
5539  */
5541 
5542  if (argc > optind)
5543  dbName = argv[optind++];
5544  else
5545  {
5546  if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
5547  dbName = env;
5548  else if (login != NULL && *login != '\0')
5549  dbName = login;
5550  else
5551  dbName = "";
5552  }
5553 
5554  if (optind < argc)
5555  {
5556  fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
5557  progname, argv[optind]);
5558  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
5559  exit(1);
5560  }
5561 
5562  if (is_init_mode)
5563  {
5564  if (benchmarking_option_set)
5565  {
5566  fprintf(stderr, "some of the specified options cannot be used in initialization (-i) mode\n");
5567  exit(1);
5568  }
5569 
5570  if (initialize_steps == NULL)
5571  initialize_steps = pg_strdup(DEFAULT_INIT_STEPS);
5572 
5573  if (is_no_vacuum)
5574  {
5575  /* Remove any vacuum step in initialize_steps */
5576  char *p;
5577 
5578  while ((p = strchr(initialize_steps, 'v')) != NULL)
5579  *p = ' ';
5580  }
5581 
5582  if (foreign_keys)
5583  {
5584  /* Add 'f' to end of initialize_steps, if not already there */
5585  if (strchr(initialize_steps, 'f') == NULL)
5586  {
5587  initialize_steps = (char *)
5588  pg_realloc(initialize_steps,
5589  strlen(initialize_steps) + 2);
5590  strcat(initialize_steps, "f");
5591  }
5592  }
5593 
5594  runInitSteps(initialize_steps);
5595  exit(0);
5596  }
5597  else
5598  {
5599  if (initialization_option_set)
5600  {
5601  fprintf(stderr, "some of the specified options cannot be used in benchmarking mode\n");
5602  exit(1);
5603  }
5604  }
5605 
5606  if (nxacts > 0 && duration > 0)
5607  {
5608  fprintf(stderr, "specify either a number of transactions (-t) or a duration (-T), not both\n");
5609  exit(1);
5610  }
5611 
5612  /* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
5613  if (nxacts <= 0 && duration <= 0)
5615 
5616  /* --sampling-rate may be used only with -l */
5617  if (sample_rate > 0.0 && !use_log)
5618  {
5619  fprintf(stderr, "log sampling (--sampling-rate) is allowed only when logging transactions (-l)\n");
5620  exit(1);
5621  }
5622 
5623  /* --sampling-rate may not be used with --aggregate-interval */
5624  if (sample_rate > 0.0 && agg_interval > 0)
5625  {
5626  fprintf(stderr, "log sampling (--sampling-rate) and aggregation (--aggregate-interval) cannot be used at the same time\n");
5627  exit(1);
5628  }
5629 
5630  if (agg_interval > 0 && !use_log)
5631  {
5632  fprintf(stderr, "log aggregation is allowed only when actually logging transactions\n");
5633  exit(1);
5634  }
5635 
5636  if (!use_log && logfile_prefix)
5637  {
5638  fprintf(stderr, "log file prefix (--log-prefix) is allowed only when logging transactions (-l)\n");
5639  exit(1);
5640  }
5641 
5642  if (duration > 0 && agg_interval > duration)
5643  {
5644  fprintf(stderr, "number of seconds for aggregation (%d) must not be higher than test duration (%d)\n", agg_interval, duration);
5645  exit(1);
5646  }
5647 
5648  if (duration > 0 && agg_interval > 0 && duration % agg_interval != 0)
5649  {
5650  fprintf(stderr, "duration (%d) must be a multiple of aggregation interval (%d)\n", duration, agg_interval);
5651  exit(1);
5652  }
5653 
5654  if (progress_timestamp && progress == 0)
5655  {
5656  fprintf(stderr, "--progress-timestamp is allowed only under --progress\n");
5657  exit(1);
5658  }
5659 
5660  /*
5661  * save main process id in the global variable because process id will be
5662  * changed after fork.
5663  */
5664  main_pid = (int) getpid();
5665 
5666  if (nclients > 1)
5667  {
5668  state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
5669  memset(state + 1, 0, sizeof(CState) * (nclients - 1));
5670 
5671  /* copy any -D switch values to all clients */
5672  for (i = 1; i < nclients; i++)
5673  {
5674  int j;
5675 
5676  state[i].id = i;
5677  for (j = 0; j < state[0].nvariables; j++)
5678  {
5679  Variable *var = &state[0].variables[j];
5680 
5681  if (var->value.type != PGBT_NO_VALUE)
5682  {
5683  if (!putVariableValue(&state[i], "startup",
5684  var->name, &var->value))
5685  exit(1);
5686  }
5687  else
5688  {
5689  if (!putVariable(&state[i], "startup",
5690  var->name, var->svalue))
5691  exit(1);
5692  }
5693  }
5694  }
5695  }
5696 
5697  /* other CState initializations */
5698  for (i = 0; i < nclients; i++)
5699  {
5700  state[i].cstack = conditional_stack_create();
5701  initRandomState(&state[i].cs_func_rs);
5702  }
5703 
5704  if (debug)
5705  {
5706  if (duration <= 0)
5707  printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
5708  pghost, pgport, nclients, nxacts, dbName);
5709  else
5710  printf("pghost: %s pgport: %s nclients: %d duration: %d dbName: %s\n",
5711  pghost, pgport, nclients, duration, dbName);
5712  }
5713 
5714  /* opening connection... */
5715  con = doConnect();
5716  if (con == NULL)
5717  exit(1);
5718 
5719  if (PQstatus(con) == CONNECTION_BAD)
5720  {
5721  fprintf(stderr, "connection to database \"%s\" failed\n", dbName);
5722  fprintf(stderr, "%s", PQerrorMessage(con));
5723  exit(1);
5724  }
5725 
5726  if (internal_script_used)
5727  {
5728  /*
5729  * get the scaling factor that should be same as count(*) from
5730  * pgbench_branches if this is not a custom query
5731  */
5732  res = PQexec(con, "select count(*) from pgbench_branches");
5733  if (PQresultStatus(res) != PGRES_TUPLES_OK)
5734  {
5735  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5736 
5737  fprintf(stderr, "%s", PQerrorMessage(con));
5738  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5739  {
5740  fprintf(stderr, "Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\"\n", PQdb(con));
5741  }
5742 
5743  exit(1);
5744  }
5745  scale = atoi(PQgetvalue(res, 0, 0));
5746  if (scale < 0)
5747  {
5748  fprintf(stderr, "invalid count(*) from pgbench_branches: \"%s\"\n",
5749  PQgetvalue(res, 0, 0));
5750  exit(1);
5751  }
5752  PQclear(res);
5753 
5754  /* warn if we override user-given -s switch */
5755  if (scale_given)
5756  fprintf(stderr,
5757  "scale option ignored, using count from pgbench_branches table (%d)\n",
5758  scale);
5759  }
5760 
5761  /*
5762  * :scale variables normally get -s or database scale, but don't override
5763  * an explicit -D switch
5764  */
5765  if (lookupVariable(&state[0], "scale") == NULL)
5766  {
5767  for (i = 0; i < nclients; i++)
5768  {
5769  if (!putVariableInt(&state[i], "star